Merge "i2c: i2c-qcom-geni: Add lock and unlock tre support in I2C GSI mode"

This commit is contained in:
qctecmdr
2019-11-18 21:05:28 -08:00
committed by Gerrit - the friendly Code Review server
5 changed files with 114 additions and 47 deletions

View File

@@ -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 ieob_set;
};
struct gpi_desc {
@@ -1496,20 +1498,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 +1513,9 @@ 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 (imed_event->code == MSM_GPI_TCE_EOT && gpii->ieob_set)
return;
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 +1531,12 @@ 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);
}
spin_lock_irqsave(&gpii_chan->vc.lock, flags);
list_del(&vd->node);
spin_unlock_irqrestore(&gpii_chan->vc.lock, flags);
kfree(gpi_desc);
gpi_desc = NULL;
}
/* processing transfer completion events */
@@ -1583,20 +1579,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 +1594,9 @@ static void gpi_process_xfer_compl_event(struct gpii_chan *gpii_chan,
/* update must be visible to other cores */
smp_wmb();
if (compl_event->code == MSM_GPI_TCE_EOT && gpii->ieob_set)
return;
tx_cb_param = vd->tx.callback_param;
if (vd->tx.callback && tx_cb_param) {
GPII_VERB(gpii, gpii_chan->chid,
@@ -1623,7 +1608,13 @@ 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);
}
spin_lock_irqsave(&gpii_chan->vc.lock, flags);
list_del(&vd->node);
spin_unlock_irqrestore(&gpii_chan->vc.lock, flags);
kfree(gpi_desc);
gpi_desc = NULL;
}
/* process all events */
@@ -2299,6 +2290,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 +2311,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;
gpii->ieob_set = false;
GPII_VERB(gpii, gpii_chan->chid, "enter\n");
@@ -2352,10 +2345,22 @@ 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 has ieob set */
if (i == sg_len - 1) {
if ((((struct msm_gpi_tre *)tre)->dword[3] &
GPI_IEOB_BMSK) >> GPI_IEOB_BMSK_SHIFT)
gpii->ieob_set = true;
else
gpii->ieob_set = 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 +2812,8 @@ static int gpi_probe(struct platform_device *pdev)
return -ENOMEM;
/* debug purpose */
gpi_dev_dbg = gpi_dev;
gpi_dev_dbg[arr_idx] = gpi_dev;
arr_idx++;
gpi_dev->dev = &pdev->dev;
gpi_dev->klog_lvl = DEFAULT_KLOG_LVL;

View File

@@ -228,3 +228,7 @@ enum CNTXT_OFFS {
#define GPI_DEBUG_QSB_LOG_1 (0x5068)
#define GPI_DEBUG_QSB_LOG_2 (0x506C)
#define GPI_DEBUG_QSB_LOG_LAST_MISC_ID(n) (0x5070 + (0x4*n))
/* IEOB bit set */
#define GPI_IEOB_BMSK (0x100)
#define GPI_IEOB_BMSK_SHIFT (8)

View File

@@ -98,6 +98,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;
@@ -370,9 +372,9 @@ static void gi2c_ev_cb(struct dma_chan *ch, struct msm_gpi_cb const *cb_str,
}
if (cb_str->cb_event != MSM_GPI_QUP_NOTIFY)
GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
"GSI QN err:0x%x, status:0x%x, err:%d\n",
cb_str->error_log.error_code,
m_stat, cb_str->cb_event);
"GSI QN err:0x%x, status:0x%x, err:%d slv_addr: 0x%x R/W: %d\n",
cb_str->error_log.error_code, m_stat,
cb_str->cb_event, gi2c->cur->addr, gi2c->cur->flags);
}
static void gi2c_gsi_cb_err(struct msm_gpi_dma_async_tx_cb_param *cb,
@@ -398,7 +400,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)) {
if (tx_cb->completion_code == MSM_GPI_TCE_EOB) {
complete(&gi2c->xfer);
} else if (!(gi2c->cur->flags & I2C_M_RD)) {
gi2c_gsi_cb_err(tx_cb, "TX");
complete(&gi2c->xfer);
}
@@ -460,6 +464,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 */
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;
@@ -499,24 +520,34 @@ 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)
sg_set_buf(&gi2c->tx_sg[index++], &gi2c->lock_t,
sizeof(gi2c->lock_t));
} else {
sg_init_table(gi2c->tx_sg, segs);
}
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,
go_t->dword[3] = MSM_GPI_I2C_GO_TRE_DWORD3(1, 0, 0, 0,
0);
} else {
go_t->dword[2] = MSM_GPI_I2C_GO_TRE_DWORD2(0);
@@ -588,13 +619,22 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
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)
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) {
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 |
@@ -616,8 +656,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);
"GSI Txn timed out: %u len: %d slv:addr: 0x%x R/W: %d\n",
gi2c->xfer_timeout, gi2c->cur->len,
gi2c->cur->addr, gi2c->cur->flags);
geni_se_dump_dbg_regs(&gi2c->i2c_rsc, gi2c->base,
gi2c->ipcl);
gi2c->err = -ETIMEDOUT;
@@ -1001,7 +1042,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);
}

View File

@@ -397,7 +397,7 @@ static struct msm_gpi_tre *setup_go_tre(int cmd, int cs, int rx_len, int flags,
if (cmd == SPI_RX_ONLY) {
eot = 0;
chain = 0;
eob = 1;
eob = 0;
} else {
eot = 0;
chain = 1;

View File

@@ -27,6 +27,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)