// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2020 MediaTek Inc. */ #include #include #include #include #include #include #include #include #define DRV_NAME "i3c-master-mtk" #define SLAVE_ADDR 0x04 #define INTR_MASK 0x08 #define INTR_STAT 0x0c #define INTR_TRANSAC_COMP BIT(0) #define INTR_ACKERR GENMASK(2, 1) #define INTR_ARB_LOST BIT(3) #define INTR_RS_MULTI BIT(4) #define INTR_IBI BIT(7) #define INTR_MAS_ERR BIT(8) #define INTR_ALL (INTR_MAS_ERR | INTR_ARB_LOST |\ INTR_ACKERR | INTR_TRANSAC_COMP) #define DATA_PORT 0x0 #define CONTROL 0x10 #define CONTROL_WRAPPER BIT(0) #define CONTROL_RS BIT(1) #define CONTROL_DMA_EN BIT(2) #define CONTROL_CLK_EXT_EN BIT(3) #define CONTROL_DIR_CHANGE BIT(4) #define CONTROL_ACKERR_DET_EN BIT(5) #define CONTROL_LEN_CHANGE BIT(6) #define CONTROL_DMAACK_EN BIT(8) #define CONTROL_ASYNC_MODE BIT(9) #define TRANSFER_LEN 0x14 #define TRANSAC_LEN 0x18 #define TRANSAC_LEN_WRRD 0x0002 #define TRANS_ONE_LEN 0x0001 #define DELAY_LEN 0x1c #define DELAY_LEN_DEFAULT 0x000a #define TIMING 0x20 #define TIMING_VALUE(sample_cnt, step_cnt) ({ \ typeof(sample_cnt) sample_cnt_ = (sample_cnt); \ typeof(step_cnt) step_cnt_ = (step_cnt); \ (((sample_cnt_) << 8) | (step_cnt_)); \ }) #define START 0x24 #define START_EN BIT(0) #define START_MUL_TRIG BIT(14) #define START_MUL_CNFG BIT(15) #define EXT_CONF 0x28 #define EXT_CONF_DEFAULT 0x0a1f #define LTIMING 0x2c #define LTIMING_VALUE(sample_cnt, step_cnt) ({ \ typeof(sample_cnt) sample_cnt_ = (sample_cnt); \ typeof(step_cnt) step_cnt_ = (step_cnt); \ (((sample_cnt_) << 6) | (step_cnt_)); \ }) #define HS_LTIMING_VALUE(i3c_sample_cnt, i3c_step_cnt) ({ \ typeof(i3c_sample_cnt) i3c_sample_cnt_ = (i3c_sample_cnt); \ typeof(i3c_step_cnt) i3c_step_cnt_ = (i3c_step_cnt); \ ((i3c_sample_cnt_ << 12) | (i3c_step_cnt_ << 9)); \ }) #define HS 0x30 #define HS_CLR_VALUE 0x0000 #define HS_DEFAULT_VALUE 0x0083 #define HS_VALUE(sample_cnt, step_cnt) ({ \ typeof(sample_cnt) sample_cnt_ = (sample_cnt); \ typeof(step_cnt) step_cnt_ = (step_cnt); \ (HS_DEFAULT_VALUE | \ ((sample_cnt_) << 12) | ((step_cnt_) << 8)); \ }) #define IO_CONFIG 0x34 #define IO_CONFIG_PUSH_PULL 0x0000 #define FIFO_ADDR_CLR 0x38 #define FIFO_CLR 0x0003 #define MCU_INTR 0x40 #define MCU_INTR_EN BIT(0) #define TRANSFER_LEN_AUX 0x44 #define CLOCK_DIV 0x48 #define CLOCK_DIV_DEFAULT ((INTER_CLK_DIV - 1) << 8 |\ (INTER_CLK_DIV - 1)) #define CLOCK_DIV_HS ((HS_CLK_DIV - 1) << 8 | (INTER_CLK_DIV - 1)) #define SOFTRESET 0x50 #define SOFT_RST BIT(0) #define I3C_ERR_RST BIT(3) #define TRAFFIC 0x54 #define TRAFFIC_DAA_EN BIT(4) #define TRAFFIC_TBIT BIT(7) #define TRAFFIC_HEAD_ONLY BIT(9) #define TRAFFIC_SKIP_SLV_ADDR BIT(10) #define TRAFFIC_IBI_EN BIT(13) #define TRAFFIC_HANDOFF BIT(14) #define DEF_DA 0x68 #define DEF_DAA_SLV_PARITY BIT(8) #define USE_DEF_DA BIT(7) #define SHAPE 0x6c #define SHAPE_T_STALL BIT(1) #define SHAPE_T_PARITY BIT(2) #define HFIFO_DATA 0x70 #define NINTH_BIT_IGNORE 0 #define NINTH_BIT_ACK 1 #define NINTH_BIT_NACK 2 #define NINTH_BIT_ODD_PAR 3 #define INST_WITH_HS BIT(10) #define UNLOCK_HFIFO BIT(15) #define HFIFO_DATA_08 0x8208 #define HFIFO_DATA_7E (UNLOCK_HFIFO |\ (I3C_BROADCAST_ADDR << 1) |\ (NINTH_BIT_ACK << 8)) #define HFIFO_HEAD (UNLOCK_HFIFO | INST_WITH_HS |\ (NINTH_BIT_ODD_PAR << 8)) #define FIFO_STAT 0xf4 #define DMA_INT_FLAG 0x0 #define DMA_EN 0x08 #define DMA_RST 0x0c #define DMA_CON 0x18 #define DMA_TX_MEM_ADDR 0x1c #define DMA_RX_MEM_ADDR 0x20 #define DMA_TX_LEN 0x24 #define DMA_RX_LEN 0x28 #define DMA_TX_4G_MODE 0x54 #define DMA_RX_4G_MODE 0x58 #define CHN_ERROR 0xd0 #define DEBUGSTAT 0xe4 #define DEBUGCTRL 0xe8 #define IBI_SWITCH BIT(2) #define DMA_EN_START BIT(0) #define DMA_RST_HARD BIT(1) #define DMA_4G_MODE BIT(0) #define DMA_CLR_FLAG 0x0000 #define DMA_CON_TX 0x0000 #define DMA_CON_RX 0x0001 #define HS_CLK_DIV 1 #define INTER_CLK_DIV 5 #define MAX_SAMPLE_CNT 8 #define MAX_STEP_CNT 64 #define MAX_HS_STEP_CNT 8 #define MAX_I3C_DEVS 3 #define MTK_I3C_BCR 0x01 #define MTK_I3C_DCR 0x02 #define MTK_I3C_PID 0x03040506 #define MIN(x, y) ((x) > (y) ? (y) : (x)) enum mtk_trans_op { MASTER_WR = 1, MASTER_RD, MASTER_WRRD, /* I3C private op */ MASTER_CCC_BROADCAST, MASTER_DAA, }; enum mtk_trans_mode { I2C_TRANSFER = 1, I3C_TRANSFER, I3C_CCC, }; struct daa_addr_ary { u8 addr; bool used; }; struct daa_anchor { struct daa_addr_ary daa_addr[MAX_I3C_DEVS]; int idx; }; struct mtk_i3c_cmd { enum mtk_trans_op op; u8 ccc_id; u16 addr; /* device addr */ u16 tx_len; const void *tx_buf; u16 rx_len; void *rx_buf; }; struct mtk_i3c_xfer { struct list_head node; struct completion complete; /* i3c transfer stop */ int ret; u16 irq_stat; /* interrupt status */ enum mtk_trans_mode mode; bool ignore_restart_irq; bool auto_restart; unsigned int ncmds; unsigned int trans_num; u8 *msg_buf_w; u8 *msg_buf_r; dma_addr_t rpaddr; dma_addr_t wpaddr; struct mtk_i3c_cmd cmds[0]; }; struct mtk_i3c_i2c_dev_data { u16 id; s16 ibi; struct i3c_generic_ibi_pool *ibi_pool; }; struct mtk_i3c_master { struct device *dev; struct i3c_master_controller mas_ctrler; struct { unsigned int num_slots; struct i3c_dev_desc **slots; spinlock_t lock; int ibi_en_count; } ibi; /* set in i3c probe */ void __iomem *regs; /* i3c base addr */ void __iomem *dma_regs; /* apdma base address*/ struct clk *clk_main; /* main clock for i3c bus */ struct clk *clk_dma; /* DMA clock for i3c via DMA */ struct clk *clk_arb; /* Arbitrator clock for i3c */ struct daa_anchor daa_anchor; u16 timing_reg[2]; u16 ltiming_reg[2]; u16 high_speed_reg[2]; struct { struct list_head list; struct mtk_i3c_xfer *cur; spinlock_t lock; /* Lock for stats update */ } xferqueue; u16 irqnr; u16 ibi_addr; u16 ibi_intr; u16 daa_count; }; static inline struct mtk_i3c_master * to_mt_i3c_master(struct i3c_master_controller *master) { return container_of(master, struct mtk_i3c_master, mas_ctrler); } static u16 mtk_i3c_readw(struct mtk_i3c_master *master, u16 offset) { return readw(master->regs + offset); } static bool i3c_debug; static void mtk_i3c_writew(struct mtk_i3c_master *master, u16 val, u16 offset) { if (i3c_debug) pr_info("wrg: %x val:0x%x\n", offset, val); writew(val, master->regs + offset); } static void i3c_reg_dump(struct mtk_i3c_master *master) { pr_info("SLAVES val:0x%x\n", mtk_i3c_readw(master, SLAVE_ADDR)); pr_info("INTR_STAT:0x%x\n", mtk_i3c_readw(master, INTR_STAT)); pr_info("INTR_MASK val:0x%x\n", mtk_i3c_readw(master, INTR_MASK)); pr_info("CONTROL val:0x%x\n", mtk_i3c_readw(master, CONTROL)); pr_info("START val:0x%x\n", mtk_i3c_readw(master, START)); pr_info("TRAFFIC val:0x%x\n", mtk_i3c_readw(master, TRAFFIC)); pr_info("SHAPE val:0x%x\n", mtk_i3c_readw(master, SHAPE)); pr_info("TIMING val:0x%x\n", mtk_i3c_readw(master, TIMING)); pr_info("LTIMING val:0x%x\n", mtk_i3c_readw(master, LTIMING)); pr_info("HS val:0x%x\n", mtk_i3c_readw(master, HS)); pr_info("ERROR val:0x%x\n", mtk_i3c_readw(master, CHN_ERROR)); pr_info("DEF DA:0x%x\n", mtk_i3c_readw(master, DEF_DA)); pr_info("TRANSFER_LEN val:0x%x\n", mtk_i3c_readw(master, TRANSFER_LEN)); pr_info("TRANSAC_LEN val:0x%x\n", mtk_i3c_readw(master, TRANSAC_LEN)); pr_info("FIFO_STAT val:0x%x\n", mtk_i3c_readw(master, FIFO_STAT)); pr_info("DEBUGSTAT val:0x%x\n", mtk_i3c_readw(master, DEBUGSTAT)); } /** * Calculate i3c port speed * * Hardware design: * i3c_bus_freq = parent_clk / (clock_div * 2 * sample_cnt * step_cnt) * clock_div: fixed in hardware, but may be various in different SoCs * * The calculation want to pick the highest bus frequency that is still * less than or equal to master->speed_hz. The calculation try to get * sample_cnt and step_cn */ static int mtk_i3c_calculate_speed(struct mtk_i3c_master *master, unsigned int clk_src, unsigned int target_speed, unsigned int *timing_step_cnt, unsigned int *timing_sample_cnt) { unsigned int sample_cnt, step_cnt, max_step_cnt, opt_div; unsigned int best_mul, cnt_mul, base_step_cnt; unsigned int base_sample_cnt = MAX_SAMPLE_CNT; pr_info("i3c target speed:%d,clk_src:%d\n", target_speed, clk_src); if (target_speed > I3C_BUS_I2C_FM_PLUS_SCL_RATE) max_step_cnt = MAX_HS_STEP_CNT; else max_step_cnt = MAX_STEP_CNT; base_step_cnt = max_step_cnt; /* Find the best combination */ opt_div = DIV_ROUND_UP(clk_src >> 1, target_speed); pr_info("i3c opt_div:%d\n", opt_div); best_mul = MAX_SAMPLE_CNT * max_step_cnt; /* Search for the best pair (sample_cnt, step_cnt) with * 1 < sample_cnt < MAX_SAMPLE_CNT * 1 < step_cnt < max_step_cnt * sample_cnt * step_cnt >= opt_div * optimizing for sample_cnt * step_cnt being minimal */ for (sample_cnt = 1; sample_cnt <= MAX_SAMPLE_CNT; sample_cnt++) { step_cnt = DIV_ROUND_UP(opt_div, sample_cnt); cnt_mul = step_cnt * sample_cnt; if (step_cnt > max_step_cnt/* || step_cnt < 2*/) continue; if (cnt_mul < best_mul) { best_mul = cnt_mul; base_sample_cnt = sample_cnt; base_step_cnt = step_cnt; if (best_mul == opt_div) break; } } sample_cnt = base_sample_cnt; step_cnt = base_step_cnt; if ((clk_src / (2 * sample_cnt * step_cnt)) > target_speed) { dev_err(master->dev, "Unsupport speed (%uhz)\n", target_speed); return -EINVAL; } *timing_step_cnt = step_cnt - 1; *timing_sample_cnt = sample_cnt - 1; pr_info("i3c step:%d, sample:%d\n", step_cnt, sample_cnt); return 0; } static int mtk_i3c_set_speed(struct mtk_i3c_master *master, unsigned int clk_src, unsigned int bc_clk_rate) { struct i3c_bus *bus = i3c_master_get_bus(&master->mas_ctrler); unsigned int i2c_step_cnt, i2c_sample_cnt, i3c_step_cnt, i3c_sample_cnt; int ret; ret = mtk_i3c_calculate_speed(master, bc_clk_rate, bus->scl_rate.i2c, &i2c_step_cnt, &i2c_sample_cnt); if (ret < 0) return ret; master->timing_reg[0] = TIMING_VALUE(i2c_sample_cnt, i2c_step_cnt); /* Disable the high speed transaction */ master->high_speed_reg[0] = HS_CLR_VALUE; master->ltiming_reg[0] = LTIMING_VALUE(i2c_sample_cnt, i2c_step_cnt); ret = mtk_i3c_calculate_speed(master, clk_src, bus->scl_rate.i3c, &i3c_step_cnt, &i3c_sample_cnt); if (ret < 0) return ret; master->high_speed_reg[1] = HS_VALUE(i3c_sample_cnt, i3c_step_cnt); master->ltiming_reg[1] = HS_LTIMING_VALUE(i3c_sample_cnt, i3c_step_cnt); return 0; } static inline u32 mtk_i3c_set_4g_mode(dma_addr_t addr) { return (addr & BIT_ULL(32)) ? DMA_4G_MODE : DMA_CLR_FLAG; } static inline struct mtk_i3c_master * to_mtk_i3c_master(struct i3c_master_controller *master) { return container_of(master, struct mtk_i3c_master, mas_ctrler); } static u8 mtk_i3c_master_get_free_addr(struct mtk_i3c_master *master) { int slot = 0; for (slot = 0; slot < MAX_I3C_DEVS; slot++) { if (master->daa_anchor.daa_addr[slot].used) continue; master->daa_anchor.idx = slot; master->daa_anchor.daa_addr[slot].used = true; return master->daa_anchor.daa_addr[slot].addr; } return 0; } static int mtk_i3c_master_clock_enable(struct mtk_i3c_master *master) { int ret; ret = clk_prepare_enable(master->clk_dma); if (ret) return ret; ret = clk_prepare_enable(master->clk_main); if (ret) goto err_main; if (!IS_ERR(master->clk_arb)) { ret = clk_prepare_enable(master->clk_arb); if (ret) goto err_arb; } return 0; err_arb: clk_disable_unprepare(master->clk_main); err_main: clk_disable_unprepare(master->clk_dma); return ret; } static void mtk_i3c_master_clock_disable(struct mtk_i3c_master *master) { if (!IS_ERR(master->clk_arb)) clk_disable_unprepare(master->clk_arb); clk_disable_unprepare(master->clk_main); clk_disable_unprepare(master->clk_dma); } static inline void mtk_i3c_master_init_hw(struct mtk_i3c_master *master) { struct mtk_i3c_xfer *mtk_xfer = master->xferqueue.cur; if (!mtk_xfer->trans_num) mtk_i3c_writew(master, SOFT_RST, SOFTRESET); mtk_i3c_writew(master, IO_CONFIG_PUSH_PULL, IO_CONFIG); mtk_i3c_writew(master, CLOCK_DIV_DEFAULT, CLOCK_DIV); mtk_i3c_writew(master, DELAY_LEN_DEFAULT, DELAY_LEN); mtk_i3c_writew(master, EXT_CONF_DEFAULT, EXT_CONF); mtk_i3c_writew(master, FIFO_CLR, FIFO_ADDR_CLR); /* DMA hard reset */ writel(DMA_RST_HARD, master->dma_regs + DMA_RST); writel(DMA_CLR_FLAG, master->dma_regs + DMA_RST); } static int mtk_i3c_master_apdma_tx(struct mtk_i3c_master *master) { struct mtk_i3c_xfer *xfer = master->xferqueue.cur; struct mtk_i3c_cmd *cmd = &xfer->cmds[xfer->trans_num]; u32 reg_4g_mode; xfer->msg_buf_w = kzalloc(cmd->tx_len, GFP_ATOMIC); if (!xfer->msg_buf_w) return -ENOMEM; memcpy(xfer->msg_buf_w, cmd->tx_buf, cmd->tx_len); writel(DMA_CLR_FLAG, master->dma_regs + DMA_INT_FLAG); writel(DMA_CON_TX, master->dma_regs + DMA_CON); xfer->wpaddr = dma_map_single(master->dev, xfer->msg_buf_w, cmd->tx_len, DMA_TO_DEVICE); if (dma_mapping_error(master->dev, xfer->wpaddr)) { kfree(xfer->msg_buf_w); return -ENOMEM; } reg_4g_mode = mtk_i3c_set_4g_mode(xfer->wpaddr); writel(reg_4g_mode, master->dma_regs + DMA_TX_4G_MODE); writel((u32)xfer->wpaddr, master->dma_regs + DMA_TX_MEM_ADDR); writel(cmd->tx_len, master->dma_regs + DMA_TX_LEN); return 0; } static int mtk_i3c_master_apdma_rx(struct mtk_i3c_master *master) { struct mtk_i3c_xfer *xfer = master->xferqueue.cur; struct mtk_i3c_cmd *cmd = &xfer->cmds[xfer->trans_num]; u32 reg_4g_mode; xfer->msg_buf_r = kzalloc(cmd->rx_len, GFP_ATOMIC); if (!xfer->msg_buf_r) return -ENOMEM; writel(DMA_CLR_FLAG, master->dma_regs + DMA_INT_FLAG); writel(DMA_CON_RX, master->dma_regs + DMA_CON); xfer->rpaddr = dma_map_single(master->dev, xfer->msg_buf_r, cmd->rx_len, DMA_FROM_DEVICE); if (dma_mapping_error(master->dev, xfer->rpaddr)) { kfree(xfer->msg_buf_r); return -ENOMEM; } reg_4g_mode = mtk_i3c_set_4g_mode(xfer->rpaddr); writel(reg_4g_mode, master->dma_regs + DMA_RX_4G_MODE); writel((u32)xfer->rpaddr, master->dma_regs + DMA_RX_MEM_ADDR); writel(cmd->rx_len, master->dma_regs + DMA_RX_LEN); return 0; } static void mtk_i3c_master_apdma_end(struct mtk_i3c_master *master) { struct mtk_i3c_xfer *xfer = master->xferqueue.cur; struct mtk_i3c_cmd *cmd; u16 int_reg = 0; if (!xfer) { pr_info("i3c debug xfer NULL FLOW\n"); return; } cmd = &xfer->cmds[xfer->trans_num]; if (master->ibi.ibi_en_count > 0) int_reg |= INTR_IBI; mtk_i3c_writew(master, int_reg, INTR_MASK); if (cmd->op == MASTER_WR) { dma_unmap_single(master->dev, xfer->wpaddr, cmd->tx_len, DMA_TO_DEVICE); kfree(xfer->msg_buf_w); } else if (cmd->op == MASTER_RD && cmd->ccc_id != I3C_CCC_GETMXDS) { dma_unmap_single(master->dev, xfer->rpaddr, cmd->rx_len, DMA_FROM_DEVICE); memcpy(cmd->rx_buf, xfer->msg_buf_r, cmd->rx_len); kfree(xfer->msg_buf_r); } else if (cmd->op == MASTER_WRRD) { dma_unmap_single(master->dev, xfer->wpaddr, cmd->tx_len, DMA_TO_DEVICE); dma_unmap_single(master->dev, xfer->rpaddr, cmd->rx_len, DMA_FROM_DEVICE); memcpy(cmd->rx_buf, xfer->msg_buf_r, cmd->rx_len); kfree(xfer->msg_buf_w); kfree(xfer->msg_buf_r); } } static int mtk_i3c_master_start_transfer(struct mtk_i3c_master *master) { struct mtk_i3c_xfer *xfer = master->xferqueue.cur; struct mtk_i3c_cmd *cmd = &xfer->cmds[xfer->trans_num]; u16 addr_reg, control_reg, start_reg, tmp_rg_val; u16 int_reg = 0, data_size; int ret = 0; u8 *ptr; xfer->irq_stat = 0; mtk_i3c_master_init_hw(master); control_reg = CONTROL_ACKERR_DET_EN | CONTROL_RS; if ((cmd->op != MASTER_DAA) && (cmd->ccc_id != I3C_CCC_GETMXDS)) control_reg |= CONTROL_DMA_EN | CONTROL_DMAACK_EN | CONTROL_ASYNC_MODE; if (cmd->op == MASTER_WRRD) control_reg |= CONTROL_DIR_CHANGE; mtk_i3c_writew(master, control_reg, CONTROL); addr_reg = cmd->addr << 1; if (cmd->op == MASTER_RD || cmd->op == MASTER_DAA) addr_reg |= 0x1; mtk_i3c_writew(master, addr_reg, SLAVE_ADDR); if (xfer->auto_restart) int_reg = INTR_RS_MULTI; int_reg |= INTR_ALL; if (master->ibi.ibi_en_count > 0) int_reg |= INTR_IBI; /* Clear interrupt status */ mtk_i3c_writew(master, int_reg, INTR_STAT); /* Enable interrupt */ mtk_i3c_writew(master, int_reg, INTR_MASK); /* Set transfer and transaction len */ switch (cmd->op) { case MASTER_WRRD: mtk_i3c_writew(master, cmd->tx_len, TRANSFER_LEN); mtk_i3c_writew(master, cmd->rx_len, TRANSFER_LEN_AUX); mtk_i3c_writew(master, TRANSAC_LEN_WRRD, TRANSAC_LEN); break; case MASTER_WR: mtk_i3c_writew(master, cmd->tx_len, TRANSFER_LEN); mtk_i3c_writew(master, xfer->ncmds, TRANSAC_LEN); break; case MASTER_RD: mtk_i3c_writew(master, cmd->rx_len, TRANSFER_LEN); mtk_i3c_writew(master, xfer->ncmds, TRANSAC_LEN); break; case MASTER_CCC_BROADCAST: mtk_i3c_writew(master, TRANS_ONE_LEN, TRANSFER_LEN); mtk_i3c_writew(master, TRANS_ONE_LEN, TRANSAC_LEN); break; case MASTER_DAA: mtk_i3c_writew(master, cmd->rx_len + cmd->tx_len, TRANSFER_LEN); mtk_i3c_writew(master, MAX_I3C_DEVS, TRANSAC_LEN); break; } mtk_i3c_writew(master, master->timing_reg[0], TIMING); mtk_i3c_writew(master, master->ltiming_reg[0], LTIMING); if (cmd->op == MASTER_DAA) mtk_i3c_writew(master, master->high_speed_reg[1] & 0xff7f, HS); else mtk_i3c_writew(master, master->high_speed_reg[1], HS); mtk_i3c_writew(master, master->ltiming_reg[0] | master->ltiming_reg[1], LTIMING); mtk_i3c_writew(master, CLOCK_DIV_HS, CLOCK_DIV); if (xfer->mode == I2C_TRANSFER) { mtk_i3c_writew(master, master->timing_reg[0], TIMING); mtk_i3c_writew(master, master->ltiming_reg[0], LTIMING); mtk_i3c_writew(master, master->high_speed_reg[0], HS); mtk_i3c_writew(master, 0, TRAFFIC); mtk_i3c_writew(master, 0, SHAPE); } else if ((xfer->mode == I3C_TRANSFER) && (!xfer->trans_num)) { mtk_i3c_writew(master, HFIFO_DATA_7E, HFIFO_DATA); mtk_i3c_writew(master, TRAFFIC_HANDOFF | TRAFFIC_TBIT, TRAFFIC); mtk_i3c_writew(master, SHAPE_T_STALL | SHAPE_T_PARITY, SHAPE); } else if (xfer->mode == I3C_CCC) { if (cmd->op == MASTER_DAA) tmp_rg_val = TRAFFIC_HANDOFF; else tmp_rg_val = TRAFFIC_HANDOFF | TRAFFIC_TBIT; mtk_i3c_writew(master, HFIFO_DATA_7E, HFIFO_DATA); mtk_i3c_writew(master, HFIFO_HEAD | cmd->ccc_id, HFIFO_DATA); if (cmd->op == MASTER_DAA) { tmp_rg_val |= TRAFFIC_DAA_EN; } else if (cmd->op == MASTER_CCC_BROADCAST) { tmp_rg_val |= TRAFFIC_HEAD_ONLY | TRAFFIC_SKIP_SLV_ADDR; data_size = cmd->tx_len; ptr = (u8 *)cmd->tx_buf; while (data_size--) mtk_i3c_writew(master, HFIFO_HEAD | *ptr++, HFIFO_DATA); } mtk_i3c_writew(master, tmp_rg_val, TRAFFIC); mtk_i3c_writew(master, SHAPE_T_PARITY | SHAPE_T_STALL, SHAPE); if (cmd->op == MASTER_DAA) mtk_i3c_writew(master, SHAPE_T_STALL, SHAPE); } if (master->ibi.ibi_en_count > 0) { tmp_rg_val = mtk_i3c_readw(master, TRAFFIC); tmp_rg_val |= TRAFFIC_IBI_EN; mtk_i3c_writew(master, tmp_rg_val, TRAFFIC); } /* Prepare buffer data to start transfer */ if (cmd->op == MASTER_RD && cmd->ccc_id != I3C_CCC_GETMXDS) { ret = mtk_i3c_master_apdma_rx(master); } else if (cmd->op == MASTER_WR) { ret = mtk_i3c_master_apdma_tx(master); } else if (cmd->op == MASTER_WRRD) { ret = mtk_i3c_master_apdma_rx(master); ret |= mtk_i3c_master_apdma_tx(master); } if (ret) return ret; if (cmd->op != MASTER_DAA && cmd->ccc_id != I3C_CCC_GETMXDS) writel(DMA_EN_START, master->dma_regs + DMA_EN); start_reg = START_EN; if (xfer->auto_restart) { start_reg |= START_MUL_TRIG; if ((xfer->ncmds - xfer->trans_num) >= 2 || cmd->op == MASTER_DAA) start_reg |= START_MUL_CNFG; } mtk_i3c_writew(master, MCU_INTR_EN, MCU_INTR); mtk_i3c_writew(master, start_reg, START); return 0; } static struct mtk_i3c_xfer * mtk_i3c_master_alloc_xfer(struct mtk_i3c_master *master, unsigned int ncmds) { struct mtk_i3c_xfer *xfer; xfer = kzalloc(struct_size(xfer, cmds, ncmds), GFP_KERNEL); if (!xfer) return NULL; INIT_LIST_HEAD(&xfer->node); xfer->ncmds = ncmds; xfer->ret = -ETIMEDOUT; return xfer; } static void mtk_i3c_master_free_xfer(struct mtk_i3c_xfer *xfer) { kfree(xfer); } static void mtk_i3c_master_start_xfer_locked(struct mtk_i3c_master *master) { struct mtk_i3c_xfer *xfer = master->xferqueue.cur; unsigned int ret = 0; if (!xfer) return; xfer->trans_num = 0; ret = mtk_i3c_master_start_transfer(master); xfer->ret = ret; } static void mtk_i3c_master_end_xfer_locked(struct mtk_i3c_master *master) { struct mtk_i3c_xfer *xfer = master->xferqueue.cur; struct mtk_i3c_cmd *cmd = &xfer->cmds[xfer->trans_num]; int slot = 0; u16 fifo_offset = 0; u8 *data; if (!xfer) return; if (xfer->irq_stat & (INTR_ACKERR | INTR_MAS_ERR)) { if (cmd->op == MASTER_DAA) { slot = master->daa_anchor.idx; master->daa_anchor.daa_addr[slot].used = false; } /* GETMXDS 5bytes, but slave maybe response less than 5bytes */ fifo_offset = 0x1f & mtk_i3c_readw(master, FIFO_STAT); if ((cmd->ccc_id == I3C_CCC_GETMXDS) && (fifo_offset > 0)) { data = xfer->cmds->rx_buf; while (fifo_offset--) { *data = readb(master->regs + DATA_PORT); data++; } xfer->ret = 0; } else { dev_err(master->dev, "Addr: %x, device ACK error\n", cmd->addr); xfer->ret = -ENXIO; i3c_reg_dump(master); } } mtk_i3c_master_apdma_end(master); complete(&xfer->complete); xfer = list_first_entry_or_null(&master->xferqueue.list, struct mtk_i3c_xfer, node); if (xfer) list_del_init(&xfer->node); master->xferqueue.cur = xfer; mtk_i3c_master_start_xfer_locked(master); } static void mtk_i3c_handle_ibi_payload(struct mtk_i3c_master *master) { struct mtk_i3c_i2c_dev_data *data; struct i3c_ibi_slot *slot; struct i3c_dev_desc *i3cdev = NULL; u32 i; u16 fifo_len; u16 reg; u8 *buf; bool match = false; i3c_bus_for_each_i3cdev(&master->mas_ctrler.bus, i3cdev) { if (i3cdev->info.dyn_addr == 0x8) continue; if (i3cdev->info.dyn_addr == master->ibi_addr) { match = true; break; } } if (!i3cdev) { pr_err("[%s] not matched i3cdev(addr:%x)\n", __func__, master->ibi_addr); return; } if (!match) { pr_err("ibi addr not matched\n"); return; } data = i3c_dev_get_master_data(i3cdev); spin_lock(&master->ibi.lock); slot = i3c_generic_ibi_get_free_slot(data->ibi_pool); if (!slot) { pr_err("[%s] not free slot\n", __func__); goto out_unlock; } buf = slot->data; fifo_len = 0x1f & mtk_i3c_readw(master, FIFO_STAT); fifo_len = MIN(fifo_len, i3cdev->info.max_ibi_len); fifo_len = MIN(fifo_len, i3cdev->ibi->max_payload_len); slot->len = fifo_len; for (i = 0; i < fifo_len; i++) *(buf + i) = mtk_i3c_readw(master, DATA_PORT); /* disable slave ibi */ mtk_i3c_writew(master, FIFO_CLR, FIFO_ADDR_CLR); reg = mtk_i3c_readw(master, CONTROL); mtk_i3c_writew(master, reg | CONTROL_RS, CONTROL); mtk_i3c_writew(master, i3cdev->info.dyn_addr << 1, SLAVE_ADDR); mtk_i3c_writew(master, 1, TRANSFER_LEN); mtk_i3c_writew(master, 0, TRANSFER_LEN_AUX); mtk_i3c_writew(master, 1, TRANSAC_LEN); mtk_i3c_writew(master, 0x4080, TRAFFIC); mtk_i3c_writew(master, 6, SHAPE); mtk_i3c_writew(master, HFIFO_DATA_7E, HFIFO_DATA); mtk_i3c_writew(master, HFIFO_HEAD | I3C_CCC_ID(0x1, false), HFIFO_DATA); mtk_i3c_writew(master, 1, DATA_PORT); /* execute START after DATA_PORT */ mb(); mtk_i3c_writew(master, 1, START); /* disable master ibi */ reg = mtk_i3c_readw(master, INTR_MASK); mtk_i3c_writew(master, reg & ~(INTR_IBI), INTR_MASK); reg = mtk_i3c_readw(master, TRAFFIC); mtk_i3c_writew(master, reg & (~TRAFFIC_IBI_EN), TRAFFIC); i3c_master_queue_ibi(i3cdev, slot); out_unlock: spin_unlock(&master->ibi.lock); } static void mtk_i3c_handle_ibi(struct mtk_i3c_master *master) { struct i3c_dev_desc *i3cdev = NULL; u16 ibi_addr; u16 ibi_len; u16 control_reg; bool match; match = false; ibi_addr = mtk_i3c_readw(master, CHN_ERROR); ibi_addr = ibi_addr >> 9; master->ibi_addr = ibi_addr; /* read ibi payload */ i3c_bus_for_each_i3cdev(&master->mas_ctrler.bus, i3cdev) { if (i3cdev->info.dyn_addr == 0x8) continue; if (i3cdev->info.dyn_addr == ibi_addr) { match = true; break; } } if (!i3cdev) { pr_err("[%s] not matched i3cdev(addr:%x)\n", __func__, ibi_addr); return; } if (!match) { mtk_i3c_writew(master, 1, SOFTRESET); return; } /* Select min value between max_ibi_len and max_payload_len */ ibi_len = MIN(i3cdev->info.max_ibi_len, i3cdev->ibi->max_payload_len); spin_lock(&master->ibi.lock); control_reg = CONTROL_ACKERR_DET_EN; mtk_i3c_writew(master, control_reg, CONTROL); mtk_i3c_writew(master, FIFO_CLR, FIFO_ADDR_CLR); /* Clear IBI INT */ mtk_i3c_writew(master, 0x1ff, INTR_STAT); mtk_i3c_writew(master, INTR_ALL | INTR_IBI, INTR_MASK); mtk_i3c_writew(master, TRAFFIC_SKIP_SLV_ADDR | TRAFFIC_HANDOFF | TRAFFIC_TBIT | TRAFFIC_IBI_EN, TRAFFIC); mtk_i3c_writew(master, 0x6, SHAPE); mtk_i3c_writew(master, ibi_len, TRANSFER_LEN); mtk_i3c_writew(master, 0, TRANSFER_LEN_AUX); mtk_i3c_writew(master, 1, TRANSAC_LEN); mtk_i3c_writew(master, START_EN | START_MUL_TRIG | START_MUL_CNFG, START); /* Execute START before SLAVE_ADDR */ mb(); mtk_i3c_writew(master, (ibi_addr << 1) | 0x1, SLAVE_ADDR); /* Execute START after SLAVE_ADDR */ mb(); mtk_i3c_writew(master, 0x4001, START); /* Execute START before SOFTRESET */ mb(); mtk_i3c_writew(master, I3C_ERR_RST, SOFTRESET); spin_unlock(&master->ibi.lock); } static irqreturn_t mtk_i3c_master_irq(int irqno, void *dev_id) { struct mtk_i3c_master *master = dev_id; struct mtk_i3c_xfer *xfer; struct mtk_i3c_cmd *cmd; u16 restart_flag = 0, intr_stat; unsigned long flags; int ret = 0; u8 addr; intr_stat = mtk_i3c_readw(master, INTR_STAT); mtk_i3c_writew(master, intr_stat, INTR_STAT); xfer = master->xferqueue.cur; if (intr_stat & INTR_IBI) { master->ibi_intr = intr_stat; mtk_i3c_handle_ibi(master); return IRQ_HANDLED; } if ((master->ibi_intr & INTR_IBI) && (intr_stat & INTR_TRANSAC_COMP)) { mtk_i3c_handle_ibi_payload(master); master->ibi_intr = 0; return IRQ_HANDLED; } if (!xfer) return IRQ_HANDLED; cmd = &xfer->cmds[xfer->trans_num]; if (xfer->auto_restart) restart_flag = INTR_RS_MULTI; spin_lock_irqsave(&master->xferqueue.lock, flags); /* * when occurs ack error, i3c controller generate two interrupts * first is the ack error interrupt, then the complete interrupt * i3c->irq_stat need keep the two interrupt value. */ xfer->irq_stat |= intr_stat; if (xfer->irq_stat & INTR_TRANSAC_COMP) { mtk_i3c_master_end_xfer_locked(master); goto exit_irq; } if (xfer->irq_stat & restart_flag) { xfer->irq_stat = 0; if (xfer->ignore_restart_irq) { xfer->ignore_restart_irq = false; mtk_i3c_writew(master, START_MUL_CNFG | START_MUL_TRIG | START_EN, START); } else if (cmd->op == MASTER_DAA) { mtk_i3c_writew(master, FIFO_CLR, FIFO_ADDR_CLR); master->daa_count++; if (master->daa_count < MAX_I3C_DEVS) { addr = mtk_i3c_master_get_free_addr(master); mtk_i3c_writew(master, (DEF_DAA_SLV_PARITY | USE_DEF_DA | addr), DEF_DA); } else master->daa_count = 0; mtk_i3c_writew(master, START_MUL_CNFG | START_MUL_TRIG | START_EN, START); } else { mtk_i3c_master_apdma_end(master); xfer->trans_num++; ret = mtk_i3c_master_start_transfer(master); xfer->ret = ret; } } exit_irq: spin_unlock_irqrestore(&master->xferqueue.lock, flags); return IRQ_HANDLED; } static void mtk_i3c_master_queue_xfer(struct mtk_i3c_master *master, struct mtk_i3c_xfer *xfer) { unsigned long flags; init_completion(&xfer->complete); spin_lock_irqsave(&master->xferqueue.lock, flags); if (master->xferqueue.cur) { list_add_tail(&xfer->node, &master->xferqueue.list); } else { master->xferqueue.cur = xfer; i3c_debug = 0; mtk_i3c_master_start_xfer_locked(master); i3c_debug = 0; } spin_unlock_irqrestore(&master->xferqueue.lock, flags); } static void mtk_i3c_master_unqueue_xfer(struct mtk_i3c_master *master, struct mtk_i3c_xfer *xfer) { struct mtk_i3c_cmd *ccmd = &xfer->cmds[xfer->trans_num]; unsigned long flags; dev_err(master->dev, "addr: %x, transfer timeout\n", ccmd->addr); xfer->ret = -ETIMEDOUT; i3c_reg_dump(master); spin_lock_irqsave(&master->xferqueue.lock, flags); mtk_i3c_master_apdma_end(master); if (master->xferqueue.cur == xfer) master->xferqueue.cur = NULL; else list_del_init(&xfer->node); spin_unlock_irqrestore(&master->xferqueue.lock, flags); } static bool mtk_i3c_master_supports_ccc_cmd(struct i3c_master_controller *m, const struct i3c_ccc_cmd *cmd) { if (cmd->ndests > 1) return false; switch (cmd->id) { case I3C_CCC_ENEC(true): case I3C_CCC_ENEC(false): case I3C_CCC_DISEC(true): case I3C_CCC_DISEC(false): case I3C_CCC_ENTAS(0, true): case I3C_CCC_ENTAS(0, false): case I3C_CCC_RSTDAA(true): case I3C_CCC_RSTDAA(false): /* FALL THROUGH */ case I3C_CCC_ENTDAA: case I3C_CCC_SETMWL(true): case I3C_CCC_SETMWL(false): case I3C_CCC_SETMRL(true): case I3C_CCC_SETMRL(false): /* FALL THROUGH */ case I3C_CCC_DEFSLVS: case I3C_CCC_ENTHDR(0): case I3C_CCC_SETDASA: case I3C_CCC_SETNEWDA: case I3C_CCC_GETMWL: case I3C_CCC_GETMRL: case I3C_CCC_GETPID: case I3C_CCC_GETBCR: case I3C_CCC_GETDCR: case I3C_CCC_GETSTATUS: case I3C_CCC_GETACCMST: case I3C_CCC_GETMXDS: case I3C_CCC_GETHDRCAP: return true; default: break; } return false; } static int mtk_i3c_master_send_ccc_cmd(struct i3c_master_controller *m, struct i3c_ccc_cmd *cmd) { struct mtk_i3c_master *master = to_mtk_i3c_master(m); struct mtk_i3c_xfer *mtk_xfer; struct mtk_i3c_cmd *ccmd; int ret = 0; mtk_xfer = mtk_i3c_master_alloc_xfer(master, 1); if (!mtk_xfer) return -ENOMEM; mtk_xfer->mode = I3C_CCC; mtk_xfer->ignore_restart_irq = false; mtk_xfer->auto_restart = false; ccmd = mtk_xfer->cmds; ccmd->addr = cmd->dests[0].addr; ccmd->ccc_id = cmd->id; if (cmd->rnw) { ccmd->op = MASTER_RD; ccmd->rx_len = cmd->dests[0].payload.len; ccmd->rx_buf = cmd->dests[0].payload.data; } else { ccmd->op = MASTER_WR; ccmd->tx_len = cmd->dests[0].payload.len; ccmd->tx_buf = cmd->dests[0].payload.data; } if (ccmd->ccc_id < I3C_CCC_DIRECT) { ccmd->op = MASTER_CCC_BROADCAST; if (ccmd->ccc_id == I3C_CCC_ENTDAA) { ccmd->op = MASTER_DAA; ccmd->rx_len = 8; ccmd->tx_len = 1; mtk_xfer->ignore_restart_irq = false; mtk_xfer->auto_restart = true; } } mtk_i3c_master_queue_xfer(master, mtk_xfer); if (!wait_for_completion_timeout(&mtk_xfer->complete, msecs_to_jiffies(2000))) mtk_i3c_master_unqueue_xfer(master, mtk_xfer); ret = mtk_xfer->ret; mtk_i3c_master_free_xfer(mtk_xfer); if (ret == -ENXIO) return I3C_ERROR_M2; return ret; } static int mtk_i3c_master_priv_xfers(struct i3c_dev_desc *dev, struct i3c_priv_xfer *xfers, int nxfers) { struct i3c_master_controller *m = i3c_dev_get_master(dev); struct mtk_i3c_master *master = to_mtk_i3c_master(m); struct mtk_i3c_xfer *mtk_xfer; int i, ret = 0; if (!nxfers) return 0; mtk_xfer = mtk_i3c_master_alloc_xfer(master, nxfers); if (!mtk_xfer) return -ENOMEM; mtk_xfer->mode = I3C_TRANSFER; if (nxfers == 2 && !xfers[0].rnw && xfers[1].rnw) mtk_xfer->auto_restart = false; else mtk_xfer->auto_restart = true; if (mtk_xfer->auto_restart && nxfers >= 2) mtk_xfer->ignore_restart_irq = true; else mtk_xfer->ignore_restart_irq = false; for (i = 0; i < nxfers; i++) { struct mtk_i3c_cmd *ccmd = &mtk_xfer->cmds[i]; ccmd->addr = dev->info.dyn_addr; ccmd->ccc_id = 0; if (!mtk_xfer->auto_restart) { /* combined two messages into one transaction */ ccmd->op = MASTER_WRRD; ccmd->tx_len = xfers[i].len; ccmd->rx_len = xfers[i + 1].len; ccmd->tx_buf = xfers->data.out; ccmd->rx_buf = xfers[i + 1].data.in; break; } if (xfers[i].rnw) { ccmd->op = MASTER_RD; ccmd->rx_len = xfers->len; ccmd->rx_buf = xfers->data.in; } else { ccmd->op = MASTER_WR; ccmd->tx_len = xfers->len; ccmd->tx_buf = xfers->data.out; } } mtk_i3c_master_queue_xfer(master, mtk_xfer); if (!wait_for_completion_timeout(&mtk_xfer->complete, msecs_to_jiffies(2000))) mtk_i3c_master_unqueue_xfer(master, mtk_xfer); ret = mtk_xfer->ret; mtk_i3c_master_free_xfer(mtk_xfer); return ret; } static int mtk_i3c_master_i2c_xfers(struct i2c_dev_desc *dev, const struct i2c_msg *xfers, int nxfers) { struct i3c_master_controller *m = i2c_dev_get_master(dev); struct mtk_i3c_master *master = to_mtk_i3c_master(m); struct mtk_i3c_xfer *mtk_xfer; int i, ret = 0; mtk_xfer = mtk_i3c_master_alloc_xfer(master, nxfers); if (!mtk_xfer) return -ENOMEM; mtk_xfer->mode = I2C_TRANSFER; if (!(xfers[0].flags & I2C_M_RD) && (xfers[1].flags & I2C_M_RD) && xfers[0].addr == xfers[1].addr && nxfers == 2) mtk_xfer->auto_restart = false; else mtk_xfer->auto_restart = true; mtk_xfer->ignore_restart_irq = false; for (i = 0; i < nxfers; i++) { struct mtk_i3c_cmd *ccmd = &mtk_xfer->cmds[i]; ccmd->addr = xfers->addr; ccmd->ccc_id = 0; if (!mtk_xfer->auto_restart) { /* combined two messages into one transaction */ ccmd->op = MASTER_WRRD; ccmd->tx_len = xfers[i].len; ccmd->rx_len = xfers[i + 1].len; ccmd->tx_buf = xfers[i].buf; ccmd->rx_buf = xfers[i + 1].buf; break; } if (xfers[i].flags & I2C_M_RD) { ccmd->op = MASTER_RD; ccmd->rx_len = xfers[i].len; ccmd->rx_buf = xfers[i].buf; } else { ccmd->op = MASTER_WR; ccmd->tx_len = xfers[i].len; ccmd->tx_buf = xfers[i].buf; } } mtk_i3c_master_queue_xfer(master, mtk_xfer); if (!wait_for_completion_timeout(&mtk_xfer->complete, msecs_to_jiffies(2000))) mtk_i3c_master_unqueue_xfer(master, mtk_xfer); ret = mtk_xfer->ret; mtk_i3c_master_free_xfer(mtk_xfer); return ret; } static int mtk_i3c_master_do_daa(struct i3c_master_controller *m) { struct mtk_i3c_master *master = to_mtk_i3c_master(m); int ret = 0, slot; u8 last_addr = 0; for (slot = 0; slot < MAX_I3C_DEVS; slot++) { if (master->daa_anchor.daa_addr[slot].used) continue; ret = i3c_master_get_free_addr(m, last_addr + 1); if (ret < 0) return -ENOSPC; last_addr = ret; master->daa_anchor.daa_addr[slot].addr = last_addr; } ret = i3c_master_entdaa_locked(&master->mas_ctrler); if (ret && ret != I3C_ERROR_M2) return ret; /* * Clear all retaining registers filled during DAA. We already * have the addressed assigned to them in the addrs array. */ for (slot = 1; slot < MAX_I3C_DEVS; slot++) { if (master->daa_anchor.daa_addr[slot].used) { last_addr = master->daa_anchor.daa_addr[slot].addr; i3c_master_add_i3c_dev_locked(m, last_addr); } } /* * Clear slots that ended up not being used. Can be caused by I3C * device creation failure or when the I3C device was already known * by the system but with a different address (in this case the device * already has a slot and does not need a new one). */ i3c_master_defslvs_locked(&master->mas_ctrler); /* Unmask Hot-Join and Mastership request interrupts. */ i3c_master_enec_locked(m, I3C_BROADCAST_ADDR, I3C_CCC_EVENT_HJ | I3C_CCC_EVENT_MR); return 0; } static int mtk_i3c_master_bus_init(struct i3c_master_controller *m) { struct mtk_i3c_master *master = to_mtk_i3c_master(m); struct i3c_device_info info = { }; unsigned long source_clk_rate; unsigned long bc_clk_rate; int ret; source_clk_rate = clk_get_rate(master->clk_main) / HS_CLK_DIV; bc_clk_rate = clk_get_rate(master->clk_main) / INTER_CLK_DIV; ret = mtk_i3c_set_speed(master, source_clk_rate, bc_clk_rate); if (ret) { dev_err(master->dev, "Failed to set the bus speed.\n"); return -EINVAL; } /* Get an address for the master. */ ret = i3c_master_get_free_addr(m, 0); if (ret < 0) return ret; master->daa_anchor.daa_addr[0].addr = (u8)ret; master->daa_anchor.daa_addr[0].used = true; master->daa_anchor.idx = 0; /* * In I3C protocol host controller is also with device role, * so the driver should provide dcr, bcr, and pid info * of host controller itself */ memset(&info, 0, sizeof(info)); info.dyn_addr = ret; info.dcr = MTK_I3C_DCR; info.bcr = MTK_I3C_BCR; info.pid = MTK_I3C_PID; if (info.bcr & I3C_BCR_HDR_CAP) info.hdr_cap = I3C_CCC_HDR_MODE(I3C_HDR_DDR); return i3c_master_set_info(&master->mas_ctrler, &info); } static int mt_i3c_master_disable_ibi(struct i3c_dev_desc *dev) { int ret = 0; struct i3c_master_controller *m = i3c_dev_get_master(dev); struct mtk_i3c_master *master = to_mt_i3c_master(m); unsigned long flags; u16 reg; dev_info(master->dev, "enter %s\n", __func__); ret = i3c_master_disec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR); if (ret) goto DONE; spin_lock_irqsave(&master->ibi.lock, flags); master->ibi.ibi_en_count--; reg = mtk_i3c_readw(master, INTR_MASK); mtk_i3c_writew(master, reg & ~(INTR_IBI), INTR_MASK); reg = mtk_i3c_readw(master, TRAFFIC); mtk_i3c_writew(master, reg & (~TRAFFIC_IBI_EN), TRAFFIC); reg = mtk_i3c_readw(master, INTR_STAT); mtk_i3c_writew(master, INTR_IBI, INTR_STAT); spin_unlock_irqrestore(&master->ibi.lock, flags); DONE: return ret; } static int mt_i3c_master_enable_ibi(struct i3c_dev_desc *dev) { struct i3c_master_controller *m = i3c_dev_get_master(dev); struct mtk_i3c_master *master = to_mt_i3c_master(m); unsigned long flags; int ret = 0; u16 reg; spin_lock_irqsave(&master->ibi.lock, flags); reg = mtk_i3c_readw(master, INTR_STAT); mtk_i3c_writew(master, INTR_IBI, INTR_STAT); master->ibi.ibi_en_count++; spin_unlock_irqrestore(&master->ibi.lock, flags); ret = i3c_master_enec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR); if (ret) { spin_lock_irqsave(&master->ibi.lock, flags); reg = mtk_i3c_readw(master, TRAFFIC); mtk_i3c_writew(master, reg & (~TRAFFIC_IBI_EN), TRAFFIC); master->ibi.ibi_en_count--; spin_unlock_irqrestore(&master->ibi.lock, flags); pr_err("Fail to CCC ENEC addr:0x%x", dev->info.dyn_addr); goto DONE; } DONE: return ret; } static int mt_i3c_master_request_ibi(struct i3c_dev_desc *dev, const struct i3c_ibi_setup *req) { struct i3c_master_controller *m = i3c_dev_get_master(dev); struct mtk_i3c_master *master = to_mt_i3c_master(m); struct mtk_i3c_i2c_dev_data *data; unsigned long flags; unsigned int i; data = kzalloc(sizeof(struct mtk_i3c_i2c_dev_data), GFP_KERNEL); i3c_dev_set_master_data(dev, data); dev_info(master->dev, "enter %s\n", __func__); data->ibi_pool = i3c_generic_ibi_alloc_pool(dev, req); if (IS_ERR(data->ibi_pool)) return PTR_ERR(data->ibi_pool); spin_lock_irqsave(&master->ibi.lock, flags); for (i = 0; i < master->ibi.num_slots; i++) { if (!master->ibi.slots[i]) { data->ibi = i; master->ibi.slots[i] = dev; break; } } spin_unlock_irqrestore(&master->ibi.lock, flags); if (i < master->ibi.num_slots) return 0; i3c_generic_ibi_free_pool(data->ibi_pool); data->ibi_pool = NULL; return -ENOSPC; } static void mt_i3c_master_free_ibi(struct i3c_dev_desc *dev) { struct i3c_master_controller *m = i3c_dev_get_master(dev); struct mtk_i3c_master *master = to_mt_i3c_master(m); struct mtk_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); unsigned long flags; spin_lock_irqsave(&master->ibi.lock, flags); master->ibi.slots[data->ibi] = NULL; data->ibi = -1; spin_unlock_irqrestore(&master->ibi.lock, flags); i3c_generic_ibi_free_pool(data->ibi_pool); } static void mt_i3c_master_recycle_ibi_slot(struct i3c_dev_desc *dev, struct i3c_ibi_slot *slot) { struct mtk_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); i3c_generic_ibi_recycle_slot(data->ibi_pool, slot); } static const struct i3c_master_controller_ops mtk_i3c_master_ops = { .bus_init = mtk_i3c_master_bus_init, .do_daa = mtk_i3c_master_do_daa, .supports_ccc_cmd = mtk_i3c_master_supports_ccc_cmd, .send_ccc_cmd = mtk_i3c_master_send_ccc_cmd, .priv_xfers = mtk_i3c_master_priv_xfers, .i2c_xfers = mtk_i3c_master_i2c_xfers, .enable_ibi = mt_i3c_master_enable_ibi, .disable_ibi = mt_i3c_master_disable_ibi, .request_ibi = mt_i3c_master_request_ibi, .free_ibi = mt_i3c_master_free_ibi, .recycle_ibi_slot = mt_i3c_master_recycle_ibi_slot, }; static int mtk_i3c_master_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct mtk_i3c_master *master; struct resource *res; int ret, irqnr; master = devm_kzalloc(dev, sizeof(*master), GFP_KERNEL); if (!master) return -ENOMEM; master->ibi.ibi_en_count = 0; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); master->regs = devm_ioremap_resource(dev, res); if (IS_ERR(master->regs)) return PTR_ERR(master->regs); res = platform_get_resource(pdev, IORESOURCE_MEM, 1); master->dma_regs = devm_ioremap_resource(dev, res); if (IS_ERR(master->dma_regs)) return PTR_ERR(master->dma_regs); irqnr = platform_get_irq(pdev, 0); if (irqnr < 0) return irqnr; master->irqnr = irqnr; ret = devm_request_irq(dev, irqnr, mtk_i3c_master_irq, IRQF_TRIGGER_NONE, DRV_NAME, master); if (ret < 0) { dev_err(dev, "Request I3C IRQ %d fail\n", irqnr); return ret; } spin_lock_init(&master->xferqueue.lock); INIT_LIST_HEAD(&master->xferqueue.list); if (dma_set_mask(dev, DMA_BIT_MASK(33))) { dev_err(dev, "dma_set_mask return error.\n"); return -EINVAL; } master->clk_main = devm_clk_get(dev, "main"); if (IS_ERR(master->clk_main)) { dev_err(dev, "cannot get main clock\n"); return PTR_ERR(master->clk_main); } master->clk_dma = devm_clk_get(dev, "dma"); if (IS_ERR(master->clk_dma)) { dev_err(dev, "cannot get dma clock\n"); return PTR_ERR(master->clk_dma); } master->clk_arb = devm_clk_get(dev, "arb"); if (IS_ERR(master->clk_arb)) dev_err(dev, "get fail arb clock or no need\n"); ret = mtk_i3c_master_clock_enable(master); if (ret) { dev_err(dev, "clock enable failed!\n"); return ret; } master->dev = dev; platform_set_drvdata(pdev, master); master->ibi.num_slots = MAX_I3C_DEVS; master->ibi.slots = devm_kcalloc(&pdev->dev, master->ibi.num_slots, sizeof(*master->ibi.slots), GFP_KERNEL); if (!master->ibi.slots) return -ENOMEM; master->ibi_intr = 0; master->daa_count = 0; ret = i3c_master_register(&master->mas_ctrler, dev, &mtk_i3c_master_ops, false); if (ret) { dev_err(dev, "Failed to add i3c bus to i3c core\n"); mtk_i3c_master_clock_disable(master); return ret; } return 0; } static int mtk_i3c_master_remove(struct platform_device *pdev) { struct mtk_i3c_master *master = platform_get_drvdata(pdev); i3c_master_unregister(&master->mas_ctrler); mtk_i3c_master_clock_disable(master); return 0; } static const struct of_device_id mtk_i3c_master_of_ids[] = { { .compatible = "mediatek,i3c-master" }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, mtk_i3c_master_of_ids); static int mtk_i3c_suspend_noirq(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct mtk_i3c_master *master = platform_get_drvdata(pdev); mtk_i3c_master_clock_disable(master); return 0; } static int mtk_i3c_resume_noirq(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct mtk_i3c_master *master = platform_get_drvdata(pdev); int ret; ret = mtk_i3c_master_clock_enable(master); return ret; } static const struct dev_pm_ops mtk_i3c_dev_pm_ops = { #ifdef CONFIG_PM_SLEEP .suspend_noirq = mtk_i3c_suspend_noirq, .resume_noirq = mtk_i3c_resume_noirq, #endif }; static struct platform_driver mtk_i3c_master_driver = { .probe = mtk_i3c_master_probe, .remove = mtk_i3c_master_remove, .driver = { .name = DRV_NAME, .pm = &mtk_i3c_dev_pm_ops, .of_match_table = mtk_i3c_master_of_ids, }, }; module_platform_driver(mtk_i3c_master_driver); MODULE_DESCRIPTION("MediaTek I3C master driver"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:mtk-i3c-master");