162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2018 Cadence Design Systems Inc. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Author: Boris Brezillon <boris.brezillon@bootlin.com> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/bitops.h> 962306a36Sopenharmony_ci#include <linux/clk.h> 1062306a36Sopenharmony_ci#include <linux/err.h> 1162306a36Sopenharmony_ci#include <linux/errno.h> 1262306a36Sopenharmony_ci#include <linux/i3c/master.h> 1362306a36Sopenharmony_ci#include <linux/interrupt.h> 1462306a36Sopenharmony_ci#include <linux/io.h> 1562306a36Sopenharmony_ci#include <linux/iopoll.h> 1662306a36Sopenharmony_ci#include <linux/ioport.h> 1762306a36Sopenharmony_ci#include <linux/kernel.h> 1862306a36Sopenharmony_ci#include <linux/list.h> 1962306a36Sopenharmony_ci#include <linux/module.h> 2062306a36Sopenharmony_ci#include <linux/of.h> 2162306a36Sopenharmony_ci#include <linux/platform_device.h> 2262306a36Sopenharmony_ci#include <linux/slab.h> 2362306a36Sopenharmony_ci#include <linux/spinlock.h> 2462306a36Sopenharmony_ci#include <linux/workqueue.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define DEV_ID 0x0 2762306a36Sopenharmony_ci#define DEV_ID_I3C_MASTER 0x5034 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define CONF_STATUS0 0x4 3062306a36Sopenharmony_ci#define CONF_STATUS0_CMDR_DEPTH(x) (4 << (((x) & GENMASK(31, 29)) >> 29)) 3162306a36Sopenharmony_ci#define CONF_STATUS0_ECC_CHK BIT(28) 3262306a36Sopenharmony_ci#define CONF_STATUS0_INTEG_CHK BIT(27) 3362306a36Sopenharmony_ci#define CONF_STATUS0_CSR_DAP_CHK BIT(26) 3462306a36Sopenharmony_ci#define CONF_STATUS0_TRANS_TOUT_CHK BIT(25) 3562306a36Sopenharmony_ci#define CONF_STATUS0_PROT_FAULTS_CHK BIT(24) 3662306a36Sopenharmony_ci#define CONF_STATUS0_GPO_NUM(x) (((x) & GENMASK(23, 16)) >> 16) 3762306a36Sopenharmony_ci#define CONF_STATUS0_GPI_NUM(x) (((x) & GENMASK(15, 8)) >> 8) 3862306a36Sopenharmony_ci#define CONF_STATUS0_IBIR_DEPTH(x) (4 << (((x) & GENMASK(7, 6)) >> 7)) 3962306a36Sopenharmony_ci#define CONF_STATUS0_SUPPORTS_DDR BIT(5) 4062306a36Sopenharmony_ci#define CONF_STATUS0_SEC_MASTER BIT(4) 4162306a36Sopenharmony_ci#define CONF_STATUS0_DEVS_NUM(x) ((x) & GENMASK(3, 0)) 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#define CONF_STATUS1 0x8 4462306a36Sopenharmony_ci#define CONF_STATUS1_IBI_HW_RES(x) ((((x) & GENMASK(31, 28)) >> 28) + 1) 4562306a36Sopenharmony_ci#define CONF_STATUS1_CMD_DEPTH(x) (4 << (((x) & GENMASK(27, 26)) >> 26)) 4662306a36Sopenharmony_ci#define CONF_STATUS1_SLVDDR_RX_DEPTH(x) (8 << (((x) & GENMASK(25, 21)) >> 21)) 4762306a36Sopenharmony_ci#define CONF_STATUS1_SLVDDR_TX_DEPTH(x) (8 << (((x) & GENMASK(20, 16)) >> 16)) 4862306a36Sopenharmony_ci#define CONF_STATUS1_IBI_DEPTH(x) (2 << (((x) & GENMASK(12, 10)) >> 10)) 4962306a36Sopenharmony_ci#define CONF_STATUS1_RX_DEPTH(x) (8 << (((x) & GENMASK(9, 5)) >> 5)) 5062306a36Sopenharmony_ci#define CONF_STATUS1_TX_DEPTH(x) (8 << ((x) & GENMASK(4, 0))) 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#define REV_ID 0xc 5362306a36Sopenharmony_ci#define REV_ID_VID(id) (((id) & GENMASK(31, 20)) >> 20) 5462306a36Sopenharmony_ci#define REV_ID_PID(id) (((id) & GENMASK(19, 8)) >> 8) 5562306a36Sopenharmony_ci#define REV_ID_REV_MAJOR(id) (((id) & GENMASK(7, 4)) >> 4) 5662306a36Sopenharmony_ci#define REV_ID_REV_MINOR(id) ((id) & GENMASK(3, 0)) 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci#define CTRL 0x10 5962306a36Sopenharmony_ci#define CTRL_DEV_EN BIT(31) 6062306a36Sopenharmony_ci#define CTRL_HALT_EN BIT(30) 6162306a36Sopenharmony_ci#define CTRL_MCS BIT(29) 6262306a36Sopenharmony_ci#define CTRL_MCS_EN BIT(28) 6362306a36Sopenharmony_ci#define CTRL_THD_DELAY(x) (((x) << 24) & GENMASK(25, 24)) 6462306a36Sopenharmony_ci#define CTRL_HJ_DISEC BIT(8) 6562306a36Sopenharmony_ci#define CTRL_MST_ACK BIT(7) 6662306a36Sopenharmony_ci#define CTRL_HJ_ACK BIT(6) 6762306a36Sopenharmony_ci#define CTRL_HJ_INIT BIT(5) 6862306a36Sopenharmony_ci#define CTRL_MST_INIT BIT(4) 6962306a36Sopenharmony_ci#define CTRL_AHDR_OPT BIT(3) 7062306a36Sopenharmony_ci#define CTRL_PURE_BUS_MODE 0 7162306a36Sopenharmony_ci#define CTRL_MIXED_FAST_BUS_MODE 2 7262306a36Sopenharmony_ci#define CTRL_MIXED_SLOW_BUS_MODE 3 7362306a36Sopenharmony_ci#define CTRL_BUS_MODE_MASK GENMASK(1, 0) 7462306a36Sopenharmony_ci#define THD_DELAY_MAX 3 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci#define PRESCL_CTRL0 0x14 7762306a36Sopenharmony_ci#define PRESCL_CTRL0_I2C(x) ((x) << 16) 7862306a36Sopenharmony_ci#define PRESCL_CTRL0_I3C(x) (x) 7962306a36Sopenharmony_ci#define PRESCL_CTRL0_I3C_MAX GENMASK(9, 0) 8062306a36Sopenharmony_ci#define PRESCL_CTRL0_I2C_MAX GENMASK(15, 0) 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci#define PRESCL_CTRL1 0x18 8362306a36Sopenharmony_ci#define PRESCL_CTRL1_PP_LOW_MASK GENMASK(15, 8) 8462306a36Sopenharmony_ci#define PRESCL_CTRL1_PP_LOW(x) ((x) << 8) 8562306a36Sopenharmony_ci#define PRESCL_CTRL1_OD_LOW_MASK GENMASK(7, 0) 8662306a36Sopenharmony_ci#define PRESCL_CTRL1_OD_LOW(x) (x) 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci#define MST_IER 0x20 8962306a36Sopenharmony_ci#define MST_IDR 0x24 9062306a36Sopenharmony_ci#define MST_IMR 0x28 9162306a36Sopenharmony_ci#define MST_ICR 0x2c 9262306a36Sopenharmony_ci#define MST_ISR 0x30 9362306a36Sopenharmony_ci#define MST_INT_HALTED BIT(18) 9462306a36Sopenharmony_ci#define MST_INT_MR_DONE BIT(17) 9562306a36Sopenharmony_ci#define MST_INT_IMM_COMP BIT(16) 9662306a36Sopenharmony_ci#define MST_INT_TX_THR BIT(15) 9762306a36Sopenharmony_ci#define MST_INT_TX_OVF BIT(14) 9862306a36Sopenharmony_ci#define MST_INT_IBID_THR BIT(12) 9962306a36Sopenharmony_ci#define MST_INT_IBID_UNF BIT(11) 10062306a36Sopenharmony_ci#define MST_INT_IBIR_THR BIT(10) 10162306a36Sopenharmony_ci#define MST_INT_IBIR_UNF BIT(9) 10262306a36Sopenharmony_ci#define MST_INT_IBIR_OVF BIT(8) 10362306a36Sopenharmony_ci#define MST_INT_RX_THR BIT(7) 10462306a36Sopenharmony_ci#define MST_INT_RX_UNF BIT(6) 10562306a36Sopenharmony_ci#define MST_INT_CMDD_EMP BIT(5) 10662306a36Sopenharmony_ci#define MST_INT_CMDD_THR BIT(4) 10762306a36Sopenharmony_ci#define MST_INT_CMDD_OVF BIT(3) 10862306a36Sopenharmony_ci#define MST_INT_CMDR_THR BIT(2) 10962306a36Sopenharmony_ci#define MST_INT_CMDR_UNF BIT(1) 11062306a36Sopenharmony_ci#define MST_INT_CMDR_OVF BIT(0) 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci#define MST_STATUS0 0x34 11362306a36Sopenharmony_ci#define MST_STATUS0_IDLE BIT(18) 11462306a36Sopenharmony_ci#define MST_STATUS0_HALTED BIT(17) 11562306a36Sopenharmony_ci#define MST_STATUS0_MASTER_MODE BIT(16) 11662306a36Sopenharmony_ci#define MST_STATUS0_TX_FULL BIT(13) 11762306a36Sopenharmony_ci#define MST_STATUS0_IBID_FULL BIT(12) 11862306a36Sopenharmony_ci#define MST_STATUS0_IBIR_FULL BIT(11) 11962306a36Sopenharmony_ci#define MST_STATUS0_RX_FULL BIT(10) 12062306a36Sopenharmony_ci#define MST_STATUS0_CMDD_FULL BIT(9) 12162306a36Sopenharmony_ci#define MST_STATUS0_CMDR_FULL BIT(8) 12262306a36Sopenharmony_ci#define MST_STATUS0_TX_EMP BIT(5) 12362306a36Sopenharmony_ci#define MST_STATUS0_IBID_EMP BIT(4) 12462306a36Sopenharmony_ci#define MST_STATUS0_IBIR_EMP BIT(3) 12562306a36Sopenharmony_ci#define MST_STATUS0_RX_EMP BIT(2) 12662306a36Sopenharmony_ci#define MST_STATUS0_CMDD_EMP BIT(1) 12762306a36Sopenharmony_ci#define MST_STATUS0_CMDR_EMP BIT(0) 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci#define CMDR 0x38 13062306a36Sopenharmony_ci#define CMDR_NO_ERROR 0 13162306a36Sopenharmony_ci#define CMDR_DDR_PREAMBLE_ERROR 1 13262306a36Sopenharmony_ci#define CMDR_DDR_PARITY_ERROR 2 13362306a36Sopenharmony_ci#define CMDR_DDR_RX_FIFO_OVF 3 13462306a36Sopenharmony_ci#define CMDR_DDR_TX_FIFO_UNF 4 13562306a36Sopenharmony_ci#define CMDR_M0_ERROR 5 13662306a36Sopenharmony_ci#define CMDR_M1_ERROR 6 13762306a36Sopenharmony_ci#define CMDR_M2_ERROR 7 13862306a36Sopenharmony_ci#define CMDR_MST_ABORT 8 13962306a36Sopenharmony_ci#define CMDR_NACK_RESP 9 14062306a36Sopenharmony_ci#define CMDR_INVALID_DA 10 14162306a36Sopenharmony_ci#define CMDR_DDR_DROPPED 11 14262306a36Sopenharmony_ci#define CMDR_ERROR(x) (((x) & GENMASK(27, 24)) >> 24) 14362306a36Sopenharmony_ci#define CMDR_XFER_BYTES(x) (((x) & GENMASK(19, 8)) >> 8) 14462306a36Sopenharmony_ci#define CMDR_CMDID_HJACK_DISEC 0xfe 14562306a36Sopenharmony_ci#define CMDR_CMDID_HJACK_ENTDAA 0xff 14662306a36Sopenharmony_ci#define CMDR_CMDID(x) ((x) & GENMASK(7, 0)) 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci#define IBIR 0x3c 14962306a36Sopenharmony_ci#define IBIR_ACKED BIT(12) 15062306a36Sopenharmony_ci#define IBIR_SLVID(x) (((x) & GENMASK(11, 8)) >> 8) 15162306a36Sopenharmony_ci#define IBIR_ERROR BIT(7) 15262306a36Sopenharmony_ci#define IBIR_XFER_BYTES(x) (((x) & GENMASK(6, 2)) >> 2) 15362306a36Sopenharmony_ci#define IBIR_TYPE_IBI 0 15462306a36Sopenharmony_ci#define IBIR_TYPE_HJ 1 15562306a36Sopenharmony_ci#define IBIR_TYPE_MR 2 15662306a36Sopenharmony_ci#define IBIR_TYPE(x) ((x) & GENMASK(1, 0)) 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci#define SLV_IER 0x40 15962306a36Sopenharmony_ci#define SLV_IDR 0x44 16062306a36Sopenharmony_ci#define SLV_IMR 0x48 16162306a36Sopenharmony_ci#define SLV_ICR 0x4c 16262306a36Sopenharmony_ci#define SLV_ISR 0x50 16362306a36Sopenharmony_ci#define SLV_INT_TM BIT(20) 16462306a36Sopenharmony_ci#define SLV_INT_ERROR BIT(19) 16562306a36Sopenharmony_ci#define SLV_INT_EVENT_UP BIT(18) 16662306a36Sopenharmony_ci#define SLV_INT_HJ_DONE BIT(17) 16762306a36Sopenharmony_ci#define SLV_INT_MR_DONE BIT(16) 16862306a36Sopenharmony_ci#define SLV_INT_DA_UPD BIT(15) 16962306a36Sopenharmony_ci#define SLV_INT_SDR_FAIL BIT(14) 17062306a36Sopenharmony_ci#define SLV_INT_DDR_FAIL BIT(13) 17162306a36Sopenharmony_ci#define SLV_INT_M_RD_ABORT BIT(12) 17262306a36Sopenharmony_ci#define SLV_INT_DDR_RX_THR BIT(11) 17362306a36Sopenharmony_ci#define SLV_INT_DDR_TX_THR BIT(10) 17462306a36Sopenharmony_ci#define SLV_INT_SDR_RX_THR BIT(9) 17562306a36Sopenharmony_ci#define SLV_INT_SDR_TX_THR BIT(8) 17662306a36Sopenharmony_ci#define SLV_INT_DDR_RX_UNF BIT(7) 17762306a36Sopenharmony_ci#define SLV_INT_DDR_TX_OVF BIT(6) 17862306a36Sopenharmony_ci#define SLV_INT_SDR_RX_UNF BIT(5) 17962306a36Sopenharmony_ci#define SLV_INT_SDR_TX_OVF BIT(4) 18062306a36Sopenharmony_ci#define SLV_INT_DDR_RD_COMP BIT(3) 18162306a36Sopenharmony_ci#define SLV_INT_DDR_WR_COMP BIT(2) 18262306a36Sopenharmony_ci#define SLV_INT_SDR_RD_COMP BIT(1) 18362306a36Sopenharmony_ci#define SLV_INT_SDR_WR_COMP BIT(0) 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci#define SLV_STATUS0 0x54 18662306a36Sopenharmony_ci#define SLV_STATUS0_REG_ADDR(s) (((s) & GENMASK(23, 16)) >> 16) 18762306a36Sopenharmony_ci#define SLV_STATUS0_XFRD_BYTES(s) ((s) & GENMASK(15, 0)) 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci#define SLV_STATUS1 0x58 19062306a36Sopenharmony_ci#define SLV_STATUS1_AS(s) (((s) & GENMASK(21, 20)) >> 20) 19162306a36Sopenharmony_ci#define SLV_STATUS1_VEN_TM BIT(19) 19262306a36Sopenharmony_ci#define SLV_STATUS1_HJ_DIS BIT(18) 19362306a36Sopenharmony_ci#define SLV_STATUS1_MR_DIS BIT(17) 19462306a36Sopenharmony_ci#define SLV_STATUS1_PROT_ERR BIT(16) 19562306a36Sopenharmony_ci#define SLV_STATUS1_DA(s) (((s) & GENMASK(15, 9)) >> 9) 19662306a36Sopenharmony_ci#define SLV_STATUS1_HAS_DA BIT(8) 19762306a36Sopenharmony_ci#define SLV_STATUS1_DDR_RX_FULL BIT(7) 19862306a36Sopenharmony_ci#define SLV_STATUS1_DDR_TX_FULL BIT(6) 19962306a36Sopenharmony_ci#define SLV_STATUS1_DDR_RX_EMPTY BIT(5) 20062306a36Sopenharmony_ci#define SLV_STATUS1_DDR_TX_EMPTY BIT(4) 20162306a36Sopenharmony_ci#define SLV_STATUS1_SDR_RX_FULL BIT(3) 20262306a36Sopenharmony_ci#define SLV_STATUS1_SDR_TX_FULL BIT(2) 20362306a36Sopenharmony_ci#define SLV_STATUS1_SDR_RX_EMPTY BIT(1) 20462306a36Sopenharmony_ci#define SLV_STATUS1_SDR_TX_EMPTY BIT(0) 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci#define CMD0_FIFO 0x60 20762306a36Sopenharmony_ci#define CMD0_FIFO_IS_DDR BIT(31) 20862306a36Sopenharmony_ci#define CMD0_FIFO_IS_CCC BIT(30) 20962306a36Sopenharmony_ci#define CMD0_FIFO_BCH BIT(29) 21062306a36Sopenharmony_ci#define XMIT_BURST_STATIC_SUBADDR 0 21162306a36Sopenharmony_ci#define XMIT_SINGLE_INC_SUBADDR 1 21262306a36Sopenharmony_ci#define XMIT_SINGLE_STATIC_SUBADDR 2 21362306a36Sopenharmony_ci#define XMIT_BURST_WITHOUT_SUBADDR 3 21462306a36Sopenharmony_ci#define CMD0_FIFO_PRIV_XMIT_MODE(m) ((m) << 27) 21562306a36Sopenharmony_ci#define CMD0_FIFO_SBCA BIT(26) 21662306a36Sopenharmony_ci#define CMD0_FIFO_RSBC BIT(25) 21762306a36Sopenharmony_ci#define CMD0_FIFO_IS_10B BIT(24) 21862306a36Sopenharmony_ci#define CMD0_FIFO_PL_LEN(l) ((l) << 12) 21962306a36Sopenharmony_ci#define CMD0_FIFO_PL_LEN_MAX 4095 22062306a36Sopenharmony_ci#define CMD0_FIFO_DEV_ADDR(a) ((a) << 1) 22162306a36Sopenharmony_ci#define CMD0_FIFO_RNW BIT(0) 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci#define CMD1_FIFO 0x64 22462306a36Sopenharmony_ci#define CMD1_FIFO_CMDID(id) ((id) << 24) 22562306a36Sopenharmony_ci#define CMD1_FIFO_CSRADDR(a) (a) 22662306a36Sopenharmony_ci#define CMD1_FIFO_CCC(id) (id) 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci#define TX_FIFO 0x68 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci#define IMD_CMD0 0x70 23162306a36Sopenharmony_ci#define IMD_CMD0_PL_LEN(l) ((l) << 12) 23262306a36Sopenharmony_ci#define IMD_CMD0_DEV_ADDR(a) ((a) << 1) 23362306a36Sopenharmony_ci#define IMD_CMD0_RNW BIT(0) 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci#define IMD_CMD1 0x74 23662306a36Sopenharmony_ci#define IMD_CMD1_CCC(id) (id) 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci#define IMD_DATA 0x78 23962306a36Sopenharmony_ci#define RX_FIFO 0x80 24062306a36Sopenharmony_ci#define IBI_DATA_FIFO 0x84 24162306a36Sopenharmony_ci#define SLV_DDR_TX_FIFO 0x88 24262306a36Sopenharmony_ci#define SLV_DDR_RX_FIFO 0x8c 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci#define CMD_IBI_THR_CTRL 0x90 24562306a36Sopenharmony_ci#define IBIR_THR(t) ((t) << 24) 24662306a36Sopenharmony_ci#define CMDR_THR(t) ((t) << 16) 24762306a36Sopenharmony_ci#define IBI_THR(t) ((t) << 8) 24862306a36Sopenharmony_ci#define CMD_THR(t) (t) 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci#define TX_RX_THR_CTRL 0x94 25162306a36Sopenharmony_ci#define RX_THR(t) ((t) << 16) 25262306a36Sopenharmony_ci#define TX_THR(t) (t) 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci#define SLV_DDR_TX_RX_THR_CTRL 0x98 25562306a36Sopenharmony_ci#define SLV_DDR_RX_THR(t) ((t) << 16) 25662306a36Sopenharmony_ci#define SLV_DDR_TX_THR(t) (t) 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci#define FLUSH_CTRL 0x9c 25962306a36Sopenharmony_ci#define FLUSH_IBI_RESP BIT(23) 26062306a36Sopenharmony_ci#define FLUSH_CMD_RESP BIT(22) 26162306a36Sopenharmony_ci#define FLUSH_SLV_DDR_RX_FIFO BIT(22) 26262306a36Sopenharmony_ci#define FLUSH_SLV_DDR_TX_FIFO BIT(21) 26362306a36Sopenharmony_ci#define FLUSH_IMM_FIFO BIT(20) 26462306a36Sopenharmony_ci#define FLUSH_IBI_FIFO BIT(19) 26562306a36Sopenharmony_ci#define FLUSH_RX_FIFO BIT(18) 26662306a36Sopenharmony_ci#define FLUSH_TX_FIFO BIT(17) 26762306a36Sopenharmony_ci#define FLUSH_CMD_FIFO BIT(16) 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci#define TTO_PRESCL_CTRL0 0xb0 27062306a36Sopenharmony_ci#define TTO_PRESCL_CTRL0_DIVB(x) ((x) << 16) 27162306a36Sopenharmony_ci#define TTO_PRESCL_CTRL0_DIVA(x) (x) 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci#define TTO_PRESCL_CTRL1 0xb4 27462306a36Sopenharmony_ci#define TTO_PRESCL_CTRL1_DIVB(x) ((x) << 16) 27562306a36Sopenharmony_ci#define TTO_PRESCL_CTRL1_DIVA(x) (x) 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci#define DEVS_CTRL 0xb8 27862306a36Sopenharmony_ci#define DEVS_CTRL_DEV_CLR_SHIFT 16 27962306a36Sopenharmony_ci#define DEVS_CTRL_DEV_CLR_ALL GENMASK(31, 16) 28062306a36Sopenharmony_ci#define DEVS_CTRL_DEV_CLR(dev) BIT(16 + (dev)) 28162306a36Sopenharmony_ci#define DEVS_CTRL_DEV_ACTIVE(dev) BIT(dev) 28262306a36Sopenharmony_ci#define DEVS_CTRL_DEVS_ACTIVE_MASK GENMASK(15, 0) 28362306a36Sopenharmony_ci#define MAX_DEVS 16 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci#define DEV_ID_RR0(d) (0xc0 + ((d) * 0x10)) 28662306a36Sopenharmony_ci#define DEV_ID_RR0_LVR_EXT_ADDR BIT(11) 28762306a36Sopenharmony_ci#define DEV_ID_RR0_HDR_CAP BIT(10) 28862306a36Sopenharmony_ci#define DEV_ID_RR0_IS_I3C BIT(9) 28962306a36Sopenharmony_ci#define DEV_ID_RR0_DEV_ADDR_MASK (GENMASK(6, 0) | GENMASK(15, 13)) 29062306a36Sopenharmony_ci#define DEV_ID_RR0_SET_DEV_ADDR(a) (((a) & GENMASK(6, 0)) | \ 29162306a36Sopenharmony_ci (((a) & GENMASK(9, 7)) << 6)) 29262306a36Sopenharmony_ci#define DEV_ID_RR0_GET_DEV_ADDR(x) ((((x) >> 1) & GENMASK(6, 0)) | \ 29362306a36Sopenharmony_ci (((x) >> 6) & GENMASK(9, 7))) 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci#define DEV_ID_RR1(d) (0xc4 + ((d) * 0x10)) 29662306a36Sopenharmony_ci#define DEV_ID_RR1_PID_MSB(pid) (pid) 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci#define DEV_ID_RR2(d) (0xc8 + ((d) * 0x10)) 29962306a36Sopenharmony_ci#define DEV_ID_RR2_PID_LSB(pid) ((pid) << 16) 30062306a36Sopenharmony_ci#define DEV_ID_RR2_BCR(bcr) ((bcr) << 8) 30162306a36Sopenharmony_ci#define DEV_ID_RR2_DCR(dcr) (dcr) 30262306a36Sopenharmony_ci#define DEV_ID_RR2_LVR(lvr) (lvr) 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci#define SIR_MAP(x) (0x180 + ((x) * 4)) 30562306a36Sopenharmony_ci#define SIR_MAP_DEV_REG(d) SIR_MAP((d) / 2) 30662306a36Sopenharmony_ci#define SIR_MAP_DEV_SHIFT(d, fs) ((fs) + (((d) % 2) ? 16 : 0)) 30762306a36Sopenharmony_ci#define SIR_MAP_DEV_CONF_MASK(d) (GENMASK(15, 0) << (((d) % 2) ? 16 : 0)) 30862306a36Sopenharmony_ci#define SIR_MAP_DEV_CONF(d, c) ((c) << (((d) % 2) ? 16 : 0)) 30962306a36Sopenharmony_ci#define DEV_ROLE_SLAVE 0 31062306a36Sopenharmony_ci#define DEV_ROLE_MASTER 1 31162306a36Sopenharmony_ci#define SIR_MAP_DEV_ROLE(role) ((role) << 14) 31262306a36Sopenharmony_ci#define SIR_MAP_DEV_SLOW BIT(13) 31362306a36Sopenharmony_ci#define SIR_MAP_DEV_PL(l) ((l) << 8) 31462306a36Sopenharmony_ci#define SIR_MAP_PL_MAX GENMASK(4, 0) 31562306a36Sopenharmony_ci#define SIR_MAP_DEV_DA(a) ((a) << 1) 31662306a36Sopenharmony_ci#define SIR_MAP_DEV_ACK BIT(0) 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci#define GPIR_WORD(x) (0x200 + ((x) * 4)) 31962306a36Sopenharmony_ci#define GPI_REG(val, id) \ 32062306a36Sopenharmony_ci (((val) >> (((id) % 4) * 8)) & GENMASK(7, 0)) 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci#define GPOR_WORD(x) (0x220 + ((x) * 4)) 32362306a36Sopenharmony_ci#define GPO_REG(val, id) \ 32462306a36Sopenharmony_ci (((val) >> (((id) % 4) * 8)) & GENMASK(7, 0)) 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci#define ASF_INT_STATUS 0x300 32762306a36Sopenharmony_ci#define ASF_INT_RAW_STATUS 0x304 32862306a36Sopenharmony_ci#define ASF_INT_MASK 0x308 32962306a36Sopenharmony_ci#define ASF_INT_TEST 0x30c 33062306a36Sopenharmony_ci#define ASF_INT_FATAL_SELECT 0x310 33162306a36Sopenharmony_ci#define ASF_INTEGRITY_ERR BIT(6) 33262306a36Sopenharmony_ci#define ASF_PROTOCOL_ERR BIT(5) 33362306a36Sopenharmony_ci#define ASF_TRANS_TIMEOUT_ERR BIT(4) 33462306a36Sopenharmony_ci#define ASF_CSR_ERR BIT(3) 33562306a36Sopenharmony_ci#define ASF_DAP_ERR BIT(2) 33662306a36Sopenharmony_ci#define ASF_SRAM_UNCORR_ERR BIT(1) 33762306a36Sopenharmony_ci#define ASF_SRAM_CORR_ERR BIT(0) 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci#define ASF_SRAM_CORR_FAULT_STATUS 0x320 34062306a36Sopenharmony_ci#define ASF_SRAM_UNCORR_FAULT_STATUS 0x324 34162306a36Sopenharmony_ci#define ASF_SRAM_CORR_FAULT_INSTANCE(x) ((x) >> 24) 34262306a36Sopenharmony_ci#define ASF_SRAM_CORR_FAULT_ADDR(x) ((x) & GENMASK(23, 0)) 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci#define ASF_SRAM_FAULT_STATS 0x328 34562306a36Sopenharmony_ci#define ASF_SRAM_FAULT_UNCORR_STATS(x) ((x) >> 16) 34662306a36Sopenharmony_ci#define ASF_SRAM_FAULT_CORR_STATS(x) ((x) & GENMASK(15, 0)) 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci#define ASF_TRANS_TOUT_CTRL 0x330 34962306a36Sopenharmony_ci#define ASF_TRANS_TOUT_EN BIT(31) 35062306a36Sopenharmony_ci#define ASF_TRANS_TOUT_VAL(x) (x) 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci#define ASF_TRANS_TOUT_FAULT_MASK 0x334 35362306a36Sopenharmony_ci#define ASF_TRANS_TOUT_FAULT_STATUS 0x338 35462306a36Sopenharmony_ci#define ASF_TRANS_TOUT_FAULT_APB BIT(3) 35562306a36Sopenharmony_ci#define ASF_TRANS_TOUT_FAULT_SCL_LOW BIT(2) 35662306a36Sopenharmony_ci#define ASF_TRANS_TOUT_FAULT_SCL_HIGH BIT(1) 35762306a36Sopenharmony_ci#define ASF_TRANS_TOUT_FAULT_FSCL_HIGH BIT(0) 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci#define ASF_PROTO_FAULT_MASK 0x340 36062306a36Sopenharmony_ci#define ASF_PROTO_FAULT_STATUS 0x344 36162306a36Sopenharmony_ci#define ASF_PROTO_FAULT_SLVSDR_RD_ABORT BIT(31) 36262306a36Sopenharmony_ci#define ASF_PROTO_FAULT_SLVDDR_FAIL BIT(30) 36362306a36Sopenharmony_ci#define ASF_PROTO_FAULT_S(x) BIT(16 + (x)) 36462306a36Sopenharmony_ci#define ASF_PROTO_FAULT_MSTSDR_RD_ABORT BIT(15) 36562306a36Sopenharmony_ci#define ASF_PROTO_FAULT_MSTDDR_FAIL BIT(14) 36662306a36Sopenharmony_ci#define ASF_PROTO_FAULT_M(x) BIT(x) 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_cistruct cdns_i3c_master_caps { 36962306a36Sopenharmony_ci u32 cmdfifodepth; 37062306a36Sopenharmony_ci u32 cmdrfifodepth; 37162306a36Sopenharmony_ci u32 txfifodepth; 37262306a36Sopenharmony_ci u32 rxfifodepth; 37362306a36Sopenharmony_ci u32 ibirfifodepth; 37462306a36Sopenharmony_ci}; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_cistruct cdns_i3c_cmd { 37762306a36Sopenharmony_ci u32 cmd0; 37862306a36Sopenharmony_ci u32 cmd1; 37962306a36Sopenharmony_ci u32 tx_len; 38062306a36Sopenharmony_ci const void *tx_buf; 38162306a36Sopenharmony_ci u32 rx_len; 38262306a36Sopenharmony_ci void *rx_buf; 38362306a36Sopenharmony_ci u32 error; 38462306a36Sopenharmony_ci}; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_cistruct cdns_i3c_xfer { 38762306a36Sopenharmony_ci struct list_head node; 38862306a36Sopenharmony_ci struct completion comp; 38962306a36Sopenharmony_ci int ret; 39062306a36Sopenharmony_ci unsigned int ncmds; 39162306a36Sopenharmony_ci struct cdns_i3c_cmd cmds[]; 39262306a36Sopenharmony_ci}; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cistruct cdns_i3c_data { 39562306a36Sopenharmony_ci u8 thd_delay_ns; 39662306a36Sopenharmony_ci}; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_cistruct cdns_i3c_master { 39962306a36Sopenharmony_ci struct work_struct hj_work; 40062306a36Sopenharmony_ci struct i3c_master_controller base; 40162306a36Sopenharmony_ci u32 free_rr_slots; 40262306a36Sopenharmony_ci unsigned int maxdevs; 40362306a36Sopenharmony_ci struct { 40462306a36Sopenharmony_ci unsigned int num_slots; 40562306a36Sopenharmony_ci struct i3c_dev_desc **slots; 40662306a36Sopenharmony_ci spinlock_t lock; 40762306a36Sopenharmony_ci } ibi; 40862306a36Sopenharmony_ci struct { 40962306a36Sopenharmony_ci struct list_head list; 41062306a36Sopenharmony_ci struct cdns_i3c_xfer *cur; 41162306a36Sopenharmony_ci spinlock_t lock; 41262306a36Sopenharmony_ci } xferqueue; 41362306a36Sopenharmony_ci void __iomem *regs; 41462306a36Sopenharmony_ci struct clk *sysclk; 41562306a36Sopenharmony_ci struct clk *pclk; 41662306a36Sopenharmony_ci struct cdns_i3c_master_caps caps; 41762306a36Sopenharmony_ci unsigned long i3c_scl_lim; 41862306a36Sopenharmony_ci const struct cdns_i3c_data *devdata; 41962306a36Sopenharmony_ci}; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_cistatic inline struct cdns_i3c_master * 42262306a36Sopenharmony_cito_cdns_i3c_master(struct i3c_master_controller *master) 42362306a36Sopenharmony_ci{ 42462306a36Sopenharmony_ci return container_of(master, struct cdns_i3c_master, base); 42562306a36Sopenharmony_ci} 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_cistatic void cdns_i3c_master_wr_to_tx_fifo(struct cdns_i3c_master *master, 42862306a36Sopenharmony_ci const u8 *bytes, int nbytes) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci writesl(master->regs + TX_FIFO, bytes, nbytes / 4); 43162306a36Sopenharmony_ci if (nbytes & 3) { 43262306a36Sopenharmony_ci u32 tmp = 0; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci memcpy(&tmp, bytes + (nbytes & ~3), nbytes & 3); 43562306a36Sopenharmony_ci writesl(master->regs + TX_FIFO, &tmp, 1); 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cistatic void cdns_i3c_master_rd_from_rx_fifo(struct cdns_i3c_master *master, 44062306a36Sopenharmony_ci u8 *bytes, int nbytes) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci readsl(master->regs + RX_FIFO, bytes, nbytes / 4); 44362306a36Sopenharmony_ci if (nbytes & 3) { 44462306a36Sopenharmony_ci u32 tmp; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci readsl(master->regs + RX_FIFO, &tmp, 1); 44762306a36Sopenharmony_ci memcpy(bytes + (nbytes & ~3), &tmp, nbytes & 3); 44862306a36Sopenharmony_ci } 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cistatic bool cdns_i3c_master_supports_ccc_cmd(struct i3c_master_controller *m, 45262306a36Sopenharmony_ci const struct i3c_ccc_cmd *cmd) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci if (cmd->ndests > 1) 45562306a36Sopenharmony_ci return false; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci switch (cmd->id) { 45862306a36Sopenharmony_ci case I3C_CCC_ENEC(true): 45962306a36Sopenharmony_ci case I3C_CCC_ENEC(false): 46062306a36Sopenharmony_ci case I3C_CCC_DISEC(true): 46162306a36Sopenharmony_ci case I3C_CCC_DISEC(false): 46262306a36Sopenharmony_ci case I3C_CCC_ENTAS(0, true): 46362306a36Sopenharmony_ci case I3C_CCC_ENTAS(0, false): 46462306a36Sopenharmony_ci case I3C_CCC_RSTDAA(true): 46562306a36Sopenharmony_ci case I3C_CCC_RSTDAA(false): 46662306a36Sopenharmony_ci case I3C_CCC_ENTDAA: 46762306a36Sopenharmony_ci case I3C_CCC_SETMWL(true): 46862306a36Sopenharmony_ci case I3C_CCC_SETMWL(false): 46962306a36Sopenharmony_ci case I3C_CCC_SETMRL(true): 47062306a36Sopenharmony_ci case I3C_CCC_SETMRL(false): 47162306a36Sopenharmony_ci case I3C_CCC_DEFSLVS: 47262306a36Sopenharmony_ci case I3C_CCC_ENTHDR(0): 47362306a36Sopenharmony_ci case I3C_CCC_SETDASA: 47462306a36Sopenharmony_ci case I3C_CCC_SETNEWDA: 47562306a36Sopenharmony_ci case I3C_CCC_GETMWL: 47662306a36Sopenharmony_ci case I3C_CCC_GETMRL: 47762306a36Sopenharmony_ci case I3C_CCC_GETPID: 47862306a36Sopenharmony_ci case I3C_CCC_GETBCR: 47962306a36Sopenharmony_ci case I3C_CCC_GETDCR: 48062306a36Sopenharmony_ci case I3C_CCC_GETSTATUS: 48162306a36Sopenharmony_ci case I3C_CCC_GETACCMST: 48262306a36Sopenharmony_ci case I3C_CCC_GETMXDS: 48362306a36Sopenharmony_ci case I3C_CCC_GETHDRCAP: 48462306a36Sopenharmony_ci return true; 48562306a36Sopenharmony_ci default: 48662306a36Sopenharmony_ci break; 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci return false; 49062306a36Sopenharmony_ci} 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_cistatic int cdns_i3c_master_disable(struct cdns_i3c_master *master) 49362306a36Sopenharmony_ci{ 49462306a36Sopenharmony_ci u32 status; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci writel(readl(master->regs + CTRL) & ~CTRL_DEV_EN, master->regs + CTRL); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci return readl_poll_timeout(master->regs + MST_STATUS0, status, 49962306a36Sopenharmony_ci status & MST_STATUS0_IDLE, 10, 1000000); 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_cistatic void cdns_i3c_master_enable(struct cdns_i3c_master *master) 50362306a36Sopenharmony_ci{ 50462306a36Sopenharmony_ci writel(readl(master->regs + CTRL) | CTRL_DEV_EN, master->regs + CTRL); 50562306a36Sopenharmony_ci} 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_cistatic struct cdns_i3c_xfer * 50862306a36Sopenharmony_cicdns_i3c_master_alloc_xfer(struct cdns_i3c_master *master, unsigned int ncmds) 50962306a36Sopenharmony_ci{ 51062306a36Sopenharmony_ci struct cdns_i3c_xfer *xfer; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci xfer = kzalloc(struct_size(xfer, cmds, ncmds), GFP_KERNEL); 51362306a36Sopenharmony_ci if (!xfer) 51462306a36Sopenharmony_ci return NULL; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci INIT_LIST_HEAD(&xfer->node); 51762306a36Sopenharmony_ci xfer->ncmds = ncmds; 51862306a36Sopenharmony_ci xfer->ret = -ETIMEDOUT; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci return xfer; 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_cistatic void cdns_i3c_master_free_xfer(struct cdns_i3c_xfer *xfer) 52462306a36Sopenharmony_ci{ 52562306a36Sopenharmony_ci kfree(xfer); 52662306a36Sopenharmony_ci} 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_cistatic void cdns_i3c_master_start_xfer_locked(struct cdns_i3c_master *master) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci struct cdns_i3c_xfer *xfer = master->xferqueue.cur; 53162306a36Sopenharmony_ci unsigned int i; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci if (!xfer) 53462306a36Sopenharmony_ci return; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci writel(MST_INT_CMDD_EMP, master->regs + MST_ICR); 53762306a36Sopenharmony_ci for (i = 0; i < xfer->ncmds; i++) { 53862306a36Sopenharmony_ci struct cdns_i3c_cmd *cmd = &xfer->cmds[i]; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci cdns_i3c_master_wr_to_tx_fifo(master, cmd->tx_buf, 54162306a36Sopenharmony_ci cmd->tx_len); 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci for (i = 0; i < xfer->ncmds; i++) { 54562306a36Sopenharmony_ci struct cdns_i3c_cmd *cmd = &xfer->cmds[i]; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci writel(cmd->cmd1 | CMD1_FIFO_CMDID(i), 54862306a36Sopenharmony_ci master->regs + CMD1_FIFO); 54962306a36Sopenharmony_ci writel(cmd->cmd0, master->regs + CMD0_FIFO); 55062306a36Sopenharmony_ci } 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci writel(readl(master->regs + CTRL) | CTRL_MCS, 55362306a36Sopenharmony_ci master->regs + CTRL); 55462306a36Sopenharmony_ci writel(MST_INT_CMDD_EMP, master->regs + MST_IER); 55562306a36Sopenharmony_ci} 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_cistatic void cdns_i3c_master_end_xfer_locked(struct cdns_i3c_master *master, 55862306a36Sopenharmony_ci u32 isr) 55962306a36Sopenharmony_ci{ 56062306a36Sopenharmony_ci struct cdns_i3c_xfer *xfer = master->xferqueue.cur; 56162306a36Sopenharmony_ci int i, ret = 0; 56262306a36Sopenharmony_ci u32 status0; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci if (!xfer) 56562306a36Sopenharmony_ci return; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci if (!(isr & MST_INT_CMDD_EMP)) 56862306a36Sopenharmony_ci return; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci writel(MST_INT_CMDD_EMP, master->regs + MST_IDR); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci for (status0 = readl(master->regs + MST_STATUS0); 57362306a36Sopenharmony_ci !(status0 & MST_STATUS0_CMDR_EMP); 57462306a36Sopenharmony_ci status0 = readl(master->regs + MST_STATUS0)) { 57562306a36Sopenharmony_ci struct cdns_i3c_cmd *cmd; 57662306a36Sopenharmony_ci u32 cmdr, rx_len, id; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci cmdr = readl(master->regs + CMDR); 57962306a36Sopenharmony_ci id = CMDR_CMDID(cmdr); 58062306a36Sopenharmony_ci if (id == CMDR_CMDID_HJACK_DISEC || 58162306a36Sopenharmony_ci id == CMDR_CMDID_HJACK_ENTDAA || 58262306a36Sopenharmony_ci WARN_ON(id >= xfer->ncmds)) 58362306a36Sopenharmony_ci continue; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci cmd = &xfer->cmds[CMDR_CMDID(cmdr)]; 58662306a36Sopenharmony_ci rx_len = min_t(u32, CMDR_XFER_BYTES(cmdr), cmd->rx_len); 58762306a36Sopenharmony_ci cdns_i3c_master_rd_from_rx_fifo(master, cmd->rx_buf, rx_len); 58862306a36Sopenharmony_ci cmd->error = CMDR_ERROR(cmdr); 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci for (i = 0; i < xfer->ncmds; i++) { 59262306a36Sopenharmony_ci switch (xfer->cmds[i].error) { 59362306a36Sopenharmony_ci case CMDR_NO_ERROR: 59462306a36Sopenharmony_ci break; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci case CMDR_DDR_PREAMBLE_ERROR: 59762306a36Sopenharmony_ci case CMDR_DDR_PARITY_ERROR: 59862306a36Sopenharmony_ci case CMDR_M0_ERROR: 59962306a36Sopenharmony_ci case CMDR_M1_ERROR: 60062306a36Sopenharmony_ci case CMDR_M2_ERROR: 60162306a36Sopenharmony_ci case CMDR_MST_ABORT: 60262306a36Sopenharmony_ci case CMDR_NACK_RESP: 60362306a36Sopenharmony_ci case CMDR_DDR_DROPPED: 60462306a36Sopenharmony_ci ret = -EIO; 60562306a36Sopenharmony_ci break; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci case CMDR_DDR_RX_FIFO_OVF: 60862306a36Sopenharmony_ci case CMDR_DDR_TX_FIFO_UNF: 60962306a36Sopenharmony_ci ret = -ENOSPC; 61062306a36Sopenharmony_ci break; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci case CMDR_INVALID_DA: 61362306a36Sopenharmony_ci default: 61462306a36Sopenharmony_ci ret = -EINVAL; 61562306a36Sopenharmony_ci break; 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci xfer->ret = ret; 62062306a36Sopenharmony_ci complete(&xfer->comp); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci xfer = list_first_entry_or_null(&master->xferqueue.list, 62362306a36Sopenharmony_ci struct cdns_i3c_xfer, node); 62462306a36Sopenharmony_ci if (xfer) 62562306a36Sopenharmony_ci list_del_init(&xfer->node); 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci master->xferqueue.cur = xfer; 62862306a36Sopenharmony_ci cdns_i3c_master_start_xfer_locked(master); 62962306a36Sopenharmony_ci} 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_cistatic void cdns_i3c_master_queue_xfer(struct cdns_i3c_master *master, 63262306a36Sopenharmony_ci struct cdns_i3c_xfer *xfer) 63362306a36Sopenharmony_ci{ 63462306a36Sopenharmony_ci unsigned long flags; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci init_completion(&xfer->comp); 63762306a36Sopenharmony_ci spin_lock_irqsave(&master->xferqueue.lock, flags); 63862306a36Sopenharmony_ci if (master->xferqueue.cur) { 63962306a36Sopenharmony_ci list_add_tail(&xfer->node, &master->xferqueue.list); 64062306a36Sopenharmony_ci } else { 64162306a36Sopenharmony_ci master->xferqueue.cur = xfer; 64262306a36Sopenharmony_ci cdns_i3c_master_start_xfer_locked(master); 64362306a36Sopenharmony_ci } 64462306a36Sopenharmony_ci spin_unlock_irqrestore(&master->xferqueue.lock, flags); 64562306a36Sopenharmony_ci} 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_cistatic void cdns_i3c_master_unqueue_xfer(struct cdns_i3c_master *master, 64862306a36Sopenharmony_ci struct cdns_i3c_xfer *xfer) 64962306a36Sopenharmony_ci{ 65062306a36Sopenharmony_ci unsigned long flags; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci spin_lock_irqsave(&master->xferqueue.lock, flags); 65362306a36Sopenharmony_ci if (master->xferqueue.cur == xfer) { 65462306a36Sopenharmony_ci u32 status; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci writel(readl(master->regs + CTRL) & ~CTRL_DEV_EN, 65762306a36Sopenharmony_ci master->regs + CTRL); 65862306a36Sopenharmony_ci readl_poll_timeout_atomic(master->regs + MST_STATUS0, status, 65962306a36Sopenharmony_ci status & MST_STATUS0_IDLE, 10, 66062306a36Sopenharmony_ci 1000000); 66162306a36Sopenharmony_ci master->xferqueue.cur = NULL; 66262306a36Sopenharmony_ci writel(FLUSH_RX_FIFO | FLUSH_TX_FIFO | FLUSH_CMD_FIFO | 66362306a36Sopenharmony_ci FLUSH_CMD_RESP, 66462306a36Sopenharmony_ci master->regs + FLUSH_CTRL); 66562306a36Sopenharmony_ci writel(MST_INT_CMDD_EMP, master->regs + MST_IDR); 66662306a36Sopenharmony_ci writel(readl(master->regs + CTRL) | CTRL_DEV_EN, 66762306a36Sopenharmony_ci master->regs + CTRL); 66862306a36Sopenharmony_ci } else { 66962306a36Sopenharmony_ci list_del_init(&xfer->node); 67062306a36Sopenharmony_ci } 67162306a36Sopenharmony_ci spin_unlock_irqrestore(&master->xferqueue.lock, flags); 67262306a36Sopenharmony_ci} 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_cistatic enum i3c_error_code cdns_i3c_cmd_get_err(struct cdns_i3c_cmd *cmd) 67562306a36Sopenharmony_ci{ 67662306a36Sopenharmony_ci switch (cmd->error) { 67762306a36Sopenharmony_ci case CMDR_M0_ERROR: 67862306a36Sopenharmony_ci return I3C_ERROR_M0; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci case CMDR_M1_ERROR: 68162306a36Sopenharmony_ci return I3C_ERROR_M1; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci case CMDR_M2_ERROR: 68462306a36Sopenharmony_ci case CMDR_NACK_RESP: 68562306a36Sopenharmony_ci return I3C_ERROR_M2; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci default: 68862306a36Sopenharmony_ci break; 68962306a36Sopenharmony_ci } 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci return I3C_ERROR_UNKNOWN; 69262306a36Sopenharmony_ci} 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_cistatic int cdns_i3c_master_send_ccc_cmd(struct i3c_master_controller *m, 69562306a36Sopenharmony_ci struct i3c_ccc_cmd *cmd) 69662306a36Sopenharmony_ci{ 69762306a36Sopenharmony_ci struct cdns_i3c_master *master = to_cdns_i3c_master(m); 69862306a36Sopenharmony_ci struct cdns_i3c_xfer *xfer; 69962306a36Sopenharmony_ci struct cdns_i3c_cmd *ccmd; 70062306a36Sopenharmony_ci int ret; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci xfer = cdns_i3c_master_alloc_xfer(master, 1); 70362306a36Sopenharmony_ci if (!xfer) 70462306a36Sopenharmony_ci return -ENOMEM; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci ccmd = xfer->cmds; 70762306a36Sopenharmony_ci ccmd->cmd1 = CMD1_FIFO_CCC(cmd->id); 70862306a36Sopenharmony_ci ccmd->cmd0 = CMD0_FIFO_IS_CCC | 70962306a36Sopenharmony_ci CMD0_FIFO_PL_LEN(cmd->dests[0].payload.len); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci if (cmd->id & I3C_CCC_DIRECT) 71262306a36Sopenharmony_ci ccmd->cmd0 |= CMD0_FIFO_DEV_ADDR(cmd->dests[0].addr); 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci if (cmd->rnw) { 71562306a36Sopenharmony_ci ccmd->cmd0 |= CMD0_FIFO_RNW; 71662306a36Sopenharmony_ci ccmd->rx_buf = cmd->dests[0].payload.data; 71762306a36Sopenharmony_ci ccmd->rx_len = cmd->dests[0].payload.len; 71862306a36Sopenharmony_ci } else { 71962306a36Sopenharmony_ci ccmd->tx_buf = cmd->dests[0].payload.data; 72062306a36Sopenharmony_ci ccmd->tx_len = cmd->dests[0].payload.len; 72162306a36Sopenharmony_ci } 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci cdns_i3c_master_queue_xfer(master, xfer); 72462306a36Sopenharmony_ci if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000))) 72562306a36Sopenharmony_ci cdns_i3c_master_unqueue_xfer(master, xfer); 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci ret = xfer->ret; 72862306a36Sopenharmony_ci cmd->err = cdns_i3c_cmd_get_err(&xfer->cmds[0]); 72962306a36Sopenharmony_ci cdns_i3c_master_free_xfer(xfer); 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci return ret; 73262306a36Sopenharmony_ci} 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_cistatic int cdns_i3c_master_priv_xfers(struct i3c_dev_desc *dev, 73562306a36Sopenharmony_ci struct i3c_priv_xfer *xfers, 73662306a36Sopenharmony_ci int nxfers) 73762306a36Sopenharmony_ci{ 73862306a36Sopenharmony_ci struct i3c_master_controller *m = i3c_dev_get_master(dev); 73962306a36Sopenharmony_ci struct cdns_i3c_master *master = to_cdns_i3c_master(m); 74062306a36Sopenharmony_ci int txslots = 0, rxslots = 0, i, ret; 74162306a36Sopenharmony_ci struct cdns_i3c_xfer *cdns_xfer; 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci for (i = 0; i < nxfers; i++) { 74462306a36Sopenharmony_ci if (xfers[i].len > CMD0_FIFO_PL_LEN_MAX) 74562306a36Sopenharmony_ci return -ENOTSUPP; 74662306a36Sopenharmony_ci } 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci if (!nxfers) 74962306a36Sopenharmony_ci return 0; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci if (nxfers > master->caps.cmdfifodepth || 75262306a36Sopenharmony_ci nxfers > master->caps.cmdrfifodepth) 75362306a36Sopenharmony_ci return -ENOTSUPP; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci /* 75662306a36Sopenharmony_ci * First make sure that all transactions (block of transfers separated 75762306a36Sopenharmony_ci * by a STOP marker) fit in the FIFOs. 75862306a36Sopenharmony_ci */ 75962306a36Sopenharmony_ci for (i = 0; i < nxfers; i++) { 76062306a36Sopenharmony_ci if (xfers[i].rnw) 76162306a36Sopenharmony_ci rxslots += DIV_ROUND_UP(xfers[i].len, 4); 76262306a36Sopenharmony_ci else 76362306a36Sopenharmony_ci txslots += DIV_ROUND_UP(xfers[i].len, 4); 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci if (rxslots > master->caps.rxfifodepth || 76762306a36Sopenharmony_ci txslots > master->caps.txfifodepth) 76862306a36Sopenharmony_ci return -ENOTSUPP; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci cdns_xfer = cdns_i3c_master_alloc_xfer(master, nxfers); 77162306a36Sopenharmony_ci if (!cdns_xfer) 77262306a36Sopenharmony_ci return -ENOMEM; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci for (i = 0; i < nxfers; i++) { 77562306a36Sopenharmony_ci struct cdns_i3c_cmd *ccmd = &cdns_xfer->cmds[i]; 77662306a36Sopenharmony_ci u32 pl_len = xfers[i].len; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci ccmd->cmd0 = CMD0_FIFO_DEV_ADDR(dev->info.dyn_addr) | 77962306a36Sopenharmony_ci CMD0_FIFO_PRIV_XMIT_MODE(XMIT_BURST_WITHOUT_SUBADDR); 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci if (xfers[i].rnw) { 78262306a36Sopenharmony_ci ccmd->cmd0 |= CMD0_FIFO_RNW; 78362306a36Sopenharmony_ci ccmd->rx_buf = xfers[i].data.in; 78462306a36Sopenharmony_ci ccmd->rx_len = xfers[i].len; 78562306a36Sopenharmony_ci pl_len++; 78662306a36Sopenharmony_ci } else { 78762306a36Sopenharmony_ci ccmd->tx_buf = xfers[i].data.out; 78862306a36Sopenharmony_ci ccmd->tx_len = xfers[i].len; 78962306a36Sopenharmony_ci } 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci ccmd->cmd0 |= CMD0_FIFO_PL_LEN(pl_len); 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci if (i < nxfers - 1) 79462306a36Sopenharmony_ci ccmd->cmd0 |= CMD0_FIFO_RSBC; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci if (!i) 79762306a36Sopenharmony_ci ccmd->cmd0 |= CMD0_FIFO_BCH; 79862306a36Sopenharmony_ci } 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci cdns_i3c_master_queue_xfer(master, cdns_xfer); 80162306a36Sopenharmony_ci if (!wait_for_completion_timeout(&cdns_xfer->comp, 80262306a36Sopenharmony_ci msecs_to_jiffies(1000))) 80362306a36Sopenharmony_ci cdns_i3c_master_unqueue_xfer(master, cdns_xfer); 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci ret = cdns_xfer->ret; 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci for (i = 0; i < nxfers; i++) 80862306a36Sopenharmony_ci xfers[i].err = cdns_i3c_cmd_get_err(&cdns_xfer->cmds[i]); 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci cdns_i3c_master_free_xfer(cdns_xfer); 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci return ret; 81362306a36Sopenharmony_ci} 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_cistatic int cdns_i3c_master_i2c_xfers(struct i2c_dev_desc *dev, 81662306a36Sopenharmony_ci const struct i2c_msg *xfers, int nxfers) 81762306a36Sopenharmony_ci{ 81862306a36Sopenharmony_ci struct i3c_master_controller *m = i2c_dev_get_master(dev); 81962306a36Sopenharmony_ci struct cdns_i3c_master *master = to_cdns_i3c_master(m); 82062306a36Sopenharmony_ci unsigned int nrxwords = 0, ntxwords = 0; 82162306a36Sopenharmony_ci struct cdns_i3c_xfer *xfer; 82262306a36Sopenharmony_ci int i, ret = 0; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci if (nxfers > master->caps.cmdfifodepth) 82562306a36Sopenharmony_ci return -ENOTSUPP; 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci for (i = 0; i < nxfers; i++) { 82862306a36Sopenharmony_ci if (xfers[i].len > CMD0_FIFO_PL_LEN_MAX) 82962306a36Sopenharmony_ci return -ENOTSUPP; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci if (xfers[i].flags & I2C_M_RD) 83262306a36Sopenharmony_ci nrxwords += DIV_ROUND_UP(xfers[i].len, 4); 83362306a36Sopenharmony_ci else 83462306a36Sopenharmony_ci ntxwords += DIV_ROUND_UP(xfers[i].len, 4); 83562306a36Sopenharmony_ci } 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci if (ntxwords > master->caps.txfifodepth || 83862306a36Sopenharmony_ci nrxwords > master->caps.rxfifodepth) 83962306a36Sopenharmony_ci return -ENOTSUPP; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci xfer = cdns_i3c_master_alloc_xfer(master, nxfers); 84262306a36Sopenharmony_ci if (!xfer) 84362306a36Sopenharmony_ci return -ENOMEM; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci for (i = 0; i < nxfers; i++) { 84662306a36Sopenharmony_ci struct cdns_i3c_cmd *ccmd = &xfer->cmds[i]; 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci ccmd->cmd0 = CMD0_FIFO_DEV_ADDR(xfers[i].addr) | 84962306a36Sopenharmony_ci CMD0_FIFO_PL_LEN(xfers[i].len) | 85062306a36Sopenharmony_ci CMD0_FIFO_PRIV_XMIT_MODE(XMIT_BURST_WITHOUT_SUBADDR); 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci if (xfers[i].flags & I2C_M_TEN) 85362306a36Sopenharmony_ci ccmd->cmd0 |= CMD0_FIFO_IS_10B; 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci if (xfers[i].flags & I2C_M_RD) { 85662306a36Sopenharmony_ci ccmd->cmd0 |= CMD0_FIFO_RNW; 85762306a36Sopenharmony_ci ccmd->rx_buf = xfers[i].buf; 85862306a36Sopenharmony_ci ccmd->rx_len = xfers[i].len; 85962306a36Sopenharmony_ci } else { 86062306a36Sopenharmony_ci ccmd->tx_buf = xfers[i].buf; 86162306a36Sopenharmony_ci ccmd->tx_len = xfers[i].len; 86262306a36Sopenharmony_ci } 86362306a36Sopenharmony_ci } 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci cdns_i3c_master_queue_xfer(master, xfer); 86662306a36Sopenharmony_ci if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000))) 86762306a36Sopenharmony_ci cdns_i3c_master_unqueue_xfer(master, xfer); 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci ret = xfer->ret; 87062306a36Sopenharmony_ci cdns_i3c_master_free_xfer(xfer); 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci return ret; 87362306a36Sopenharmony_ci} 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_cistruct cdns_i3c_i2c_dev_data { 87662306a36Sopenharmony_ci u16 id; 87762306a36Sopenharmony_ci s16 ibi; 87862306a36Sopenharmony_ci struct i3c_generic_ibi_pool *ibi_pool; 87962306a36Sopenharmony_ci}; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_cistatic u32 prepare_rr0_dev_address(u32 addr) 88262306a36Sopenharmony_ci{ 88362306a36Sopenharmony_ci u32 ret = (addr << 1) & 0xff; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci /* RR0[7:1] = addr[6:0] */ 88662306a36Sopenharmony_ci ret |= (addr & GENMASK(6, 0)) << 1; 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci /* RR0[15:13] = addr[9:7] */ 88962306a36Sopenharmony_ci ret |= (addr & GENMASK(9, 7)) << 6; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci /* RR0[0] = ~XOR(addr[6:0]) */ 89262306a36Sopenharmony_ci if (!(hweight8(addr & 0x7f) & 1)) 89362306a36Sopenharmony_ci ret |= 1; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci return ret; 89662306a36Sopenharmony_ci} 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_cistatic void cdns_i3c_master_upd_i3c_addr(struct i3c_dev_desc *dev) 89962306a36Sopenharmony_ci{ 90062306a36Sopenharmony_ci struct i3c_master_controller *m = i3c_dev_get_master(dev); 90162306a36Sopenharmony_ci struct cdns_i3c_master *master = to_cdns_i3c_master(m); 90262306a36Sopenharmony_ci struct cdns_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); 90362306a36Sopenharmony_ci u32 rr; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci rr = prepare_rr0_dev_address(dev->info.dyn_addr ? 90662306a36Sopenharmony_ci dev->info.dyn_addr : 90762306a36Sopenharmony_ci dev->info.static_addr); 90862306a36Sopenharmony_ci writel(DEV_ID_RR0_IS_I3C | rr, master->regs + DEV_ID_RR0(data->id)); 90962306a36Sopenharmony_ci} 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_cistatic int cdns_i3c_master_get_rr_slot(struct cdns_i3c_master *master, 91262306a36Sopenharmony_ci u8 dyn_addr) 91362306a36Sopenharmony_ci{ 91462306a36Sopenharmony_ci unsigned long activedevs; 91562306a36Sopenharmony_ci u32 rr; 91662306a36Sopenharmony_ci int i; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci if (!dyn_addr) { 91962306a36Sopenharmony_ci if (!master->free_rr_slots) 92062306a36Sopenharmony_ci return -ENOSPC; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci return ffs(master->free_rr_slots) - 1; 92362306a36Sopenharmony_ci } 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci activedevs = readl(master->regs + DEVS_CTRL) & DEVS_CTRL_DEVS_ACTIVE_MASK; 92662306a36Sopenharmony_ci activedevs &= ~BIT(0); 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci for_each_set_bit(i, &activedevs, master->maxdevs + 1) { 92962306a36Sopenharmony_ci rr = readl(master->regs + DEV_ID_RR0(i)); 93062306a36Sopenharmony_ci if (!(rr & DEV_ID_RR0_IS_I3C) || 93162306a36Sopenharmony_ci DEV_ID_RR0_GET_DEV_ADDR(rr) != dyn_addr) 93262306a36Sopenharmony_ci continue; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci return i; 93562306a36Sopenharmony_ci } 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci return -EINVAL; 93862306a36Sopenharmony_ci} 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_cistatic int cdns_i3c_master_reattach_i3c_dev(struct i3c_dev_desc *dev, 94162306a36Sopenharmony_ci u8 old_dyn_addr) 94262306a36Sopenharmony_ci{ 94362306a36Sopenharmony_ci cdns_i3c_master_upd_i3c_addr(dev); 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci return 0; 94662306a36Sopenharmony_ci} 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_cistatic int cdns_i3c_master_attach_i3c_dev(struct i3c_dev_desc *dev) 94962306a36Sopenharmony_ci{ 95062306a36Sopenharmony_ci struct i3c_master_controller *m = i3c_dev_get_master(dev); 95162306a36Sopenharmony_ci struct cdns_i3c_master *master = to_cdns_i3c_master(m); 95262306a36Sopenharmony_ci struct cdns_i3c_i2c_dev_data *data; 95362306a36Sopenharmony_ci int slot; 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci data = kzalloc(sizeof(*data), GFP_KERNEL); 95662306a36Sopenharmony_ci if (!data) 95762306a36Sopenharmony_ci return -ENOMEM; 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci slot = cdns_i3c_master_get_rr_slot(master, dev->info.dyn_addr); 96062306a36Sopenharmony_ci if (slot < 0) { 96162306a36Sopenharmony_ci kfree(data); 96262306a36Sopenharmony_ci return slot; 96362306a36Sopenharmony_ci } 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci data->ibi = -1; 96662306a36Sopenharmony_ci data->id = slot; 96762306a36Sopenharmony_ci i3c_dev_set_master_data(dev, data); 96862306a36Sopenharmony_ci master->free_rr_slots &= ~BIT(slot); 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci if (!dev->info.dyn_addr) { 97162306a36Sopenharmony_ci cdns_i3c_master_upd_i3c_addr(dev); 97262306a36Sopenharmony_ci writel(readl(master->regs + DEVS_CTRL) | 97362306a36Sopenharmony_ci DEVS_CTRL_DEV_ACTIVE(data->id), 97462306a36Sopenharmony_ci master->regs + DEVS_CTRL); 97562306a36Sopenharmony_ci } 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci return 0; 97862306a36Sopenharmony_ci} 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_cistatic void cdns_i3c_master_detach_i3c_dev(struct i3c_dev_desc *dev) 98162306a36Sopenharmony_ci{ 98262306a36Sopenharmony_ci struct i3c_master_controller *m = i3c_dev_get_master(dev); 98362306a36Sopenharmony_ci struct cdns_i3c_master *master = to_cdns_i3c_master(m); 98462306a36Sopenharmony_ci struct cdns_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci writel(readl(master->regs + DEVS_CTRL) | 98762306a36Sopenharmony_ci DEVS_CTRL_DEV_CLR(data->id), 98862306a36Sopenharmony_ci master->regs + DEVS_CTRL); 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci i3c_dev_set_master_data(dev, NULL); 99162306a36Sopenharmony_ci master->free_rr_slots |= BIT(data->id); 99262306a36Sopenharmony_ci kfree(data); 99362306a36Sopenharmony_ci} 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_cistatic int cdns_i3c_master_attach_i2c_dev(struct i2c_dev_desc *dev) 99662306a36Sopenharmony_ci{ 99762306a36Sopenharmony_ci struct i3c_master_controller *m = i2c_dev_get_master(dev); 99862306a36Sopenharmony_ci struct cdns_i3c_master *master = to_cdns_i3c_master(m); 99962306a36Sopenharmony_ci struct cdns_i3c_i2c_dev_data *data; 100062306a36Sopenharmony_ci int slot; 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci slot = cdns_i3c_master_get_rr_slot(master, 0); 100362306a36Sopenharmony_ci if (slot < 0) 100462306a36Sopenharmony_ci return slot; 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci data = kzalloc(sizeof(*data), GFP_KERNEL); 100762306a36Sopenharmony_ci if (!data) 100862306a36Sopenharmony_ci return -ENOMEM; 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci data->id = slot; 101162306a36Sopenharmony_ci master->free_rr_slots &= ~BIT(slot); 101262306a36Sopenharmony_ci i2c_dev_set_master_data(dev, data); 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci writel(prepare_rr0_dev_address(dev->addr), 101562306a36Sopenharmony_ci master->regs + DEV_ID_RR0(data->id)); 101662306a36Sopenharmony_ci writel(dev->lvr, master->regs + DEV_ID_RR2(data->id)); 101762306a36Sopenharmony_ci writel(readl(master->regs + DEVS_CTRL) | 101862306a36Sopenharmony_ci DEVS_CTRL_DEV_ACTIVE(data->id), 101962306a36Sopenharmony_ci master->regs + DEVS_CTRL); 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci return 0; 102262306a36Sopenharmony_ci} 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_cistatic void cdns_i3c_master_detach_i2c_dev(struct i2c_dev_desc *dev) 102562306a36Sopenharmony_ci{ 102662306a36Sopenharmony_ci struct i3c_master_controller *m = i2c_dev_get_master(dev); 102762306a36Sopenharmony_ci struct cdns_i3c_master *master = to_cdns_i3c_master(m); 102862306a36Sopenharmony_ci struct cdns_i3c_i2c_dev_data *data = i2c_dev_get_master_data(dev); 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci writel(readl(master->regs + DEVS_CTRL) | 103162306a36Sopenharmony_ci DEVS_CTRL_DEV_CLR(data->id), 103262306a36Sopenharmony_ci master->regs + DEVS_CTRL); 103362306a36Sopenharmony_ci master->free_rr_slots |= BIT(data->id); 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci i2c_dev_set_master_data(dev, NULL); 103662306a36Sopenharmony_ci kfree(data); 103762306a36Sopenharmony_ci} 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_cistatic void cdns_i3c_master_bus_cleanup(struct i3c_master_controller *m) 104062306a36Sopenharmony_ci{ 104162306a36Sopenharmony_ci struct cdns_i3c_master *master = to_cdns_i3c_master(m); 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci cdns_i3c_master_disable(master); 104462306a36Sopenharmony_ci} 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_cistatic void cdns_i3c_master_dev_rr_to_info(struct cdns_i3c_master *master, 104762306a36Sopenharmony_ci unsigned int slot, 104862306a36Sopenharmony_ci struct i3c_device_info *info) 104962306a36Sopenharmony_ci{ 105062306a36Sopenharmony_ci u32 rr; 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci memset(info, 0, sizeof(*info)); 105362306a36Sopenharmony_ci rr = readl(master->regs + DEV_ID_RR0(slot)); 105462306a36Sopenharmony_ci info->dyn_addr = DEV_ID_RR0_GET_DEV_ADDR(rr); 105562306a36Sopenharmony_ci rr = readl(master->regs + DEV_ID_RR2(slot)); 105662306a36Sopenharmony_ci info->dcr = rr; 105762306a36Sopenharmony_ci info->bcr = rr >> 8; 105862306a36Sopenharmony_ci info->pid = rr >> 16; 105962306a36Sopenharmony_ci info->pid |= (u64)readl(master->regs + DEV_ID_RR1(slot)) << 16; 106062306a36Sopenharmony_ci} 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_cistatic void cdns_i3c_master_upd_i3c_scl_lim(struct cdns_i3c_master *master) 106362306a36Sopenharmony_ci{ 106462306a36Sopenharmony_ci struct i3c_master_controller *m = &master->base; 106562306a36Sopenharmony_ci unsigned long i3c_lim_period, pres_step, ncycles; 106662306a36Sopenharmony_ci struct i3c_bus *bus = i3c_master_get_bus(m); 106762306a36Sopenharmony_ci unsigned long new_i3c_scl_lim = 0; 106862306a36Sopenharmony_ci struct i3c_dev_desc *dev; 106962306a36Sopenharmony_ci u32 prescl1, ctrl; 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci i3c_bus_for_each_i3cdev(bus, dev) { 107262306a36Sopenharmony_ci unsigned long max_fscl; 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci max_fscl = max(I3C_CCC_MAX_SDR_FSCL(dev->info.max_read_ds), 107562306a36Sopenharmony_ci I3C_CCC_MAX_SDR_FSCL(dev->info.max_write_ds)); 107662306a36Sopenharmony_ci switch (max_fscl) { 107762306a36Sopenharmony_ci case I3C_SDR1_FSCL_8MHZ: 107862306a36Sopenharmony_ci max_fscl = 8000000; 107962306a36Sopenharmony_ci break; 108062306a36Sopenharmony_ci case I3C_SDR2_FSCL_6MHZ: 108162306a36Sopenharmony_ci max_fscl = 6000000; 108262306a36Sopenharmony_ci break; 108362306a36Sopenharmony_ci case I3C_SDR3_FSCL_4MHZ: 108462306a36Sopenharmony_ci max_fscl = 4000000; 108562306a36Sopenharmony_ci break; 108662306a36Sopenharmony_ci case I3C_SDR4_FSCL_2MHZ: 108762306a36Sopenharmony_ci max_fscl = 2000000; 108862306a36Sopenharmony_ci break; 108962306a36Sopenharmony_ci case I3C_SDR0_FSCL_MAX: 109062306a36Sopenharmony_ci default: 109162306a36Sopenharmony_ci max_fscl = 0; 109262306a36Sopenharmony_ci break; 109362306a36Sopenharmony_ci } 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci if (max_fscl && 109662306a36Sopenharmony_ci (new_i3c_scl_lim > max_fscl || !new_i3c_scl_lim)) 109762306a36Sopenharmony_ci new_i3c_scl_lim = max_fscl; 109862306a36Sopenharmony_ci } 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci /* Only update PRESCL_CTRL1 if the I3C SCL limitation has changed. */ 110162306a36Sopenharmony_ci if (new_i3c_scl_lim == master->i3c_scl_lim) 110262306a36Sopenharmony_ci return; 110362306a36Sopenharmony_ci master->i3c_scl_lim = new_i3c_scl_lim; 110462306a36Sopenharmony_ci if (!new_i3c_scl_lim) 110562306a36Sopenharmony_ci return; 110662306a36Sopenharmony_ci pres_step = 1000000000UL / (bus->scl_rate.i3c * 4); 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci /* Configure PP_LOW to meet I3C slave limitations. */ 110962306a36Sopenharmony_ci prescl1 = readl(master->regs + PRESCL_CTRL1) & 111062306a36Sopenharmony_ci ~PRESCL_CTRL1_PP_LOW_MASK; 111162306a36Sopenharmony_ci ctrl = readl(master->regs + CTRL); 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci i3c_lim_period = DIV_ROUND_UP(1000000000, master->i3c_scl_lim); 111462306a36Sopenharmony_ci ncycles = DIV_ROUND_UP(i3c_lim_period, pres_step); 111562306a36Sopenharmony_ci if (ncycles < 4) 111662306a36Sopenharmony_ci ncycles = 0; 111762306a36Sopenharmony_ci else 111862306a36Sopenharmony_ci ncycles -= 4; 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci prescl1 |= PRESCL_CTRL1_PP_LOW(ncycles); 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci /* Disable I3C master before updating PRESCL_CTRL1. */ 112362306a36Sopenharmony_ci if (ctrl & CTRL_DEV_EN) 112462306a36Sopenharmony_ci cdns_i3c_master_disable(master); 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci writel(prescl1, master->regs + PRESCL_CTRL1); 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci if (ctrl & CTRL_DEV_EN) 112962306a36Sopenharmony_ci cdns_i3c_master_enable(master); 113062306a36Sopenharmony_ci} 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_cistatic int cdns_i3c_master_do_daa(struct i3c_master_controller *m) 113362306a36Sopenharmony_ci{ 113462306a36Sopenharmony_ci struct cdns_i3c_master *master = to_cdns_i3c_master(m); 113562306a36Sopenharmony_ci unsigned long olddevs, newdevs; 113662306a36Sopenharmony_ci int ret, slot; 113762306a36Sopenharmony_ci u8 addrs[MAX_DEVS] = { }; 113862306a36Sopenharmony_ci u8 last_addr = 0; 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci olddevs = readl(master->regs + DEVS_CTRL) & DEVS_CTRL_DEVS_ACTIVE_MASK; 114162306a36Sopenharmony_ci olddevs |= BIT(0); 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci /* Prepare RR slots before launching DAA. */ 114462306a36Sopenharmony_ci for_each_clear_bit(slot, &olddevs, master->maxdevs + 1) { 114562306a36Sopenharmony_ci ret = i3c_master_get_free_addr(m, last_addr + 1); 114662306a36Sopenharmony_ci if (ret < 0) 114762306a36Sopenharmony_ci return -ENOSPC; 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci last_addr = ret; 115062306a36Sopenharmony_ci addrs[slot] = last_addr; 115162306a36Sopenharmony_ci writel(prepare_rr0_dev_address(last_addr) | DEV_ID_RR0_IS_I3C, 115262306a36Sopenharmony_ci master->regs + DEV_ID_RR0(slot)); 115362306a36Sopenharmony_ci writel(0, master->regs + DEV_ID_RR1(slot)); 115462306a36Sopenharmony_ci writel(0, master->regs + DEV_ID_RR2(slot)); 115562306a36Sopenharmony_ci } 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci ret = i3c_master_entdaa_locked(&master->base); 115862306a36Sopenharmony_ci if (ret && ret != I3C_ERROR_M2) 115962306a36Sopenharmony_ci return ret; 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci newdevs = readl(master->regs + DEVS_CTRL) & DEVS_CTRL_DEVS_ACTIVE_MASK; 116262306a36Sopenharmony_ci newdevs &= ~olddevs; 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci /* 116562306a36Sopenharmony_ci * Clear all retaining registers filled during DAA. We already 116662306a36Sopenharmony_ci * have the addressed assigned to them in the addrs array. 116762306a36Sopenharmony_ci */ 116862306a36Sopenharmony_ci for_each_set_bit(slot, &newdevs, master->maxdevs + 1) 116962306a36Sopenharmony_ci i3c_master_add_i3c_dev_locked(m, addrs[slot]); 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci /* 117262306a36Sopenharmony_ci * Clear slots that ended up not being used. Can be caused by I3C 117362306a36Sopenharmony_ci * device creation failure or when the I3C device was already known 117462306a36Sopenharmony_ci * by the system but with a different address (in this case the device 117562306a36Sopenharmony_ci * already has a slot and does not need a new one). 117662306a36Sopenharmony_ci */ 117762306a36Sopenharmony_ci writel(readl(master->regs + DEVS_CTRL) | 117862306a36Sopenharmony_ci master->free_rr_slots << DEVS_CTRL_DEV_CLR_SHIFT, 117962306a36Sopenharmony_ci master->regs + DEVS_CTRL); 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci i3c_master_defslvs_locked(&master->base); 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci cdns_i3c_master_upd_i3c_scl_lim(master); 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci /* Unmask Hot-Join and Mastership request interrupts. */ 118662306a36Sopenharmony_ci i3c_master_enec_locked(m, I3C_BROADCAST_ADDR, 118762306a36Sopenharmony_ci I3C_CCC_EVENT_HJ | I3C_CCC_EVENT_MR); 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci return 0; 119062306a36Sopenharmony_ci} 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_cistatic u8 cdns_i3c_master_calculate_thd_delay(struct cdns_i3c_master *master) 119362306a36Sopenharmony_ci{ 119462306a36Sopenharmony_ci unsigned long sysclk_rate = clk_get_rate(master->sysclk); 119562306a36Sopenharmony_ci u8 thd_delay = DIV_ROUND_UP(master->devdata->thd_delay_ns, 119662306a36Sopenharmony_ci (NSEC_PER_SEC / sysclk_rate)); 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci /* Every value greater than 3 is not valid. */ 119962306a36Sopenharmony_ci if (thd_delay > THD_DELAY_MAX) 120062306a36Sopenharmony_ci thd_delay = THD_DELAY_MAX; 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci /* CTLR_THD_DEL value is encoded. */ 120362306a36Sopenharmony_ci return (THD_DELAY_MAX - thd_delay); 120462306a36Sopenharmony_ci} 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_cistatic int cdns_i3c_master_bus_init(struct i3c_master_controller *m) 120762306a36Sopenharmony_ci{ 120862306a36Sopenharmony_ci struct cdns_i3c_master *master = to_cdns_i3c_master(m); 120962306a36Sopenharmony_ci unsigned long pres_step, sysclk_rate, max_i2cfreq; 121062306a36Sopenharmony_ci struct i3c_bus *bus = i3c_master_get_bus(m); 121162306a36Sopenharmony_ci u32 ctrl, prescl0, prescl1, pres, low; 121262306a36Sopenharmony_ci struct i3c_device_info info = { }; 121362306a36Sopenharmony_ci int ret, ncycles; 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci switch (bus->mode) { 121662306a36Sopenharmony_ci case I3C_BUS_MODE_PURE: 121762306a36Sopenharmony_ci ctrl = CTRL_PURE_BUS_MODE; 121862306a36Sopenharmony_ci break; 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci case I3C_BUS_MODE_MIXED_FAST: 122162306a36Sopenharmony_ci ctrl = CTRL_MIXED_FAST_BUS_MODE; 122262306a36Sopenharmony_ci break; 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci case I3C_BUS_MODE_MIXED_SLOW: 122562306a36Sopenharmony_ci ctrl = CTRL_MIXED_SLOW_BUS_MODE; 122662306a36Sopenharmony_ci break; 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci default: 122962306a36Sopenharmony_ci return -EINVAL; 123062306a36Sopenharmony_ci } 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci sysclk_rate = clk_get_rate(master->sysclk); 123362306a36Sopenharmony_ci if (!sysclk_rate) 123462306a36Sopenharmony_ci return -EINVAL; 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci pres = DIV_ROUND_UP(sysclk_rate, (bus->scl_rate.i3c * 4)) - 1; 123762306a36Sopenharmony_ci if (pres > PRESCL_CTRL0_I3C_MAX) 123862306a36Sopenharmony_ci return -ERANGE; 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci bus->scl_rate.i3c = sysclk_rate / ((pres + 1) * 4); 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci prescl0 = PRESCL_CTRL0_I3C(pres); 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci low = ((I3C_BUS_TLOW_OD_MIN_NS * sysclk_rate) / (pres + 1)) - 2; 124562306a36Sopenharmony_ci prescl1 = PRESCL_CTRL1_OD_LOW(low); 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci max_i2cfreq = bus->scl_rate.i2c; 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci pres = (sysclk_rate / (max_i2cfreq * 5)) - 1; 125062306a36Sopenharmony_ci if (pres > PRESCL_CTRL0_I2C_MAX) 125162306a36Sopenharmony_ci return -ERANGE; 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci bus->scl_rate.i2c = sysclk_rate / ((pres + 1) * 5); 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci prescl0 |= PRESCL_CTRL0_I2C(pres); 125662306a36Sopenharmony_ci writel(prescl0, master->regs + PRESCL_CTRL0); 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci /* Calculate OD and PP low. */ 125962306a36Sopenharmony_ci pres_step = 1000000000 / (bus->scl_rate.i3c * 4); 126062306a36Sopenharmony_ci ncycles = DIV_ROUND_UP(I3C_BUS_TLOW_OD_MIN_NS, pres_step) - 2; 126162306a36Sopenharmony_ci if (ncycles < 0) 126262306a36Sopenharmony_ci ncycles = 0; 126362306a36Sopenharmony_ci prescl1 = PRESCL_CTRL1_OD_LOW(ncycles); 126462306a36Sopenharmony_ci writel(prescl1, master->regs + PRESCL_CTRL1); 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci /* Get an address for the master. */ 126762306a36Sopenharmony_ci ret = i3c_master_get_free_addr(m, 0); 126862306a36Sopenharmony_ci if (ret < 0) 126962306a36Sopenharmony_ci return ret; 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci writel(prepare_rr0_dev_address(ret) | DEV_ID_RR0_IS_I3C, 127262306a36Sopenharmony_ci master->regs + DEV_ID_RR0(0)); 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci cdns_i3c_master_dev_rr_to_info(master, 0, &info); 127562306a36Sopenharmony_ci if (info.bcr & I3C_BCR_HDR_CAP) 127662306a36Sopenharmony_ci info.hdr_cap = I3C_CCC_HDR_MODE(I3C_HDR_DDR); 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci ret = i3c_master_set_info(&master->base, &info); 127962306a36Sopenharmony_ci if (ret) 128062306a36Sopenharmony_ci return ret; 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci /* 128362306a36Sopenharmony_ci * Enable Hot-Join, and, when a Hot-Join request happens, disable all 128462306a36Sopenharmony_ci * events coming from this device. 128562306a36Sopenharmony_ci * 128662306a36Sopenharmony_ci * We will issue ENTDAA afterwards from the threaded IRQ handler. 128762306a36Sopenharmony_ci */ 128862306a36Sopenharmony_ci ctrl |= CTRL_HJ_ACK | CTRL_HJ_DISEC | CTRL_HALT_EN | CTRL_MCS_EN; 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci /* 129162306a36Sopenharmony_ci * Configure data hold delay based on device-specific data. 129262306a36Sopenharmony_ci * 129362306a36Sopenharmony_ci * MIPI I3C Specification 1.0 defines non-zero minimal tHD_PP timing on 129462306a36Sopenharmony_ci * master output. This setting allows to meet this timing on master's 129562306a36Sopenharmony_ci * SoC outputs, regardless of PCB balancing. 129662306a36Sopenharmony_ci */ 129762306a36Sopenharmony_ci ctrl |= CTRL_THD_DELAY(cdns_i3c_master_calculate_thd_delay(master)); 129862306a36Sopenharmony_ci writel(ctrl, master->regs + CTRL); 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci cdns_i3c_master_enable(master); 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci return 0; 130362306a36Sopenharmony_ci} 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_cistatic void cdns_i3c_master_handle_ibi(struct cdns_i3c_master *master, 130662306a36Sopenharmony_ci u32 ibir) 130762306a36Sopenharmony_ci{ 130862306a36Sopenharmony_ci struct cdns_i3c_i2c_dev_data *data; 130962306a36Sopenharmony_ci bool data_consumed = false; 131062306a36Sopenharmony_ci struct i3c_ibi_slot *slot; 131162306a36Sopenharmony_ci u32 id = IBIR_SLVID(ibir); 131262306a36Sopenharmony_ci struct i3c_dev_desc *dev; 131362306a36Sopenharmony_ci size_t nbytes; 131462306a36Sopenharmony_ci u8 *buf; 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci /* 131762306a36Sopenharmony_ci * FIXME: maybe we should report the FIFO OVF errors to the upper 131862306a36Sopenharmony_ci * layer. 131962306a36Sopenharmony_ci */ 132062306a36Sopenharmony_ci if (id >= master->ibi.num_slots || (ibir & IBIR_ERROR)) 132162306a36Sopenharmony_ci goto out; 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci dev = master->ibi.slots[id]; 132462306a36Sopenharmony_ci spin_lock(&master->ibi.lock); 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci data = i3c_dev_get_master_data(dev); 132762306a36Sopenharmony_ci slot = i3c_generic_ibi_get_free_slot(data->ibi_pool); 132862306a36Sopenharmony_ci if (!slot) 132962306a36Sopenharmony_ci goto out_unlock; 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci buf = slot->data; 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci nbytes = IBIR_XFER_BYTES(ibir); 133462306a36Sopenharmony_ci readsl(master->regs + IBI_DATA_FIFO, buf, nbytes / 4); 133562306a36Sopenharmony_ci if (nbytes % 3) { 133662306a36Sopenharmony_ci u32 tmp = __raw_readl(master->regs + IBI_DATA_FIFO); 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci memcpy(buf + (nbytes & ~3), &tmp, nbytes & 3); 133962306a36Sopenharmony_ci } 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci slot->len = min_t(unsigned int, IBIR_XFER_BYTES(ibir), 134262306a36Sopenharmony_ci dev->ibi->max_payload_len); 134362306a36Sopenharmony_ci i3c_master_queue_ibi(dev, slot); 134462306a36Sopenharmony_ci data_consumed = true; 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ciout_unlock: 134762306a36Sopenharmony_ci spin_unlock(&master->ibi.lock); 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ciout: 135062306a36Sopenharmony_ci /* Consume data from the FIFO if it's not been done already. */ 135162306a36Sopenharmony_ci if (!data_consumed) { 135262306a36Sopenharmony_ci int i; 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci for (i = 0; i < IBIR_XFER_BYTES(ibir); i += 4) 135562306a36Sopenharmony_ci readl(master->regs + IBI_DATA_FIFO); 135662306a36Sopenharmony_ci } 135762306a36Sopenharmony_ci} 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_cistatic void cnds_i3c_master_demux_ibis(struct cdns_i3c_master *master) 136062306a36Sopenharmony_ci{ 136162306a36Sopenharmony_ci u32 status0; 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci writel(MST_INT_IBIR_THR, master->regs + MST_ICR); 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci for (status0 = readl(master->regs + MST_STATUS0); 136662306a36Sopenharmony_ci !(status0 & MST_STATUS0_IBIR_EMP); 136762306a36Sopenharmony_ci status0 = readl(master->regs + MST_STATUS0)) { 136862306a36Sopenharmony_ci u32 ibir = readl(master->regs + IBIR); 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci switch (IBIR_TYPE(ibir)) { 137162306a36Sopenharmony_ci case IBIR_TYPE_IBI: 137262306a36Sopenharmony_ci cdns_i3c_master_handle_ibi(master, ibir); 137362306a36Sopenharmony_ci break; 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci case IBIR_TYPE_HJ: 137662306a36Sopenharmony_ci WARN_ON(IBIR_XFER_BYTES(ibir) || (ibir & IBIR_ERROR)); 137762306a36Sopenharmony_ci queue_work(master->base.wq, &master->hj_work); 137862306a36Sopenharmony_ci break; 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci case IBIR_TYPE_MR: 138162306a36Sopenharmony_ci WARN_ON(IBIR_XFER_BYTES(ibir) || (ibir & IBIR_ERROR)); 138262306a36Sopenharmony_ci break; 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci default: 138562306a36Sopenharmony_ci break; 138662306a36Sopenharmony_ci } 138762306a36Sopenharmony_ci } 138862306a36Sopenharmony_ci} 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_cistatic irqreturn_t cdns_i3c_master_interrupt(int irq, void *data) 139162306a36Sopenharmony_ci{ 139262306a36Sopenharmony_ci struct cdns_i3c_master *master = data; 139362306a36Sopenharmony_ci u32 status; 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci status = readl(master->regs + MST_ISR); 139662306a36Sopenharmony_ci if (!(status & readl(master->regs + MST_IMR))) 139762306a36Sopenharmony_ci return IRQ_NONE; 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci spin_lock(&master->xferqueue.lock); 140062306a36Sopenharmony_ci cdns_i3c_master_end_xfer_locked(master, status); 140162306a36Sopenharmony_ci spin_unlock(&master->xferqueue.lock); 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci if (status & MST_INT_IBIR_THR) 140462306a36Sopenharmony_ci cnds_i3c_master_demux_ibis(master); 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci return IRQ_HANDLED; 140762306a36Sopenharmony_ci} 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_cistatic int cdns_i3c_master_disable_ibi(struct i3c_dev_desc *dev) 141062306a36Sopenharmony_ci{ 141162306a36Sopenharmony_ci struct i3c_master_controller *m = i3c_dev_get_master(dev); 141262306a36Sopenharmony_ci struct cdns_i3c_master *master = to_cdns_i3c_master(m); 141362306a36Sopenharmony_ci struct cdns_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); 141462306a36Sopenharmony_ci unsigned long flags; 141562306a36Sopenharmony_ci u32 sirmap; 141662306a36Sopenharmony_ci int ret; 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci ret = i3c_master_disec_locked(m, dev->info.dyn_addr, 141962306a36Sopenharmony_ci I3C_CCC_EVENT_SIR); 142062306a36Sopenharmony_ci if (ret) 142162306a36Sopenharmony_ci return ret; 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci spin_lock_irqsave(&master->ibi.lock, flags); 142462306a36Sopenharmony_ci sirmap = readl(master->regs + SIR_MAP_DEV_REG(data->ibi)); 142562306a36Sopenharmony_ci sirmap &= ~SIR_MAP_DEV_CONF_MASK(data->ibi); 142662306a36Sopenharmony_ci sirmap |= SIR_MAP_DEV_CONF(data->ibi, 142762306a36Sopenharmony_ci SIR_MAP_DEV_DA(I3C_BROADCAST_ADDR)); 142862306a36Sopenharmony_ci writel(sirmap, master->regs + SIR_MAP_DEV_REG(data->ibi)); 142962306a36Sopenharmony_ci spin_unlock_irqrestore(&master->ibi.lock, flags); 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci return ret; 143262306a36Sopenharmony_ci} 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_cistatic int cdns_i3c_master_enable_ibi(struct i3c_dev_desc *dev) 143562306a36Sopenharmony_ci{ 143662306a36Sopenharmony_ci struct i3c_master_controller *m = i3c_dev_get_master(dev); 143762306a36Sopenharmony_ci struct cdns_i3c_master *master = to_cdns_i3c_master(m); 143862306a36Sopenharmony_ci struct cdns_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); 143962306a36Sopenharmony_ci unsigned long flags; 144062306a36Sopenharmony_ci u32 sircfg, sirmap; 144162306a36Sopenharmony_ci int ret; 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_ci spin_lock_irqsave(&master->ibi.lock, flags); 144462306a36Sopenharmony_ci sirmap = readl(master->regs + SIR_MAP_DEV_REG(data->ibi)); 144562306a36Sopenharmony_ci sirmap &= ~SIR_MAP_DEV_CONF_MASK(data->ibi); 144662306a36Sopenharmony_ci sircfg = SIR_MAP_DEV_ROLE(dev->info.bcr >> 6) | 144762306a36Sopenharmony_ci SIR_MAP_DEV_DA(dev->info.dyn_addr) | 144862306a36Sopenharmony_ci SIR_MAP_DEV_PL(dev->info.max_ibi_len) | 144962306a36Sopenharmony_ci SIR_MAP_DEV_ACK; 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci if (dev->info.bcr & I3C_BCR_MAX_DATA_SPEED_LIM) 145262306a36Sopenharmony_ci sircfg |= SIR_MAP_DEV_SLOW; 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci sirmap |= SIR_MAP_DEV_CONF(data->ibi, sircfg); 145562306a36Sopenharmony_ci writel(sirmap, master->regs + SIR_MAP_DEV_REG(data->ibi)); 145662306a36Sopenharmony_ci spin_unlock_irqrestore(&master->ibi.lock, flags); 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci ret = i3c_master_enec_locked(m, dev->info.dyn_addr, 145962306a36Sopenharmony_ci I3C_CCC_EVENT_SIR); 146062306a36Sopenharmony_ci if (ret) { 146162306a36Sopenharmony_ci spin_lock_irqsave(&master->ibi.lock, flags); 146262306a36Sopenharmony_ci sirmap = readl(master->regs + SIR_MAP_DEV_REG(data->ibi)); 146362306a36Sopenharmony_ci sirmap &= ~SIR_MAP_DEV_CONF_MASK(data->ibi); 146462306a36Sopenharmony_ci sirmap |= SIR_MAP_DEV_CONF(data->ibi, 146562306a36Sopenharmony_ci SIR_MAP_DEV_DA(I3C_BROADCAST_ADDR)); 146662306a36Sopenharmony_ci writel(sirmap, master->regs + SIR_MAP_DEV_REG(data->ibi)); 146762306a36Sopenharmony_ci spin_unlock_irqrestore(&master->ibi.lock, flags); 146862306a36Sopenharmony_ci } 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci return ret; 147162306a36Sopenharmony_ci} 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_cistatic int cdns_i3c_master_request_ibi(struct i3c_dev_desc *dev, 147462306a36Sopenharmony_ci const struct i3c_ibi_setup *req) 147562306a36Sopenharmony_ci{ 147662306a36Sopenharmony_ci struct i3c_master_controller *m = i3c_dev_get_master(dev); 147762306a36Sopenharmony_ci struct cdns_i3c_master *master = to_cdns_i3c_master(m); 147862306a36Sopenharmony_ci struct cdns_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); 147962306a36Sopenharmony_ci unsigned long flags; 148062306a36Sopenharmony_ci unsigned int i; 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci data->ibi_pool = i3c_generic_ibi_alloc_pool(dev, req); 148362306a36Sopenharmony_ci if (IS_ERR(data->ibi_pool)) 148462306a36Sopenharmony_ci return PTR_ERR(data->ibi_pool); 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci spin_lock_irqsave(&master->ibi.lock, flags); 148762306a36Sopenharmony_ci for (i = 0; i < master->ibi.num_slots; i++) { 148862306a36Sopenharmony_ci if (!master->ibi.slots[i]) { 148962306a36Sopenharmony_ci data->ibi = i; 149062306a36Sopenharmony_ci master->ibi.slots[i] = dev; 149162306a36Sopenharmony_ci break; 149262306a36Sopenharmony_ci } 149362306a36Sopenharmony_ci } 149462306a36Sopenharmony_ci spin_unlock_irqrestore(&master->ibi.lock, flags); 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci if (i < master->ibi.num_slots) 149762306a36Sopenharmony_ci return 0; 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_ci i3c_generic_ibi_free_pool(data->ibi_pool); 150062306a36Sopenharmony_ci data->ibi_pool = NULL; 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci return -ENOSPC; 150362306a36Sopenharmony_ci} 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_cistatic void cdns_i3c_master_free_ibi(struct i3c_dev_desc *dev) 150662306a36Sopenharmony_ci{ 150762306a36Sopenharmony_ci struct i3c_master_controller *m = i3c_dev_get_master(dev); 150862306a36Sopenharmony_ci struct cdns_i3c_master *master = to_cdns_i3c_master(m); 150962306a36Sopenharmony_ci struct cdns_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); 151062306a36Sopenharmony_ci unsigned long flags; 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci spin_lock_irqsave(&master->ibi.lock, flags); 151362306a36Sopenharmony_ci master->ibi.slots[data->ibi] = NULL; 151462306a36Sopenharmony_ci data->ibi = -1; 151562306a36Sopenharmony_ci spin_unlock_irqrestore(&master->ibi.lock, flags); 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci i3c_generic_ibi_free_pool(data->ibi_pool); 151862306a36Sopenharmony_ci} 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_cistatic void cdns_i3c_master_recycle_ibi_slot(struct i3c_dev_desc *dev, 152162306a36Sopenharmony_ci struct i3c_ibi_slot *slot) 152262306a36Sopenharmony_ci{ 152362306a36Sopenharmony_ci struct cdns_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci i3c_generic_ibi_recycle_slot(data->ibi_pool, slot); 152662306a36Sopenharmony_ci} 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_cistatic const struct i3c_master_controller_ops cdns_i3c_master_ops = { 152962306a36Sopenharmony_ci .bus_init = cdns_i3c_master_bus_init, 153062306a36Sopenharmony_ci .bus_cleanup = cdns_i3c_master_bus_cleanup, 153162306a36Sopenharmony_ci .do_daa = cdns_i3c_master_do_daa, 153262306a36Sopenharmony_ci .attach_i3c_dev = cdns_i3c_master_attach_i3c_dev, 153362306a36Sopenharmony_ci .reattach_i3c_dev = cdns_i3c_master_reattach_i3c_dev, 153462306a36Sopenharmony_ci .detach_i3c_dev = cdns_i3c_master_detach_i3c_dev, 153562306a36Sopenharmony_ci .attach_i2c_dev = cdns_i3c_master_attach_i2c_dev, 153662306a36Sopenharmony_ci .detach_i2c_dev = cdns_i3c_master_detach_i2c_dev, 153762306a36Sopenharmony_ci .supports_ccc_cmd = cdns_i3c_master_supports_ccc_cmd, 153862306a36Sopenharmony_ci .send_ccc_cmd = cdns_i3c_master_send_ccc_cmd, 153962306a36Sopenharmony_ci .priv_xfers = cdns_i3c_master_priv_xfers, 154062306a36Sopenharmony_ci .i2c_xfers = cdns_i3c_master_i2c_xfers, 154162306a36Sopenharmony_ci .enable_ibi = cdns_i3c_master_enable_ibi, 154262306a36Sopenharmony_ci .disable_ibi = cdns_i3c_master_disable_ibi, 154362306a36Sopenharmony_ci .request_ibi = cdns_i3c_master_request_ibi, 154462306a36Sopenharmony_ci .free_ibi = cdns_i3c_master_free_ibi, 154562306a36Sopenharmony_ci .recycle_ibi_slot = cdns_i3c_master_recycle_ibi_slot, 154662306a36Sopenharmony_ci}; 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_cistatic void cdns_i3c_master_hj(struct work_struct *work) 154962306a36Sopenharmony_ci{ 155062306a36Sopenharmony_ci struct cdns_i3c_master *master = container_of(work, 155162306a36Sopenharmony_ci struct cdns_i3c_master, 155262306a36Sopenharmony_ci hj_work); 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_ci i3c_master_do_daa(&master->base); 155562306a36Sopenharmony_ci} 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_cistatic struct cdns_i3c_data cdns_i3c_devdata = { 155862306a36Sopenharmony_ci .thd_delay_ns = 10, 155962306a36Sopenharmony_ci}; 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_cistatic const struct of_device_id cdns_i3c_master_of_ids[] = { 156262306a36Sopenharmony_ci { .compatible = "cdns,i3c-master", .data = &cdns_i3c_devdata }, 156362306a36Sopenharmony_ci { /* sentinel */ }, 156462306a36Sopenharmony_ci}; 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_cistatic int cdns_i3c_master_probe(struct platform_device *pdev) 156762306a36Sopenharmony_ci{ 156862306a36Sopenharmony_ci struct cdns_i3c_master *master; 156962306a36Sopenharmony_ci int ret, irq; 157062306a36Sopenharmony_ci u32 val; 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL); 157362306a36Sopenharmony_ci if (!master) 157462306a36Sopenharmony_ci return -ENOMEM; 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci master->devdata = of_device_get_match_data(&pdev->dev); 157762306a36Sopenharmony_ci if (!master->devdata) 157862306a36Sopenharmony_ci return -EINVAL; 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci master->regs = devm_platform_ioremap_resource(pdev, 0); 158162306a36Sopenharmony_ci if (IS_ERR(master->regs)) 158262306a36Sopenharmony_ci return PTR_ERR(master->regs); 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci master->pclk = devm_clk_get(&pdev->dev, "pclk"); 158562306a36Sopenharmony_ci if (IS_ERR(master->pclk)) 158662306a36Sopenharmony_ci return PTR_ERR(master->pclk); 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci master->sysclk = devm_clk_get(&pdev->dev, "sysclk"); 158962306a36Sopenharmony_ci if (IS_ERR(master->sysclk)) 159062306a36Sopenharmony_ci return PTR_ERR(master->sysclk); 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci irq = platform_get_irq(pdev, 0); 159362306a36Sopenharmony_ci if (irq < 0) 159462306a36Sopenharmony_ci return irq; 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci ret = clk_prepare_enable(master->pclk); 159762306a36Sopenharmony_ci if (ret) 159862306a36Sopenharmony_ci return ret; 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_ci ret = clk_prepare_enable(master->sysclk); 160162306a36Sopenharmony_ci if (ret) 160262306a36Sopenharmony_ci goto err_disable_pclk; 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_ci if (readl(master->regs + DEV_ID) != DEV_ID_I3C_MASTER) { 160562306a36Sopenharmony_ci ret = -EINVAL; 160662306a36Sopenharmony_ci goto err_disable_sysclk; 160762306a36Sopenharmony_ci } 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci spin_lock_init(&master->xferqueue.lock); 161062306a36Sopenharmony_ci INIT_LIST_HEAD(&master->xferqueue.list); 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_ci INIT_WORK(&master->hj_work, cdns_i3c_master_hj); 161362306a36Sopenharmony_ci writel(0xffffffff, master->regs + MST_IDR); 161462306a36Sopenharmony_ci writel(0xffffffff, master->regs + SLV_IDR); 161562306a36Sopenharmony_ci ret = devm_request_irq(&pdev->dev, irq, cdns_i3c_master_interrupt, 0, 161662306a36Sopenharmony_ci dev_name(&pdev->dev), master); 161762306a36Sopenharmony_ci if (ret) 161862306a36Sopenharmony_ci goto err_disable_sysclk; 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_ci platform_set_drvdata(pdev, master); 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci val = readl(master->regs + CONF_STATUS0); 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci /* Device ID0 is reserved to describe this master. */ 162562306a36Sopenharmony_ci master->maxdevs = CONF_STATUS0_DEVS_NUM(val); 162662306a36Sopenharmony_ci master->free_rr_slots = GENMASK(master->maxdevs, 1); 162762306a36Sopenharmony_ci master->caps.ibirfifodepth = CONF_STATUS0_IBIR_DEPTH(val); 162862306a36Sopenharmony_ci master->caps.cmdrfifodepth = CONF_STATUS0_CMDR_DEPTH(val); 162962306a36Sopenharmony_ci 163062306a36Sopenharmony_ci val = readl(master->regs + CONF_STATUS1); 163162306a36Sopenharmony_ci master->caps.cmdfifodepth = CONF_STATUS1_CMD_DEPTH(val); 163262306a36Sopenharmony_ci master->caps.rxfifodepth = CONF_STATUS1_RX_DEPTH(val); 163362306a36Sopenharmony_ci master->caps.txfifodepth = CONF_STATUS1_TX_DEPTH(val); 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_ci spin_lock_init(&master->ibi.lock); 163662306a36Sopenharmony_ci master->ibi.num_slots = CONF_STATUS1_IBI_HW_RES(val); 163762306a36Sopenharmony_ci master->ibi.slots = devm_kcalloc(&pdev->dev, master->ibi.num_slots, 163862306a36Sopenharmony_ci sizeof(*master->ibi.slots), 163962306a36Sopenharmony_ci GFP_KERNEL); 164062306a36Sopenharmony_ci if (!master->ibi.slots) { 164162306a36Sopenharmony_ci ret = -ENOMEM; 164262306a36Sopenharmony_ci goto err_disable_sysclk; 164362306a36Sopenharmony_ci } 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci writel(IBIR_THR(1), master->regs + CMD_IBI_THR_CTRL); 164662306a36Sopenharmony_ci writel(MST_INT_IBIR_THR, master->regs + MST_IER); 164762306a36Sopenharmony_ci writel(DEVS_CTRL_DEV_CLR_ALL, master->regs + DEVS_CTRL); 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_ci ret = i3c_master_register(&master->base, &pdev->dev, 165062306a36Sopenharmony_ci &cdns_i3c_master_ops, false); 165162306a36Sopenharmony_ci if (ret) 165262306a36Sopenharmony_ci goto err_disable_sysclk; 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_ci return 0; 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_cierr_disable_sysclk: 165762306a36Sopenharmony_ci clk_disable_unprepare(master->sysclk); 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_cierr_disable_pclk: 166062306a36Sopenharmony_ci clk_disable_unprepare(master->pclk); 166162306a36Sopenharmony_ci 166262306a36Sopenharmony_ci return ret; 166362306a36Sopenharmony_ci} 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_cistatic void cdns_i3c_master_remove(struct platform_device *pdev) 166662306a36Sopenharmony_ci{ 166762306a36Sopenharmony_ci struct cdns_i3c_master *master = platform_get_drvdata(pdev); 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_ci i3c_master_unregister(&master->base); 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_ci clk_disable_unprepare(master->sysclk); 167262306a36Sopenharmony_ci clk_disable_unprepare(master->pclk); 167362306a36Sopenharmony_ci} 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_cistatic struct platform_driver cdns_i3c_master = { 167662306a36Sopenharmony_ci .probe = cdns_i3c_master_probe, 167762306a36Sopenharmony_ci .remove_new = cdns_i3c_master_remove, 167862306a36Sopenharmony_ci .driver = { 167962306a36Sopenharmony_ci .name = "cdns-i3c-master", 168062306a36Sopenharmony_ci .of_match_table = cdns_i3c_master_of_ids, 168162306a36Sopenharmony_ci }, 168262306a36Sopenharmony_ci}; 168362306a36Sopenharmony_cimodule_platform_driver(cdns_i3c_master); 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_ciMODULE_AUTHOR("Boris Brezillon <boris.brezillon@bootlin.com>"); 168662306a36Sopenharmony_ciMODULE_DESCRIPTION("Cadence I3C master driver"); 168762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 168862306a36Sopenharmony_ciMODULE_ALIAS("platform:cdns-i3c-master"); 1689