Lines Matching +full:i3c +full:- +full:hci
1 // SPDX-License-Identifier: BSD-3-Clause
7 * Core driver code with main interface to the I3C subsystem.
13 #include <linux/i3c/master.h>
20 #include "hci.h"
30 #define reg_read(r) readl(hci->base_regs + (r))
31 #define reg_write(r, v) writel(v, hci->base_regs + (r))
35 #define HCI_VERSION 0x00 /* HCI Version (in BCD) */
42 #define HC_CONTROL_HOT_JOIN_CTRL BIT(8) /* Hot-Join ACK/NACK Control */
46 #define HC_CONTROL_IBA_INCLUDE BIT(0) /* Include I3C Broadcast Address */
115 #define IBI_NOTIFY_HJ_REJECTED BIT(0) /* Rejected Hot-Join Control */
128 struct i3c_hci *hci = to_i3c_hci(m); in i3c_hci_bus_init() local
134 if (hci->cmd == &mipi_i3c_hci_cmd_v1) { in i3c_hci_bus_init()
135 ret = mipi_i3c_hci_dat_v1.init(hci); in i3c_hci_bus_init()
151 ret = hci->io->init(hci); in i3c_hci_bus_init()
163 struct i3c_hci *hci = to_i3c_hci(m); in i3c_hci_bus_cleanup() local
164 struct platform_device *pdev = to_platform_device(m->dev.parent); in i3c_hci_bus_cleanup()
170 hci->io->cleanup(hci); in i3c_hci_bus_cleanup()
171 if (hci->cmd == &mipi_i3c_hci_cmd_v1) in i3c_hci_bus_cleanup()
172 mipi_i3c_hci_dat_v1.cleanup(hci); in i3c_hci_bus_cleanup()
175 void mipi_i3c_hci_resume(struct i3c_hci *hci) in mipi_i3c_hci_resume() argument
181 void mipi_i3c_hci_pio_reset(struct i3c_hci *hci) in mipi_i3c_hci_pio_reset() argument
187 void mipi_i3c_hci_dct_index_reset(struct i3c_hci *hci) in mipi_i3c_hci_dct_index_reset() argument
195 struct i3c_hci *hci = to_i3c_hci(m); in i3c_hci_send_ccc_cmd() local
197 bool raw = !!(hci->quirks & HCI_QUIRK_RAW_CCC); in i3c_hci_send_ccc_cmd()
198 bool prefixed = raw && !!(ccc->id & I3C_CCC_DIRECT); in i3c_hci_send_ccc_cmd()
199 unsigned int nxfers = ccc->ndests + prefixed; in i3c_hci_send_ccc_cmd()
204 ccc->id, ccc->rnw, ccc->ndests, ccc->dests[0].payload.len); in i3c_hci_send_ccc_cmd()
208 return -ENOMEM; in i3c_hci_send_ccc_cmd()
211 xfer->data = NULL; in i3c_hci_send_ccc_cmd()
212 xfer->data_len = 0; in i3c_hci_send_ccc_cmd()
213 xfer->rnw = false; in i3c_hci_send_ccc_cmd()
214 hci->cmd->prep_ccc(hci, xfer, I3C_BROADCAST_ADDR, in i3c_hci_send_ccc_cmd()
215 ccc->id, true); in i3c_hci_send_ccc_cmd()
219 for (i = 0; i < nxfers - prefixed; i++) { in i3c_hci_send_ccc_cmd()
220 xfer[i].data = ccc->dests[i].payload.data; in i3c_hci_send_ccc_cmd()
221 xfer[i].data_len = ccc->dests[i].payload.len; in i3c_hci_send_ccc_cmd()
222 xfer[i].rnw = ccc->rnw; in i3c_hci_send_ccc_cmd()
223 ret = hci->cmd->prep_ccc(hci, &xfer[i], ccc->dests[i].addr, in i3c_hci_send_ccc_cmd()
224 ccc->id, raw); in i3c_hci_send_ccc_cmd()
229 last = i - 1; in i3c_hci_send_ccc_cmd()
234 xfer--; in i3c_hci_send_ccc_cmd()
236 ret = hci->io->queue_xfer(hci, xfer, nxfers); in i3c_hci_send_ccc_cmd()
240 hci->io->dequeue_xfer(hci, xfer, nxfers)) { in i3c_hci_send_ccc_cmd()
241 ret = -ETIME; in i3c_hci_send_ccc_cmd()
245 if (ccc->rnw) in i3c_hci_send_ccc_cmd()
246 ccc->dests[i - prefixed].payload.len = in i3c_hci_send_ccc_cmd()
253 ccc->err = I3C_ERROR_M2; in i3c_hci_send_ccc_cmd()
256 ret = -EIO; in i3c_hci_send_ccc_cmd()
261 if (ccc->rnw) in i3c_hci_send_ccc_cmd()
263 ccc->dests[0].payload.len, ccc->dests[0].payload.data); in i3c_hci_send_ccc_cmd()
272 struct i3c_hci *hci = to_i3c_hci(m); in i3c_hci_daa() local
276 return hci->cmd->perform_daa(hci); in i3c_hci_daa()
279 static int i3c_hci_alloc_safe_xfer_buf(struct i3c_hci *hci, in i3c_hci_alloc_safe_xfer_buf() argument
282 if (hci->io != &mipi_i3c_hci_dma || in i3c_hci_alloc_safe_xfer_buf()
283 xfer->data == NULL || !is_vmalloc_addr(xfer->data)) in i3c_hci_alloc_safe_xfer_buf()
286 if (xfer->rnw) in i3c_hci_alloc_safe_xfer_buf()
287 xfer->bounce_buf = kzalloc(xfer->data_len, GFP_KERNEL); in i3c_hci_alloc_safe_xfer_buf()
289 xfer->bounce_buf = kmemdup(xfer->data, in i3c_hci_alloc_safe_xfer_buf()
290 xfer->data_len, GFP_KERNEL); in i3c_hci_alloc_safe_xfer_buf()
292 return xfer->bounce_buf == NULL ? -ENOMEM : 0; in i3c_hci_alloc_safe_xfer_buf()
295 static void i3c_hci_free_safe_xfer_buf(struct i3c_hci *hci, in i3c_hci_free_safe_xfer_buf() argument
298 if (hci->io != &mipi_i3c_hci_dma || xfer->bounce_buf == NULL) in i3c_hci_free_safe_xfer_buf()
301 if (xfer->rnw) in i3c_hci_free_safe_xfer_buf()
302 memcpy(xfer->data, xfer->bounce_buf, xfer->data_len); in i3c_hci_free_safe_xfer_buf()
304 kfree(xfer->bounce_buf); in i3c_hci_free_safe_xfer_buf()
312 struct i3c_hci *hci = to_i3c_hci(m); in i3c_hci_priv_xfers() local
322 return -ENOMEM; in i3c_hci_priv_xfers()
324 size_limit = 1U << (16 + FIELD_GET(HC_CAP_MAX_DATA_LENGTH, hci->caps)); in i3c_hci_priv_xfers()
328 ret = -EFBIG; in i3c_hci_priv_xfers()
338 hci->cmd->prep_i3c_xfer(hci, dev, &xfer[i]); in i3c_hci_priv_xfers()
340 ret = i3c_hci_alloc_safe_xfer_buf(hci, &xfer[i]); in i3c_hci_priv_xfers()
344 last = i - 1; in i3c_hci_priv_xfers()
348 ret = hci->io->queue_xfer(hci, xfer, nxfers); in i3c_hci_priv_xfers()
352 hci->io->dequeue_xfer(hci, xfer, nxfers)) { in i3c_hci_priv_xfers()
353 ret = -ETIME; in i3c_hci_priv_xfers()
360 ret = -EIO; in i3c_hci_priv_xfers()
367 i3c_hci_free_safe_xfer_buf(hci, &xfer[i]); in i3c_hci_priv_xfers()
377 struct i3c_hci *hci = to_i3c_hci(m); in i3c_hci_i2c_xfers() local
386 return -ENOMEM; in i3c_hci_i2c_xfers()
392 hci->cmd->prep_i2c_xfer(hci, dev, &xfer[i]); in i3c_hci_i2c_xfers()
394 ret = i3c_hci_alloc_safe_xfer_buf(hci, &xfer[i]); in i3c_hci_i2c_xfers()
398 last = i - 1; in i3c_hci_i2c_xfers()
402 ret = hci->io->queue_xfer(hci, xfer, nxfers); in i3c_hci_i2c_xfers()
406 hci->io->dequeue_xfer(hci, xfer, nxfers)) { in i3c_hci_i2c_xfers()
407 ret = -ETIME; in i3c_hci_i2c_xfers()
412 ret = -EIO; in i3c_hci_i2c_xfers()
419 i3c_hci_free_safe_xfer_buf(hci, &xfer[i]); in i3c_hci_i2c_xfers()
428 struct i3c_hci *hci = to_i3c_hci(m); in i3c_hci_attach_i3c_dev() local
436 return -ENOMEM; in i3c_hci_attach_i3c_dev()
437 if (hci->cmd == &mipi_i3c_hci_cmd_v1) { in i3c_hci_attach_i3c_dev()
438 ret = mipi_i3c_hci_dat_v1.alloc_entry(hci); in i3c_hci_attach_i3c_dev()
443 mipi_i3c_hci_dat_v1.set_dynamic_addr(hci, ret, dev->info.dyn_addr); in i3c_hci_attach_i3c_dev()
444 dev_data->dat_idx = ret; in i3c_hci_attach_i3c_dev()
453 struct i3c_hci *hci = to_i3c_hci(m); in i3c_hci_reattach_i3c_dev() local
458 if (hci->cmd == &mipi_i3c_hci_cmd_v1) in i3c_hci_reattach_i3c_dev()
459 mipi_i3c_hci_dat_v1.set_dynamic_addr(hci, dev_data->dat_idx, in i3c_hci_reattach_i3c_dev()
460 dev->info.dyn_addr); in i3c_hci_reattach_i3c_dev()
467 struct i3c_hci *hci = to_i3c_hci(m); in i3c_hci_detach_i3c_dev() local
473 if (hci->cmd == &mipi_i3c_hci_cmd_v1) in i3c_hci_detach_i3c_dev()
474 mipi_i3c_hci_dat_v1.free_entry(hci, dev_data->dat_idx); in i3c_hci_detach_i3c_dev()
481 struct i3c_hci *hci = to_i3c_hci(m); in i3c_hci_attach_i2c_dev() local
487 if (hci->cmd != &mipi_i3c_hci_cmd_v1) in i3c_hci_attach_i2c_dev()
491 return -ENOMEM; in i3c_hci_attach_i2c_dev()
492 ret = mipi_i3c_hci_dat_v1.alloc_entry(hci); in i3c_hci_attach_i2c_dev()
497 mipi_i3c_hci_dat_v1.set_static_addr(hci, ret, dev->addr); in i3c_hci_attach_i2c_dev()
498 mipi_i3c_hci_dat_v1.set_flags(hci, ret, DAT_0_I2C_DEVICE, 0); in i3c_hci_attach_i2c_dev()
499 dev_data->dat_idx = ret; in i3c_hci_attach_i2c_dev()
507 struct i3c_hci *hci = to_i3c_hci(m); in i3c_hci_detach_i2c_dev() local
514 if (hci->cmd == &mipi_i3c_hci_cmd_v1) in i3c_hci_detach_i2c_dev()
515 mipi_i3c_hci_dat_v1.free_entry(hci, dev_data->dat_idx); in i3c_hci_detach_i2c_dev()
524 struct i3c_hci *hci = to_i3c_hci(m); in i3c_hci_request_ibi() local
526 unsigned int dat_idx = dev_data->dat_idx; in i3c_hci_request_ibi()
528 if (req->max_payload_len != 0) in i3c_hci_request_ibi()
529 mipi_i3c_hci_dat_v1.set_flags(hci, dat_idx, DAT_0_IBI_PAYLOAD, 0); in i3c_hci_request_ibi()
531 mipi_i3c_hci_dat_v1.clear_flags(hci, dat_idx, DAT_0_IBI_PAYLOAD, 0); in i3c_hci_request_ibi()
532 return hci->io->request_ibi(hci, dev, req); in i3c_hci_request_ibi()
538 struct i3c_hci *hci = to_i3c_hci(m); in i3c_hci_free_ibi() local
540 hci->io->free_ibi(hci, dev); in i3c_hci_free_ibi()
546 struct i3c_hci *hci = to_i3c_hci(m); in i3c_hci_enable_ibi() local
549 mipi_i3c_hci_dat_v1.clear_flags(hci, dev_data->dat_idx, DAT_0_SIR_REJECT, 0); in i3c_hci_enable_ibi()
550 return i3c_master_enec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR); in i3c_hci_enable_ibi()
556 struct i3c_hci *hci = to_i3c_hci(m); in i3c_hci_disable_ibi() local
559 mipi_i3c_hci_dat_v1.set_flags(hci, dev_data->dat_idx, DAT_0_SIR_REJECT, 0); in i3c_hci_disable_ibi()
560 return i3c_master_disec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR); in i3c_hci_disable_ibi()
567 struct i3c_hci *hci = to_i3c_hci(m); in i3c_hci_recycle_ibi_slot() local
569 hci->io->recycle_ibi_slot(hci, dev, slot); in i3c_hci_recycle_ibi_slot()
593 struct i3c_hci *hci = dev_id; in i3c_hci_irq_handler() local
612 dev_err(&hci->master.dev, "Host Controller Internal Error\n"); in i3c_hci_irq_handler()
616 hci->io->irq_handler(hci, 0); in i3c_hci_irq_handler()
620 hci->io->irq_handler(hci, val & INTR_HC_RINGS); in i3c_hci_irq_handler()
624 dev_err(&hci->master.dev, "unexpected INTR_STATUS %#x\n", val); in i3c_hci_irq_handler()
631 static int i3c_hci_init(struct i3c_hci *hci) in i3c_hci_init() argument
636 /* Validate HCI hardware version */ in i3c_hci_init()
638 hci->version_major = (regval >> 8) & 0xf; in i3c_hci_init()
639 hci->version_minor = (regval >> 4) & 0xf; in i3c_hci_init()
640 hci->revision = regval & 0xf; in i3c_hci_init()
641 dev_notice(&hci->master.dev, "MIPI I3C HCI v%u.%u r%02u\n", in i3c_hci_init()
642 hci->version_major, hci->version_minor, hci->revision); in i3c_hci_init()
650 dev_err(&hci->master.dev, "unsupported HCI version\n"); in i3c_hci_init()
651 return -EPROTONOSUPPORT; in i3c_hci_init()
654 hci->caps = reg_read(HC_CAPABILITIES); in i3c_hci_init()
655 DBG("caps = %#x", hci->caps); in i3c_hci_init()
659 hci->DAT_regs = offset ? hci->base_regs + offset : NULL; in i3c_hci_init()
660 hci->DAT_entries = FIELD_GET(DAT_TABLE_SIZE, regval); in i3c_hci_init()
661 hci->DAT_entry_size = FIELD_GET(DAT_ENTRY_SIZE, regval) ? 0 : 8; in i3c_hci_init()
662 dev_info(&hci->master.dev, "DAT: %u %u-bytes entries at offset %#x\n", in i3c_hci_init()
663 hci->DAT_entries, hci->DAT_entry_size, offset); in i3c_hci_init()
667 hci->DCT_regs = offset ? hci->base_regs + offset : NULL; in i3c_hci_init()
668 hci->DCT_entries = FIELD_GET(DCT_TABLE_SIZE, regval); in i3c_hci_init()
669 hci->DCT_entry_size = FIELD_GET(DCT_ENTRY_SIZE, regval) ? 0 : 16; in i3c_hci_init()
670 dev_info(&hci->master.dev, "DCT: %u %u-bytes entries at offset %#x\n", in i3c_hci_init()
671 hci->DCT_entries, hci->DCT_entry_size, offset); in i3c_hci_init()
675 hci->RHS_regs = offset ? hci->base_regs + offset : NULL; in i3c_hci_init()
676 dev_info(&hci->master.dev, "Ring Headers at offset %#x\n", offset); in i3c_hci_init()
680 hci->PIO_regs = offset ? hci->base_regs + offset : NULL; in i3c_hci_init()
681 dev_info(&hci->master.dev, "PIO section at offset %#x\n", offset); in i3c_hci_init()
685 hci->EXTCAPS_regs = offset ? hci->base_regs + offset : NULL; in i3c_hci_init()
686 dev_info(&hci->master.dev, "Extended Caps at offset %#x\n", offset); in i3c_hci_init()
688 ret = i3c_hci_parse_ext_caps(hci); in i3c_hci_init()
700 return -ENXIO; in i3c_hci_init()
705 return -ENXIO; in i3c_hci_init()
719 dev_err(&hci->master.dev, "cannot set BE mode\n"); in i3c_hci_init()
720 return -EOPNOTSUPP; in i3c_hci_init()
729 dev_err(&hci->master.dev, "cannot clear BE mode\n"); in i3c_hci_init()
730 return -EOPNOTSUPP; in i3c_hci_init()
736 switch (FIELD_GET(HC_CAP_CMD_SIZE, hci->caps)) { in i3c_hci_init()
738 hci->cmd = &mipi_i3c_hci_cmd_v1; in i3c_hci_init()
741 hci->cmd = &mipi_i3c_hci_cmd_v2; in i3c_hci_init()
744 dev_err(&hci->master.dev, "wrong CMD_SIZE capability value\n"); in i3c_hci_init()
745 return -EINVAL; in i3c_hci_init()
749 if (hci->RHS_regs) { in i3c_hci_init()
752 dev_err(&hci->master.dev, "PIO mode is stuck\n"); in i3c_hci_init()
753 ret = -EIO; in i3c_hci_init()
755 hci->io = &mipi_i3c_hci_dma; in i3c_hci_init()
756 dev_info(&hci->master.dev, "Using DMA\n"); in i3c_hci_init()
761 if (!hci->io && hci->PIO_regs) { in i3c_hci_init()
764 dev_err(&hci->master.dev, "DMA mode is stuck\n"); in i3c_hci_init()
765 ret = -EIO; in i3c_hci_init()
767 hci->io = &mipi_i3c_hci_pio; in i3c_hci_init()
768 dev_info(&hci->master.dev, "Using PIO\n"); in i3c_hci_init()
772 if (!hci->io) { in i3c_hci_init()
773 dev_err(&hci->master.dev, "neither DMA nor PIO can be used\n"); in i3c_hci_init()
775 ret = -EINVAL; in i3c_hci_init()
784 struct i3c_hci *hci; in i3c_hci_probe() local
787 hci = devm_kzalloc(&pdev->dev, sizeof(*hci), GFP_KERNEL); in i3c_hci_probe()
788 if (!hci) in i3c_hci_probe()
789 return -ENOMEM; in i3c_hci_probe()
790 hci->base_regs = devm_platform_ioremap_resource(pdev, 0); in i3c_hci_probe()
791 if (IS_ERR(hci->base_regs)) in i3c_hci_probe()
792 return PTR_ERR(hci->base_regs); in i3c_hci_probe()
794 platform_set_drvdata(pdev, hci); in i3c_hci_probe()
796 hci->master.dev.init_name = dev_name(&pdev->dev); in i3c_hci_probe()
798 ret = i3c_hci_init(hci); in i3c_hci_probe()
803 ret = devm_request_irq(&pdev->dev, irq, i3c_hci_irq_handler, in i3c_hci_probe()
804 0, NULL, hci); in i3c_hci_probe()
808 ret = i3c_master_register(&hci->master, &pdev->dev, in i3c_hci_probe()
818 struct i3c_hci *hci = platform_get_drvdata(pdev); in i3c_hci_remove() local
820 i3c_master_unregister(&hci->master); in i3c_hci_remove()
824 { .compatible = "mipi-i3c-hci", },
833 .name = "mipi-i3c-hci",
838 MODULE_ALIAS("platform:mipi-i3c-hci");
841 MODULE_DESCRIPTION("MIPI I3C HCI driver");