i2c: i2c-msm-geni: Propagate missing changes from 4.19 to 5.4

Propagate following changes from 4.19 to 5.4 for I2C and GSI driver.
'commit 22cec88da571 ("i2c: i2c-qcom-geni: Add lock and unlock tre
support in I2C GSI mode")',
'commit 3adda53e090d ("i2c: i2c-qcom-geni: Enable shared flag in GSI
mode only")',
'commit 6f84a3f8ca30 ("i2c: i2c-qcom-geni: Enhance IPC logging debug
infra in I2C")',
'commit d06ac0169fb7 ("i2c: i2c-qcom-geni: Correct the IEOB/IEOT
sequence for I2C GSI tres")'.

Change-Id: I8ab0b4d580b16041b751f0be3de717d32238a374
Signed-off-by: Vipin Deep Kaur <vkaur@codeaurora.org>
This commit is contained in:
Vipin Deep Kaur 2020-04-22 14:26:59 +05:30
commit d425ff3d7e
3 changed files with 300 additions and 80 deletions

View file

@ -1,6 +1,6 @@
// 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>
@ -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;
@ -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 {
@ -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)
@ -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
@ -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);
@ -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;
@ -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 */
@ -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)) {
@ -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);
@ -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,
@ -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 */
@ -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 */
@ -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");
@ -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;
@ -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;
@ -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);

View file

@ -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)
@ -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;
@ -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;
@ -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;
@ -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);
@ -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;
@ -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)) {
@ -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;
@ -434,10 +441,8 @@ 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);
}
gi2c_gsi_cb_err(tx_cb, "TX");
complete(&gi2c->xfer);
}
static void gi2c_gsi_rx_cb(void *ptr)
@ -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) {
@ -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;
@ -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);
@ -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,
@ -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);
@ -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);
@ -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);
@ -617,20 +671,40 @@ 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);
gi2c->tx_t.dword[3] =
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);
sg_set_buf(&gi2c->tx_sg[index++], &gi2c->tx_t,
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 |
@ -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;
@ -663,6 +738,10 @@ geni_i2c_err_prep_sg:
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);
@ -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,
@ -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;
@ -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;
@ -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;
@ -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 */
@ -798,16 +903,22 @@ 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;
@ -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;
}
}
@ -842,7 +954,8 @@ geni_i2c_txn_ret:
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;
}
@ -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);
@ -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;
@ -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;
}
@ -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;
}
@ -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);
}
@ -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;
}
@ -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);

View file

@ -1,6 +1,6 @@
/* 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_
@ -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)