Lines Matching +full:dw +full:- +full:i3c +full:- +full:master +full:- +full:1

1 // SPDX-License-Identifier: GPL-2.0
13 #include <linux/i3c/master.h>
24 #include "dw-i3c-master.h"
66 #define RESPONSE_ERROR_CRC 1
81 #define IBI_QUEUE_IBI_ADDR(x) (IBI_QUEUE_STATUS_IBI_ID(x) >> 1)
92 #define QUEUE_THLD_CTRL_IBI_STAT(x) (((x) - 1) << 24)
96 #define QUEUE_THLD_CTRL_RESP_BUF(x) (((x) - 1) << 8)
111 #define RESET_CTRL_CMD_QUEUE BIT(1)
130 #define INTR_RX_THLD_STAT BIT(1)
249 return (0x9669 >> p) & 1; in even_parity()
255 if (cmd->ndests > 1) in dw_i3c_master_supports_ccc_cmd()
258 switch (cmd->id) { in dw_i3c_master_supports_ccc_cmd()
290 to_dw_i3c_master(struct i3c_master_controller *master) in to_dw_i3c_master() argument
292 return container_of(master, struct dw_i3c_master, base); in to_dw_i3c_master()
295 static void dw_i3c_master_disable(struct dw_i3c_master *master) in dw_i3c_master_disable() argument
297 writel(readl(master->regs + DEVICE_CTRL) & ~DEV_CTRL_ENABLE, in dw_i3c_master_disable()
298 master->regs + DEVICE_CTRL); in dw_i3c_master_disable()
301 static void dw_i3c_master_enable(struct dw_i3c_master *master) in dw_i3c_master_enable() argument
303 writel(readl(master->regs + DEVICE_CTRL) | DEV_CTRL_ENABLE, in dw_i3c_master_enable()
304 master->regs + DEVICE_CTRL); in dw_i3c_master_enable()
307 static int dw_i3c_master_get_addr_pos(struct dw_i3c_master *master, u8 addr) in dw_i3c_master_get_addr_pos() argument
311 for (pos = 0; pos < master->maxdevs; pos++) { in dw_i3c_master_get_addr_pos()
312 if (addr == master->devs[pos].addr) in dw_i3c_master_get_addr_pos()
316 return -EINVAL; in dw_i3c_master_get_addr_pos()
319 static int dw_i3c_master_get_free_pos(struct dw_i3c_master *master) in dw_i3c_master_get_free_pos() argument
321 if (!(master->free_pos & GENMASK(master->maxdevs - 1, 0))) in dw_i3c_master_get_free_pos()
322 return -ENOSPC; in dw_i3c_master_get_free_pos()
324 return ffs(master->free_pos) - 1; in dw_i3c_master_get_free_pos()
327 static void dw_i3c_master_wr_tx_fifo(struct dw_i3c_master *master, in dw_i3c_master_wr_tx_fifo() argument
330 writesl(master->regs + RX_TX_DATA_PORT, bytes, nbytes / 4); in dw_i3c_master_wr_tx_fifo()
335 writesl(master->regs + RX_TX_DATA_PORT, &tmp, 1); in dw_i3c_master_wr_tx_fifo()
339 static void dw_i3c_master_read_fifo(struct dw_i3c_master *master, in dw_i3c_master_read_fifo() argument
342 readsl(master->regs + reg, bytes, nbytes / 4); in dw_i3c_master_read_fifo()
346 readsl(master->regs + reg, &tmp, 1); in dw_i3c_master_read_fifo()
351 static void dw_i3c_master_read_rx_fifo(struct dw_i3c_master *master, in dw_i3c_master_read_rx_fifo() argument
354 return dw_i3c_master_read_fifo(master, RX_TX_DATA_PORT, bytes, nbytes); in dw_i3c_master_read_rx_fifo()
357 static void dw_i3c_master_read_ibi_fifo(struct dw_i3c_master *master, in dw_i3c_master_read_ibi_fifo() argument
360 return dw_i3c_master_read_fifo(master, IBI_QUEUE_STATUS, bytes, nbytes); in dw_i3c_master_read_ibi_fifo()
364 dw_i3c_master_alloc_xfer(struct dw_i3c_master *master, unsigned int ncmds) in dw_i3c_master_alloc_xfer() argument
372 INIT_LIST_HEAD(&xfer->node); in dw_i3c_master_alloc_xfer()
373 xfer->ncmds = ncmds; in dw_i3c_master_alloc_xfer()
374 xfer->ret = -ETIMEDOUT; in dw_i3c_master_alloc_xfer()
384 static void dw_i3c_master_start_xfer_locked(struct dw_i3c_master *master) in dw_i3c_master_start_xfer_locked() argument
386 struct dw_i3c_xfer *xfer = master->xferqueue.cur; in dw_i3c_master_start_xfer_locked()
393 for (i = 0; i < xfer->ncmds; i++) { in dw_i3c_master_start_xfer_locked()
394 struct dw_i3c_cmd *cmd = &xfer->cmds[i]; in dw_i3c_master_start_xfer_locked()
396 dw_i3c_master_wr_tx_fifo(master, cmd->tx_buf, cmd->tx_len); in dw_i3c_master_start_xfer_locked()
399 thld_ctrl = readl(master->regs + QUEUE_THLD_CTRL); in dw_i3c_master_start_xfer_locked()
401 thld_ctrl |= QUEUE_THLD_CTRL_RESP_BUF(xfer->ncmds); in dw_i3c_master_start_xfer_locked()
402 writel(thld_ctrl, master->regs + QUEUE_THLD_CTRL); in dw_i3c_master_start_xfer_locked()
404 for (i = 0; i < xfer->ncmds; i++) { in dw_i3c_master_start_xfer_locked()
405 struct dw_i3c_cmd *cmd = &xfer->cmds[i]; in dw_i3c_master_start_xfer_locked()
407 writel(cmd->cmd_hi, master->regs + COMMAND_QUEUE_PORT); in dw_i3c_master_start_xfer_locked()
408 writel(cmd->cmd_lo, master->regs + COMMAND_QUEUE_PORT); in dw_i3c_master_start_xfer_locked()
412 static void dw_i3c_master_enqueue_xfer(struct dw_i3c_master *master, in dw_i3c_master_enqueue_xfer() argument
417 init_completion(&xfer->comp); in dw_i3c_master_enqueue_xfer()
418 spin_lock_irqsave(&master->xferqueue.lock, flags); in dw_i3c_master_enqueue_xfer()
419 if (master->xferqueue.cur) { in dw_i3c_master_enqueue_xfer()
420 list_add_tail(&xfer->node, &master->xferqueue.list); in dw_i3c_master_enqueue_xfer()
422 master->xferqueue.cur = xfer; in dw_i3c_master_enqueue_xfer()
423 dw_i3c_master_start_xfer_locked(master); in dw_i3c_master_enqueue_xfer()
425 spin_unlock_irqrestore(&master->xferqueue.lock, flags); in dw_i3c_master_enqueue_xfer()
428 static void dw_i3c_master_dequeue_xfer_locked(struct dw_i3c_master *master, in dw_i3c_master_dequeue_xfer_locked() argument
431 if (master->xferqueue.cur == xfer) { in dw_i3c_master_dequeue_xfer_locked()
434 master->xferqueue.cur = NULL; in dw_i3c_master_dequeue_xfer_locked()
438 master->regs + RESET_CTRL); in dw_i3c_master_dequeue_xfer_locked()
440 readl_poll_timeout_atomic(master->regs + RESET_CTRL, status, in dw_i3c_master_dequeue_xfer_locked()
443 list_del_init(&xfer->node); in dw_i3c_master_dequeue_xfer_locked()
447 static void dw_i3c_master_dequeue_xfer(struct dw_i3c_master *master, in dw_i3c_master_dequeue_xfer() argument
452 spin_lock_irqsave(&master->xferqueue.lock, flags); in dw_i3c_master_dequeue_xfer()
453 dw_i3c_master_dequeue_xfer_locked(master, xfer); in dw_i3c_master_dequeue_xfer()
454 spin_unlock_irqrestore(&master->xferqueue.lock, flags); in dw_i3c_master_dequeue_xfer()
457 static void dw_i3c_master_end_xfer_locked(struct dw_i3c_master *master, u32 isr) in dw_i3c_master_end_xfer_locked() argument
459 struct dw_i3c_xfer *xfer = master->xferqueue.cur; in dw_i3c_master_end_xfer_locked()
466 nresp = readl(master->regs + QUEUE_STATUS_LEVEL); in dw_i3c_master_end_xfer_locked()
473 resp = readl(master->regs + RESPONSE_QUEUE_PORT); in dw_i3c_master_end_xfer_locked()
475 cmd = &xfer->cmds[RESPONSE_PORT_TID(resp)]; in dw_i3c_master_end_xfer_locked()
476 cmd->rx_len = RESPONSE_PORT_DATA_LEN(resp); in dw_i3c_master_end_xfer_locked()
477 cmd->error = RESPONSE_PORT_ERR_STATUS(resp); in dw_i3c_master_end_xfer_locked()
478 if (cmd->rx_len && !cmd->error) in dw_i3c_master_end_xfer_locked()
479 dw_i3c_master_read_rx_fifo(master, cmd->rx_buf, in dw_i3c_master_end_xfer_locked()
480 cmd->rx_len); in dw_i3c_master_end_xfer_locked()
484 switch (xfer->cmds[i].error) { in dw_i3c_master_end_xfer_locked()
492 ret = -EIO; in dw_i3c_master_end_xfer_locked()
495 ret = -ENOSPC; in dw_i3c_master_end_xfer_locked()
500 ret = -EINVAL; in dw_i3c_master_end_xfer_locked()
505 xfer->ret = ret; in dw_i3c_master_end_xfer_locked()
506 complete(&xfer->comp); in dw_i3c_master_end_xfer_locked()
509 dw_i3c_master_dequeue_xfer_locked(master, xfer); in dw_i3c_master_end_xfer_locked()
510 writel(readl(master->regs + DEVICE_CTRL) | DEV_CTRL_RESUME, in dw_i3c_master_end_xfer_locked()
511 master->regs + DEVICE_CTRL); in dw_i3c_master_end_xfer_locked()
514 xfer = list_first_entry_or_null(&master->xferqueue.list, in dw_i3c_master_end_xfer_locked()
518 list_del_init(&xfer->node); in dw_i3c_master_end_xfer_locked()
520 master->xferqueue.cur = xfer; in dw_i3c_master_end_xfer_locked()
521 dw_i3c_master_start_xfer_locked(master); in dw_i3c_master_end_xfer_locked()
524 static int dw_i3c_clk_cfg(struct dw_i3c_master *master) in dw_i3c_clk_cfg() argument
530 core_rate = clk_get_rate(master->core_clk); in dw_i3c_clk_cfg()
532 return -EINVAL; in dw_i3c_clk_cfg()
536 hcnt = DIV_ROUND_UP(I3C_BUS_THIGH_MAX_NS, core_period) - 1; in dw_i3c_clk_cfg()
540 lcnt = DIV_ROUND_UP(core_rate, master->base.bus.scl_rate.i3c) - hcnt; in dw_i3c_clk_cfg()
545 writel(scl_timing, master->regs + SCL_I3C_PP_TIMING); in dw_i3c_clk_cfg()
548 * In pure i3c mode, MST_FREE represents tCAS. In shared mode, this in dw_i3c_clk_cfg()
551 if (master->base.bus.mode == I3C_BUS_MODE_PURE) in dw_i3c_clk_cfg()
552 writel(BUS_I3C_MST_FREE(lcnt), master->regs + BUS_FREE_TIMING); in dw_i3c_clk_cfg()
557 writel(scl_timing, master->regs + SCL_I3C_OD_TIMING); in dw_i3c_clk_cfg()
559 lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_SDR1_SCL_RATE) - hcnt; in dw_i3c_clk_cfg()
561 lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_SDR2_SCL_RATE) - hcnt; in dw_i3c_clk_cfg()
563 lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_SDR3_SCL_RATE) - hcnt; in dw_i3c_clk_cfg()
565 lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_SDR4_SCL_RATE) - hcnt; in dw_i3c_clk_cfg()
567 writel(scl_timing, master->regs + SCL_EXT_LCNT_TIMING); in dw_i3c_clk_cfg()
572 static int dw_i2c_clk_cfg(struct dw_i3c_master *master) in dw_i2c_clk_cfg() argument
578 core_rate = clk_get_rate(master->core_clk); in dw_i2c_clk_cfg()
580 return -EINVAL; in dw_i2c_clk_cfg()
585 hcnt = DIV_ROUND_UP(core_rate, I3C_BUS_I2C_FM_PLUS_SCL_RATE) - lcnt; in dw_i2c_clk_cfg()
588 writel(scl_timing, master->regs + SCL_I2C_FMP_TIMING); in dw_i2c_clk_cfg()
591 hcnt = DIV_ROUND_UP(core_rate, I3C_BUS_I2C_FM_SCL_RATE) - lcnt; in dw_i2c_clk_cfg()
594 writel(scl_timing, master->regs + SCL_I2C_FM_TIMING); in dw_i2c_clk_cfg()
596 writel(BUS_I3C_MST_FREE(lcnt), master->regs + BUS_FREE_TIMING); in dw_i2c_clk_cfg()
597 writel(readl(master->regs + DEVICE_CTRL) | DEV_CTRL_I2C_SLAVE_PRESENT, in dw_i2c_clk_cfg()
598 master->regs + DEVICE_CTRL); in dw_i2c_clk_cfg()
605 struct dw_i3c_master *master = to_dw_i3c_master(m); in dw_i3c_master_bus_init() local
611 ret = master->platform_ops->init(master); in dw_i3c_master_bus_init()
615 switch (bus->mode) { in dw_i3c_master_bus_init()
618 ret = dw_i2c_clk_cfg(master); in dw_i3c_master_bus_init()
623 ret = dw_i3c_clk_cfg(master); in dw_i3c_master_bus_init()
628 return -EINVAL; in dw_i3c_master_bus_init()
631 thld_ctrl = readl(master->regs + QUEUE_THLD_CTRL); in dw_i3c_master_bus_init()
635 thld_ctrl |= QUEUE_THLD_CTRL_IBI_STAT(1) | in dw_i3c_master_bus_init()
637 writel(thld_ctrl, master->regs + QUEUE_THLD_CTRL); in dw_i3c_master_bus_init()
639 thld_ctrl = readl(master->regs + DATA_BUFFER_THLD_CTRL); in dw_i3c_master_bus_init()
641 writel(thld_ctrl, master->regs + DATA_BUFFER_THLD_CTRL); in dw_i3c_master_bus_init()
643 writel(INTR_ALL, master->regs + INTR_STATUS); in dw_i3c_master_bus_init()
644 writel(INTR_MASTER_MASK, master->regs + INTR_STATUS_EN); in dw_i3c_master_bus_init()
645 writel(INTR_MASTER_MASK, master->regs + INTR_SIGNAL_EN); in dw_i3c_master_bus_init()
652 master->regs + DEVICE_ADDR); in dw_i3c_master_bus_init()
657 ret = i3c_master_set_info(&master->base, &info); in dw_i3c_master_bus_init()
661 writel(IBI_REQ_REJECT_ALL, master->regs + IBI_SIR_REQ_REJECT); in dw_i3c_master_bus_init()
662 writel(IBI_REQ_REJECT_ALL, master->regs + IBI_MR_REQ_REJECT); in dw_i3c_master_bus_init()
664 /* For now don't support Hot-Join */ in dw_i3c_master_bus_init()
665 writel(readl(master->regs + DEVICE_CTRL) | DEV_CTRL_HOT_JOIN_NACK, in dw_i3c_master_bus_init()
666 master->regs + DEVICE_CTRL); in dw_i3c_master_bus_init()
668 dw_i3c_master_enable(master); in dw_i3c_master_bus_init()
675 struct dw_i3c_master *master = to_dw_i3c_master(m); in dw_i3c_master_bus_cleanup() local
677 dw_i3c_master_disable(master); in dw_i3c_master_bus_cleanup()
680 static int dw_i3c_ccc_set(struct dw_i3c_master *master, in dw_i3c_ccc_set() argument
687 if (ccc->id & I3C_CCC_DIRECT) { in dw_i3c_ccc_set()
688 pos = dw_i3c_master_get_addr_pos(master, ccc->dests[0].addr); in dw_i3c_ccc_set()
693 xfer = dw_i3c_master_alloc_xfer(master, 1); in dw_i3c_ccc_set()
695 return -ENOMEM; in dw_i3c_ccc_set()
697 cmd = xfer->cmds; in dw_i3c_ccc_set()
698 cmd->tx_buf = ccc->dests[0].payload.data; in dw_i3c_ccc_set()
699 cmd->tx_len = ccc->dests[0].payload.len; in dw_i3c_ccc_set()
701 cmd->cmd_hi = COMMAND_PORT_ARG_DATA_LEN(ccc->dests[0].payload.len) | in dw_i3c_ccc_set()
704 cmd->cmd_lo = COMMAND_PORT_CP | in dw_i3c_ccc_set()
706 COMMAND_PORT_CMD(ccc->id) | in dw_i3c_ccc_set()
710 dw_i3c_master_enqueue_xfer(master, xfer); in dw_i3c_ccc_set()
711 if (!wait_for_completion_timeout(&xfer->comp, XFER_TIMEOUT)) in dw_i3c_ccc_set()
712 dw_i3c_master_dequeue_xfer(master, xfer); in dw_i3c_ccc_set()
714 ret = xfer->ret; in dw_i3c_ccc_set()
715 if (xfer->cmds[0].error == RESPONSE_ERROR_IBA_NACK) in dw_i3c_ccc_set()
716 ccc->err = I3C_ERROR_M2; in dw_i3c_ccc_set()
723 static int dw_i3c_ccc_get(struct dw_i3c_master *master, struct i3c_ccc_cmd *ccc) in dw_i3c_ccc_get() argument
729 pos = dw_i3c_master_get_addr_pos(master, ccc->dests[0].addr); in dw_i3c_ccc_get()
733 xfer = dw_i3c_master_alloc_xfer(master, 1); in dw_i3c_ccc_get()
735 return -ENOMEM; in dw_i3c_ccc_get()
737 cmd = xfer->cmds; in dw_i3c_ccc_get()
738 cmd->rx_buf = ccc->dests[0].payload.data; in dw_i3c_ccc_get()
739 cmd->rx_len = ccc->dests[0].payload.len; in dw_i3c_ccc_get()
741 cmd->cmd_hi = COMMAND_PORT_ARG_DATA_LEN(ccc->dests[0].payload.len) | in dw_i3c_ccc_get()
744 cmd->cmd_lo = COMMAND_PORT_READ_TRANSFER | in dw_i3c_ccc_get()
747 COMMAND_PORT_CMD(ccc->id) | in dw_i3c_ccc_get()
751 dw_i3c_master_enqueue_xfer(master, xfer); in dw_i3c_ccc_get()
752 if (!wait_for_completion_timeout(&xfer->comp, XFER_TIMEOUT)) in dw_i3c_ccc_get()
753 dw_i3c_master_dequeue_xfer(master, xfer); in dw_i3c_ccc_get()
755 ret = xfer->ret; in dw_i3c_ccc_get()
756 if (xfer->cmds[0].error == RESPONSE_ERROR_IBA_NACK) in dw_i3c_ccc_get()
757 ccc->err = I3C_ERROR_M2; in dw_i3c_ccc_get()
766 struct dw_i3c_master *master = to_dw_i3c_master(m); in dw_i3c_master_send_ccc_cmd() local
769 if (ccc->id == I3C_CCC_ENTDAA) in dw_i3c_master_send_ccc_cmd()
770 return -EINVAL; in dw_i3c_master_send_ccc_cmd()
772 if (ccc->rnw) in dw_i3c_master_send_ccc_cmd()
773 ret = dw_i3c_ccc_get(master, ccc); in dw_i3c_master_send_ccc_cmd()
775 ret = dw_i3c_ccc_set(master, ccc); in dw_i3c_master_send_ccc_cmd()
782 struct dw_i3c_master *master = to_dw_i3c_master(m); in dw_i3c_master_daa() local
789 olddevs = ~(master->free_pos); in dw_i3c_master_daa()
792 for (pos = 0; pos < master->maxdevs; pos++) { in dw_i3c_master_daa()
796 ret = i3c_master_get_free_addr(m, last_addr + 1); in dw_i3c_master_daa()
798 return -ENOSPC; in dw_i3c_master_daa()
800 master->devs[pos].addr = ret; in dw_i3c_master_daa()
806 master->regs + in dw_i3c_master_daa()
807 DEV_ADDR_TABLE_LOC(master->datstartaddr, pos)); in dw_i3c_master_daa()
810 xfer = dw_i3c_master_alloc_xfer(master, 1); in dw_i3c_master_daa()
812 return -ENOMEM; in dw_i3c_master_daa()
814 pos = dw_i3c_master_get_free_pos(master); in dw_i3c_master_daa()
819 cmd = &xfer->cmds[0]; in dw_i3c_master_daa()
820 cmd->cmd_hi = 0x1; in dw_i3c_master_daa()
821 cmd->cmd_lo = COMMAND_PORT_DEV_COUNT(master->maxdevs - pos) | in dw_i3c_master_daa()
828 dw_i3c_master_enqueue_xfer(master, xfer); in dw_i3c_master_daa()
829 if (!wait_for_completion_timeout(&xfer->comp, XFER_TIMEOUT)) in dw_i3c_master_daa()
830 dw_i3c_master_dequeue_xfer(master, xfer); in dw_i3c_master_daa()
832 newdevs = GENMASK(master->maxdevs - cmd->rx_len - 1, 0); in dw_i3c_master_daa()
835 for (pos = 0; pos < master->maxdevs; pos++) { in dw_i3c_master_daa()
837 i3c_master_add_i3c_dev_locked(m, master->devs[pos].addr); in dw_i3c_master_daa()
851 struct dw_i3c_master *master = to_dw_i3c_master(m); in dw_i3c_master_priv_xfers() local
859 if (i3c_nxfers > master->caps.cmdfifodepth) in dw_i3c_master_priv_xfers()
860 return -ENOTSUPP; in dw_i3c_master_priv_xfers()
869 if (ntxwords > master->caps.datafifodepth || in dw_i3c_master_priv_xfers()
870 nrxwords > master->caps.datafifodepth) in dw_i3c_master_priv_xfers()
871 return -ENOTSUPP; in dw_i3c_master_priv_xfers()
873 xfer = dw_i3c_master_alloc_xfer(master, i3c_nxfers); in dw_i3c_master_priv_xfers()
875 return -ENOMEM; in dw_i3c_master_priv_xfers()
878 struct dw_i3c_cmd *cmd = &xfer->cmds[i]; in dw_i3c_master_priv_xfers()
880 cmd->cmd_hi = COMMAND_PORT_ARG_DATA_LEN(i3c_xfers[i].len) | in dw_i3c_master_priv_xfers()
884 cmd->rx_buf = i3c_xfers[i].data.in; in dw_i3c_master_priv_xfers()
885 cmd->rx_len = i3c_xfers[i].len; in dw_i3c_master_priv_xfers()
886 cmd->cmd_lo = COMMAND_PORT_READ_TRANSFER | in dw_i3c_master_priv_xfers()
887 COMMAND_PORT_SPEED(dev->info.max_read_ds); in dw_i3c_master_priv_xfers()
890 cmd->tx_buf = i3c_xfers[i].data.out; in dw_i3c_master_priv_xfers()
891 cmd->tx_len = i3c_xfers[i].len; in dw_i3c_master_priv_xfers()
892 cmd->cmd_lo = in dw_i3c_master_priv_xfers()
893 COMMAND_PORT_SPEED(dev->info.max_write_ds); in dw_i3c_master_priv_xfers()
896 cmd->cmd_lo |= COMMAND_PORT_TID(i) | in dw_i3c_master_priv_xfers()
897 COMMAND_PORT_DEV_INDEX(data->index) | in dw_i3c_master_priv_xfers()
900 if (i == (i3c_nxfers - 1)) in dw_i3c_master_priv_xfers()
901 cmd->cmd_lo |= COMMAND_PORT_TOC; in dw_i3c_master_priv_xfers()
904 dw_i3c_master_enqueue_xfer(master, xfer); in dw_i3c_master_priv_xfers()
905 if (!wait_for_completion_timeout(&xfer->comp, XFER_TIMEOUT)) in dw_i3c_master_priv_xfers()
906 dw_i3c_master_dequeue_xfer(master, xfer); in dw_i3c_master_priv_xfers()
909 struct dw_i3c_cmd *cmd = &xfer->cmds[i]; in dw_i3c_master_priv_xfers()
912 i3c_xfers[i].len = cmd->rx_len; in dw_i3c_master_priv_xfers()
915 ret = xfer->ret; in dw_i3c_master_priv_xfers()
926 struct dw_i3c_master *master = to_dw_i3c_master(m); in dw_i3c_master_reattach_i3c_dev() local
929 pos = dw_i3c_master_get_free_pos(master); in dw_i3c_master_reattach_i3c_dev()
931 if (data->index > pos && pos > 0) { in dw_i3c_master_reattach_i3c_dev()
933 master->regs + in dw_i3c_master_reattach_i3c_dev()
934 DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index)); in dw_i3c_master_reattach_i3c_dev()
936 master->devs[data->index].addr = 0; in dw_i3c_master_reattach_i3c_dev()
937 master->free_pos |= BIT(data->index); in dw_i3c_master_reattach_i3c_dev()
939 data->index = pos; in dw_i3c_master_reattach_i3c_dev()
940 master->devs[pos].addr = dev->info.dyn_addr; in dw_i3c_master_reattach_i3c_dev()
941 master->free_pos &= ~BIT(pos); in dw_i3c_master_reattach_i3c_dev()
944 writel(DEV_ADDR_TABLE_DYNAMIC_ADDR(dev->info.dyn_addr), in dw_i3c_master_reattach_i3c_dev()
945 master->regs + in dw_i3c_master_reattach_i3c_dev()
946 DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index)); in dw_i3c_master_reattach_i3c_dev()
948 master->devs[data->index].addr = dev->info.dyn_addr; in dw_i3c_master_reattach_i3c_dev()
956 struct dw_i3c_master *master = to_dw_i3c_master(m); in dw_i3c_master_attach_i3c_dev() local
960 pos = dw_i3c_master_get_free_pos(master); in dw_i3c_master_attach_i3c_dev()
966 return -ENOMEM; in dw_i3c_master_attach_i3c_dev()
968 data->index = pos; in dw_i3c_master_attach_i3c_dev()
969 master->devs[pos].addr = dev->info.dyn_addr ? : dev->info.static_addr; in dw_i3c_master_attach_i3c_dev()
970 master->free_pos &= ~BIT(pos); in dw_i3c_master_attach_i3c_dev()
973 writel(DEV_ADDR_TABLE_DYNAMIC_ADDR(master->devs[pos].addr), in dw_i3c_master_attach_i3c_dev()
974 master->regs + in dw_i3c_master_attach_i3c_dev()
975 DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index)); in dw_i3c_master_attach_i3c_dev()
984 struct dw_i3c_master *master = to_dw_i3c_master(m); in dw_i3c_master_detach_i3c_dev() local
987 master->regs + in dw_i3c_master_detach_i3c_dev()
988 DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index)); in dw_i3c_master_detach_i3c_dev()
991 master->devs[data->index].addr = 0; in dw_i3c_master_detach_i3c_dev()
992 master->free_pos |= BIT(data->index); in dw_i3c_master_detach_i3c_dev()
1002 struct dw_i3c_master *master = to_dw_i3c_master(m); in dw_i3c_master_i2c_xfers() local
1010 if (i2c_nxfers > master->caps.cmdfifodepth) in dw_i3c_master_i2c_xfers()
1011 return -ENOTSUPP; in dw_i3c_master_i2c_xfers()
1020 if (ntxwords > master->caps.datafifodepth || in dw_i3c_master_i2c_xfers()
1021 nrxwords > master->caps.datafifodepth) in dw_i3c_master_i2c_xfers()
1022 return -ENOTSUPP; in dw_i3c_master_i2c_xfers()
1024 xfer = dw_i3c_master_alloc_xfer(master, i2c_nxfers); in dw_i3c_master_i2c_xfers()
1026 return -ENOMEM; in dw_i3c_master_i2c_xfers()
1029 struct dw_i3c_cmd *cmd = &xfer->cmds[i]; in dw_i3c_master_i2c_xfers()
1031 cmd->cmd_hi = COMMAND_PORT_ARG_DATA_LEN(i2c_xfers[i].len) | in dw_i3c_master_i2c_xfers()
1034 cmd->cmd_lo = COMMAND_PORT_TID(i) | in dw_i3c_master_i2c_xfers()
1035 COMMAND_PORT_DEV_INDEX(data->index) | in dw_i3c_master_i2c_xfers()
1039 cmd->cmd_lo |= COMMAND_PORT_READ_TRANSFER; in dw_i3c_master_i2c_xfers()
1040 cmd->rx_buf = i2c_xfers[i].buf; in dw_i3c_master_i2c_xfers()
1041 cmd->rx_len = i2c_xfers[i].len; in dw_i3c_master_i2c_xfers()
1043 cmd->tx_buf = i2c_xfers[i].buf; in dw_i3c_master_i2c_xfers()
1044 cmd->tx_len = i2c_xfers[i].len; in dw_i3c_master_i2c_xfers()
1047 if (i == (i2c_nxfers - 1)) in dw_i3c_master_i2c_xfers()
1048 cmd->cmd_lo |= COMMAND_PORT_TOC; in dw_i3c_master_i2c_xfers()
1051 dw_i3c_master_enqueue_xfer(master, xfer); in dw_i3c_master_i2c_xfers()
1052 if (!wait_for_completion_timeout(&xfer->comp, XFER_TIMEOUT)) in dw_i3c_master_i2c_xfers()
1053 dw_i3c_master_dequeue_xfer(master, xfer); in dw_i3c_master_i2c_xfers()
1055 ret = xfer->ret; in dw_i3c_master_i2c_xfers()
1064 struct dw_i3c_master *master = to_dw_i3c_master(m); in dw_i3c_master_attach_i2c_dev() local
1068 pos = dw_i3c_master_get_free_pos(master); in dw_i3c_master_attach_i2c_dev()
1074 return -ENOMEM; in dw_i3c_master_attach_i2c_dev()
1076 data->index = pos; in dw_i3c_master_attach_i2c_dev()
1077 master->devs[pos].addr = dev->addr; in dw_i3c_master_attach_i2c_dev()
1078 master->free_pos &= ~BIT(pos); in dw_i3c_master_attach_i2c_dev()
1082 DEV_ADDR_TABLE_STATIC_ADDR(dev->addr), in dw_i3c_master_attach_i2c_dev()
1083 master->regs + in dw_i3c_master_attach_i2c_dev()
1084 DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index)); in dw_i3c_master_attach_i2c_dev()
1093 struct dw_i3c_master *master = to_dw_i3c_master(m); in dw_i3c_master_detach_i2c_dev() local
1096 master->regs + in dw_i3c_master_detach_i2c_dev()
1097 DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index)); in dw_i3c_master_detach_i2c_dev()
1100 master->devs[data->index].addr = 0; in dw_i3c_master_detach_i2c_dev()
1101 master->free_pos |= BIT(data->index); in dw_i3c_master_detach_i2c_dev()
1110 struct dw_i3c_master *master = to_dw_i3c_master(m); in dw_i3c_master_request_ibi() local
1113 data->ibi_pool = i3c_generic_ibi_alloc_pool(dev, req); in dw_i3c_master_request_ibi()
1114 if (IS_ERR(data->ibi_pool)) in dw_i3c_master_request_ibi()
1115 return PTR_ERR(data->ibi_pool); in dw_i3c_master_request_ibi()
1117 spin_lock_irqsave(&master->devs_lock, flags); in dw_i3c_master_request_ibi()
1118 master->devs[data->index].ibi_dev = dev; in dw_i3c_master_request_ibi()
1119 spin_unlock_irqrestore(&master->devs_lock, flags); in dw_i3c_master_request_ibi()
1128 struct dw_i3c_master *master = to_dw_i3c_master(m); in dw_i3c_master_free_ibi() local
1131 spin_lock_irqsave(&master->devs_lock, flags); in dw_i3c_master_free_ibi()
1132 master->devs[data->index].ibi_dev = NULL; in dw_i3c_master_free_ibi()
1133 spin_unlock_irqrestore(&master->devs_lock, flags); in dw_i3c_master_free_ibi()
1135 i3c_generic_ibi_free_pool(data->ibi_pool); in dw_i3c_master_free_ibi()
1136 data->ibi_pool = NULL; in dw_i3c_master_free_ibi()
1139 static void dw_i3c_master_enable_sir_signal(struct dw_i3c_master *master, bool enable) in dw_i3c_master_enable_sir_signal() argument
1143 reg = readl(master->regs + INTR_STATUS_EN); in dw_i3c_master_enable_sir_signal()
1147 writel(reg, master->regs + INTR_STATUS_EN); in dw_i3c_master_enable_sir_signal()
1149 reg = readl(master->regs + INTR_SIGNAL_EN); in dw_i3c_master_enable_sir_signal()
1153 writel(reg, master->regs + INTR_SIGNAL_EN); in dw_i3c_master_enable_sir_signal()
1156 static void dw_i3c_master_set_sir_enabled(struct dw_i3c_master *master, in dw_i3c_master_set_sir_enabled() argument
1164 dat_entry = DEV_ADDR_TABLE_LOC(master->datstartaddr, idx); in dw_i3c_master_set_sir_enabled()
1166 spin_lock_irqsave(&master->devs_lock, flags); in dw_i3c_master_set_sir_enabled()
1167 reg = readl(master->regs + dat_entry); in dw_i3c_master_set_sir_enabled()
1170 if (dev->info.bcr & I3C_BCR_IBI_PAYLOAD) in dw_i3c_master_set_sir_enabled()
1175 master->platform_ops->set_dat_ibi(master, dev, enable, &reg); in dw_i3c_master_set_sir_enabled()
1176 writel(reg, master->regs + dat_entry); in dw_i3c_master_set_sir_enabled()
1178 reg = readl(master->regs + IBI_SIR_REQ_REJECT); in dw_i3c_master_set_sir_enabled()
1183 bool hj_rejected = !!(readl(master->regs + DEVICE_CTRL) & DEV_CTRL_HOT_JOIN_NACK); in dw_i3c_master_set_sir_enabled()
1188 writel(reg, master->regs + IBI_SIR_REQ_REJECT); in dw_i3c_master_set_sir_enabled()
1191 dw_i3c_master_enable_sir_signal(master, enable); in dw_i3c_master_set_sir_enabled()
1194 spin_unlock_irqrestore(&master->devs_lock, flags); in dw_i3c_master_set_sir_enabled()
1199 struct dw_i3c_master *master = to_dw_i3c_master(m); in dw_i3c_master_enable_hotjoin() local
1201 dw_i3c_master_enable_sir_signal(master, true); in dw_i3c_master_enable_hotjoin()
1202 writel(readl(master->regs + DEVICE_CTRL) & ~DEV_CTRL_HOT_JOIN_NACK, in dw_i3c_master_enable_hotjoin()
1203 master->regs + DEVICE_CTRL); in dw_i3c_master_enable_hotjoin()
1210 struct dw_i3c_master *master = to_dw_i3c_master(m); in dw_i3c_master_disable_hotjoin() local
1212 writel(readl(master->regs + DEVICE_CTRL) | DEV_CTRL_HOT_JOIN_NACK, in dw_i3c_master_disable_hotjoin()
1213 master->regs + DEVICE_CTRL); in dw_i3c_master_disable_hotjoin()
1222 struct dw_i3c_master *master = to_dw_i3c_master(m); in dw_i3c_master_enable_ibi() local
1225 dw_i3c_master_set_sir_enabled(master, dev, data->index, true); in dw_i3c_master_enable_ibi()
1227 rc = i3c_master_enec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR); in dw_i3c_master_enable_ibi()
1230 dw_i3c_master_set_sir_enabled(master, dev, data->index, false); in dw_i3c_master_enable_ibi()
1239 struct dw_i3c_master *master = to_dw_i3c_master(m); in dw_i3c_master_disable_ibi() local
1242 rc = i3c_master_disec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR); in dw_i3c_master_disable_ibi()
1246 dw_i3c_master_set_sir_enabled(master, dev, data->index, false); in dw_i3c_master_disable_ibi()
1256 i3c_generic_ibi_recycle_slot(data->ibi_pool, slot); in dw_i3c_master_recycle_ibi_slot()
1259 static void dw_i3c_master_drain_ibi_queue(struct dw_i3c_master *master, in dw_i3c_master_drain_ibi_queue() argument
1265 readl(master->regs + IBI_QUEUE_STATUS); in dw_i3c_master_drain_ibi_queue()
1268 static void dw_i3c_master_handle_ibi_sir(struct dw_i3c_master *master, in dw_i3c_master_handle_ibi_sir() argument
1292 spin_lock_irqsave(&master->devs_lock, flags); in dw_i3c_master_handle_ibi_sir()
1293 idx = dw_i3c_master_get_addr_pos(master, addr); in dw_i3c_master_handle_ibi_sir()
1295 dev_dbg_ratelimited(&master->base.dev, in dw_i3c_master_handle_ibi_sir()
1300 dev = master->devs[idx].ibi_dev; in dw_i3c_master_handle_ibi_sir()
1301 if (!dev || !dev->ibi) { in dw_i3c_master_handle_ibi_sir()
1302 dev_dbg_ratelimited(&master->base.dev, in dw_i3c_master_handle_ibi_sir()
1303 "IBI from non-requested dev idx %d\n", idx); in dw_i3c_master_handle_ibi_sir()
1308 slot = i3c_generic_ibi_get_free_slot(data->ibi_pool); in dw_i3c_master_handle_ibi_sir()
1310 dev_dbg_ratelimited(&master->base.dev, in dw_i3c_master_handle_ibi_sir()
1315 if (dev->ibi->max_payload_len < len) { in dw_i3c_master_handle_ibi_sir()
1316 dev_dbg_ratelimited(&master->base.dev, in dw_i3c_master_handle_ibi_sir()
1318 len, dev->ibi->max_payload_len); in dw_i3c_master_handle_ibi_sir()
1323 dw_i3c_master_read_ibi_fifo(master, slot->data, len); in dw_i3c_master_handle_ibi_sir()
1324 slot->len = len; in dw_i3c_master_handle_ibi_sir()
1328 spin_unlock_irqrestore(&master->devs_lock, flags); in dw_i3c_master_handle_ibi_sir()
1333 dw_i3c_master_drain_ibi_queue(master, len); in dw_i3c_master_handle_ibi_sir()
1335 spin_unlock_irqrestore(&master->devs_lock, flags); in dw_i3c_master_handle_ibi_sir()
1338 /* "ibis": referring to In-Band Interrupts, and not
1342 static void dw_i3c_master_irq_handle_ibis(struct dw_i3c_master *master) in dw_i3c_master_irq_handle_ibis() argument
1347 reg = readl(master->regs + QUEUE_STATUS_LEVEL); in dw_i3c_master_irq_handle_ibis()
1353 reg = readl(master->regs + IBI_QUEUE_STATUS); in dw_i3c_master_irq_handle_ibis()
1356 dw_i3c_master_handle_ibi_sir(master, reg); in dw_i3c_master_irq_handle_ibis()
1358 queue_work(master->base.wq, &master->hj_work); in dw_i3c_master_irq_handle_ibis()
1361 dev_info(&master->base.dev, in dw_i3c_master_irq_handle_ibis()
1364 dw_i3c_master_drain_ibi_queue(master, len); in dw_i3c_master_irq_handle_ibis()
1371 struct dw_i3c_master *master = dev_id; in dw_i3c_master_irq_handler() local
1374 status = readl(master->regs + INTR_STATUS); in dw_i3c_master_irq_handler()
1376 if (!(status & readl(master->regs + INTR_STATUS_EN))) { in dw_i3c_master_irq_handler()
1377 writel(INTR_ALL, master->regs + INTR_STATUS); in dw_i3c_master_irq_handler()
1381 spin_lock(&master->xferqueue.lock); in dw_i3c_master_irq_handler()
1382 dw_i3c_master_end_xfer_locked(master, status); in dw_i3c_master_irq_handler()
1384 writel(INTR_TRANSFER_ERR_STAT, master->regs + INTR_STATUS); in dw_i3c_master_irq_handler()
1385 spin_unlock(&master->xferqueue.lock); in dw_i3c_master_irq_handler()
1388 dw_i3c_master_irq_handle_ibis(master); in dw_i3c_master_irq_handler()
1431 static int dw_i3c_platform_init_nop(struct dw_i3c_master *i3c) in dw_i3c_platform_init_nop() argument
1436 static void dw_i3c_platform_set_dat_ibi_nop(struct dw_i3c_master *i3c, in dw_i3c_platform_set_dat_ibi_nop() argument
1449 struct dw_i3c_master *master = in dw_i3c_hj_work() local
1450 container_of(work, typeof(*master), hj_work); in dw_i3c_hj_work()
1452 i3c_master_do_daa(&master->base); in dw_i3c_hj_work()
1455 int dw_i3c_common_probe(struct dw_i3c_master *master, in dw_i3c_common_probe() argument
1461 if (!master->platform_ops) in dw_i3c_common_probe()
1462 master->platform_ops = &dw_i3c_platform_ops_default; in dw_i3c_common_probe()
1464 master->regs = devm_platform_ioremap_resource(pdev, 0); in dw_i3c_common_probe()
1465 if (IS_ERR(master->regs)) in dw_i3c_common_probe()
1466 return PTR_ERR(master->regs); in dw_i3c_common_probe()
1468 master->core_clk = devm_clk_get(&pdev->dev, NULL); in dw_i3c_common_probe()
1469 if (IS_ERR(master->core_clk)) in dw_i3c_common_probe()
1470 return PTR_ERR(master->core_clk); in dw_i3c_common_probe()
1472 master->core_rst = devm_reset_control_get_optional_exclusive(&pdev->dev, in dw_i3c_common_probe()
1474 if (IS_ERR(master->core_rst)) in dw_i3c_common_probe()
1475 return PTR_ERR(master->core_rst); in dw_i3c_common_probe()
1477 ret = clk_prepare_enable(master->core_clk); in dw_i3c_common_probe()
1481 reset_control_deassert(master->core_rst); in dw_i3c_common_probe()
1483 spin_lock_init(&master->xferqueue.lock); in dw_i3c_common_probe()
1484 INIT_LIST_HEAD(&master->xferqueue.list); in dw_i3c_common_probe()
1486 writel(INTR_ALL, master->regs + INTR_STATUS); in dw_i3c_common_probe()
1488 ret = devm_request_irq(&pdev->dev, irq, in dw_i3c_common_probe()
1490 dev_name(&pdev->dev), master); in dw_i3c_common_probe()
1494 platform_set_drvdata(pdev, master); in dw_i3c_common_probe()
1497 ret = readl(master->regs + QUEUE_STATUS_LEVEL); in dw_i3c_common_probe()
1498 master->caps.cmdfifodepth = QUEUE_STATUS_LEVEL_CMD(ret); in dw_i3c_common_probe()
1500 ret = readl(master->regs + DATA_BUFFER_STATUS_LEVEL); in dw_i3c_common_probe()
1501 master->caps.datafifodepth = DATA_BUFFER_STATUS_LEVEL_TX(ret); in dw_i3c_common_probe()
1503 ret = readl(master->regs + DEVICE_ADDR_TABLE_POINTER); in dw_i3c_common_probe()
1504 master->datstartaddr = ret; in dw_i3c_common_probe()
1505 master->maxdevs = ret >> 16; in dw_i3c_common_probe()
1506 master->free_pos = GENMASK(master->maxdevs - 1, 0); in dw_i3c_common_probe()
1509 if (master->ibi_capable) in dw_i3c_common_probe()
1512 INIT_WORK(&master->hj_work, dw_i3c_hj_work); in dw_i3c_common_probe()
1513 ret = i3c_master_register(&master->base, &pdev->dev, ops, false); in dw_i3c_common_probe()
1520 reset_control_assert(master->core_rst); in dw_i3c_common_probe()
1523 clk_disable_unprepare(master->core_clk); in dw_i3c_common_probe()
1529 void dw_i3c_common_remove(struct dw_i3c_master *master) in dw_i3c_common_remove() argument
1531 cancel_work_sync(&master->hj_work); in dw_i3c_common_remove()
1532 i3c_master_unregister(&master->base); in dw_i3c_common_remove()
1534 reset_control_assert(master->core_rst); in dw_i3c_common_remove()
1536 clk_disable_unprepare(master->core_clk); in dw_i3c_common_remove()
1544 struct dw_i3c_master *master; in dw_i3c_probe() local
1546 master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL); in dw_i3c_probe()
1547 if (!master) in dw_i3c_probe()
1548 return -ENOMEM; in dw_i3c_probe()
1550 return dw_i3c_common_probe(master, pdev); in dw_i3c_probe()
1555 struct dw_i3c_master *master = platform_get_drvdata(pdev); in dw_i3c_remove() local
1557 dw_i3c_common_remove(master); in dw_i3c_remove()
1561 { .compatible = "snps,dw-i3c-master-1.00a", },
1570 .name = "dw-i3c-master",
1577 MODULE_DESCRIPTION("DesignWare MIPI I3C driver");