[PATCH v4 2/3] i3c: mipi-i3c-hci: Add PIO queue management support for HCI v1.2
Jian-Ming Liao <[email protected]>
| Newsgroups | org.infradead.lists.linux-i3c |
|---|---|
| Message-ID | <[email protected]> |
Support explicit enablement and starting of PIO queues as required by HCI v1.2. Handle alternate PIO queue sizes via ALT_QUEUE_SIZE register. Implement explicit PIO queue stopping/disabling and restart logic after errors. Co-developed-by: Patrick Yen <[email protected]> Signed-off-by: Patrick Yen <[email protected]> Signed-off-by: Jian-Ming Liao <[email protected]> --- v4: - No content changes. Resent to fix From:/Signed-off-by: address mismatch caused by mail relay configuration (Frank). v3: - No functional code changes. - Aligned From: and Signed-off-by: email addresses (Adrian). v2: - Removed '-' prefixes from commit message (Frank). - Aligned GENMASK bit definitions with existing macro styles (Frank). - Reverted unnecessary dev_dbg line movements (Frank). - Removed manual kfree(pio) as pio is devm managed (Frank). - Introduced helper macro for HCI version checks (Frank). drivers/i3c/master/mipi-i3c-hci/core.c | 1 + drivers/i3c/master/mipi-i3c-hci/hci.h | 5 ++ drivers/i3c/master/mipi-i3c-hci/pio.c | 67 ++++++++++++++++++++++++-- 3 files changed, 69 insertions(+), 4 deletions(-) diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c index e80aa1f5722e..dccc974ef15a 100644 --- a/drivers/i3c/master/mipi-i3c-hci/core.c +++ b/drivers/i3c/master/mipi-i3c-hci/core.c @@ -1031,6 +1031,7 @@ static int i3c_hci_init(struct i3c_hci *hci) switch (regval & ~0xf) { case 0x100: /* version 1.0 */ case 0x110: /* version 1.1 */ + case 0x120: /* version 1.2 */ case 0x200: /* version 2.0 */ break; default: diff --git a/drivers/i3c/master/mipi-i3c-hci/hci.h b/drivers/i3c/master/mipi-i3c-hci/hci.h index b3d9803b1968..becccb1a8cf5 100644 --- a/drivers/i3c/master/mipi-i3c-hci/hci.h +++ b/drivers/i3c/master/mipi-i3c-hci/hci.h @@ -30,6 +30,11 @@ #define reg_set(r, v) reg_write(r, reg_read(r) | (v)) #define reg_clear(r, v) reg_write(r, reg_read(r) & ~(v)) +/* helper macro for HCI version check */ +#define hci_version_at_least(hci, maj, min) \ + ((hci)->version_major > (maj) || \ + ((hci)->version_major == (maj) && (hci)->version_minor >= (min))) + struct hci_cmd_ops; struct dat_words { diff --git a/drivers/i3c/master/mipi-i3c-hci/pio.c b/drivers/i3c/master/mipi-i3c-hci/pio.c index a1341d66bc65..439578a6eb54 100644 --- a/drivers/i3c/master/mipi-i3c-hci/pio.c +++ b/drivers/i3c/master/mipi-i3c-hci/pio.c @@ -45,6 +45,11 @@ #define IBI_STATUS_SIZE GENMASK(15, 8) #define CR_QUEUE_SIZE GENMASK(7, 0) +#define PIO_ALT_QUEUE_SIZE 0x1C +#define EXT_IBI_QUEUE_EN BIT(28) +#define ALT_RESP_QUEUE_EN BIT(24) +#define ALT_RESP_QUEUE_SIZE GENMASK(7, 0) + #define PIO_INTR_STATUS 0x20 #define PIO_INTR_STATUS_ENABLE 0x24 #define PIO_INTR_SIGNAL_ENABLE 0x28 @@ -72,6 +77,11 @@ #define STAT_RX_THLD BIT(1) #define STAT_TX_THLD BIT(0) +#define PIO_CONTROL 0x30 +#define PIO_CONTROL_ABORT BIT(2) +#define PIO_CONTROL_RS BIT(1) +#define PIO_CONTROL_ENABLE BIT(0) + #define PIO_QUEUE_CUR_STATUS 0x38 #define CUR_IBI_Q_LEVEL GENMASK(28, 20) #define CUR_RESP_Q_LEVEL GENMASK(18, 10) @@ -173,6 +183,14 @@ static void __hci_pio_init(struct i3c_hci *hci, u32 *size_val_ptr) * IBI queue size within allowed bounds. */ ibi_val = FIELD_GET(IBI_STATUS_SIZE, size_val); + /* Adjust actual IBI queue size based on v1.2 ALT_QUEUE_SIZE */ + if (hci_version_at_least(hci, 1, 2)) { + u32 alt_val = pio_reg_read(ALT_QUEUE_SIZE); + + if (alt_val & EXT_IBI_QUEUE_EN) + ibi_val *= 8; + } + pio->max_ibi_thresh = clamp_val(ibi_val/2, 1, 63); val = FIELD_PREP(QUEUE_IBI_STATUS_THLD, 1) | FIELD_PREP(QUEUE_IBI_DATA_THLD, pio->max_ibi_thresh) | @@ -190,6 +208,17 @@ static void __hci_pio_init(struct i3c_hci *hci, u32 *size_val_ptr) * (will be activated on first xfer). */ pio->enabled_irqs = STAT_ALL_ERRORS | STAT_IBI_STATUS_THLD; + + /* MIPI I3C HCI v1.2 requires explicitly enabling and starting PIO queues */ + if (hci_version_at_least(hci, 1, 2)) { + u32 ctl_val = pio_reg_read(CONTROL); + + if (!(ctl_val & PIO_CONTROL_ENABLE)) { + ctl_val |= PIO_CONTROL_ENABLE; + pio_reg_write(CONTROL, ctl_val); + } + pio_reg_write(CONTROL, ctl_val | PIO_CONTROL_RS); + } } static void hci_pio_suspend(struct i3c_hci *hci) @@ -208,6 +237,7 @@ static int hci_pio_init(struct i3c_hci *hci) { struct hci_pio_data *pio; u32 size_val; + u32 cmd_sz, resp_sz, ibi_val; pio = devm_kzalloc(hci->master.dev.parent, sizeof(*pio), GFP_KERNEL); if (!pio) @@ -217,10 +247,24 @@ static int hci_pio_init(struct i3c_hci *hci) __hci_pio_init(hci, &size_val); - dev_dbg(&hci->master.dev, "CMD/RESP FIFO = %ld entries\n", - FIELD_GET(CR_QUEUE_SIZE, size_val)); - dev_dbg(&hci->master.dev, "IBI FIFO = %ld bytes\n", - 4 * FIELD_GET(IBI_STATUS_SIZE, size_val)); + cmd_sz = FIELD_GET(CR_QUEUE_SIZE, size_val); + resp_sz = cmd_sz; + ibi_val = FIELD_GET(IBI_STATUS_SIZE, size_val); + + /* MIPI I3C HCI v1.2 supports alternate RESP/IBI queue size */ + if (hci_version_at_least(hci, 1, 2)) { + u32 alt_val = pio_reg_read(ALT_QUEUE_SIZE); + + if (alt_val & ALT_RESP_QUEUE_EN) + resp_sz = FIELD_GET(ALT_RESP_QUEUE_SIZE, alt_val); + if (alt_val & EXT_IBI_QUEUE_EN) + ibi_val *= 8; + } + + dev_dbg(&hci->master.dev, "CMD FIFO = %u, RESP FIFO = %u entries\n", + cmd_sz, resp_sz); + dev_dbg(&hci->master.dev, "IBI FIFO = %u bytes\n", + 4 * ibi_val); dev_dbg(&hci->master.dev, "RX data FIFO = %d bytes\n", 4 * (2 << FIELD_GET(RX_DATA_BUFFER_SIZE, size_val))); dev_dbg(&hci->master.dev, "TX data FIFO = %d bytes\n", @@ -244,6 +288,9 @@ static void hci_pio_cleanup(struct i3c_hci *hci) BUG_ON(pio->curr_rx); BUG_ON(pio->curr_tx); BUG_ON(pio->curr_resp); + /* MIPI I3C HCI v1.2 requires explicitly stopping and disabling PIO queues */ + if (hci_version_at_least(hci, 1, 2)) + pio_reg_write(CONTROL, 0x0); } } @@ -764,6 +811,18 @@ static void hci_pio_err(struct i3c_hci *hci, struct hci_pio_data *pio, hci_pio_dequeue_xfer_common(hci, pio, pio->curr_tx, 1); /* then reset the hardware */ mipi_i3c_hci_pio_reset(hci); + + /* MIPI I3C HCI v1.2 requires explicitly restarting PIO queues after error/abort */ + if (hci_version_at_least(hci, 1, 2)) { + u32 ctl_val = pio_reg_read(CONTROL); + + if (!(ctl_val & PIO_CONTROL_ENABLE)) { + ctl_val |= PIO_CONTROL_ENABLE; + pio_reg_write(CONTROL, ctl_val); + } + pio_reg_write(CONTROL, ctl_val | PIO_CONTROL_RS); + } + mipi_i3c_hci_resume(hci); dev_dbg(&hci->master.dev, "status=%#x/%#x", -- 2.43.0 ================================================================================================================== This email and any attachments to it contain confidential information and are intended solely for the use of the individual to whom it is addressed.If you are not the intended recipient or receive it accidentally, please immediately notify the sender by e-mail and delete the message and any attachments from your computer system, and destroy all hard copies. If any, please be advised that any unauthorized disclosure, copying, distribution or any action taken or omitted in reliance on this, is illegal and prohibited. Furthermore, any views or opinions expressed are solely those of the author and do not represent those of ASMedia Technology Inc. Thank you for your cooperation. ================================================================================================================== -- linux-i3c mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-i3c