summaryrefslogtreecommitdiff
path: root/drivers/i3c
diff options
context:
space:
mode:
authorIwona Winiarska <iwona.winiarska@intel.com>2022-01-06 19:24:48 +0300
committerGitHub <noreply@github.com>2022-01-06 19:24:48 +0300
commitaaccb149bfa6ff74dc8e9ff043191730060002db (patch)
treef14988692031666d28c76629280ab1722cbc16a8 /drivers/i3c
parent2c0a19ad326477ac0cad3ffe5f467de445ac3623 (diff)
downloadlinux-aaccb149bfa6ff74dc8e9ff043191730060002db.tar.xz
iklimasz/i3c-fixups (#1)
* i3c: master: dw: Enable IBI starting from LC release The current implementation of IBI handling on DW controller expects that the HW supports MDB/payload. This support is not available for older hardware releases. Let's enable IBI support only for hardware versions that support it. Signed-off-by: Iwona Winiarska <iwona.winiarska@intel.com> * i3c: master: dw: Set dw_i3c_master.dev dw_i3c_master.dev is not initialized, which can be observed in logs: [246977.695838] (NULL device *): no matching dev Set dw_i3c_master.dev in probe time to avoid using it as a NULL. Signed-off-by: Iwona Winiarska <iwona.winiarska@intel.com> * i3c: dw: master: Fix IBI reading dw_i3c_master_read_fifo() uses readsl() that allows to read all requested data and writes it to the given buffer. Calling it in a loop may cause the data to be overwritten. Signed-off-by: Iwona Winiarska <iwona.winiarska@intel.com>
Diffstat (limited to 'drivers/i3c')
-rw-r--r--drivers/i3c/master/dw-i3c-master.c42
1 files changed, 28 insertions, 14 deletions
diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c
index a026b7e6dca6..f883256665a6 100644
--- a/drivers/i3c/master/dw-i3c-master.c
+++ b/drivers/i3c/master/dw-i3c-master.c
@@ -146,8 +146,7 @@
INTR_TX_THLD_STAT | \
INTR_RX_THLD_STAT)
#define INTR_MASTER_MASK (INTR_TRANSFER_ERR_STAT | \
- INTR_RESP_READY_STAT | \
- INTR_IBI_THLD_STAT)
+ INTR_RESP_READY_STAT)
#define QUEUE_STATUS_LEVEL 0x4c
#define QUEUE_STATUS_IBI_STATUS_CNT(x) (((x) & GENMASK(28, 24)) >> 24)
@@ -201,6 +200,11 @@
#define BUS_IDLE_TIMING 0xd8
#define I3C_VER_ID 0xe0
#define I3C_VER_TYPE 0xe4
+#define I3C_VER_RELEASE_TYPE(x) (((x) & GENMASK(31, 16)) >> 16)
+#define I3C_VER_RELEASE_VERSION(x) ((x) & GENMASK(15, 0))
+
+#define I3C_LC_RELEASE 0x6c63
+
#define EXTENDED_CAPABILITY 0xe8
#define SLAVE_CONFIG 0xec
@@ -275,8 +279,8 @@ struct dw_i3c_master {
void __iomem *regs;
struct reset_control *core_rst;
struct clk *core_clk;
- char version[5];
- char type[5];
+ u32 ver_id;
+ u16 ver_type;
u8 addrs[MAX_DEVS];
};
@@ -704,6 +708,7 @@ static int dw_i3c_master_bus_init(struct i3c_master_controller *m)
{
struct dw_i3c_master *master = to_dw_i3c_master(m);
struct i3c_bus *bus = i3c_master_get_bus(m);
+ u32 interrupt_mask = INTR_MASTER_MASK;
struct i3c_device_info info = { };
u32 thld_ctrl;
int ret;
@@ -732,15 +737,18 @@ static int dw_i3c_master_bus_init(struct i3c_master_controller *m)
thld_ctrl &= ~DATA_BUFFER_THLD_CTRL_RX_BUF;
writel(thld_ctrl, master->regs + DATA_BUFFER_THLD_CTRL);
+ if (master->ver_type >= I3C_LC_RELEASE) {
+ thld_ctrl = readl(master->regs + QUEUE_THLD_CTRL);
+ thld_ctrl &= ~(QUEUE_THLD_CTRL_IBI_STA_MASK | QUEUE_THLD_CTRL_IBI_DAT_MASK);
+ thld_ctrl |= QUEUE_THLD_CTRL_IBI_STA(1) | QUEUE_THLD_CTRL_IBI_DAT(1);
+ writel(thld_ctrl, master->regs + QUEUE_THLD_CTRL);
+ interrupt_mask |= INTR_IBI_THLD_STAT;
+ }
+
writel(INTR_ALL, master->regs + INTR_STATUS);
- writel(INTR_MASTER_MASK, master->regs + INTR_STATUS_EN);
- writel(INTR_MASTER_MASK, master->regs + INTR_SIGNAL_EN);
+ writel(interrupt_mask, master->regs + INTR_STATUS_EN);
+ writel(interrupt_mask, master->regs + INTR_SIGNAL_EN);
- thld_ctrl = readl(master->regs + QUEUE_THLD_CTRL);
- thld_ctrl &= ~(QUEUE_THLD_CTRL_IBI_STA_MASK | QUEUE_THLD_CTRL_IBI_DAT_MASK);
- thld_ctrl |= QUEUE_THLD_CTRL_IBI_STA(1);
- thld_ctrl |= QUEUE_THLD_CTRL_IBI_DAT(1);
- writel(thld_ctrl, master->regs + QUEUE_THLD_CTRL);
ret = i3c_master_get_free_addr(m, 0);
if (ret < 0)
@@ -1263,6 +1271,9 @@ static int dw_i3c_master_request_ibi(struct i3c_dev_desc *dev,
struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
unsigned int i;
+ if (master->ver_type < I3C_LC_RELEASE)
+ return -EOPNOTSUPP;
+
data->ibi_pool = i3c_generic_ibi_alloc_pool(dev, req);
if (IS_ERR(data->ibi_pool))
return PTR_ERR(data->ibi_pool);
@@ -1456,7 +1467,6 @@ static void dw_i3c_master_sir_handler(struct dw_i3c_master *master,
struct i3c_ibi_slot *slot;
struct i3c_dev_desc *dev;
u8 *buf;
- int i;
dev = dw_get_i3c_dev_by_addr(master, addr);
if (!dev) {
@@ -1475,8 +1485,7 @@ static void dw_i3c_master_sir_handler(struct dw_i3c_master *master,
memcpy(buf, &ibi_status, sizeof(ibi_status));
buf += sizeof(ibi_status);
- for (i = 0; i < (!(length % 4) ? (length / 4) : (length / 4 + 1)); i++)
- dw_i3c_master_read_ibi_fifo(master, buf, length);
+ dw_i3c_master_read_ibi_fifo(master, buf, length);
slot->len = length + sizeof(ibi_status);
@@ -1572,6 +1581,8 @@ static int dw_i3c_probe(struct platform_device *pdev)
if (!master)
return -ENOMEM;
+ master->dev = &pdev->dev;
+
master->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(master->regs))
return PTR_ERR(master->regs);
@@ -1628,6 +1639,9 @@ static int dw_i3c_probe(struct platform_device *pdev)
if (ret)
goto err_assert_rst;
+ ret = readl(master->regs + I3C_VER_TYPE);
+ master->ver_type = I3C_VER_RELEASE_TYPE(ret);
+
ret = i3c_master_register(&master->base, &pdev->dev,
&dw_mipi_i3c_ops, false);
if (ret)