Loading drivers/dma/qcom/gpi.c +109 −35 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include <linux/atomic.h> Loading Loading @@ -447,7 +447,8 @@ struct gpi_dev { struct dentry *dentry; }; static struct gpi_dev *gpi_dev_dbg; static struct gpi_dev *gpi_dev_dbg[5]; static int arr_idx; struct reg_info { char *name; Loading Loading @@ -581,6 +582,7 @@ struct gpii { struct gpi_reg_table dbg_reg_table; bool reg_table_dump; u32 dbg_gpi_irq_cnt; bool unlock_tre_set; }; struct gpi_desc { Loading Loading @@ -1447,6 +1449,22 @@ static void gpi_process_qup_notif_event(struct gpii_chan *gpii_chan, client_info->cb_param); } /* free gpi_desc for the specified channel */ static void gpi_free_chan_desc(struct gpii_chan *gpii_chan) { struct virt_dma_desc *vd; struct gpi_desc *gpi_desc; unsigned long flags; spin_lock_irqsave(&gpii_chan->vc.lock, flags); vd = vchan_next_desc(&gpii_chan->vc); gpi_desc = to_gpi_desc(vd); list_del(&vd->node); spin_unlock_irqrestore(&gpii_chan->vc.lock, flags); kfree(gpi_desc); gpi_desc = NULL; } /* process DMA Immediate completion data events */ static void gpi_process_imed_data_event(struct gpii_chan *gpii_chan, struct immediate_data_event *imed_event) Loading @@ -1459,6 +1477,8 @@ static void gpi_process_imed_data_event(struct gpii_chan *gpii_chan, (ch_ring->el_size * imed_event->tre_index); struct msm_gpi_dma_async_tx_cb_param *tx_cb_param; unsigned long flags; u32 chid; struct gpii_chan *gpii_tx_chan = &gpii->gpii_chan[GPI_TX_CHAN]; /* * If channel not active don't process event but let Loading Loading @@ -1496,20 +1516,6 @@ static void gpi_process_imed_data_event(struct gpii_chan *gpii_chan, return; } gpi_desc = to_gpi_desc(vd); /* Event TR RP gen. don't match descriptor TR */ if (gpi_desc->wp != tre) { spin_unlock_irqrestore(&gpii_chan->vc.lock, flags); GPII_ERR(gpii, gpii_chan->chid, "EOT/EOB received for wrong TRE 0x%0llx != 0x%0llx\n", to_physical(ch_ring, gpi_desc->wp), to_physical(ch_ring, tre)); gpi_generate_cb_event(gpii_chan, MSM_GPI_QUP_EOT_DESC_MISMATCH, __LINE__); return; } list_del(&vd->node); spin_unlock_irqrestore(&gpii_chan->vc.lock, flags); Loading @@ -1525,6 +1531,35 @@ static void gpi_process_imed_data_event(struct gpii_chan *gpii_chan, /* make sure rp updates are immediately visible to all cores */ smp_wmb(); /* * If unlock tre is present, don't send transfer callback on * on IEOT, wait for unlock IEOB. Free the respective channel * descriptors. * If unlock is not present, IEOB indicates freeing the descriptor * and IEOT indicates channel transfer completion. */ chid = imed_event->chid; if (gpii->unlock_tre_set) { if (chid == GPI_RX_CHAN) { if (imed_event->code == MSM_GPI_TCE_EOT) goto gpi_free_desc; else if (imed_event->code == MSM_GPI_TCE_UNEXP_ERR) /* * In case of an error in a read transfer on a * shared se, unlock tre will not be processed * as channels go to bad state so tx desc should * be freed manually. */ gpi_free_chan_desc(gpii_tx_chan); else return; } else if (imed_event->code == MSM_GPI_TCE_EOT) { return; } } else if (imed_event->code == MSM_GPI_TCE_EOB) { goto gpi_free_desc; } tx_cb_param = vd->tx.callback_param; if (vd->tx.callback && tx_cb_param) { struct msm_gpi_tre *imed_tre = &tx_cb_param->imed_tre; Loading @@ -1540,7 +1575,9 @@ static void gpi_process_imed_data_event(struct gpii_chan *gpii_chan, tx_cb_param->status = imed_event->status; vd->tx.callback(tx_cb_param); } kfree(gpi_desc); gpi_free_desc: gpi_free_chan_desc(gpii_chan); } /* processing transfer completion events */ Loading @@ -1554,6 +1591,8 @@ static void gpi_process_xfer_compl_event(struct gpii_chan *gpii_chan, struct msm_gpi_dma_async_tx_cb_param *tx_cb_param; struct gpi_desc *gpi_desc; unsigned long flags; u32 chid; struct gpii_chan *gpii_tx_chan = &gpii->gpii_chan[GPI_TX_CHAN]; /* only process events on active channel */ if (unlikely(gpii_chan->pm_state != ACTIVE_STATE)) { Loading Loading @@ -1583,20 +1622,6 @@ static void gpi_process_xfer_compl_event(struct gpii_chan *gpii_chan, } gpi_desc = to_gpi_desc(vd); /* TRE Event generated didn't match descriptor's TRE */ if (gpi_desc->wp != ev_rp) { spin_unlock_irqrestore(&gpii_chan->vc.lock, flags); GPII_ERR(gpii, gpii_chan->chid, "EOT\EOB received for wrong TRE 0x%0llx != 0x%0llx\n", to_physical(ch_ring, gpi_desc->wp), to_physical(ch_ring, ev_rp)); gpi_generate_cb_event(gpii_chan, MSM_GPI_QUP_EOT_DESC_MISMATCH, __LINE__); return; } list_del(&vd->node); spin_unlock_irqrestore(&gpii_chan->vc.lock, flags); Loading @@ -1612,6 +1637,35 @@ static void gpi_process_xfer_compl_event(struct gpii_chan *gpii_chan, /* update must be visible to other cores */ smp_wmb(); /* * If unlock tre is present, don't send transfer callback on * on IEOT, wait for unlock IEOB. Free the respective channel * descriptors. * If unlock is not present, IEOB indicates freeing the descriptor * and IEOT indicates channel transfer completion. */ chid = compl_event->chid; if (gpii->unlock_tre_set) { if (chid == GPI_RX_CHAN) { if (compl_event->code == MSM_GPI_TCE_EOT) goto gpi_free_desc; else if (compl_event->code == MSM_GPI_TCE_UNEXP_ERR) /* * In case of an error in a read transfer on a * shared se, unlock tre will not be processed * as channels go to bad state so tx desc should * be freed manually. */ gpi_free_chan_desc(gpii_tx_chan); else return; } else if (compl_event->code == MSM_GPI_TCE_EOT) { return; } } else if (compl_event->code == MSM_GPI_TCE_EOB) { goto gpi_free_desc; } tx_cb_param = vd->tx.callback_param; if (vd->tx.callback && tx_cb_param) { GPII_VERB(gpii, gpii_chan->chid, Loading @@ -1623,7 +1677,10 @@ static void gpi_process_xfer_compl_event(struct gpii_chan *gpii_chan, tx_cb_param->status = compl_event->status; vd->tx.callback(tx_cb_param); } kfree(gpi_desc); gpi_free_desc: gpi_free_chan_desc(gpii_chan); } /* process all events */ Loading Loading @@ -2299,6 +2356,7 @@ void gpi_desc_free(struct virt_dma_desc *vd) struct gpi_desc *gpi_desc = to_gpi_desc(vd); kfree(gpi_desc); gpi_desc = NULL; } /* copy tre into transfer ring */ Loading @@ -2319,6 +2377,7 @@ struct dma_async_tx_descriptor *gpi_prep_slave_sg(struct dma_chan *chan, void *tre, *wp = NULL; const gfp_t gfp = GFP_ATOMIC; struct gpi_desc *gpi_desc; u32 tre_type; GPII_VERB(gpii, gpii_chan->chid, "enter\n"); Loading Loading @@ -2352,10 +2411,21 @@ struct dma_async_tx_descriptor *gpi_prep_slave_sg(struct dma_chan *chan, } /* copy each tre into transfer ring */ for_each_sg(sgl, sg, sg_len, i) for (j = 0, tre = sg_virt(sg); j < sg->length; for_each_sg(sgl, sg, sg_len, i) { tre = sg_virt(sg); /* Check if last tre is an unlock tre */ if (i == sg_len - 1) { tre_type = MSM_GPI_TRE_TYPE(((struct msm_gpi_tre *)tre)); gpii->unlock_tre_set = tre_type == MSM_GPI_TRE_UNLOCK ? true : false; } for (j = 0; j < sg->length; j += ch_ring->el_size, tre += ch_ring->el_size) gpi_queue_xfer(gpii, gpii_chan, tre, &wp); } /* set up the descriptor */ gpi_desc->db = ch_ring->wp; Loading Loading @@ -2807,7 +2877,7 @@ static int gpi_probe(struct platform_device *pdev) return -ENOMEM; /* debug purpose */ gpi_dev_dbg = gpi_dev; gpi_dev_dbg[arr_idx++] = gpi_dev; gpi_dev->dev = &pdev->dev; gpi_dev->klog_lvl = DEFAULT_KLOG_LVL; Loading Loading @@ -3018,6 +3088,10 @@ static int gpi_remove(struct platform_device *pdev) ipc_log_context_destroy(gpii->ilctxt); } for (i = 0; i < arr_idx; i++) gpi_dev_dbg[i] = NULL; arr_idx = 0; if (gpi_dev->ilctxt) ipc_log_context_destroy(gpi_dev->ilctxt); Loading drivers/i2c/busses/i2c-msm-geni.c +174 −44 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include <linux/msm_gpi.h> #include <linux/ioctl.h> #include <linux/pinctrl/consumer.h> #include <linux/slab.h> #define SE_I2C_TX_TRANS_LEN (0x26C) #define SE_I2C_RX_TRANS_LEN (0x270) Loading Loading @@ -73,12 +74,19 @@ #define I2C_TIMEOUT_MIN_USEC 500000 #define MAX_SE 20 enum i2c_se_mode { UNINITIALIZED, FIFO_SE_DMA, GSI_ONLY, }; struct dbg_buf_ctxt { void *virt_buf; void *map_buf; }; struct geni_i2c_dev { struct device *dev; void __iomem *base; Loading @@ -97,6 +105,8 @@ struct geni_i2c_dev { int clk_fld_idx; struct dma_chan *tx_c; struct dma_chan *rx_c; struct msm_gpi_tre lock_t; struct msm_gpi_tre unlock_t; struct msm_gpi_tre cfg0_t; struct msm_gpi_tre go_t; struct msm_gpi_tre tx_t; Loading @@ -115,9 +125,14 @@ struct geni_i2c_dev { enum i2c_se_mode se_mode; bool cmd_done; bool is_shared; u32 dbg_num; struct dbg_buf_ctxt *dbg_buf_ptr; bool is_le_vm; }; static struct geni_i2c_dev *gi2c_dev_dbg[MAX_SE]; static int arr_idx; struct geni_i2c_err_log { int err; const char *msg; Loading Loading @@ -207,12 +222,6 @@ static inline void qcom_geni_i2c_calc_timeout(struct geni_i2c_dev *gi2c) static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err) { if (gi2c->cur) GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "len:%d, slv-addr:0x%x, RD/WR:%d timeout:%u\n", gi2c->cur->len, gi2c->cur->addr, gi2c->cur->flags, gi2c->xfer_timeout); if (err == I2C_NACK || err == GENI_ABORT_DONE) { GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n", gi2c_log[err].msg); Loading @@ -221,8 +230,6 @@ static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err) GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "%s\n", gi2c_log[err].msg); } GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s: se-mode:%d\n", __func__, gi2c->se_mode); geni_se_dump_dbg_regs(&gi2c->i2c_rsc, gi2c->base, gi2c->ipcl); err_ret: gi2c->err = gi2c_log[err].err; Loading Loading @@ -275,7 +282,13 @@ static irqreturn_t geni_i2c_irq(int irq, void *dev) u32 dma = readl_relaxed(gi2c->base + SE_GENI_DMA_MODE_EN); struct i2c_msg *cur = gi2c->cur; if (!cur || (m_stat & M_CMD_FAILURE_EN) || if (!cur) { geni_se_dump_dbg_regs(&gi2c->i2c_rsc, gi2c->base, gi2c->ipcl); GENI_SE_ERR(gi2c->ipcl, false, gi2c->dev, "Spurious irq\n"); goto irqret; } if ((m_stat & M_CMD_FAILURE_EN) || (dm_rx_st & (DM_I2C_CB_ERR)) || (m_stat & M_CMD_CANCEL_EN) || (m_stat & M_CMD_ABORT_EN)) { Loading @@ -302,12 +315,6 @@ static irqreturn_t geni_i2c_irq(int irq, void *dev) goto irqret; } if (dma) { dev_dbg(gi2c->dev, "i2c dma tx:0x%x, dma rx:0x%x\n", dm_tx_st, dm_rx_st); goto irqret; } if (((m_stat & M_RX_FIFO_WATERMARK_EN) || (m_stat & M_RX_FIFO_LAST_EN)) && (cur->flags & I2C_M_RD)) { u32 rxcnt = rx_st & RX_FIFO_WC_MSK; Loading Loading @@ -434,11 +441,9 @@ static void gi2c_gsi_tx_cb(void *ptr) struct msm_gpi_dma_async_tx_cb_param *tx_cb = ptr; struct geni_i2c_dev *gi2c = tx_cb->userdata; if (!(gi2c->cur->flags & I2C_M_RD)) { gi2c_gsi_cb_err(tx_cb, "TX"); complete(&gi2c->xfer); } } static void gi2c_gsi_rx_cb(void *ptr) { Loading Loading @@ -476,6 +481,7 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], goto geni_i2c_gsi_xfer_out; } } if (!gi2c->rx_c) { gi2c->rx_c = dma_request_slave_channel(gi2c->dev, "rx"); if (!gi2c->rx_c) { Loading @@ -496,6 +502,23 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], } } if (gi2c->is_shared) { struct msm_gpi_tre *lock_t = &gi2c->lock_t; struct msm_gpi_tre *unlock_t = &gi2c->unlock_t; /* lock */ lock_t->dword[0] = MSM_GPI_LOCK_TRE_DWORD0; lock_t->dword[1] = MSM_GPI_LOCK_TRE_DWORD1; lock_t->dword[2] = MSM_GPI_LOCK_TRE_DWORD2; lock_t->dword[3] = MSM_GPI_LOCK_TRE_DWORD3(0, 0, 0, 0, 1); /* unlock tre: ieob set */ unlock_t->dword[0] = MSM_GPI_UNLOCK_TRE_DWORD0; unlock_t->dword[1] = MSM_GPI_UNLOCK_TRE_DWORD1; unlock_t->dword[2] = MSM_GPI_UNLOCK_TRE_DWORD2; unlock_t->dword[3] = MSM_GPI_UNLOCK_TRE_DWORD3(0, 0, 0, 1, 0); } if (!gi2c->cfg_sent) { struct geni_i2c_clk_fld *itr = geni_i2c_clk_map + gi2c->clk_fld_idx; Loading Loading @@ -535,26 +558,47 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], } qcom_geni_i2c_calc_timeout(gi2c); if (!gi2c->cfg_sent) { if (!gi2c->cfg_sent) segs++; if (gi2c->is_shared && (i == 0 || i == num-1)) { segs++; if (num == 1) segs++; sg_init_table(gi2c->tx_sg, segs); sg_set_buf(gi2c->tx_sg, &gi2c->cfg0_t, sizeof(gi2c->cfg0_t)); gi2c->cfg_sent = 1; index++; if (i == 0) /* Send lock tre for first transfer in a msg */ sg_set_buf(&gi2c->tx_sg[index++], &gi2c->lock_t, sizeof(gi2c->lock_t)); } else { sg_init_table(gi2c->tx_sg, segs); } /* Send cfg tre when cfg not sent already */ if (!gi2c->cfg_sent) { sg_set_buf(&gi2c->tx_sg[index++], &gi2c->cfg0_t, sizeof(gi2c->cfg0_t)); gi2c->cfg_sent = 1; } go_t->dword[0] = MSM_GPI_I2C_GO_TRE_DWORD0((stretch << 2), msgs[i].addr, op); go_t->dword[1] = MSM_GPI_I2C_GO_TRE_DWORD1; if (msgs[i].flags & I2C_M_RD) { go_t->dword[2] = MSM_GPI_I2C_GO_TRE_DWORD2(msgs[i].len); go_t->dword[3] = MSM_GPI_I2C_GO_TRE_DWORD3(1, 0, 0, 1, 0); /* * For Rx Go tre: Set ieob for non-shared se and for all * but last transfer in shared se */ if (!gi2c->is_shared || (gi2c->is_shared && i != num-1)) go_t->dword[3] = MSM_GPI_I2C_GO_TRE_DWORD3(1, 0, 0, 1, 0); else go_t->dword[3] = MSM_GPI_I2C_GO_TRE_DWORD3(1, 0, 0, 0, 0); } else { /* For Tx Go tre: ieob is not set, chain bit is set */ go_t->dword[2] = MSM_GPI_I2C_GO_TRE_DWORD2(0); go_t->dword[3] = MSM_GPI_I2C_GO_TRE_DWORD3(0, 0, 0, 0, 1); Loading @@ -564,6 +608,8 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], sizeof(gi2c->go_t)); if (msgs[i].flags & I2C_M_RD) { GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "msg[%d].len:%d R\n", i, gi2c->cur->len); sg_init_table(&gi2c->rx_sg, 1); ret = geni_se_iommu_map_buf(rx_dev, &gi2c->rx_ph, dma_buf, msgs[i].len, Loading @@ -576,6 +622,11 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], false); goto geni_i2c_gsi_xfer_out; } else if (gi2c->dbg_buf_ptr) { gi2c->dbg_buf_ptr[i].virt_buf = (void *)dma_buf; gi2c->dbg_buf_ptr[i].map_buf = (void *)&gi2c->rx_ph; } gi2c->rx_t.dword[0] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD0(gi2c->rx_ph); Loading @@ -583,6 +634,7 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], MSM_GPI_DMA_W_BUFFER_TRE_DWORD1(gi2c->rx_ph); gi2c->rx_t.dword[2] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD2(msgs[i].len); /* Set ieot for all Rx/Tx DMA tres */ gi2c->rx_t.dword[3] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD3(0, 0, 1, 0, 0); Loading @@ -606,6 +658,8 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], rx_cookie = dmaengine_submit(gi2c->rx_desc); dma_async_issue_pending(gi2c->rx_c); } else { GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "msg[%d].len:%d W\n", i, gi2c->cur->len); ret = geni_se_iommu_map_buf(tx_dev, &gi2c->tx_ph, dma_buf, msgs[i].len, DMA_TO_DEVICE); Loading @@ -617,13 +671,27 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], false); goto geni_i2c_gsi_xfer_out; } else if (gi2c->dbg_buf_ptr) { gi2c->dbg_buf_ptr[i].virt_buf = (void *)dma_buf; gi2c->dbg_buf_ptr[i].map_buf = (void *)&gi2c->tx_ph; } gi2c->tx_t.dword[0] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD0(gi2c->tx_ph); gi2c->tx_t.dword[1] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD1(gi2c->tx_ph); gi2c->tx_t.dword[2] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD2(msgs[i].len); if (gi2c->is_shared && i == num-1) /* * For Tx: unlock tre is send for last transfer * so set chain bit for last transfer DMA tre. */ gi2c->tx_t.dword[3] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD3(0, 0, 1, 0, 1); else gi2c->tx_t.dword[3] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD3(0, 0, 1, 0, 0); Loading @@ -631,6 +699,12 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], sizeof(gi2c->tx_t)); } if (gi2c->is_shared && i == num-1) { /* Send unlock tre at the end of last transfer */ sg_set_buf(&gi2c->tx_sg[index++], &gi2c->unlock_t, sizeof(gi2c->unlock_t)); } gi2c->tx_desc = dmaengine_prep_slave_sg(gi2c->tx_c, gi2c->tx_sg, segs, DMA_MEM_TO_DEV, (DMA_PREP_INTERRUPT | Loading @@ -652,8 +726,9 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], gi2c->xfer_timeout); if (!timeout) { GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "GSI Txn timed out: %u len: %d\n", gi2c->xfer_timeout, gi2c->cur->len); "I2C gsi xfer timeout:%u flags:%d addr:0x%x\n", gi2c->xfer_timeout, gi2c->cur->flags, gi2c->cur->addr); geni_se_dump_dbg_regs(&gi2c->i2c_rsc, gi2c->base, gi2c->ipcl); gi2c->err = -ETIMEDOUT; Loading @@ -663,6 +738,10 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], dmaengine_terminate_all(gi2c->tx_c); gi2c->cfg_sent = 0; } if (gi2c->is_shared) /* Resend cfg tre for every new message on shared se */ gi2c->cfg_sent = 0; if (msgs[i].flags & I2C_M_RD) geni_se_iommu_unmap_buf(rx_dev, &gi2c->rx_ph, msgs[i].len, DMA_FROM_DEVICE); Loading @@ -688,8 +767,15 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, int i, ret = 0, timeout = 0; gi2c->err = 0; gi2c->cur = &msgs[0]; reinit_completion(&gi2c->xfer); /* Client to respect system suspend */ if (!pm_runtime_enabled(gi2c->dev)) { GENI_SE_ERR(gi2c->ipcl, false, gi2c->dev, "%s: System suspended\n", __func__); return -EACCES; } ret = pm_runtime_get_sync(gi2c->dev); if (ret < 0) { GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, Loading @@ -709,14 +795,25 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, } } GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "n:%d addr:0x%x\n", num, msgs[0].addr); gi2c->dbg_num = num; kfree(gi2c->dbg_buf_ptr); gi2c->dbg_buf_ptr = kcalloc(num, sizeof(struct dbg_buf_ctxt), GFP_KERNEL); if (!gi2c->dbg_buf_ptr) GENI_SE_ERR(gi2c->ipcl, false, gi2c->dev, "Buf logging pointer not available\n"); if (gi2c->se_mode == GSI_ONLY) { ret = geni_i2c_gsi_xfer(adap, msgs, num); goto geni_i2c_txn_ret; } else { /* Don't set shared flag in non-GSI mode */ gi2c->is_shared = false; } qcom_geni_i2c_conf(gi2c, 0); dev_dbg(gi2c->dev, "i2c xfer:num:%d, msgs:len:%d,flg:%d\n", num, msgs[0].len, msgs[0].flags); for (i = 0; i < num; i++) { int stretch = (i < (num - 1)); u32 m_param = 0; Loading Loading @@ -751,9 +848,8 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, } if (msgs[i].flags & I2C_M_RD) { dev_dbg(gi2c->dev, "READ,n:%d,i:%d len:%d, stretch:%d\n", num, i, msgs[i].len, stretch); GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "msgs[%d].len:%d R\n", i, msgs[i].len); geni_write_reg(msgs[i].len, gi2c->base, SE_I2C_RX_TRANS_LEN); m_cmd = I2C_READ; Loading @@ -768,12 +864,16 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, mode = FIFO_MODE; ret = geni_se_select_mode(gi2c->base, mode); } else if (gi2c->dbg_buf_ptr) { gi2c->dbg_buf_ptr[i].virt_buf = (void *)dma_buf; gi2c->dbg_buf_ptr[i].map_buf = (void *)&rx_dma; } } } else { dev_dbg(gi2c->dev, "WRITE:n:%d,i:%d len:%d, stretch:%d, m_param:0x%x\n", num, i, msgs[i].len, stretch, m_param); GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "msgs[%d].len:%d W\n", i, msgs[i].len); geni_write_reg(msgs[i].len, gi2c->base, SE_I2C_TX_TRANS_LEN); m_cmd = I2C_WRITE; Loading @@ -788,6 +888,11 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, mode = FIFO_MODE; ret = geni_se_select_mode(gi2c->base, mode); } else if (gi2c->dbg_buf_ptr) { gi2c->dbg_buf_ptr[i].virt_buf = (void *)dma_buf; gi2c->dbg_buf_ptr[i].map_buf = (void *)&tx_dma; } } if (mode == FIFO_MODE) /* Get FIFO IRQ */ Loading @@ -798,17 +903,23 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, mb(); timeout = wait_for_completion_timeout(&gi2c->xfer, gi2c->xfer_timeout); if (!timeout) if (!timeout) { GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "I2C xfer timeout: %d\n", gi2c->xfer_timeout); geni_i2c_err(gi2c, GENI_TIMEOUT); } if (gi2c->err) { reinit_completion(&gi2c->xfer); gi2c->cur = NULL; geni_cancel_m_cmd(gi2c->base); timeout = wait_for_completion_timeout(&gi2c->xfer, HZ); if (!timeout) if (!timeout) { GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "Abort\n"); geni_abort_m_cmd(gi2c->base); } } gi2c->cur_wr = 0; gi2c->cur_rd = 0; if (mode == SE_DMA) { Loading @@ -830,7 +941,8 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, } ret = gi2c->err; if (gi2c->err) { dev_err(gi2c->dev, "i2c error :%d\n", gi2c->err); GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "i2c error :%d\n", gi2c->err); break; } } Loading @@ -842,7 +954,8 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, pm_runtime_put_autosuspend(gi2c->dev); gi2c->cur = NULL; gi2c->err = 0; dev_dbg(gi2c->dev, "i2c txn ret:%d\n", ret); GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "i2c txn ret:%d\n", ret); return ret; } Loading @@ -868,6 +981,10 @@ static int geni_i2c_probe(struct platform_device *pdev) if (!gi2c) return -ENOMEM; if (arr_idx < MAX_SE) /* Debug purpose */ gi2c_dev_dbg[arr_idx++] = gi2c; gi2c->dev = &pdev->dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); Loading Loading @@ -1029,9 +1146,15 @@ static int geni_i2c_probe(struct platform_device *pdev) static int geni_i2c_remove(struct platform_device *pdev) { struct geni_i2c_dev *gi2c = platform_get_drvdata(pdev); int i; pm_runtime_disable(gi2c->dev); i2c_del_adapter(&gi2c->adap); for (i = 0; i < arr_idx; i++) gi2c_dev_dbg[i] = NULL; arr_idx = 0; if (gi2c->ipcl) ipc_log_context_destroy(gi2c->ipcl); return 0; Loading @@ -1039,6 +1162,9 @@ static int geni_i2c_remove(struct platform_device *pdev) static int geni_i2c_resume_noirq(struct device *device) { struct geni_i2c_dev *gi2c = dev_get_drvdata(device); GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n", __func__); return 0; } Loading @@ -1059,6 +1185,7 @@ static int geni_i2c_runtime_suspend(struct device *dev) } else { se_geni_resources_off(&gi2c->i2c_rsc); } GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n", __func__); return 0; } Loading @@ -1070,7 +1197,7 @@ static int geni_i2c_runtime_resume(struct device *dev) if (!gi2c->ipcl) { char ipc_name[I2C_NAME_SIZE]; snprintf(ipc_name, I2C_NAME_SIZE, "i2c-%d", gi2c->adap.nr); snprintf(ipc_name, I2C_NAME_SIZE, "%s", dev_name(gi2c->dev)); gi2c->ipcl = ipc_log_context_create(2, ipc_name, 0); } Loading @@ -1096,6 +1223,7 @@ static int geni_i2c_runtime_resume(struct device *dev) if (gi2c->se_mode == FIFO_SE_DMA) enable_irq(gi2c->irq); } GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n", __func__); return 0; } Loading @@ -1113,6 +1241,8 @@ static int geni_i2c_suspend_noirq(struct device *device) return -EBUSY; } if (!pm_runtime_status_suspended(device)) { GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n", __func__); geni_i2c_runtime_suspend(device); pm_runtime_disable(device); pm_runtime_set_suspended(device); Loading include/linux/msm_gpi.h +17 −1 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef __MSM_GPI_H_ Loading Loading @@ -29,6 +29,22 @@ enum msm_gpi_tre_type { #define MSM_GPI_TRE_TYPE(tre) ((tre->dword[3] >> 16) & 0xFF) /* Lock TRE */ #define MSM_GPI_LOCK_TRE_DWORD0 (0) #define MSM_GPI_LOCK_TRE_DWORD1 (0) #define MSM_GPI_LOCK_TRE_DWORD2 (0) #define MSM_GPI_LOCK_TRE_DWORD3(link_rx, bei, ieot, ieob, ch) \ ((0x3 << 20) | (0x0 << 16) | (link_rx << 11) | (bei << 10) | \ (ieot << 9) | (ieob << 8) | ch) /* Unlock TRE */ #define MSM_GPI_UNLOCK_TRE_DWORD0 (0) #define MSM_GPI_UNLOCK_TRE_DWORD1 (0) #define MSM_GPI_UNLOCK_TRE_DWORD2 (0) #define MSM_GPI_UNLOCK_TRE_DWORD3(link_rx, bei, ieot, ieob, ch) \ ((0x3 << 20) | (0x1 << 16) | (link_rx << 11) | (bei << 10) | \ (ieot << 9) | (ieob << 8) | ch) /* DMA w. Buffer TRE */ #ifdef CONFIG_ARM64 #define MSM_GPI_DMA_W_BUFFER_TRE_DWORD0(ptr) ((u32)ptr) Loading Loading
drivers/dma/qcom/gpi.c +109 −35 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include <linux/atomic.h> Loading Loading @@ -447,7 +447,8 @@ struct gpi_dev { struct dentry *dentry; }; static struct gpi_dev *gpi_dev_dbg; static struct gpi_dev *gpi_dev_dbg[5]; static int arr_idx; struct reg_info { char *name; Loading Loading @@ -581,6 +582,7 @@ struct gpii { struct gpi_reg_table dbg_reg_table; bool reg_table_dump; u32 dbg_gpi_irq_cnt; bool unlock_tre_set; }; struct gpi_desc { Loading Loading @@ -1447,6 +1449,22 @@ static void gpi_process_qup_notif_event(struct gpii_chan *gpii_chan, client_info->cb_param); } /* free gpi_desc for the specified channel */ static void gpi_free_chan_desc(struct gpii_chan *gpii_chan) { struct virt_dma_desc *vd; struct gpi_desc *gpi_desc; unsigned long flags; spin_lock_irqsave(&gpii_chan->vc.lock, flags); vd = vchan_next_desc(&gpii_chan->vc); gpi_desc = to_gpi_desc(vd); list_del(&vd->node); spin_unlock_irqrestore(&gpii_chan->vc.lock, flags); kfree(gpi_desc); gpi_desc = NULL; } /* process DMA Immediate completion data events */ static void gpi_process_imed_data_event(struct gpii_chan *gpii_chan, struct immediate_data_event *imed_event) Loading @@ -1459,6 +1477,8 @@ static void gpi_process_imed_data_event(struct gpii_chan *gpii_chan, (ch_ring->el_size * imed_event->tre_index); struct msm_gpi_dma_async_tx_cb_param *tx_cb_param; unsigned long flags; u32 chid; struct gpii_chan *gpii_tx_chan = &gpii->gpii_chan[GPI_TX_CHAN]; /* * If channel not active don't process event but let Loading Loading @@ -1496,20 +1516,6 @@ static void gpi_process_imed_data_event(struct gpii_chan *gpii_chan, return; } gpi_desc = to_gpi_desc(vd); /* Event TR RP gen. don't match descriptor TR */ if (gpi_desc->wp != tre) { spin_unlock_irqrestore(&gpii_chan->vc.lock, flags); GPII_ERR(gpii, gpii_chan->chid, "EOT/EOB received for wrong TRE 0x%0llx != 0x%0llx\n", to_physical(ch_ring, gpi_desc->wp), to_physical(ch_ring, tre)); gpi_generate_cb_event(gpii_chan, MSM_GPI_QUP_EOT_DESC_MISMATCH, __LINE__); return; } list_del(&vd->node); spin_unlock_irqrestore(&gpii_chan->vc.lock, flags); Loading @@ -1525,6 +1531,35 @@ static void gpi_process_imed_data_event(struct gpii_chan *gpii_chan, /* make sure rp updates are immediately visible to all cores */ smp_wmb(); /* * If unlock tre is present, don't send transfer callback on * on IEOT, wait for unlock IEOB. Free the respective channel * descriptors. * If unlock is not present, IEOB indicates freeing the descriptor * and IEOT indicates channel transfer completion. */ chid = imed_event->chid; if (gpii->unlock_tre_set) { if (chid == GPI_RX_CHAN) { if (imed_event->code == MSM_GPI_TCE_EOT) goto gpi_free_desc; else if (imed_event->code == MSM_GPI_TCE_UNEXP_ERR) /* * In case of an error in a read transfer on a * shared se, unlock tre will not be processed * as channels go to bad state so tx desc should * be freed manually. */ gpi_free_chan_desc(gpii_tx_chan); else return; } else if (imed_event->code == MSM_GPI_TCE_EOT) { return; } } else if (imed_event->code == MSM_GPI_TCE_EOB) { goto gpi_free_desc; } tx_cb_param = vd->tx.callback_param; if (vd->tx.callback && tx_cb_param) { struct msm_gpi_tre *imed_tre = &tx_cb_param->imed_tre; Loading @@ -1540,7 +1575,9 @@ static void gpi_process_imed_data_event(struct gpii_chan *gpii_chan, tx_cb_param->status = imed_event->status; vd->tx.callback(tx_cb_param); } kfree(gpi_desc); gpi_free_desc: gpi_free_chan_desc(gpii_chan); } /* processing transfer completion events */ Loading @@ -1554,6 +1591,8 @@ static void gpi_process_xfer_compl_event(struct gpii_chan *gpii_chan, struct msm_gpi_dma_async_tx_cb_param *tx_cb_param; struct gpi_desc *gpi_desc; unsigned long flags; u32 chid; struct gpii_chan *gpii_tx_chan = &gpii->gpii_chan[GPI_TX_CHAN]; /* only process events on active channel */ if (unlikely(gpii_chan->pm_state != ACTIVE_STATE)) { Loading Loading @@ -1583,20 +1622,6 @@ static void gpi_process_xfer_compl_event(struct gpii_chan *gpii_chan, } gpi_desc = to_gpi_desc(vd); /* TRE Event generated didn't match descriptor's TRE */ if (gpi_desc->wp != ev_rp) { spin_unlock_irqrestore(&gpii_chan->vc.lock, flags); GPII_ERR(gpii, gpii_chan->chid, "EOT\EOB received for wrong TRE 0x%0llx != 0x%0llx\n", to_physical(ch_ring, gpi_desc->wp), to_physical(ch_ring, ev_rp)); gpi_generate_cb_event(gpii_chan, MSM_GPI_QUP_EOT_DESC_MISMATCH, __LINE__); return; } list_del(&vd->node); spin_unlock_irqrestore(&gpii_chan->vc.lock, flags); Loading @@ -1612,6 +1637,35 @@ static void gpi_process_xfer_compl_event(struct gpii_chan *gpii_chan, /* update must be visible to other cores */ smp_wmb(); /* * If unlock tre is present, don't send transfer callback on * on IEOT, wait for unlock IEOB. Free the respective channel * descriptors. * If unlock is not present, IEOB indicates freeing the descriptor * and IEOT indicates channel transfer completion. */ chid = compl_event->chid; if (gpii->unlock_tre_set) { if (chid == GPI_RX_CHAN) { if (compl_event->code == MSM_GPI_TCE_EOT) goto gpi_free_desc; else if (compl_event->code == MSM_GPI_TCE_UNEXP_ERR) /* * In case of an error in a read transfer on a * shared se, unlock tre will not be processed * as channels go to bad state so tx desc should * be freed manually. */ gpi_free_chan_desc(gpii_tx_chan); else return; } else if (compl_event->code == MSM_GPI_TCE_EOT) { return; } } else if (compl_event->code == MSM_GPI_TCE_EOB) { goto gpi_free_desc; } tx_cb_param = vd->tx.callback_param; if (vd->tx.callback && tx_cb_param) { GPII_VERB(gpii, gpii_chan->chid, Loading @@ -1623,7 +1677,10 @@ static void gpi_process_xfer_compl_event(struct gpii_chan *gpii_chan, tx_cb_param->status = compl_event->status; vd->tx.callback(tx_cb_param); } kfree(gpi_desc); gpi_free_desc: gpi_free_chan_desc(gpii_chan); } /* process all events */ Loading Loading @@ -2299,6 +2356,7 @@ void gpi_desc_free(struct virt_dma_desc *vd) struct gpi_desc *gpi_desc = to_gpi_desc(vd); kfree(gpi_desc); gpi_desc = NULL; } /* copy tre into transfer ring */ Loading @@ -2319,6 +2377,7 @@ struct dma_async_tx_descriptor *gpi_prep_slave_sg(struct dma_chan *chan, void *tre, *wp = NULL; const gfp_t gfp = GFP_ATOMIC; struct gpi_desc *gpi_desc; u32 tre_type; GPII_VERB(gpii, gpii_chan->chid, "enter\n"); Loading Loading @@ -2352,10 +2411,21 @@ struct dma_async_tx_descriptor *gpi_prep_slave_sg(struct dma_chan *chan, } /* copy each tre into transfer ring */ for_each_sg(sgl, sg, sg_len, i) for (j = 0, tre = sg_virt(sg); j < sg->length; for_each_sg(sgl, sg, sg_len, i) { tre = sg_virt(sg); /* Check if last tre is an unlock tre */ if (i == sg_len - 1) { tre_type = MSM_GPI_TRE_TYPE(((struct msm_gpi_tre *)tre)); gpii->unlock_tre_set = tre_type == MSM_GPI_TRE_UNLOCK ? true : false; } for (j = 0; j < sg->length; j += ch_ring->el_size, tre += ch_ring->el_size) gpi_queue_xfer(gpii, gpii_chan, tre, &wp); } /* set up the descriptor */ gpi_desc->db = ch_ring->wp; Loading Loading @@ -2807,7 +2877,7 @@ static int gpi_probe(struct platform_device *pdev) return -ENOMEM; /* debug purpose */ gpi_dev_dbg = gpi_dev; gpi_dev_dbg[arr_idx++] = gpi_dev; gpi_dev->dev = &pdev->dev; gpi_dev->klog_lvl = DEFAULT_KLOG_LVL; Loading Loading @@ -3018,6 +3088,10 @@ static int gpi_remove(struct platform_device *pdev) ipc_log_context_destroy(gpii->ilctxt); } for (i = 0; i < arr_idx; i++) gpi_dev_dbg[i] = NULL; arr_idx = 0; if (gpi_dev->ilctxt) ipc_log_context_destroy(gpi_dev->ilctxt); Loading
drivers/i2c/busses/i2c-msm-geni.c +174 −44 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include <linux/msm_gpi.h> #include <linux/ioctl.h> #include <linux/pinctrl/consumer.h> #include <linux/slab.h> #define SE_I2C_TX_TRANS_LEN (0x26C) #define SE_I2C_RX_TRANS_LEN (0x270) Loading Loading @@ -73,12 +74,19 @@ #define I2C_TIMEOUT_MIN_USEC 500000 #define MAX_SE 20 enum i2c_se_mode { UNINITIALIZED, FIFO_SE_DMA, GSI_ONLY, }; struct dbg_buf_ctxt { void *virt_buf; void *map_buf; }; struct geni_i2c_dev { struct device *dev; void __iomem *base; Loading @@ -97,6 +105,8 @@ struct geni_i2c_dev { int clk_fld_idx; struct dma_chan *tx_c; struct dma_chan *rx_c; struct msm_gpi_tre lock_t; struct msm_gpi_tre unlock_t; struct msm_gpi_tre cfg0_t; struct msm_gpi_tre go_t; struct msm_gpi_tre tx_t; Loading @@ -115,9 +125,14 @@ struct geni_i2c_dev { enum i2c_se_mode se_mode; bool cmd_done; bool is_shared; u32 dbg_num; struct dbg_buf_ctxt *dbg_buf_ptr; bool is_le_vm; }; static struct geni_i2c_dev *gi2c_dev_dbg[MAX_SE]; static int arr_idx; struct geni_i2c_err_log { int err; const char *msg; Loading Loading @@ -207,12 +222,6 @@ static inline void qcom_geni_i2c_calc_timeout(struct geni_i2c_dev *gi2c) static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err) { if (gi2c->cur) GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "len:%d, slv-addr:0x%x, RD/WR:%d timeout:%u\n", gi2c->cur->len, gi2c->cur->addr, gi2c->cur->flags, gi2c->xfer_timeout); if (err == I2C_NACK || err == GENI_ABORT_DONE) { GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n", gi2c_log[err].msg); Loading @@ -221,8 +230,6 @@ static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err) GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "%s\n", gi2c_log[err].msg); } GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s: se-mode:%d\n", __func__, gi2c->se_mode); geni_se_dump_dbg_regs(&gi2c->i2c_rsc, gi2c->base, gi2c->ipcl); err_ret: gi2c->err = gi2c_log[err].err; Loading Loading @@ -275,7 +282,13 @@ static irqreturn_t geni_i2c_irq(int irq, void *dev) u32 dma = readl_relaxed(gi2c->base + SE_GENI_DMA_MODE_EN); struct i2c_msg *cur = gi2c->cur; if (!cur || (m_stat & M_CMD_FAILURE_EN) || if (!cur) { geni_se_dump_dbg_regs(&gi2c->i2c_rsc, gi2c->base, gi2c->ipcl); GENI_SE_ERR(gi2c->ipcl, false, gi2c->dev, "Spurious irq\n"); goto irqret; } if ((m_stat & M_CMD_FAILURE_EN) || (dm_rx_st & (DM_I2C_CB_ERR)) || (m_stat & M_CMD_CANCEL_EN) || (m_stat & M_CMD_ABORT_EN)) { Loading @@ -302,12 +315,6 @@ static irqreturn_t geni_i2c_irq(int irq, void *dev) goto irqret; } if (dma) { dev_dbg(gi2c->dev, "i2c dma tx:0x%x, dma rx:0x%x\n", dm_tx_st, dm_rx_st); goto irqret; } if (((m_stat & M_RX_FIFO_WATERMARK_EN) || (m_stat & M_RX_FIFO_LAST_EN)) && (cur->flags & I2C_M_RD)) { u32 rxcnt = rx_st & RX_FIFO_WC_MSK; Loading Loading @@ -434,11 +441,9 @@ static void gi2c_gsi_tx_cb(void *ptr) struct msm_gpi_dma_async_tx_cb_param *tx_cb = ptr; struct geni_i2c_dev *gi2c = tx_cb->userdata; if (!(gi2c->cur->flags & I2C_M_RD)) { gi2c_gsi_cb_err(tx_cb, "TX"); complete(&gi2c->xfer); } } static void gi2c_gsi_rx_cb(void *ptr) { Loading Loading @@ -476,6 +481,7 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], goto geni_i2c_gsi_xfer_out; } } if (!gi2c->rx_c) { gi2c->rx_c = dma_request_slave_channel(gi2c->dev, "rx"); if (!gi2c->rx_c) { Loading @@ -496,6 +502,23 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], } } if (gi2c->is_shared) { struct msm_gpi_tre *lock_t = &gi2c->lock_t; struct msm_gpi_tre *unlock_t = &gi2c->unlock_t; /* lock */ lock_t->dword[0] = MSM_GPI_LOCK_TRE_DWORD0; lock_t->dword[1] = MSM_GPI_LOCK_TRE_DWORD1; lock_t->dword[2] = MSM_GPI_LOCK_TRE_DWORD2; lock_t->dword[3] = MSM_GPI_LOCK_TRE_DWORD3(0, 0, 0, 0, 1); /* unlock tre: ieob set */ unlock_t->dword[0] = MSM_GPI_UNLOCK_TRE_DWORD0; unlock_t->dword[1] = MSM_GPI_UNLOCK_TRE_DWORD1; unlock_t->dword[2] = MSM_GPI_UNLOCK_TRE_DWORD2; unlock_t->dword[3] = MSM_GPI_UNLOCK_TRE_DWORD3(0, 0, 0, 1, 0); } if (!gi2c->cfg_sent) { struct geni_i2c_clk_fld *itr = geni_i2c_clk_map + gi2c->clk_fld_idx; Loading Loading @@ -535,26 +558,47 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], } qcom_geni_i2c_calc_timeout(gi2c); if (!gi2c->cfg_sent) { if (!gi2c->cfg_sent) segs++; if (gi2c->is_shared && (i == 0 || i == num-1)) { segs++; if (num == 1) segs++; sg_init_table(gi2c->tx_sg, segs); sg_set_buf(gi2c->tx_sg, &gi2c->cfg0_t, sizeof(gi2c->cfg0_t)); gi2c->cfg_sent = 1; index++; if (i == 0) /* Send lock tre for first transfer in a msg */ sg_set_buf(&gi2c->tx_sg[index++], &gi2c->lock_t, sizeof(gi2c->lock_t)); } else { sg_init_table(gi2c->tx_sg, segs); } /* Send cfg tre when cfg not sent already */ if (!gi2c->cfg_sent) { sg_set_buf(&gi2c->tx_sg[index++], &gi2c->cfg0_t, sizeof(gi2c->cfg0_t)); gi2c->cfg_sent = 1; } go_t->dword[0] = MSM_GPI_I2C_GO_TRE_DWORD0((stretch << 2), msgs[i].addr, op); go_t->dword[1] = MSM_GPI_I2C_GO_TRE_DWORD1; if (msgs[i].flags & I2C_M_RD) { go_t->dword[2] = MSM_GPI_I2C_GO_TRE_DWORD2(msgs[i].len); go_t->dword[3] = MSM_GPI_I2C_GO_TRE_DWORD3(1, 0, 0, 1, 0); /* * For Rx Go tre: Set ieob for non-shared se and for all * but last transfer in shared se */ if (!gi2c->is_shared || (gi2c->is_shared && i != num-1)) go_t->dword[3] = MSM_GPI_I2C_GO_TRE_DWORD3(1, 0, 0, 1, 0); else go_t->dword[3] = MSM_GPI_I2C_GO_TRE_DWORD3(1, 0, 0, 0, 0); } else { /* For Tx Go tre: ieob is not set, chain bit is set */ go_t->dword[2] = MSM_GPI_I2C_GO_TRE_DWORD2(0); go_t->dword[3] = MSM_GPI_I2C_GO_TRE_DWORD3(0, 0, 0, 0, 1); Loading @@ -564,6 +608,8 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], sizeof(gi2c->go_t)); if (msgs[i].flags & I2C_M_RD) { GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "msg[%d].len:%d R\n", i, gi2c->cur->len); sg_init_table(&gi2c->rx_sg, 1); ret = geni_se_iommu_map_buf(rx_dev, &gi2c->rx_ph, dma_buf, msgs[i].len, Loading @@ -576,6 +622,11 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], false); goto geni_i2c_gsi_xfer_out; } else if (gi2c->dbg_buf_ptr) { gi2c->dbg_buf_ptr[i].virt_buf = (void *)dma_buf; gi2c->dbg_buf_ptr[i].map_buf = (void *)&gi2c->rx_ph; } gi2c->rx_t.dword[0] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD0(gi2c->rx_ph); Loading @@ -583,6 +634,7 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], MSM_GPI_DMA_W_BUFFER_TRE_DWORD1(gi2c->rx_ph); gi2c->rx_t.dword[2] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD2(msgs[i].len); /* Set ieot for all Rx/Tx DMA tres */ gi2c->rx_t.dword[3] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD3(0, 0, 1, 0, 0); Loading @@ -606,6 +658,8 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], rx_cookie = dmaengine_submit(gi2c->rx_desc); dma_async_issue_pending(gi2c->rx_c); } else { GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "msg[%d].len:%d W\n", i, gi2c->cur->len); ret = geni_se_iommu_map_buf(tx_dev, &gi2c->tx_ph, dma_buf, msgs[i].len, DMA_TO_DEVICE); Loading @@ -617,13 +671,27 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], false); goto geni_i2c_gsi_xfer_out; } else if (gi2c->dbg_buf_ptr) { gi2c->dbg_buf_ptr[i].virt_buf = (void *)dma_buf; gi2c->dbg_buf_ptr[i].map_buf = (void *)&gi2c->tx_ph; } gi2c->tx_t.dword[0] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD0(gi2c->tx_ph); gi2c->tx_t.dword[1] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD1(gi2c->tx_ph); gi2c->tx_t.dword[2] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD2(msgs[i].len); if (gi2c->is_shared && i == num-1) /* * For Tx: unlock tre is send for last transfer * so set chain bit for last transfer DMA tre. */ gi2c->tx_t.dword[3] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD3(0, 0, 1, 0, 1); else gi2c->tx_t.dword[3] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD3(0, 0, 1, 0, 0); Loading @@ -631,6 +699,12 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], sizeof(gi2c->tx_t)); } if (gi2c->is_shared && i == num-1) { /* Send unlock tre at the end of last transfer */ sg_set_buf(&gi2c->tx_sg[index++], &gi2c->unlock_t, sizeof(gi2c->unlock_t)); } gi2c->tx_desc = dmaengine_prep_slave_sg(gi2c->tx_c, gi2c->tx_sg, segs, DMA_MEM_TO_DEV, (DMA_PREP_INTERRUPT | Loading @@ -652,8 +726,9 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], gi2c->xfer_timeout); if (!timeout) { GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "GSI Txn timed out: %u len: %d\n", gi2c->xfer_timeout, gi2c->cur->len); "I2C gsi xfer timeout:%u flags:%d addr:0x%x\n", gi2c->xfer_timeout, gi2c->cur->flags, gi2c->cur->addr); geni_se_dump_dbg_regs(&gi2c->i2c_rsc, gi2c->base, gi2c->ipcl); gi2c->err = -ETIMEDOUT; Loading @@ -663,6 +738,10 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], dmaengine_terminate_all(gi2c->tx_c); gi2c->cfg_sent = 0; } if (gi2c->is_shared) /* Resend cfg tre for every new message on shared se */ gi2c->cfg_sent = 0; if (msgs[i].flags & I2C_M_RD) geni_se_iommu_unmap_buf(rx_dev, &gi2c->rx_ph, msgs[i].len, DMA_FROM_DEVICE); Loading @@ -688,8 +767,15 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, int i, ret = 0, timeout = 0; gi2c->err = 0; gi2c->cur = &msgs[0]; reinit_completion(&gi2c->xfer); /* Client to respect system suspend */ if (!pm_runtime_enabled(gi2c->dev)) { GENI_SE_ERR(gi2c->ipcl, false, gi2c->dev, "%s: System suspended\n", __func__); return -EACCES; } ret = pm_runtime_get_sync(gi2c->dev); if (ret < 0) { GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, Loading @@ -709,14 +795,25 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, } } GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "n:%d addr:0x%x\n", num, msgs[0].addr); gi2c->dbg_num = num; kfree(gi2c->dbg_buf_ptr); gi2c->dbg_buf_ptr = kcalloc(num, sizeof(struct dbg_buf_ctxt), GFP_KERNEL); if (!gi2c->dbg_buf_ptr) GENI_SE_ERR(gi2c->ipcl, false, gi2c->dev, "Buf logging pointer not available\n"); if (gi2c->se_mode == GSI_ONLY) { ret = geni_i2c_gsi_xfer(adap, msgs, num); goto geni_i2c_txn_ret; } else { /* Don't set shared flag in non-GSI mode */ gi2c->is_shared = false; } qcom_geni_i2c_conf(gi2c, 0); dev_dbg(gi2c->dev, "i2c xfer:num:%d, msgs:len:%d,flg:%d\n", num, msgs[0].len, msgs[0].flags); for (i = 0; i < num; i++) { int stretch = (i < (num - 1)); u32 m_param = 0; Loading Loading @@ -751,9 +848,8 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, } if (msgs[i].flags & I2C_M_RD) { dev_dbg(gi2c->dev, "READ,n:%d,i:%d len:%d, stretch:%d\n", num, i, msgs[i].len, stretch); GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "msgs[%d].len:%d R\n", i, msgs[i].len); geni_write_reg(msgs[i].len, gi2c->base, SE_I2C_RX_TRANS_LEN); m_cmd = I2C_READ; Loading @@ -768,12 +864,16 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, mode = FIFO_MODE; ret = geni_se_select_mode(gi2c->base, mode); } else if (gi2c->dbg_buf_ptr) { gi2c->dbg_buf_ptr[i].virt_buf = (void *)dma_buf; gi2c->dbg_buf_ptr[i].map_buf = (void *)&rx_dma; } } } else { dev_dbg(gi2c->dev, "WRITE:n:%d,i:%d len:%d, stretch:%d, m_param:0x%x\n", num, i, msgs[i].len, stretch, m_param); GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "msgs[%d].len:%d W\n", i, msgs[i].len); geni_write_reg(msgs[i].len, gi2c->base, SE_I2C_TX_TRANS_LEN); m_cmd = I2C_WRITE; Loading @@ -788,6 +888,11 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, mode = FIFO_MODE; ret = geni_se_select_mode(gi2c->base, mode); } else if (gi2c->dbg_buf_ptr) { gi2c->dbg_buf_ptr[i].virt_buf = (void *)dma_buf; gi2c->dbg_buf_ptr[i].map_buf = (void *)&tx_dma; } } if (mode == FIFO_MODE) /* Get FIFO IRQ */ Loading @@ -798,17 +903,23 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, mb(); timeout = wait_for_completion_timeout(&gi2c->xfer, gi2c->xfer_timeout); if (!timeout) if (!timeout) { GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "I2C xfer timeout: %d\n", gi2c->xfer_timeout); geni_i2c_err(gi2c, GENI_TIMEOUT); } if (gi2c->err) { reinit_completion(&gi2c->xfer); gi2c->cur = NULL; geni_cancel_m_cmd(gi2c->base); timeout = wait_for_completion_timeout(&gi2c->xfer, HZ); if (!timeout) if (!timeout) { GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "Abort\n"); geni_abort_m_cmd(gi2c->base); } } gi2c->cur_wr = 0; gi2c->cur_rd = 0; if (mode == SE_DMA) { Loading @@ -830,7 +941,8 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, } ret = gi2c->err; if (gi2c->err) { dev_err(gi2c->dev, "i2c error :%d\n", gi2c->err); GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "i2c error :%d\n", gi2c->err); break; } } Loading @@ -842,7 +954,8 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, pm_runtime_put_autosuspend(gi2c->dev); gi2c->cur = NULL; gi2c->err = 0; dev_dbg(gi2c->dev, "i2c txn ret:%d\n", ret); GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "i2c txn ret:%d\n", ret); return ret; } Loading @@ -868,6 +981,10 @@ static int geni_i2c_probe(struct platform_device *pdev) if (!gi2c) return -ENOMEM; if (arr_idx < MAX_SE) /* Debug purpose */ gi2c_dev_dbg[arr_idx++] = gi2c; gi2c->dev = &pdev->dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); Loading Loading @@ -1029,9 +1146,15 @@ static int geni_i2c_probe(struct platform_device *pdev) static int geni_i2c_remove(struct platform_device *pdev) { struct geni_i2c_dev *gi2c = platform_get_drvdata(pdev); int i; pm_runtime_disable(gi2c->dev); i2c_del_adapter(&gi2c->adap); for (i = 0; i < arr_idx; i++) gi2c_dev_dbg[i] = NULL; arr_idx = 0; if (gi2c->ipcl) ipc_log_context_destroy(gi2c->ipcl); return 0; Loading @@ -1039,6 +1162,9 @@ static int geni_i2c_remove(struct platform_device *pdev) static int geni_i2c_resume_noirq(struct device *device) { struct geni_i2c_dev *gi2c = dev_get_drvdata(device); GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n", __func__); return 0; } Loading @@ -1059,6 +1185,7 @@ static int geni_i2c_runtime_suspend(struct device *dev) } else { se_geni_resources_off(&gi2c->i2c_rsc); } GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n", __func__); return 0; } Loading @@ -1070,7 +1197,7 @@ static int geni_i2c_runtime_resume(struct device *dev) if (!gi2c->ipcl) { char ipc_name[I2C_NAME_SIZE]; snprintf(ipc_name, I2C_NAME_SIZE, "i2c-%d", gi2c->adap.nr); snprintf(ipc_name, I2C_NAME_SIZE, "%s", dev_name(gi2c->dev)); gi2c->ipcl = ipc_log_context_create(2, ipc_name, 0); } Loading @@ -1096,6 +1223,7 @@ static int geni_i2c_runtime_resume(struct device *dev) if (gi2c->se_mode == FIFO_SE_DMA) enable_irq(gi2c->irq); } GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n", __func__); return 0; } Loading @@ -1113,6 +1241,8 @@ static int geni_i2c_suspend_noirq(struct device *device) return -EBUSY; } if (!pm_runtime_status_suspended(device)) { GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n", __func__); geni_i2c_runtime_suspend(device); pm_runtime_disable(device); pm_runtime_set_suspended(device); Loading
include/linux/msm_gpi.h +17 −1 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef __MSM_GPI_H_ Loading Loading @@ -29,6 +29,22 @@ enum msm_gpi_tre_type { #define MSM_GPI_TRE_TYPE(tre) ((tre->dword[3] >> 16) & 0xFF) /* Lock TRE */ #define MSM_GPI_LOCK_TRE_DWORD0 (0) #define MSM_GPI_LOCK_TRE_DWORD1 (0) #define MSM_GPI_LOCK_TRE_DWORD2 (0) #define MSM_GPI_LOCK_TRE_DWORD3(link_rx, bei, ieot, ieob, ch) \ ((0x3 << 20) | (0x0 << 16) | (link_rx << 11) | (bei << 10) | \ (ieot << 9) | (ieob << 8) | ch) /* Unlock TRE */ #define MSM_GPI_UNLOCK_TRE_DWORD0 (0) #define MSM_GPI_UNLOCK_TRE_DWORD1 (0) #define MSM_GPI_UNLOCK_TRE_DWORD2 (0) #define MSM_GPI_UNLOCK_TRE_DWORD3(link_rx, bei, ieot, ieob, ch) \ ((0x3 << 20) | (0x1 << 16) | (link_rx << 11) | (bei << 10) | \ (ieot << 9) | (ieob << 8) | ch) /* DMA w. Buffer TRE */ #ifdef CONFIG_ARM64 #define MSM_GPI_DMA_W_BUFFER_TRE_DWORD0(ptr) ((u32)ptr) Loading