in master/mipi-i3c-hci/core.c [583:732]
static int i3c_hci_init(struct i3c_hci *hci)
{
u32 regval, offset;
int ret;
/* Validate HCI hardware version */
regval = reg_read(HCI_VERSION);
hci->version_major = (regval >> 8) & 0xf;
hci->version_minor = (regval >> 4) & 0xf;
hci->revision = regval & 0xf;
dev_notice(&hci->master.dev, "MIPI I3C HCI v%u.%u r%02u\n",
hci->version_major, hci->version_minor, hci->revision);
/* known versions */
switch (regval & ~0xf) {
case 0x100: /* version 1.0 */
case 0x110: /* version 1.1 */
case 0x200: /* version 2.0 */
break;
default:
dev_err(&hci->master.dev, "unsupported HCI version\n");
return -EPROTONOSUPPORT;
}
hci->caps = reg_read(HC_CAPABILITIES);
DBG("caps = %#x", hci->caps);
regval = reg_read(DAT_SECTION);
offset = FIELD_GET(DAT_TABLE_OFFSET, regval);
hci->DAT_regs = offset ? hci->base_regs + offset : NULL;
hci->DAT_entries = FIELD_GET(DAT_TABLE_SIZE, regval);
hci->DAT_entry_size = FIELD_GET(DAT_ENTRY_SIZE, regval);
dev_info(&hci->master.dev, "DAT: %u %u-bytes entries at offset %#x\n",
hci->DAT_entries, hci->DAT_entry_size * 4, offset);
regval = reg_read(DCT_SECTION);
offset = FIELD_GET(DCT_TABLE_OFFSET, regval);
hci->DCT_regs = offset ? hci->base_regs + offset : NULL;
hci->DCT_entries = FIELD_GET(DCT_TABLE_SIZE, regval);
hci->DCT_entry_size = FIELD_GET(DCT_ENTRY_SIZE, regval);
dev_info(&hci->master.dev, "DCT: %u %u-bytes entries at offset %#x\n",
hci->DCT_entries, hci->DCT_entry_size * 4, offset);
regval = reg_read(RING_HEADERS_SECTION);
offset = FIELD_GET(RING_HEADERS_OFFSET, regval);
hci->RHS_regs = offset ? hci->base_regs + offset : NULL;
dev_info(&hci->master.dev, "Ring Headers at offset %#x\n", offset);
regval = reg_read(PIO_SECTION);
offset = FIELD_GET(PIO_REGS_OFFSET, regval);
hci->PIO_regs = offset ? hci->base_regs + offset : NULL;
dev_info(&hci->master.dev, "PIO section at offset %#x\n", offset);
regval = reg_read(EXT_CAPS_SECTION);
offset = FIELD_GET(EXT_CAPS_OFFSET, regval);
hci->EXTCAPS_regs = offset ? hci->base_regs + offset : NULL;
dev_info(&hci->master.dev, "Extended Caps at offset %#x\n", offset);
ret = i3c_hci_parse_ext_caps(hci);
if (ret)
return ret;
/*
* Now let's reset the hardware.
* SOFT_RST must be clear before we write to it.
* Then we must wait until it clears again.
*/
ret = readx_poll_timeout(reg_read, RESET_CONTROL, regval,
!(regval & SOFT_RST), 1, 10000);
if (ret)
return -ENXIO;
reg_write(RESET_CONTROL, SOFT_RST);
ret = readx_poll_timeout(reg_read, RESET_CONTROL, regval,
!(regval & SOFT_RST), 1, 10000);
if (ret)
return -ENXIO;
/* Disable all interrupts and allow all signal updates */
reg_write(INTR_SIGNAL_ENABLE, 0x0);
reg_write(INTR_STATUS_ENABLE, 0xffffffff);
/* Make sure our data ordering fits the host's */
regval = reg_read(HC_CONTROL);
if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) {
if (!(regval & HC_CONTROL_DATA_BIG_ENDIAN)) {
regval |= HC_CONTROL_DATA_BIG_ENDIAN;
reg_write(HC_CONTROL, regval);
regval = reg_read(HC_CONTROL);
if (!(regval & HC_CONTROL_DATA_BIG_ENDIAN)) {
dev_err(&hci->master.dev, "cannot set BE mode\n");
return -EOPNOTSUPP;
}
}
} else {
if (regval & HC_CONTROL_DATA_BIG_ENDIAN) {
regval &= ~HC_CONTROL_DATA_BIG_ENDIAN;
reg_write(HC_CONTROL, regval);
regval = reg_read(HC_CONTROL);
if (regval & HC_CONTROL_DATA_BIG_ENDIAN) {
dev_err(&hci->master.dev, "cannot clear BE mode\n");
return -EOPNOTSUPP;
}
}
}
/* Select our command descriptor model */
switch (FIELD_GET(HC_CAP_CMD_SIZE, hci->caps)) {
case 0:
hci->cmd = &mipi_i3c_hci_cmd_v1;
break;
case 1:
hci->cmd = &mipi_i3c_hci_cmd_v2;
break;
default:
dev_err(&hci->master.dev, "wrong CMD_SIZE capability value\n");
return -EINVAL;
}
/* Try activating DMA operations first */
if (hci->RHS_regs) {
reg_clear(HC_CONTROL, HC_CONTROL_PIO_MODE);
if (reg_read(HC_CONTROL) & HC_CONTROL_PIO_MODE) {
dev_err(&hci->master.dev, "PIO mode is stuck\n");
ret = -EIO;
} else {
hci->io = &mipi_i3c_hci_dma;
dev_info(&hci->master.dev, "Using DMA\n");
}
}
/* If no DMA, try PIO */
if (!hci->io && hci->PIO_regs) {
reg_set(HC_CONTROL, HC_CONTROL_PIO_MODE);
if (!(reg_read(HC_CONTROL) & HC_CONTROL_PIO_MODE)) {
dev_err(&hci->master.dev, "DMA mode is stuck\n");
ret = -EIO;
} else {
hci->io = &mipi_i3c_hci_pio;
dev_info(&hci->master.dev, "Using PIO\n");
}
}
if (!hci->io) {
dev_err(&hci->master.dev, "neither DMA nor PIO can be used\n");
if (!ret)
ret = -EINVAL;
return ret;
}
return 0;
}