drivers/i3c/master/mipi-i3c-hci/pio.c

Source file repositories/reference/linux-study-clean/drivers/i3c/master/mipi-i3c-hci/pio.c

File Facts

System
Linux kernel
Corpus path
drivers/i3c/master/mipi-i3c-hci/pio.c
Extension
.c
Size
30518 bytes
Lines
1080
Domain
Driver Families
Bucket
drivers/i3c
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct hci_pio_dev_ibi_data {
	struct i3c_generic_ibi_pool *pool;
	unsigned int max_len;
};

struct hci_pio_ibi_data {
	struct i3c_ibi_slot *slot;
	void *data_ptr;
	unsigned int addr;
	unsigned int seg_len, seg_cnt;
	unsigned int max_len;
	bool last_seg;
};

struct hci_pio_data {
	struct hci_xfer *curr_xfer, *xfer_queue;
	struct hci_xfer *curr_rx, *rx_queue;
	struct hci_xfer *curr_tx, *tx_queue;
	struct hci_xfer *curr_resp, *resp_queue;
	struct hci_pio_ibi_data ibi;
	unsigned int rx_thresh_size, tx_thresh_size;
	unsigned int max_ibi_thresh;
	u32 reg_queue_thresh;
	u32 enabled_irqs;
};

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;

	size_val = pio_reg_read(QUEUE_SIZE);
	if (size_val_ptr)
		*size_val_ptr = 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
	 * serviced before the corresponding command is queued.
	 */
	rx_thresh = FIELD_GET(RX_DATA_BUFFER_SIZE, size_val);
	tx_thresh = FIELD_GET(TX_DATA_BUFFER_SIZE, size_val);
	if (hci->version_major == 1) {
		/* those are expressed as 2^[n+1), so just sub 1 if not 0 */
		if (rx_thresh)
			rx_thresh -= 1;
		if (tx_thresh)
			tx_thresh -= 1;
		pio->rx_thresh_size = 2 << rx_thresh;
		pio->tx_thresh_size = 2 << tx_thresh;
	} else {
		/* size is 2^(n+1) and threshold is 2^n i.e. already halved */
		pio->rx_thresh_size = 1 << rx_thresh;
		pio->tx_thresh_size = 1 << tx_thresh;
	}
	val = FIELD_PREP(DATA_RX_BUF_THLD,   rx_thresh) |
	      FIELD_PREP(DATA_TX_BUF_THLD,   tx_thresh);
	pio_reg_write(DATA_BUFFER_THLD_CTRL, val);

	/*
	 * Let's raise an interrupt as soon as there is one free cmd slot
	 * 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) |
	      FIELD_PREP(QUEUE_RESP_BUF_THLD, 1) |
	      FIELD_PREP(QUEUE_CMD_EMPTY_BUF_THLD, 1);
	pio_reg_write(QUEUE_THLD_CTRL, val);
	pio->reg_queue_thresh = val;

	/* Disable all IRQs but allow all status bits */
	pio_reg_write(INTR_SIGNAL_ENABLE, 0x0);
	pio_reg_write(INTR_STATUS_ENABLE, 0xffffffff);

	/* Always accept error interrupts (will be activated on first xfer) */
	pio->enabled_irqs = STAT_ALL_ERRORS;
}

static void hci_pio_suspend(struct i3c_hci *hci)
{
	pio_reg_write(INTR_SIGNAL_ENABLE, 0);

	i3c_hci_sync_irq_inactive(hci);
}

static void hci_pio_resume(struct i3c_hci *hci)
{

Annotation

Implementation Notes