Re: [PATCH v12 6/9] LPC: Support the LPC host on Hip06/Hip07 with DT bindings
From: John Garry <hidden>
Date: 2018-02-14 11:36:12
Also in:
linux-acpi, linux-arch, linux-pci, lkml
Hi Dann,
quoted
+ */ +static int +hisilpc_target_in(struct hisilpc_dev *lpcdev, struct lpc_cycle_para *para, + unsigned long ptaddr, unsigned char *buf, + unsigned long opcnt) +{ + unsigned long cnt_per_trans; + unsigned int cmd_word; + unsigned int waitcnt; + int ret; + + if (!buf || !opcnt || !para || !para->csize || !lpcdev) + return -EINVAL; + + cmd_word = LPC_CMD_TYPE_IO | LPC_CMD_READ; + waitcnt = LPC_PEROP_WAITCNT; + if (!(para->opflags & FG_INCRADDR_LPC)) { + cmd_word |= LPC_CMD_SAMEADDR; + waitcnt = LPC_MAX_WAITCNT; + } + + ret = 0; + cnt_per_trans = (para->csize == 1) ? opcnt : para->csize; + for (; opcnt && !ret; cnt_per_trans = para->csize) { + unsigned long flags; + + /* whole operation must be atomic */ + spin_lock_irqsave(&lpcdev->cycle_lock, flags); + + writel_relaxed(cnt_per_trans, lpcdev->membase + LPC_REG_OP_LEN); + + writel_relaxed(cmd_word, lpcdev->membase + LPC_REG_CMD); + + writel_relaxed(ptaddr, lpcdev->membase + LPC_REG_ADDR); + + writel(LPC_START_WORK, lpcdev->membase + LPC_REG_START); + + /* whether the operation is finished */ + ret = wait_lpc_idle(lpcdev->membase, waitcnt); + if (!ret) { + opcnt -= cnt_per_trans;Do we need to check for an underflow here?
I think that underflow is ensured not to happen. Regardless, I find this code hard to follow myself, so I will rewrite a bit of this to make it more straightforward.
quoted
+ for (cnt_per_trans--; cnt_per_trans--; buf++) + *buf = readb_relaxed(lpcdev->membase + + LPC_REG_RDATA); + *buf = readb(lpcdev->membase + LPC_REG_RDATA); + } + + spin_unlock_irqrestore(&lpcdev->cycle_lock, flags); + } + + return ret; +} + +/* + * hisilpc_target_out - trigger a series of lpc cycles to write required + * data to target peripheral. + * @lpcdev: pointer to hisi lpc device + * @para: some parameters used to control the lpc I/O operations + * @ptaddr: the lpc I/O target port address + * @buf: where the data to be written is stored + * @opcnt: how many I/O operations required + * + * Only one byte data is read each I/O operation.s/read/written/ ?
Right
quoted
+ * Returns 0 on success, non-zero on fail. + * + */ +static int +hisilpc_target_out(struct hisilpc_dev *lpcdev, struct lpc_cycle_para *para, + unsigned long ptaddr, const unsigned char *buf, + unsigned long opcnt) +{ + unsigned long cnt_per_trans; + unsigned int cmd_word; + unsigned int waitcnt; + int ret; + + if (!buf || !opcnt || !para || !lpcdev) + return -EINVAL; + + /* default is increasing address */ + cmd_word = LPC_CMD_TYPE_IO | LPC_CMD_WRITE; + waitcnt = LPC_PEROP_WAITCNT; + if (!(para->opflags & FG_INCRADDR_LPC)) { + cmd_word |= LPC_CMD_SAMEADDR; + waitcnt = LPC_MAX_WAITCNT; + } + + ret = 0; + cnt_per_trans = (para->csize == 1) ? opcnt : para->csize; + for (; opcnt && !ret; cnt_per_trans = para->csize) { + unsigned long flags; + + spin_lock_irqsave(&lpcdev->cycle_lock, flags); + + writel_relaxed(cnt_per_trans, lpcdev->membase + LPC_REG_OP_LEN); + writel_relaxed(cmd_word, lpcdev->membase + LPC_REG_CMD); + writel_relaxed(ptaddr, lpcdev->membase + LPC_REG_ADDR); + + opcnt -= cnt_per_trans;Underflow check needed?
As above
-dann
Thanks, John