mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-07 04:12:04 -04:00
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:
parent
492d9b26fb
commit
d425ff3d7e
3 changed files with 300 additions and 80 deletions
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in a new issue