Re: [PATCH v12 6/9] LPC: Support the LPC host on Hip06/Hip07 with DT bindings

From: John Garry
Date: Wed Feb 14 2018 - 06:36:16 EST


Hi Dann,

+ */
+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.


+ 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


+ * 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