[PATCH 2/3] i3c: mipi-i3c-hci: Add PIO queue management support for HCI v1.2
Frank Li
Frank.li at oss.nxp.com
Thu Jul 9 11:57:19 PDT 2026
On Thu, Jul 09, 2026 at 03:17:43PM +0800, Jian-Ming Liao wrote:
> - 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.
Remove -
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.
if you prefer -, need
Some sentense ...
- abc...
>
> Co-developed-by: Patrick Yen <Patrick_Yen at asmedia.com.tw>
> Signed-off-by: Patrick Yen <Patrick_Yen at asmedia.com.tw>
> Signed-off-by: Jian-Ming Liao <Jm_Liao at asmedia.com.tw>
> ---
> drivers/i3c/master/mipi-i3c-hci/core.c | 1 +
> drivers/i3c/master/mipi-i3c-hci/pio.c | 72 ++++++++++++++++++++++----
> 2 files changed, 63 insertions(+), 10 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/pio.c b/drivers/i3c/master/mipi-i3c-hci/pio.c
> index 7870b2c7888f..c05fb3666378 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)
> +
Number start pos align to prevous GENMASK(7, 0) of CR_QUEUE_SIZE
> #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)
> @@ -138,11 +148,44 @@ static void __hci_pio_init(struct i3c_hci *hci, u32 *size_val_ptr)
> {
> u32 val, size_val, rx_thresh, tx_thresh, ibi_val;
> struct hci_pio_data *pio = hci->io_data;
> + u32 cmd_sz, resp_sz;
>
> size_val = pio_reg_read(QUEUE_SIZE);
> if (size_val_ptr)
> *size_val_ptr = 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 requires explicitly enabling and starting PIO queues
> + * and supports alternate queue sizes.
> + */
> + if (hci->version_major == 1 && hci->version_minor >= 2) {
> + u32 ctl_val = pio_reg_read(CONTROL);
> + u32 alt_val = pio_reg_read(ALT_QUEUE_SIZE);
> +
> + 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);
> +
> + /* Adjust actual FIFO sizes based on v1.2 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",
> + 4 * (2 << FIELD_GET(TX_DATA_BUFFER_SIZE, size_val)));
> +
> /*
> * Let's initialize data thresholds to half of the actual FIFO size.
> * The start thresholds aren't used (set to 0) as the FIFO is always
> @@ -172,7 +215,7 @@ static void __hci_pio_init(struct i3c_hci *hci, u32 *size_val_ptr)
> * or one available response or IBI. For IBI data let's use half the
> * IBI queue size within allowed bounds.
> */
> - ibi_val = FIELD_GET(IBI_STATUS_SIZE, size_val);
> +
> 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) |
> @@ -219,15 +262,6 @@ 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));
> - 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",
> - 4 * (2 << FIELD_GET(TX_DATA_BUFFER_SIZE, size_val)));
> -
why need move this part?
> return 0;
> }
>
> @@ -246,6 +280,12 @@ 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_major == 1 && hci->version_minor >= 2)
> + pio_reg_write(CONTROL, 0x0);
> +
> + kfree(pio);
why need kfree() here? if fix existing problem, use seperate patch.
> + hci->io_data = NULL;
> }
> }
>
> @@ -766,6 +806,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_major == 1 && hci->version_minor >= 2) {
Can you use helper macro this check, many place use similar check
Frank
> + 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
>
>
> --
> linux-i3c mailing list
> linux-i3c at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-i3c
More information about the linux-i3c
mailing list