12f52a517SVinod Koul // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
22f52a517SVinod Koul // Copyright(c) 2015-17 Intel Corporation.
32f52a517SVinod Koul
42f52a517SVinod Koul /*
52f52a517SVinod Koul * Cadence SoundWire Master module
62f52a517SVinod Koul * Used by Master driver
72f52a517SVinod Koul */
82f52a517SVinod Koul
92f52a517SVinod Koul #include <linux/delay.h>
102f52a517SVinod Koul #include <linux/device.h>
11aa85066eSPierre-Louis Bossart #include <linux/debugfs.h>
122f52a517SVinod Koul #include <linux/interrupt.h>
1318de65d9SJan Kotas #include <linux/io.h>
142f52a517SVinod Koul #include <linux/module.h>
152f52a517SVinod Koul #include <linux/mod_devicetable.h>
1632d2a893SPierre-Louis Bossart #include <linux/pm_runtime.h>
172f52a517SVinod Koul #include <linux/soundwire/sdw_registers.h>
182f52a517SVinod Koul #include <linux/soundwire/sdw.h>
195d6b3c8bSVinod Koul #include <sound/pcm_params.h>
205d6b3c8bSVinod Koul #include <sound/soc.h>
214a98a6b2SBard Liao #include <linux/workqueue.h>
222f52a517SVinod Koul #include "bus.h"
232f52a517SVinod Koul #include "cadence_master.h"
242f52a517SVinod Koul
2504592dceSPierre-Louis Bossart static int interrupt_mask;
2604592dceSPierre-Louis Bossart module_param_named(cnds_mcp_int_mask, interrupt_mask, int, 0444);
2704592dceSPierre-Louis Bossart MODULE_PARM_DESC(cdns_mcp_int_mask, "Cadence MCP IntMask");
2804592dceSPierre-Louis Bossart
292f52a517SVinod Koul #define CDNS_MCP_CONFIG 0x0
302f52a517SVinod Koul #define CDNS_MCP_CONFIG_BUS_REL BIT(6)
31c5753714SPierre-Louis Bossart
32c5753714SPierre-Louis Bossart #define CDNS_IP_MCP_CONFIG 0x0 /* IP offset added at run-time */
33c5753714SPierre-Louis Bossart
34c5753714SPierre-Louis Bossart #define CDNS_IP_MCP_CONFIG_MCMD_RETRY GENMASK(27, 24)
35c5753714SPierre-Louis Bossart #define CDNS_IP_MCP_CONFIG_MPREQ_DELAY GENMASK(20, 16)
36c5753714SPierre-Louis Bossart #define CDNS_IP_MCP_CONFIG_MMASTER BIT(7)
37c5753714SPierre-Louis Bossart #define CDNS_IP_MCP_CONFIG_SNIFFER BIT(5)
38c5753714SPierre-Louis Bossart #define CDNS_IP_MCP_CONFIG_CMD BIT(3)
39c5753714SPierre-Louis Bossart #define CDNS_IP_MCP_CONFIG_OP GENMASK(2, 0)
40c5753714SPierre-Louis Bossart #define CDNS_IP_MCP_CONFIG_OP_NORMAL 0
412f52a517SVinod Koul
422f52a517SVinod Koul #define CDNS_MCP_CONTROL 0x4
432f52a517SVinod Koul
442f52a517SVinod Koul #define CDNS_MCP_CONTROL_CMD_RST BIT(7)
452f52a517SVinod Koul #define CDNS_MCP_CONTROL_SOFT_RST BIT(6)
462f52a517SVinod Koul #define CDNS_MCP_CONTROL_HW_RST BIT(4)
472f52a517SVinod Koul #define CDNS_MCP_CONTROL_CLK_STOP_CLR BIT(2)
484dc953bcSPierre-Louis Bossart
494dc953bcSPierre-Louis Bossart #define CDNS_IP_MCP_CONTROL 0x4 /* IP offset added at run-time */
504dc953bcSPierre-Louis Bossart
514dc953bcSPierre-Louis Bossart #define CDNS_IP_MCP_CONTROL_RST_DELAY GENMASK(10, 8)
524dc953bcSPierre-Louis Bossart #define CDNS_IP_MCP_CONTROL_SW_RST BIT(5)
534dc953bcSPierre-Louis Bossart #define CDNS_IP_MCP_CONTROL_CLK_PAUSE BIT(3)
544dc953bcSPierre-Louis Bossart #define CDNS_IP_MCP_CONTROL_CMD_ACCEPT BIT(1)
554dc953bcSPierre-Louis Bossart #define CDNS_IP_MCP_CONTROL_BLOCK_WAKEUP BIT(0)
562f52a517SVinod Koul
5773a29d3fSPierre-Louis Bossart #define CDNS_IP_MCP_CMDCTRL 0x8 /* IP offset added at run-time */
5832d2a893SPierre-Louis Bossart
5973a29d3fSPierre-Louis Bossart #define CDNS_IP_MCP_CMDCTRL_INSERT_PARITY_ERR BIT(2)
6032d2a893SPierre-Louis Bossart
612f52a517SVinod Koul #define CDNS_MCP_SSPSTAT 0xC
622f52a517SVinod Koul #define CDNS_MCP_FRAME_SHAPE 0x10
632f52a517SVinod Koul #define CDNS_MCP_FRAME_SHAPE_INIT 0x14
6405be59acSPierre-Louis Bossart #define CDNS_MCP_FRAME_SHAPE_COL_MASK GENMASK(2, 0)
653cf25d63SVinod Koul #define CDNS_MCP_FRAME_SHAPE_ROW_MASK GENMASK(7, 3)
662f52a517SVinod Koul
672f52a517SVinod Koul #define CDNS_MCP_CONFIG_UPDATE 0x18
682f52a517SVinod Koul #define CDNS_MCP_CONFIG_UPDATE_BIT BIT(0)
692f52a517SVinod Koul
702f52a517SVinod Koul #define CDNS_MCP_PHYCTRL 0x1C
712f52a517SVinod Koul #define CDNS_MCP_SSP_CTRL0 0x20
722f52a517SVinod Koul #define CDNS_MCP_SSP_CTRL1 0x28
732f52a517SVinod Koul #define CDNS_MCP_CLK_CTRL0 0x30
742f52a517SVinod Koul #define CDNS_MCP_CLK_CTRL1 0x38
75a50954e2SRander Wang #define CDNS_MCP_CLK_MCLKD_MASK GENMASK(7, 0)
762f52a517SVinod Koul
772f52a517SVinod Koul #define CDNS_MCP_STAT 0x40
782f52a517SVinod Koul
792f52a517SVinod Koul #define CDNS_MCP_STAT_ACTIVE_BANK BIT(20)
802f52a517SVinod Koul #define CDNS_MCP_STAT_CLK_STOP BIT(16)
812f52a517SVinod Koul
822f52a517SVinod Koul #define CDNS_MCP_INTSTAT 0x44
832f52a517SVinod Koul #define CDNS_MCP_INTMASK 0x48
842f52a517SVinod Koul
852f52a517SVinod Koul #define CDNS_MCP_INT_IRQ BIT(31)
86a2cff9eeSPierre-Louis Bossart #define CDNS_MCP_INT_RESERVED1 GENMASK(30, 17)
872f52a517SVinod Koul #define CDNS_MCP_INT_WAKEUP BIT(16)
882f52a517SVinod Koul #define CDNS_MCP_INT_SLAVE_RSVD BIT(15)
892f52a517SVinod Koul #define CDNS_MCP_INT_SLAVE_ALERT BIT(14)
902f52a517SVinod Koul #define CDNS_MCP_INT_SLAVE_ATTACH BIT(13)
912f52a517SVinod Koul #define CDNS_MCP_INT_SLAVE_NATTACH BIT(12)
922f52a517SVinod Koul #define CDNS_MCP_INT_SLAVE_MASK GENMASK(15, 12)
932f52a517SVinod Koul #define CDNS_MCP_INT_DPINT BIT(11)
942f52a517SVinod Koul #define CDNS_MCP_INT_CTRL_CLASH BIT(10)
952f52a517SVinod Koul #define CDNS_MCP_INT_DATA_CLASH BIT(9)
969b5884a0SPierre-Louis Bossart #define CDNS_MCP_INT_PARITY BIT(8)
972f52a517SVinod Koul #define CDNS_MCP_INT_CMD_ERR BIT(7)
98a2cff9eeSPierre-Louis Bossart #define CDNS_MCP_INT_RESERVED2 GENMASK(6, 4)
999b5884a0SPierre-Louis Bossart #define CDNS_MCP_INT_RX_NE BIT(3)
1002f52a517SVinod Koul #define CDNS_MCP_INT_RX_WL BIT(2)
1012f52a517SVinod Koul #define CDNS_MCP_INT_TXE BIT(1)
1029b5884a0SPierre-Louis Bossart #define CDNS_MCP_INT_TXF BIT(0)
103a2cff9eeSPierre-Louis Bossart #define CDNS_MCP_INT_RESERVED (CDNS_MCP_INT_RESERVED1 | CDNS_MCP_INT_RESERVED2)
1042f52a517SVinod Koul
1052f52a517SVinod Koul #define CDNS_MCP_INTSET 0x4C
1062f52a517SVinod Koul
107b07dd9b4SPierre-Louis Bossart #define CDNS_MCP_SLAVE_STAT 0x50
108b07dd9b4SPierre-Louis Bossart #define CDNS_MCP_SLAVE_STAT_MASK GENMASK(1, 0)
1092f52a517SVinod Koul
1102f52a517SVinod Koul #define CDNS_MCP_SLAVE_INTSTAT0 0x54
1112f52a517SVinod Koul #define CDNS_MCP_SLAVE_INTSTAT1 0x58
1122f52a517SVinod Koul #define CDNS_MCP_SLAVE_INTSTAT_NPRESENT BIT(0)
1132f52a517SVinod Koul #define CDNS_MCP_SLAVE_INTSTAT_ATTACHED BIT(1)
1142f52a517SVinod Koul #define CDNS_MCP_SLAVE_INTSTAT_ALERT BIT(2)
1152f52a517SVinod Koul #define CDNS_MCP_SLAVE_INTSTAT_RESERVED BIT(3)
1162f52a517SVinod Koul #define CDNS_MCP_SLAVE_STATUS_BITS GENMASK(3, 0)
1172f52a517SVinod Koul #define CDNS_MCP_SLAVE_STATUS_NUM 4
1182f52a517SVinod Koul
1192f52a517SVinod Koul #define CDNS_MCP_SLAVE_INTMASK0 0x5C
1202f52a517SVinod Koul #define CDNS_MCP_SLAVE_INTMASK1 0x60
1212f52a517SVinod Koul
122664b1658SPierre-Louis Bossart #define CDNS_MCP_SLAVE_INTMASK0_MASK GENMASK(31, 0)
123664b1658SPierre-Louis Bossart #define CDNS_MCP_SLAVE_INTMASK1_MASK GENMASK(15, 0)
1242f52a517SVinod Koul
1252f52a517SVinod Koul #define CDNS_MCP_PORT_INTSTAT 0x64
1262f52a517SVinod Koul #define CDNS_MCP_PDI_STAT 0x6C
1272f52a517SVinod Koul
1282f52a517SVinod Koul #define CDNS_MCP_FIFOLEVEL 0x78
1292f52a517SVinod Koul #define CDNS_MCP_FIFOSTAT 0x7C
1302f52a517SVinod Koul #define CDNS_MCP_RX_FIFO_AVAIL GENMASK(5, 0)
1312f52a517SVinod Koul
13283ae1ccbSPierre-Louis Bossart #define CDNS_IP_MCP_CMD_BASE 0x80 /* IP offset added at run-time */
13383ae1ccbSPierre-Louis Bossart #define CDNS_IP_MCP_RESP_BASE 0x80 /* IP offset added at run-time */
1347cbfee2eSRichard Fitzgerald /* FIFO can hold 8 commands */
1357cbfee2eSRichard Fitzgerald #define CDNS_MCP_CMD_LEN 8
1362f52a517SVinod Koul #define CDNS_MCP_CMD_WORD_LEN 0x4
1372f52a517SVinod Koul
1382f52a517SVinod Koul #define CDNS_MCP_CMD_SSP_TAG BIT(31)
1392f52a517SVinod Koul #define CDNS_MCP_CMD_COMMAND GENMASK(30, 28)
1402f52a517SVinod Koul #define CDNS_MCP_CMD_DEV_ADDR GENMASK(27, 24)
1413cf25d63SVinod Koul #define CDNS_MCP_CMD_REG_ADDR GENMASK(23, 8)
1422f52a517SVinod Koul #define CDNS_MCP_CMD_REG_DATA GENMASK(7, 0)
1432f52a517SVinod Koul
1442f52a517SVinod Koul #define CDNS_MCP_CMD_READ 2
1452f52a517SVinod Koul #define CDNS_MCP_CMD_WRITE 3
1462f52a517SVinod Koul
1472f52a517SVinod Koul #define CDNS_MCP_RESP_RDATA GENMASK(15, 8)
1482f52a517SVinod Koul #define CDNS_MCP_RESP_ACK BIT(0)
1492f52a517SVinod Koul #define CDNS_MCP_RESP_NACK BIT(1)
1502f52a517SVinod Koul
1512f52a517SVinod Koul #define CDNS_DP_SIZE 128
1522f52a517SVinod Koul
1532f52a517SVinod Koul #define CDNS_DPN_B0_CONFIG(n) (0x100 + CDNS_DP_SIZE * (n))
1542f52a517SVinod Koul #define CDNS_DPN_B0_CH_EN(n) (0x104 + CDNS_DP_SIZE * (n))
1552f52a517SVinod Koul #define CDNS_DPN_B0_SAMPLE_CTRL(n) (0x108 + CDNS_DP_SIZE * (n))
1562f52a517SVinod Koul #define CDNS_DPN_B0_OFFSET_CTRL(n) (0x10C + CDNS_DP_SIZE * (n))
1572f52a517SVinod Koul #define CDNS_DPN_B0_HCTRL(n) (0x110 + CDNS_DP_SIZE * (n))
1582f52a517SVinod Koul #define CDNS_DPN_B0_ASYNC_CTRL(n) (0x114 + CDNS_DP_SIZE * (n))
1592f52a517SVinod Koul
1602f52a517SVinod Koul #define CDNS_DPN_B1_CONFIG(n) (0x118 + CDNS_DP_SIZE * (n))
1612f52a517SVinod Koul #define CDNS_DPN_B1_CH_EN(n) (0x11C + CDNS_DP_SIZE * (n))
1622f52a517SVinod Koul #define CDNS_DPN_B1_SAMPLE_CTRL(n) (0x120 + CDNS_DP_SIZE * (n))
1632f52a517SVinod Koul #define CDNS_DPN_B1_OFFSET_CTRL(n) (0x124 + CDNS_DP_SIZE * (n))
1642f52a517SVinod Koul #define CDNS_DPN_B1_HCTRL(n) (0x128 + CDNS_DP_SIZE * (n))
1652f52a517SVinod Koul #define CDNS_DPN_B1_ASYNC_CTRL(n) (0x12C + CDNS_DP_SIZE * (n))
1662f52a517SVinod Koul
1672f52a517SVinod Koul #define CDNS_DPN_CONFIG_BPM BIT(18)
1682f52a517SVinod Koul #define CDNS_DPN_CONFIG_BGC GENMASK(17, 16)
1692f52a517SVinod Koul #define CDNS_DPN_CONFIG_WL GENMASK(12, 8)
1702f52a517SVinod Koul #define CDNS_DPN_CONFIG_PORT_DAT GENMASK(3, 2)
1712f52a517SVinod Koul #define CDNS_DPN_CONFIG_PORT_FLOW GENMASK(1, 0)
1722f52a517SVinod Koul
1732f52a517SVinod Koul #define CDNS_DPN_SAMPLE_CTRL_SI GENMASK(15, 0)
1742f52a517SVinod Koul
1752f52a517SVinod Koul #define CDNS_DPN_OFFSET_CTRL_1 GENMASK(7, 0)
1762f52a517SVinod Koul #define CDNS_DPN_OFFSET_CTRL_2 GENMASK(15, 8)
1772f52a517SVinod Koul
1782f52a517SVinod Koul #define CDNS_DPN_HCTRL_HSTOP GENMASK(3, 0)
1792f52a517SVinod Koul #define CDNS_DPN_HCTRL_HSTART GENMASK(7, 4)
1802f52a517SVinod Koul #define CDNS_DPN_HCTRL_LCTRL GENMASK(10, 8)
1812f52a517SVinod Koul
1822f52a517SVinod Koul #define CDNS_PORTCTRL 0x130
1839e4e6019SPierre-Louis Bossart #define CDNS_PORTCTRL_TEST_FAILED BIT(1)
1842f52a517SVinod Koul #define CDNS_PORTCTRL_DIRN BIT(7)
1852f52a517SVinod Koul #define CDNS_PORTCTRL_BANK_INVERT BIT(8)
1862f52a517SVinod Koul
1872f52a517SVinod Koul #define CDNS_PORT_OFFSET 0x80
1882f52a517SVinod Koul
1892f52a517SVinod Koul #define CDNS_PDI_CONFIG(n) (0x1100 + (n) * 16)
1902f52a517SVinod Koul
1912f52a517SVinod Koul #define CDNS_PDI_CONFIG_SOFT_RESET BIT(24)
1922f52a517SVinod Koul #define CDNS_PDI_CONFIG_CHANNEL GENMASK(15, 8)
1932f52a517SVinod Koul #define CDNS_PDI_CONFIG_PORT GENMASK(4, 0)
1942f52a517SVinod Koul
1952f52a517SVinod Koul /* Driver defaults */
1960cff9911SPierre-Louis Bossart #define CDNS_TX_TIMEOUT 500
1972f52a517SVinod Koul
1982f52a517SVinod Koul #define CDNS_SCP_RX_FIFOLEVEL 0x2
1992f52a517SVinod Koul
2002f52a517SVinod Koul /*
2012f52a517SVinod Koul * register accessor helpers
2022f52a517SVinod Koul */
cdns_readl(struct sdw_cdns * cdns,int offset)2032f52a517SVinod Koul static inline u32 cdns_readl(struct sdw_cdns *cdns, int offset)
2042f52a517SVinod Koul {
2052f52a517SVinod Koul return readl(cdns->registers + offset);
2062f52a517SVinod Koul }
2072f52a517SVinod Koul
cdns_writel(struct sdw_cdns * cdns,int offset,u32 value)2082f52a517SVinod Koul static inline void cdns_writel(struct sdw_cdns *cdns, int offset, u32 value)
2092f52a517SVinod Koul {
2102f52a517SVinod Koul writel(value, cdns->registers + offset);
2112f52a517SVinod Koul }
2122f52a517SVinod Koul
cdns_ip_readl(struct sdw_cdns * cdns,int offset)2139402e25dSPierre-Louis Bossart static inline u32 cdns_ip_readl(struct sdw_cdns *cdns, int offset)
2149402e25dSPierre-Louis Bossart {
2159402e25dSPierre-Louis Bossart return cdns_readl(cdns, cdns->ip_offset + offset);
2169402e25dSPierre-Louis Bossart }
2179402e25dSPierre-Louis Bossart
cdns_ip_writel(struct sdw_cdns * cdns,int offset,u32 value)2189402e25dSPierre-Louis Bossart static inline void cdns_ip_writel(struct sdw_cdns *cdns, int offset, u32 value)
2199402e25dSPierre-Louis Bossart {
2209402e25dSPierre-Louis Bossart return cdns_writel(cdns, cdns->ip_offset + offset, value);
2219402e25dSPierre-Louis Bossart }
2229402e25dSPierre-Louis Bossart
cdns_updatel(struct sdw_cdns * cdns,int offset,u32 mask,u32 val)2232f52a517SVinod Koul static inline void cdns_updatel(struct sdw_cdns *cdns,
2242f52a517SVinod Koul int offset, u32 mask, u32 val)
2252f52a517SVinod Koul {
2262f52a517SVinod Koul u32 tmp;
2272f52a517SVinod Koul
2282f52a517SVinod Koul tmp = cdns_readl(cdns, offset);
2292f52a517SVinod Koul tmp = (tmp & ~mask) | val;
2302f52a517SVinod Koul cdns_writel(cdns, offset, tmp);
2312f52a517SVinod Koul }
2322f52a517SVinod Koul
cdns_ip_updatel(struct sdw_cdns * cdns,int offset,u32 mask,u32 val)2339402e25dSPierre-Louis Bossart static inline void cdns_ip_updatel(struct sdw_cdns *cdns,
2349402e25dSPierre-Louis Bossart int offset, u32 mask, u32 val)
2359402e25dSPierre-Louis Bossart {
2369402e25dSPierre-Louis Bossart cdns_updatel(cdns, cdns->ip_offset + offset, mask, val);
2379402e25dSPierre-Louis Bossart }
2389402e25dSPierre-Louis Bossart
cdns_set_wait(struct sdw_cdns * cdns,int offset,u32 mask,u32 value)2391032504fSRander Wang static int cdns_set_wait(struct sdw_cdns *cdns, int offset, u32 mask, u32 value)
2401032504fSRander Wang {
2411032504fSRander Wang int timeout = 10;
2421032504fSRander Wang u32 reg_read;
2431032504fSRander Wang
2441032504fSRander Wang /* Wait for bit to be set */
2451032504fSRander Wang do {
2461032504fSRander Wang reg_read = readl(cdns->registers + offset);
2471032504fSRander Wang if ((reg_read & mask) == value)
2481032504fSRander Wang return 0;
2491032504fSRander Wang
2501032504fSRander Wang timeout--;
2511032504fSRander Wang usleep_range(50, 100);
2521032504fSRander Wang } while (timeout != 0);
2531032504fSRander Wang
2541032504fSRander Wang return -ETIMEDOUT;
2551032504fSRander Wang }
2561032504fSRander Wang
cdns_clear_bit(struct sdw_cdns * cdns,int offset,u32 value)25712632459SPierre-Louis Bossart static int cdns_clear_bit(struct sdw_cdns *cdns, int offset, u32 value)
25812632459SPierre-Louis Bossart {
25912632459SPierre-Louis Bossart writel(value, cdns->registers + offset);
26012632459SPierre-Louis Bossart
26112632459SPierre-Louis Bossart /* Wait for bit to be self cleared */
26212632459SPierre-Louis Bossart return cdns_set_wait(cdns, offset, value, 0);
26312632459SPierre-Louis Bossart }
26412632459SPierre-Louis Bossart
2652f52a517SVinod Koul /*
26649ea07d3SPierre-Louis Bossart * all changes to the MCP_CONFIG, MCP_CONTROL, MCP_CMDCTRL and MCP_PHYCTRL
26749ea07d3SPierre-Louis Bossart * need to be confirmed with a write to MCP_CONFIG_UPDATE
26849ea07d3SPierre-Louis Bossart */
cdns_config_update(struct sdw_cdns * cdns)269ce1acf01SPierre-Louis Bossart static int cdns_config_update(struct sdw_cdns *cdns)
27049ea07d3SPierre-Louis Bossart {
27149ea07d3SPierre-Louis Bossart int ret;
27249ea07d3SPierre-Louis Bossart
2739bc87cceSPierre-Louis Bossart if (sdw_cdns_is_clock_stop(cdns)) {
2749bc87cceSPierre-Louis Bossart dev_err(cdns->dev, "Cannot program MCP_CONFIG_UPDATE in ClockStopMode\n");
2759bc87cceSPierre-Louis Bossart return -EINVAL;
2769bc87cceSPierre-Louis Bossart }
2779bc87cceSPierre-Louis Bossart
27849ea07d3SPierre-Louis Bossart ret = cdns_clear_bit(cdns, CDNS_MCP_CONFIG_UPDATE,
27949ea07d3SPierre-Louis Bossart CDNS_MCP_CONFIG_UPDATE_BIT);
28049ea07d3SPierre-Louis Bossart if (ret < 0)
28149ea07d3SPierre-Louis Bossart dev_err(cdns->dev, "Config update timedout\n");
28249ea07d3SPierre-Louis Bossart
28349ea07d3SPierre-Louis Bossart return ret;
28449ea07d3SPierre-Louis Bossart }
28549ea07d3SPierre-Louis Bossart
286ffc363d9SPierre-Louis Bossart /**
287ffc363d9SPierre-Louis Bossart * sdw_cdns_config_update() - Update configurations
288ffc363d9SPierre-Louis Bossart * @cdns: Cadence instance
289ffc363d9SPierre-Louis Bossart */
sdw_cdns_config_update(struct sdw_cdns * cdns)290ffc363d9SPierre-Louis Bossart void sdw_cdns_config_update(struct sdw_cdns *cdns)
291ffc363d9SPierre-Louis Bossart {
292ffc363d9SPierre-Louis Bossart /* commit changes */
293ffc363d9SPierre-Louis Bossart cdns_writel(cdns, CDNS_MCP_CONFIG_UPDATE, CDNS_MCP_CONFIG_UPDATE_BIT);
294ffc363d9SPierre-Louis Bossart }
295ffc363d9SPierre-Louis Bossart EXPORT_SYMBOL(sdw_cdns_config_update);
296ffc363d9SPierre-Louis Bossart
297ffc363d9SPierre-Louis Bossart /**
298ffc363d9SPierre-Louis Bossart * sdw_cdns_config_update_set_wait() - wait until configuration update bit is self-cleared
299ffc363d9SPierre-Louis Bossart * @cdns: Cadence instance
300ffc363d9SPierre-Louis Bossart */
sdw_cdns_config_update_set_wait(struct sdw_cdns * cdns)301ffc363d9SPierre-Louis Bossart int sdw_cdns_config_update_set_wait(struct sdw_cdns *cdns)
302ffc363d9SPierre-Louis Bossart {
303ffc363d9SPierre-Louis Bossart /* the hardware recommendation is to wait at least 300us */
304ffc363d9SPierre-Louis Bossart return cdns_set_wait(cdns, CDNS_MCP_CONFIG_UPDATE,
305ffc363d9SPierre-Louis Bossart CDNS_MCP_CONFIG_UPDATE_BIT, 0);
306ffc363d9SPierre-Louis Bossart }
307ffc363d9SPierre-Louis Bossart EXPORT_SYMBOL(sdw_cdns_config_update_set_wait);
308ffc363d9SPierre-Louis Bossart
30949ea07d3SPierre-Louis Bossart /*
310aa85066eSPierre-Louis Bossart * debugfs
311aa85066eSPierre-Louis Bossart */
312aa85066eSPierre-Louis Bossart #ifdef CONFIG_DEBUG_FS
313aa85066eSPierre-Louis Bossart
314aa85066eSPierre-Louis Bossart #define RD_BUF (2 * PAGE_SIZE)
315aa85066eSPierre-Louis Bossart
cdns_sprintf(struct sdw_cdns * cdns,char * buf,size_t pos,unsigned int reg)316aa85066eSPierre-Louis Bossart static ssize_t cdns_sprintf(struct sdw_cdns *cdns,
317aa85066eSPierre-Louis Bossart char *buf, size_t pos, unsigned int reg)
318aa85066eSPierre-Louis Bossart {
319aa85066eSPierre-Louis Bossart return scnprintf(buf + pos, RD_BUF - pos,
320aa85066eSPierre-Louis Bossart "%4x\t%8x\n", reg, cdns_readl(cdns, reg));
321aa85066eSPierre-Louis Bossart }
322aa85066eSPierre-Louis Bossart
cdns_reg_show(struct seq_file * s,void * data)323aa85066eSPierre-Louis Bossart static int cdns_reg_show(struct seq_file *s, void *data)
324aa85066eSPierre-Louis Bossart {
325aa85066eSPierre-Louis Bossart struct sdw_cdns *cdns = s->private;
326aa85066eSPierre-Louis Bossart char *buf;
327aa85066eSPierre-Louis Bossart ssize_t ret;
328aa85066eSPierre-Louis Bossart int num_ports;
329aa85066eSPierre-Louis Bossart int i, j;
330aa85066eSPierre-Louis Bossart
331aa85066eSPierre-Louis Bossart buf = kzalloc(RD_BUF, GFP_KERNEL);
332aa85066eSPierre-Louis Bossart if (!buf)
333aa85066eSPierre-Louis Bossart return -ENOMEM;
334aa85066eSPierre-Louis Bossart
335aa85066eSPierre-Louis Bossart ret = scnprintf(buf, RD_BUF, "Register Value\n");
336aa85066eSPierre-Louis Bossart ret += scnprintf(buf + ret, RD_BUF - ret, "\nMCP Registers\n");
337aa85066eSPierre-Louis Bossart /* 8 MCP registers */
338aa85066eSPierre-Louis Bossart for (i = CDNS_MCP_CONFIG; i <= CDNS_MCP_PHYCTRL; i += sizeof(u32))
339aa85066eSPierre-Louis Bossart ret += cdns_sprintf(cdns, buf, ret, i);
340aa85066eSPierre-Louis Bossart
341aa85066eSPierre-Louis Bossart ret += scnprintf(buf + ret, RD_BUF - ret,
342aa85066eSPierre-Louis Bossart "\nStatus & Intr Registers\n");
343aa85066eSPierre-Louis Bossart /* 13 Status & Intr registers (offsets 0x70 and 0x74 not defined) */
344aa85066eSPierre-Louis Bossart for (i = CDNS_MCP_STAT; i <= CDNS_MCP_FIFOSTAT; i += sizeof(u32))
345aa85066eSPierre-Louis Bossart ret += cdns_sprintf(cdns, buf, ret, i);
346aa85066eSPierre-Louis Bossart
347aa85066eSPierre-Louis Bossart ret += scnprintf(buf + ret, RD_BUF - ret,
348aa85066eSPierre-Louis Bossart "\nSSP & Clk ctrl Registers\n");
349aa85066eSPierre-Louis Bossart ret += cdns_sprintf(cdns, buf, ret, CDNS_MCP_SSP_CTRL0);
350aa85066eSPierre-Louis Bossart ret += cdns_sprintf(cdns, buf, ret, CDNS_MCP_SSP_CTRL1);
351aa85066eSPierre-Louis Bossart ret += cdns_sprintf(cdns, buf, ret, CDNS_MCP_CLK_CTRL0);
352aa85066eSPierre-Louis Bossart ret += cdns_sprintf(cdns, buf, ret, CDNS_MCP_CLK_CTRL1);
353aa85066eSPierre-Louis Bossart
354aa85066eSPierre-Louis Bossart ret += scnprintf(buf + ret, RD_BUF - ret,
355aa85066eSPierre-Louis Bossart "\nDPn B0 Registers\n");
356aa85066eSPierre-Louis Bossart
357807c15bcSPierre-Louis Bossart num_ports = cdns->num_ports;
358aa85066eSPierre-Louis Bossart
359aa85066eSPierre-Louis Bossart for (i = 0; i < num_ports; i++) {
360aa85066eSPierre-Louis Bossart ret += scnprintf(buf + ret, RD_BUF - ret,
361aa85066eSPierre-Louis Bossart "\nDP-%d\n", i);
362aa85066eSPierre-Louis Bossart for (j = CDNS_DPN_B0_CONFIG(i);
363aa85066eSPierre-Louis Bossart j < CDNS_DPN_B0_ASYNC_CTRL(i); j += sizeof(u32))
364aa85066eSPierre-Louis Bossart ret += cdns_sprintf(cdns, buf, ret, j);
365aa85066eSPierre-Louis Bossart }
366aa85066eSPierre-Louis Bossart
367aa85066eSPierre-Louis Bossart ret += scnprintf(buf + ret, RD_BUF - ret,
368aa85066eSPierre-Louis Bossart "\nDPn B1 Registers\n");
369aa85066eSPierre-Louis Bossart for (i = 0; i < num_ports; i++) {
370aa85066eSPierre-Louis Bossart ret += scnprintf(buf + ret, RD_BUF - ret,
371aa85066eSPierre-Louis Bossart "\nDP-%d\n", i);
372aa85066eSPierre-Louis Bossart
373aa85066eSPierre-Louis Bossart for (j = CDNS_DPN_B1_CONFIG(i);
374aa85066eSPierre-Louis Bossart j < CDNS_DPN_B1_ASYNC_CTRL(i); j += sizeof(u32))
375aa85066eSPierre-Louis Bossart ret += cdns_sprintf(cdns, buf, ret, j);
376aa85066eSPierre-Louis Bossart }
377aa85066eSPierre-Louis Bossart
378aa85066eSPierre-Louis Bossart ret += scnprintf(buf + ret, RD_BUF - ret,
379aa85066eSPierre-Louis Bossart "\nDPn Control Registers\n");
380aa85066eSPierre-Louis Bossart for (i = 0; i < num_ports; i++)
381aa85066eSPierre-Louis Bossart ret += cdns_sprintf(cdns, buf, ret,
382aa85066eSPierre-Louis Bossart CDNS_PORTCTRL + i * CDNS_PORT_OFFSET);
383aa85066eSPierre-Louis Bossart
384aa85066eSPierre-Louis Bossart ret += scnprintf(buf + ret, RD_BUF - ret,
385aa85066eSPierre-Louis Bossart "\nPDIn Config Registers\n");
386aa85066eSPierre-Louis Bossart
387aa85066eSPierre-Louis Bossart /* number of PDI and ports is interchangeable */
388aa85066eSPierre-Louis Bossart for (i = 0; i < num_ports; i++)
389aa85066eSPierre-Louis Bossart ret += cdns_sprintf(cdns, buf, ret, CDNS_PDI_CONFIG(i));
390aa85066eSPierre-Louis Bossart
391aa85066eSPierre-Louis Bossart seq_printf(s, "%s", buf);
392aa85066eSPierre-Louis Bossart kfree(buf);
393aa85066eSPierre-Louis Bossart
394aa85066eSPierre-Louis Bossart return 0;
395aa85066eSPierre-Louis Bossart }
396aa85066eSPierre-Louis Bossart DEFINE_SHOW_ATTRIBUTE(cdns_reg);
397aa85066eSPierre-Louis Bossart
cdns_hw_reset(void * data,u64 value)398675d4c9aSPierre-Louis Bossart static int cdns_hw_reset(void *data, u64 value)
399675d4c9aSPierre-Louis Bossart {
400675d4c9aSPierre-Louis Bossart struct sdw_cdns *cdns = data;
401675d4c9aSPierre-Louis Bossart int ret;
402675d4c9aSPierre-Louis Bossart
403675d4c9aSPierre-Louis Bossart if (value != 1)
404675d4c9aSPierre-Louis Bossart return -EINVAL;
405675d4c9aSPierre-Louis Bossart
406675d4c9aSPierre-Louis Bossart /* Userspace changed the hardware state behind the kernel's back */
407675d4c9aSPierre-Louis Bossart add_taint(TAINT_USER, LOCKDEP_STILL_OK);
408675d4c9aSPierre-Louis Bossart
409675d4c9aSPierre-Louis Bossart ret = sdw_cdns_exit_reset(cdns);
410675d4c9aSPierre-Louis Bossart
411675d4c9aSPierre-Louis Bossart dev_dbg(cdns->dev, "link hw_reset done: %d\n", ret);
412675d4c9aSPierre-Louis Bossart
413675d4c9aSPierre-Louis Bossart return ret;
414675d4c9aSPierre-Louis Bossart }
415675d4c9aSPierre-Louis Bossart
416675d4c9aSPierre-Louis Bossart DEFINE_DEBUGFS_ATTRIBUTE(cdns_hw_reset_fops, NULL, cdns_hw_reset, "%llu\n");
417675d4c9aSPierre-Louis Bossart
cdns_parity_error_injection(void * data,u64 value)41832d2a893SPierre-Louis Bossart static int cdns_parity_error_injection(void *data, u64 value)
41932d2a893SPierre-Louis Bossart {
42032d2a893SPierre-Louis Bossart struct sdw_cdns *cdns = data;
42132d2a893SPierre-Louis Bossart struct sdw_bus *bus;
42232d2a893SPierre-Louis Bossart int ret;
42332d2a893SPierre-Louis Bossart
42432d2a893SPierre-Louis Bossart if (value != 1)
42532d2a893SPierre-Louis Bossart return -EINVAL;
42632d2a893SPierre-Louis Bossart
42732d2a893SPierre-Louis Bossart bus = &cdns->bus;
42832d2a893SPierre-Louis Bossart
42932d2a893SPierre-Louis Bossart /*
43032d2a893SPierre-Louis Bossart * Resume Master device. If this results in a bus reset, the
43132d2a893SPierre-Louis Bossart * Slave devices will re-attach and be re-enumerated.
43232d2a893SPierre-Louis Bossart */
433915bf27aSPierre-Louis Bossart ret = pm_runtime_resume_and_get(bus->dev);
43432d2a893SPierre-Louis Bossart if (ret < 0 && ret != -EACCES) {
43532d2a893SPierre-Louis Bossart dev_err_ratelimited(cdns->dev,
436915bf27aSPierre-Louis Bossart "pm_runtime_resume_and_get failed in %s, ret %d\n",
43732d2a893SPierre-Louis Bossart __func__, ret);
43832d2a893SPierre-Louis Bossart return ret;
43932d2a893SPierre-Louis Bossart }
44032d2a893SPierre-Louis Bossart
44132d2a893SPierre-Louis Bossart /*
44232d2a893SPierre-Louis Bossart * wait long enough for Slave(s) to be in steady state. This
44332d2a893SPierre-Louis Bossart * does not need to be super precise.
44432d2a893SPierre-Louis Bossart */
44532d2a893SPierre-Louis Bossart msleep(200);
44632d2a893SPierre-Louis Bossart
44732d2a893SPierre-Louis Bossart /*
44832d2a893SPierre-Louis Bossart * Take the bus lock here to make sure that any bus transactions
44932d2a893SPierre-Louis Bossart * will be queued while we inject a parity error on a dummy read
45032d2a893SPierre-Louis Bossart */
45132d2a893SPierre-Louis Bossart mutex_lock(&bus->bus_lock);
45232d2a893SPierre-Louis Bossart
45332d2a893SPierre-Louis Bossart /* program hardware to inject parity error */
45473a29d3fSPierre-Louis Bossart cdns_ip_updatel(cdns, CDNS_IP_MCP_CMDCTRL,
45573a29d3fSPierre-Louis Bossart CDNS_IP_MCP_CMDCTRL_INSERT_PARITY_ERR,
45673a29d3fSPierre-Louis Bossart CDNS_IP_MCP_CMDCTRL_INSERT_PARITY_ERR);
45732d2a893SPierre-Louis Bossart
45832d2a893SPierre-Louis Bossart /* commit changes */
45994f89950SPierre-Louis Bossart ret = cdns_clear_bit(cdns, CDNS_MCP_CONFIG_UPDATE, CDNS_MCP_CONFIG_UPDATE_BIT);
46094f89950SPierre-Louis Bossart if (ret < 0)
46194f89950SPierre-Louis Bossart goto unlock;
46232d2a893SPierre-Louis Bossart
46332d2a893SPierre-Louis Bossart /* do a broadcast dummy read to avoid bus clashes */
46432d2a893SPierre-Louis Bossart ret = sdw_bread_no_pm_unlocked(&cdns->bus, 0xf, SDW_SCP_DEVID_0);
46532d2a893SPierre-Louis Bossart dev_info(cdns->dev, "parity error injection, read: %d\n", ret);
46632d2a893SPierre-Louis Bossart
46732d2a893SPierre-Louis Bossart /* program hardware to disable parity error */
46873a29d3fSPierre-Louis Bossart cdns_ip_updatel(cdns, CDNS_IP_MCP_CMDCTRL,
46973a29d3fSPierre-Louis Bossart CDNS_IP_MCP_CMDCTRL_INSERT_PARITY_ERR,
47032d2a893SPierre-Louis Bossart 0);
47132d2a893SPierre-Louis Bossart
47232d2a893SPierre-Louis Bossart /* commit changes */
47394f89950SPierre-Louis Bossart ret = cdns_clear_bit(cdns, CDNS_MCP_CONFIG_UPDATE, CDNS_MCP_CONFIG_UPDATE_BIT);
47494f89950SPierre-Louis Bossart if (ret < 0)
47594f89950SPierre-Louis Bossart goto unlock;
47632d2a893SPierre-Louis Bossart
47732d2a893SPierre-Louis Bossart /* Userspace changed the hardware state behind the kernel's back */
47832d2a893SPierre-Louis Bossart add_taint(TAINT_USER, LOCKDEP_STILL_OK);
47932d2a893SPierre-Louis Bossart
48094f89950SPierre-Louis Bossart unlock:
48194f89950SPierre-Louis Bossart /* Continue bus operation with parity error injection disabled */
48294f89950SPierre-Louis Bossart mutex_unlock(&bus->bus_lock);
48394f89950SPierre-Louis Bossart
48432d2a893SPierre-Louis Bossart /*
48532d2a893SPierre-Louis Bossart * allow Master device to enter pm_runtime suspend. This may
48632d2a893SPierre-Louis Bossart * also result in Slave devices suspending.
48732d2a893SPierre-Louis Bossart */
48832d2a893SPierre-Louis Bossart pm_runtime_mark_last_busy(bus->dev);
48932d2a893SPierre-Louis Bossart pm_runtime_put_autosuspend(bus->dev);
49032d2a893SPierre-Louis Bossart
49132d2a893SPierre-Louis Bossart return 0;
49232d2a893SPierre-Louis Bossart }
49332d2a893SPierre-Louis Bossart
49432d2a893SPierre-Louis Bossart DEFINE_DEBUGFS_ATTRIBUTE(cdns_parity_error_fops, NULL,
49532d2a893SPierre-Louis Bossart cdns_parity_error_injection, "%llu\n");
49632d2a893SPierre-Louis Bossart
cdns_set_pdi_loopback_source(void * data,u64 value)4978fba8acdSPierre-Louis Bossart static int cdns_set_pdi_loopback_source(void *data, u64 value)
4988fba8acdSPierre-Louis Bossart {
4998fba8acdSPierre-Louis Bossart struct sdw_cdns *cdns = data;
5008fba8acdSPierre-Louis Bossart unsigned int pdi_out_num = cdns->pcm.num_bd + cdns->pcm.num_out;
5018fba8acdSPierre-Louis Bossart
5028fba8acdSPierre-Louis Bossart if (value > pdi_out_num)
5038fba8acdSPierre-Louis Bossart return -EINVAL;
5048fba8acdSPierre-Louis Bossart
5058fba8acdSPierre-Louis Bossart /* Userspace changed the hardware state behind the kernel's back */
5068fba8acdSPierre-Louis Bossart add_taint(TAINT_USER, LOCKDEP_STILL_OK);
5078fba8acdSPierre-Louis Bossart
5088fba8acdSPierre-Louis Bossart cdns->pdi_loopback_source = value;
5098fba8acdSPierre-Louis Bossart
5108fba8acdSPierre-Louis Bossart return 0;
5118fba8acdSPierre-Louis Bossart }
5128fba8acdSPierre-Louis Bossart DEFINE_DEBUGFS_ATTRIBUTE(cdns_pdi_loopback_source_fops, NULL, cdns_set_pdi_loopback_source, "%llu\n");
5138fba8acdSPierre-Louis Bossart
cdns_set_pdi_loopback_target(void * data,u64 value)5148fba8acdSPierre-Louis Bossart static int cdns_set_pdi_loopback_target(void *data, u64 value)
5158fba8acdSPierre-Louis Bossart {
5168fba8acdSPierre-Louis Bossart struct sdw_cdns *cdns = data;
5178fba8acdSPierre-Louis Bossart unsigned int pdi_in_num = cdns->pcm.num_bd + cdns->pcm.num_in;
5188fba8acdSPierre-Louis Bossart
5198fba8acdSPierre-Louis Bossart if (value > pdi_in_num)
5208fba8acdSPierre-Louis Bossart return -EINVAL;
5218fba8acdSPierre-Louis Bossart
5228fba8acdSPierre-Louis Bossart /* Userspace changed the hardware state behind the kernel's back */
5238fba8acdSPierre-Louis Bossart add_taint(TAINT_USER, LOCKDEP_STILL_OK);
5248fba8acdSPierre-Louis Bossart
5258fba8acdSPierre-Louis Bossart cdns->pdi_loopback_target = value;
5268fba8acdSPierre-Louis Bossart
5278fba8acdSPierre-Louis Bossart return 0;
5288fba8acdSPierre-Louis Bossart }
5298fba8acdSPierre-Louis Bossart DEFINE_DEBUGFS_ATTRIBUTE(cdns_pdi_loopback_target_fops, NULL, cdns_set_pdi_loopback_target, "%llu\n");
5308fba8acdSPierre-Louis Bossart
531aa85066eSPierre-Louis Bossart /**
532aa85066eSPierre-Louis Bossart * sdw_cdns_debugfs_init() - Cadence debugfs init
533aa85066eSPierre-Louis Bossart * @cdns: Cadence instance
534aa85066eSPierre-Louis Bossart * @root: debugfs root
535aa85066eSPierre-Louis Bossart */
sdw_cdns_debugfs_init(struct sdw_cdns * cdns,struct dentry * root)536aa85066eSPierre-Louis Bossart void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root)
537aa85066eSPierre-Louis Bossart {
538aa85066eSPierre-Louis Bossart debugfs_create_file("cdns-registers", 0400, root, cdns, &cdns_reg_fops);
539675d4c9aSPierre-Louis Bossart
540675d4c9aSPierre-Louis Bossart debugfs_create_file("cdns-hw-reset", 0200, root, cdns,
541675d4c9aSPierre-Louis Bossart &cdns_hw_reset_fops);
54232d2a893SPierre-Louis Bossart
54332d2a893SPierre-Louis Bossart debugfs_create_file("cdns-parity-error-injection", 0200, root, cdns,
54432d2a893SPierre-Louis Bossart &cdns_parity_error_fops);
5458fba8acdSPierre-Louis Bossart
5468fba8acdSPierre-Louis Bossart cdns->pdi_loopback_source = -1;
5478fba8acdSPierre-Louis Bossart cdns->pdi_loopback_target = -1;
5488fba8acdSPierre-Louis Bossart
5498fba8acdSPierre-Louis Bossart debugfs_create_file("cdns-pdi-loopback-source", 0200, root, cdns,
5508fba8acdSPierre-Louis Bossart &cdns_pdi_loopback_source_fops);
5518fba8acdSPierre-Louis Bossart
5528fba8acdSPierre-Louis Bossart debugfs_create_file("cdns-pdi-loopback-target", 0200, root, cdns,
5538fba8acdSPierre-Louis Bossart &cdns_pdi_loopback_target_fops);
5548fba8acdSPierre-Louis Bossart
555aa85066eSPierre-Louis Bossart }
556aa85066eSPierre-Louis Bossart EXPORT_SYMBOL_GPL(sdw_cdns_debugfs_init);
557aa85066eSPierre-Louis Bossart
558aa85066eSPierre-Louis Bossart #endif /* CONFIG_DEBUG_FS */
559aa85066eSPierre-Louis Bossart
560aa85066eSPierre-Louis Bossart /*
561956baa19SSanyog Kale * IO Calls
562956baa19SSanyog Kale */
563bbb63817SPierre-Louis Bossart static enum sdw_command_response
cdns_fill_msg_resp(struct sdw_cdns * cdns,struct sdw_msg * msg,int count,int offset)564bbb63817SPierre-Louis Bossart cdns_fill_msg_resp(struct sdw_cdns *cdns,
565956baa19SSanyog Kale struct sdw_msg *msg, int count, int offset)
566956baa19SSanyog Kale {
567956baa19SSanyog Kale int nack = 0, no_ack = 0;
568956baa19SSanyog Kale int i;
569956baa19SSanyog Kale
570956baa19SSanyog Kale /* check message response */
571956baa19SSanyog Kale for (i = 0; i < count; i++) {
572956baa19SSanyog Kale if (!(cdns->response_buf[i] & CDNS_MCP_RESP_ACK)) {
573956baa19SSanyog Kale no_ack = 1;
5749a0c798cSPierre-Louis Bossart dev_vdbg(cdns->dev, "Msg Ack not received, cmd %d\n", i);
575db9d9f94SPierre-Louis Bossart }
576956baa19SSanyog Kale if (cdns->response_buf[i] & CDNS_MCP_RESP_NACK) {
577956baa19SSanyog Kale nack = 1;
5789a0c798cSPierre-Louis Bossart dev_err_ratelimited(cdns->dev, "Msg NACK received, cmd %d\n", i);
579956baa19SSanyog Kale }
580956baa19SSanyog Kale }
581956baa19SSanyog Kale
582956baa19SSanyog Kale if (nack) {
583eb7df4c8SPierre-Louis Bossart dev_err_ratelimited(cdns->dev, "Msg NACKed for Slave %d\n", msg->dev_num);
584956baa19SSanyog Kale return SDW_CMD_FAIL;
5856f7219feSGuennadi Liakhovetski }
5866f7219feSGuennadi Liakhovetski
5876f7219feSGuennadi Liakhovetski if (no_ack) {
588eb7df4c8SPierre-Louis Bossart dev_dbg_ratelimited(cdns->dev, "Msg ignored for Slave %d\n", msg->dev_num);
589956baa19SSanyog Kale return SDW_CMD_IGNORED;
590956baa19SSanyog Kale }
591956baa19SSanyog Kale
592ba05b39dSRichard Fitzgerald if (msg->flags == SDW_MSG_FLAG_READ) {
593956baa19SSanyog Kale /* fill response */
594956baa19SSanyog Kale for (i = 0; i < count; i++)
595ba05b39dSRichard Fitzgerald msg->buf[i + offset] = FIELD_GET(CDNS_MCP_RESP_RDATA,
596ba05b39dSRichard Fitzgerald cdns->response_buf[i]);
597ba05b39dSRichard Fitzgerald }
598956baa19SSanyog Kale
599956baa19SSanyog Kale return SDW_CMD_OK;
600956baa19SSanyog Kale }
601956baa19SSanyog Kale
cdns_read_response(struct sdw_cdns * cdns)6020603a47bSRichard Fitzgerald static void cdns_read_response(struct sdw_cdns *cdns)
6030603a47bSRichard Fitzgerald {
6040603a47bSRichard Fitzgerald u32 num_resp, cmd_base;
6050603a47bSRichard Fitzgerald int i;
6060603a47bSRichard Fitzgerald
6070603a47bSRichard Fitzgerald /* RX_FIFO_AVAIL can be 2 entries more than the FIFO size */
6080603a47bSRichard Fitzgerald BUILD_BUG_ON(ARRAY_SIZE(cdns->response_buf) < CDNS_MCP_CMD_LEN + 2);
6090603a47bSRichard Fitzgerald
6100603a47bSRichard Fitzgerald num_resp = cdns_readl(cdns, CDNS_MCP_FIFOSTAT);
6110603a47bSRichard Fitzgerald num_resp &= CDNS_MCP_RX_FIFO_AVAIL;
6120603a47bSRichard Fitzgerald if (num_resp > ARRAY_SIZE(cdns->response_buf)) {
6130603a47bSRichard Fitzgerald dev_warn(cdns->dev, "RX AVAIL %d too long\n", num_resp);
6140603a47bSRichard Fitzgerald num_resp = ARRAY_SIZE(cdns->response_buf);
6150603a47bSRichard Fitzgerald }
6160603a47bSRichard Fitzgerald
61783ae1ccbSPierre-Louis Bossart cmd_base = CDNS_IP_MCP_CMD_BASE;
6180603a47bSRichard Fitzgerald
6190603a47bSRichard Fitzgerald for (i = 0; i < num_resp; i++) {
62083ae1ccbSPierre-Louis Bossart cdns->response_buf[i] = cdns_ip_readl(cdns, cmd_base);
6210603a47bSRichard Fitzgerald cmd_base += CDNS_MCP_CMD_WORD_LEN;
6220603a47bSRichard Fitzgerald }
6230603a47bSRichard Fitzgerald }
6240603a47bSRichard Fitzgerald
625956baa19SSanyog Kale static enum sdw_command_response
_cdns_xfer_msg(struct sdw_cdns * cdns,struct sdw_msg * msg,int cmd,int offset,int count,bool defer)626956baa19SSanyog Kale _cdns_xfer_msg(struct sdw_cdns *cdns, struct sdw_msg *msg, int cmd,
627956baa19SSanyog Kale int offset, int count, bool defer)
628956baa19SSanyog Kale {
629956baa19SSanyog Kale unsigned long time;
630956baa19SSanyog Kale u32 base, i, data;
631956baa19SSanyog Kale u16 addr;
632956baa19SSanyog Kale
633956baa19SSanyog Kale /* Program the watermark level for RX FIFO */
634956baa19SSanyog Kale if (cdns->msg_count != count) {
635956baa19SSanyog Kale cdns_writel(cdns, CDNS_MCP_FIFOLEVEL, count);
636956baa19SSanyog Kale cdns->msg_count = count;
637956baa19SSanyog Kale }
638956baa19SSanyog Kale
63983ae1ccbSPierre-Louis Bossart base = CDNS_IP_MCP_CMD_BASE;
6403ed96fb4SRichard Fitzgerald addr = msg->addr + offset;
641956baa19SSanyog Kale
642956baa19SSanyog Kale for (i = 0; i < count; i++) {
6433cf25d63SVinod Koul data = FIELD_PREP(CDNS_MCP_CMD_DEV_ADDR, msg->dev_num);
6443cf25d63SVinod Koul data |= FIELD_PREP(CDNS_MCP_CMD_COMMAND, cmd);
6453cf25d63SVinod Koul data |= FIELD_PREP(CDNS_MCP_CMD_REG_ADDR, addr);
6463cf25d63SVinod Koul addr++;
647956baa19SSanyog Kale
648956baa19SSanyog Kale if (msg->flags == SDW_MSG_FLAG_WRITE)
649956baa19SSanyog Kale data |= msg->buf[i + offset];
650956baa19SSanyog Kale
6513cf25d63SVinod Koul data |= FIELD_PREP(CDNS_MCP_CMD_SSP_TAG, msg->ssp_sync);
65283ae1ccbSPierre-Louis Bossart cdns_ip_writel(cdns, base, data);
653956baa19SSanyog Kale base += CDNS_MCP_CMD_WORD_LEN;
654956baa19SSanyog Kale }
655956baa19SSanyog Kale
656956baa19SSanyog Kale if (defer)
657956baa19SSanyog Kale return SDW_CMD_OK;
658956baa19SSanyog Kale
659956baa19SSanyog Kale /* wait for timeout or response */
660956baa19SSanyog Kale time = wait_for_completion_timeout(&cdns->tx_complete,
661956baa19SSanyog Kale msecs_to_jiffies(CDNS_TX_TIMEOUT));
662956baa19SSanyog Kale if (!time) {
66353ee9572SPierre-Louis Bossart dev_err(cdns->dev, "IO transfer timed out, cmd %d device %d addr %x len %d\n",
66453ee9572SPierre-Louis Bossart cmd, msg->dev_num, msg->addr, msg->len);
665956baa19SSanyog Kale msg->len = 0;
6660603a47bSRichard Fitzgerald
6670603a47bSRichard Fitzgerald /* Drain anything in the RX_FIFO */
6680603a47bSRichard Fitzgerald cdns_read_response(cdns);
6690603a47bSRichard Fitzgerald
670956baa19SSanyog Kale return SDW_CMD_TIMEOUT;
671956baa19SSanyog Kale }
672956baa19SSanyog Kale
673956baa19SSanyog Kale return cdns_fill_msg_resp(cdns, msg, count, offset);
674956baa19SSanyog Kale }
675956baa19SSanyog Kale
676bbb63817SPierre-Louis Bossart static enum sdw_command_response
cdns_program_scp_addr(struct sdw_cdns * cdns,struct sdw_msg * msg)677bbb63817SPierre-Louis Bossart cdns_program_scp_addr(struct sdw_cdns *cdns, struct sdw_msg *msg)
678956baa19SSanyog Kale {
679956baa19SSanyog Kale int nack = 0, no_ack = 0;
680956baa19SSanyog Kale unsigned long time;
681956baa19SSanyog Kale u32 data[2], base;
682956baa19SSanyog Kale int i;
683956baa19SSanyog Kale
684956baa19SSanyog Kale /* Program the watermark level for RX FIFO */
685956baa19SSanyog Kale if (cdns->msg_count != CDNS_SCP_RX_FIFOLEVEL) {
686956baa19SSanyog Kale cdns_writel(cdns, CDNS_MCP_FIFOLEVEL, CDNS_SCP_RX_FIFOLEVEL);
687956baa19SSanyog Kale cdns->msg_count = CDNS_SCP_RX_FIFOLEVEL;
688956baa19SSanyog Kale }
689956baa19SSanyog Kale
6903cf25d63SVinod Koul data[0] = FIELD_PREP(CDNS_MCP_CMD_DEV_ADDR, msg->dev_num);
6913cf25d63SVinod Koul data[0] |= FIELD_PREP(CDNS_MCP_CMD_COMMAND, 0x3);
692956baa19SSanyog Kale data[1] = data[0];
693956baa19SSanyog Kale
6943cf25d63SVinod Koul data[0] |= FIELD_PREP(CDNS_MCP_CMD_REG_ADDR, SDW_SCP_ADDRPAGE1);
6953cf25d63SVinod Koul data[1] |= FIELD_PREP(CDNS_MCP_CMD_REG_ADDR, SDW_SCP_ADDRPAGE2);
696956baa19SSanyog Kale
697956baa19SSanyog Kale data[0] |= msg->addr_page1;
698956baa19SSanyog Kale data[1] |= msg->addr_page2;
699956baa19SSanyog Kale
70083ae1ccbSPierre-Louis Bossart base = CDNS_IP_MCP_CMD_BASE;
70183ae1ccbSPierre-Louis Bossart cdns_ip_writel(cdns, base, data[0]);
702956baa19SSanyog Kale base += CDNS_MCP_CMD_WORD_LEN;
70383ae1ccbSPierre-Louis Bossart cdns_ip_writel(cdns, base, data[1]);
704956baa19SSanyog Kale
705956baa19SSanyog Kale time = wait_for_completion_timeout(&cdns->tx_complete,
706956baa19SSanyog Kale msecs_to_jiffies(CDNS_TX_TIMEOUT));
707956baa19SSanyog Kale if (!time) {
708956baa19SSanyog Kale dev_err(cdns->dev, "SCP Msg trf timed out\n");
709956baa19SSanyog Kale msg->len = 0;
710956baa19SSanyog Kale return SDW_CMD_TIMEOUT;
711956baa19SSanyog Kale }
712956baa19SSanyog Kale
713956baa19SSanyog Kale /* check response the writes */
714956baa19SSanyog Kale for (i = 0; i < 2; i++) {
715956baa19SSanyog Kale if (!(cdns->response_buf[i] & CDNS_MCP_RESP_ACK)) {
716956baa19SSanyog Kale no_ack = 1;
71717ed5befSPierre-Louis Bossart dev_err(cdns->dev, "Program SCP Ack not received\n");
718956baa19SSanyog Kale if (cdns->response_buf[i] & CDNS_MCP_RESP_NACK) {
719956baa19SSanyog Kale nack = 1;
72017ed5befSPierre-Louis Bossart dev_err(cdns->dev, "Program SCP NACK received\n");
721956baa19SSanyog Kale }
722956baa19SSanyog Kale }
723956baa19SSanyog Kale }
724956baa19SSanyog Kale
725956baa19SSanyog Kale /* For NACK, NO ack, don't return err if we are in Broadcast mode */
726956baa19SSanyog Kale if (nack) {
727eb7df4c8SPierre-Louis Bossart dev_err_ratelimited(cdns->dev,
72817ed5befSPierre-Louis Bossart "SCP_addrpage NACKed for Slave %d\n", msg->dev_num);
729956baa19SSanyog Kale return SDW_CMD_FAIL;
7306f7219feSGuennadi Liakhovetski }
7316f7219feSGuennadi Liakhovetski
7326f7219feSGuennadi Liakhovetski if (no_ack) {
733eb7df4c8SPierre-Louis Bossart dev_dbg_ratelimited(cdns->dev,
73417ed5befSPierre-Louis Bossart "SCP_addrpage ignored for Slave %d\n", msg->dev_num);
735956baa19SSanyog Kale return SDW_CMD_IGNORED;
736956baa19SSanyog Kale }
737956baa19SSanyog Kale
738956baa19SSanyog Kale return SDW_CMD_OK;
739956baa19SSanyog Kale }
740956baa19SSanyog Kale
cdns_prep_msg(struct sdw_cdns * cdns,struct sdw_msg * msg,int * cmd)741956baa19SSanyog Kale static int cdns_prep_msg(struct sdw_cdns *cdns, struct sdw_msg *msg, int *cmd)
742956baa19SSanyog Kale {
743956baa19SSanyog Kale int ret;
744956baa19SSanyog Kale
745956baa19SSanyog Kale if (msg->page) {
746956baa19SSanyog Kale ret = cdns_program_scp_addr(cdns, msg);
747956baa19SSanyog Kale if (ret) {
748956baa19SSanyog Kale msg->len = 0;
749956baa19SSanyog Kale return ret;
750956baa19SSanyog Kale }
751956baa19SSanyog Kale }
752956baa19SSanyog Kale
753956baa19SSanyog Kale switch (msg->flags) {
754956baa19SSanyog Kale case SDW_MSG_FLAG_READ:
755956baa19SSanyog Kale *cmd = CDNS_MCP_CMD_READ;
756956baa19SSanyog Kale break;
757956baa19SSanyog Kale
758956baa19SSanyog Kale case SDW_MSG_FLAG_WRITE:
759956baa19SSanyog Kale *cmd = CDNS_MCP_CMD_WRITE;
760956baa19SSanyog Kale break;
761956baa19SSanyog Kale
762956baa19SSanyog Kale default:
763956baa19SSanyog Kale dev_err(cdns->dev, "Invalid msg cmd: %d\n", msg->flags);
764956baa19SSanyog Kale return -EINVAL;
765956baa19SSanyog Kale }
766956baa19SSanyog Kale
767956baa19SSanyog Kale return 0;
768956baa19SSanyog Kale }
769956baa19SSanyog Kale
770c91605f4SShreyas NC enum sdw_command_response
cdns_xfer_msg(struct sdw_bus * bus,struct sdw_msg * msg)771956baa19SSanyog Kale cdns_xfer_msg(struct sdw_bus *bus, struct sdw_msg *msg)
772956baa19SSanyog Kale {
773956baa19SSanyog Kale struct sdw_cdns *cdns = bus_to_cdns(bus);
774956baa19SSanyog Kale int cmd = 0, ret, i;
775956baa19SSanyog Kale
776956baa19SSanyog Kale ret = cdns_prep_msg(cdns, msg, &cmd);
777956baa19SSanyog Kale if (ret)
778956baa19SSanyog Kale return SDW_CMD_FAIL_OTHER;
779956baa19SSanyog Kale
780956baa19SSanyog Kale for (i = 0; i < msg->len / CDNS_MCP_CMD_LEN; i++) {
781956baa19SSanyog Kale ret = _cdns_xfer_msg(cdns, msg, cmd, i * CDNS_MCP_CMD_LEN,
782956baa19SSanyog Kale CDNS_MCP_CMD_LEN, false);
7837f6bad4dSRichard Fitzgerald if (ret != SDW_CMD_OK)
784bafb1eacSRichard Fitzgerald return ret;
785956baa19SSanyog Kale }
786956baa19SSanyog Kale
787956baa19SSanyog Kale if (!(msg->len % CDNS_MCP_CMD_LEN))
788bafb1eacSRichard Fitzgerald return SDW_CMD_OK;
789956baa19SSanyog Kale
790bafb1eacSRichard Fitzgerald return _cdns_xfer_msg(cdns, msg, cmd, i * CDNS_MCP_CMD_LEN,
791956baa19SSanyog Kale msg->len % CDNS_MCP_CMD_LEN, false);
792956baa19SSanyog Kale }
793c91605f4SShreyas NC EXPORT_SYMBOL(cdns_xfer_msg);
794956baa19SSanyog Kale
795c91605f4SShreyas NC enum sdw_command_response
cdns_xfer_msg_defer(struct sdw_bus * bus)79666f95de7SPierre-Louis Bossart cdns_xfer_msg_defer(struct sdw_bus *bus)
797956baa19SSanyog Kale {
798956baa19SSanyog Kale struct sdw_cdns *cdns = bus_to_cdns(bus);
79966f95de7SPierre-Louis Bossart struct sdw_defer *defer = &bus->defer_msg;
80066f95de7SPierre-Louis Bossart struct sdw_msg *msg = defer->msg;
801956baa19SSanyog Kale int cmd = 0, ret;
802956baa19SSanyog Kale
803956baa19SSanyog Kale /* for defer only 1 message is supported */
804956baa19SSanyog Kale if (msg->len > 1)
805956baa19SSanyog Kale return -ENOTSUPP;
806956baa19SSanyog Kale
807956baa19SSanyog Kale ret = cdns_prep_msg(cdns, msg, &cmd);
808956baa19SSanyog Kale if (ret)
809956baa19SSanyog Kale return SDW_CMD_FAIL_OTHER;
810956baa19SSanyog Kale
811956baa19SSanyog Kale return _cdns_xfer_msg(cdns, msg, cmd, 0, msg->len, true);
812956baa19SSanyog Kale }
813c91605f4SShreyas NC EXPORT_SYMBOL(cdns_xfer_msg_defer);
814956baa19SSanyog Kale
cdns_read_ping_status(struct sdw_bus * bus)815133547a1SPierre-Louis Bossart u32 cdns_read_ping_status(struct sdw_bus *bus)
816133547a1SPierre-Louis Bossart {
817133547a1SPierre-Louis Bossart struct sdw_cdns *cdns = bus_to_cdns(bus);
818133547a1SPierre-Louis Bossart
819133547a1SPierre-Louis Bossart return cdns_readl(cdns, CDNS_MCP_SLAVE_STAT);
820133547a1SPierre-Louis Bossart }
821133547a1SPierre-Louis Bossart EXPORT_SYMBOL(cdns_read_ping_status);
822133547a1SPierre-Louis Bossart
823956baa19SSanyog Kale /*
8242f52a517SVinod Koul * IRQ handling
8252f52a517SVinod Koul */
8262f52a517SVinod Koul
cdns_update_slave_status(struct sdw_cdns * cdns,u64 slave_intstat)8272f52a517SVinod Koul static int cdns_update_slave_status(struct sdw_cdns *cdns,
8286f206833SPierre-Louis Bossart u64 slave_intstat)
8292f52a517SVinod Koul {
8302f52a517SVinod Koul enum sdw_slave_status status[SDW_MAX_DEVICES + 1];
8312f52a517SVinod Koul bool is_slave = false;
832a78b32d9SPierre-Louis Bossart u32 mask;
833fbbc73a2SSimon Trimmer u32 val;
8342f52a517SVinod Koul int i, set_status;
8352f52a517SVinod Koul
8362f52a517SVinod Koul memset(status, 0, sizeof(status));
8372f52a517SVinod Koul
8382f52a517SVinod Koul for (i = 0; i <= SDW_MAX_DEVICES; i++) {
8396f206833SPierre-Louis Bossart mask = (slave_intstat >> (i * CDNS_MCP_SLAVE_STATUS_NUM)) &
8402f52a517SVinod Koul CDNS_MCP_SLAVE_STATUS_BITS;
8412f52a517SVinod Koul
8422f52a517SVinod Koul set_status = 0;
8432f52a517SVinod Koul
844fbbc73a2SSimon Trimmer if (mask) {
845fbbc73a2SSimon Trimmer is_slave = true;
846fbbc73a2SSimon Trimmer
8472f52a517SVinod Koul if (mask & CDNS_MCP_SLAVE_INTSTAT_RESERVED) {
8482f52a517SVinod Koul status[i] = SDW_SLAVE_RESERVED;
8492f52a517SVinod Koul set_status++;
8502f52a517SVinod Koul }
8512f52a517SVinod Koul
8522f52a517SVinod Koul if (mask & CDNS_MCP_SLAVE_INTSTAT_ATTACHED) {
8532f52a517SVinod Koul status[i] = SDW_SLAVE_ATTACHED;
8542f52a517SVinod Koul set_status++;
8552f52a517SVinod Koul }
8562f52a517SVinod Koul
8572f52a517SVinod Koul if (mask & CDNS_MCP_SLAVE_INTSTAT_ALERT) {
8582f52a517SVinod Koul status[i] = SDW_SLAVE_ALERT;
8592f52a517SVinod Koul set_status++;
8602f52a517SVinod Koul }
8612f52a517SVinod Koul
8622f52a517SVinod Koul if (mask & CDNS_MCP_SLAVE_INTSTAT_NPRESENT) {
8632f52a517SVinod Koul status[i] = SDW_SLAVE_UNATTACHED;
8642f52a517SVinod Koul set_status++;
8652f52a517SVinod Koul }
866fbbc73a2SSimon Trimmer }
8672f52a517SVinod Koul
868fbbc73a2SSimon Trimmer /*
869fbbc73a2SSimon Trimmer * check that there was a single reported Slave status and when
870fbbc73a2SSimon Trimmer * there is not use the latest status extracted from PING commands
871fbbc73a2SSimon Trimmer */
872fbbc73a2SSimon Trimmer if (set_status != 1) {
8737181b1d4SPierre-Louis Bossart val = cdns_readl(cdns, CDNS_MCP_SLAVE_STAT);
8747181b1d4SPierre-Louis Bossart val >>= (i * 2);
8757181b1d4SPierre-Louis Bossart
8767181b1d4SPierre-Louis Bossart switch (val & 0x3) {
8777181b1d4SPierre-Louis Bossart case 0:
8787181b1d4SPierre-Louis Bossart status[i] = SDW_SLAVE_UNATTACHED;
8797181b1d4SPierre-Louis Bossart break;
8807181b1d4SPierre-Louis Bossart case 1:
8817181b1d4SPierre-Louis Bossart status[i] = SDW_SLAVE_ATTACHED;
8827181b1d4SPierre-Louis Bossart break;
8837181b1d4SPierre-Louis Bossart case 2:
8847181b1d4SPierre-Louis Bossart status[i] = SDW_SLAVE_ALERT;
8857181b1d4SPierre-Louis Bossart break;
8867181b1d4SPierre-Louis Bossart case 3:
8877181b1d4SPierre-Louis Bossart default:
8887181b1d4SPierre-Louis Bossart status[i] = SDW_SLAVE_RESERVED;
8897181b1d4SPierre-Louis Bossart break;
8907181b1d4SPierre-Louis Bossart }
8912f52a517SVinod Koul }
8922f52a517SVinod Koul }
8932f52a517SVinod Koul
894*740a6059SPierre-Louis Bossart if (is_slave) {
895*740a6059SPierre-Louis Bossart int ret;
896*740a6059SPierre-Louis Bossart
897*740a6059SPierre-Louis Bossart mutex_lock(&cdns->status_update_lock);
898*740a6059SPierre-Louis Bossart ret = sdw_handle_slave_status(&cdns->bus, status);
899*740a6059SPierre-Louis Bossart mutex_unlock(&cdns->status_update_lock);
900*740a6059SPierre-Louis Bossart return ret;
901*740a6059SPierre-Louis Bossart }
9022f52a517SVinod Koul
9032f52a517SVinod Koul return 0;
9042f52a517SVinod Koul }
9052f52a517SVinod Koul
9062f52a517SVinod Koul /**
9072f52a517SVinod Koul * sdw_cdns_irq() - Cadence interrupt handler
9082f52a517SVinod Koul * @irq: irq number
9092f52a517SVinod Koul * @dev_id: irq context
9102f52a517SVinod Koul */
sdw_cdns_irq(int irq,void * dev_id)9112f52a517SVinod Koul irqreturn_t sdw_cdns_irq(int irq, void *dev_id)
9122f52a517SVinod Koul {
9132f52a517SVinod Koul struct sdw_cdns *cdns = dev_id;
9142f52a517SVinod Koul u32 int_status;
9152f52a517SVinod Koul
9162f52a517SVinod Koul /* Check if the link is up */
9172f52a517SVinod Koul if (!cdns->link_up)
9182f52a517SVinod Koul return IRQ_NONE;
9192f52a517SVinod Koul
9202f52a517SVinod Koul int_status = cdns_readl(cdns, CDNS_MCP_INTSTAT);
9212f52a517SVinod Koul
922a2cff9eeSPierre-Louis Bossart /* check for reserved values read as zero */
923a2cff9eeSPierre-Louis Bossart if (int_status & CDNS_MCP_INT_RESERVED)
924a2cff9eeSPierre-Louis Bossart return IRQ_NONE;
925a2cff9eeSPierre-Louis Bossart
9262f52a517SVinod Koul if (!(int_status & CDNS_MCP_INT_IRQ))
9272f52a517SVinod Koul return IRQ_NONE;
9282f52a517SVinod Koul
929956baa19SSanyog Kale if (int_status & CDNS_MCP_INT_RX_WL) {
930dd0b9619SPierre-Louis Bossart struct sdw_bus *bus = &cdns->bus;
931dd0b9619SPierre-Louis Bossart struct sdw_defer *defer = &bus->defer_msg;
932dd0b9619SPierre-Louis Bossart
933956baa19SSanyog Kale cdns_read_response(cdns);
934956baa19SSanyog Kale
935dd0b9619SPierre-Louis Bossart if (defer && defer->msg) {
936dd0b9619SPierre-Louis Bossart cdns_fill_msg_resp(cdns, defer->msg,
937dd0b9619SPierre-Louis Bossart defer->length, 0);
938dd0b9619SPierre-Louis Bossart complete(&defer->complete);
939f6e20967SPierre-Louis Bossart } else {
940956baa19SSanyog Kale complete(&cdns->tx_complete);
941956baa19SSanyog Kale }
942f6e20967SPierre-Louis Bossart }
943956baa19SSanyog Kale
9449b5884a0SPierre-Louis Bossart if (int_status & CDNS_MCP_INT_PARITY) {
9459b5884a0SPierre-Louis Bossart /* Parity error detected by Master */
9469b5884a0SPierre-Louis Bossart dev_err_ratelimited(cdns->dev, "Parity error\n");
9479b5884a0SPierre-Louis Bossart }
9489b5884a0SPierre-Louis Bossart
9492f52a517SVinod Koul if (int_status & CDNS_MCP_INT_CTRL_CLASH) {
9502f52a517SVinod Koul /* Slave is driving bit slot during control word */
9512f52a517SVinod Koul dev_err_ratelimited(cdns->dev, "Bus clash for control word\n");
9522f52a517SVinod Koul }
9532f52a517SVinod Koul
9542f52a517SVinod Koul if (int_status & CDNS_MCP_INT_DATA_CLASH) {
9552f52a517SVinod Koul /*
9562f52a517SVinod Koul * Multiple slaves trying to drive bit slot, or issue with
9572f52a517SVinod Koul * ownership of data bits or Slave gone bonkers
9582f52a517SVinod Koul */
9592f52a517SVinod Koul dev_err_ratelimited(cdns->dev, "Bus clash for data word\n");
9602f52a517SVinod Koul }
9612f52a517SVinod Koul
9629e4e6019SPierre-Louis Bossart if (cdns->bus.params.m_data_mode != SDW_PORT_DATA_MODE_NORMAL &&
9639e4e6019SPierre-Louis Bossart int_status & CDNS_MCP_INT_DPINT) {
9649e4e6019SPierre-Louis Bossart u32 port_intstat;
9659e4e6019SPierre-Louis Bossart
9669e4e6019SPierre-Louis Bossart /* just log which ports report an error */
9679e4e6019SPierre-Louis Bossart port_intstat = cdns_readl(cdns, CDNS_MCP_PORT_INTSTAT);
9689e4e6019SPierre-Louis Bossart dev_err_ratelimited(cdns->dev, "DP interrupt: PortIntStat %8x\n",
9699e4e6019SPierre-Louis Bossart port_intstat);
9709e4e6019SPierre-Louis Bossart
9719e4e6019SPierre-Louis Bossart /* clear status w/ write1 */
9729e4e6019SPierre-Louis Bossart cdns_writel(cdns, CDNS_MCP_PORT_INTSTAT, port_intstat);
9739e4e6019SPierre-Louis Bossart }
9749e4e6019SPierre-Louis Bossart
9752f52a517SVinod Koul if (int_status & CDNS_MCP_INT_SLAVE_MASK) {
9762f52a517SVinod Koul /* Mask the Slave interrupt and wake thread */
9772f52a517SVinod Koul cdns_updatel(cdns, CDNS_MCP_INTMASK,
9782f52a517SVinod Koul CDNS_MCP_INT_SLAVE_MASK, 0);
9792f52a517SVinod Koul
9802f52a517SVinod Koul int_status &= ~CDNS_MCP_INT_SLAVE_MASK;
981d2068da5SPierre-Louis Bossart
982d2068da5SPierre-Louis Bossart /*
983d2068da5SPierre-Louis Bossart * Deal with possible race condition between interrupt
984d2068da5SPierre-Louis Bossart * handling and disabling interrupts on suspend.
985d2068da5SPierre-Louis Bossart *
986d2068da5SPierre-Louis Bossart * If the master is in the process of disabling
987d2068da5SPierre-Louis Bossart * interrupts, don't schedule a workqueue
988d2068da5SPierre-Louis Bossart */
989d2068da5SPierre-Louis Bossart if (cdns->interrupt_enabled)
9904a98a6b2SBard Liao schedule_work(&cdns->work);
9912f52a517SVinod Koul }
9922f52a517SVinod Koul
9932f52a517SVinod Koul cdns_writel(cdns, CDNS_MCP_INTSTAT, int_status);
99400d3c2b3SPeter Ujfalusi return IRQ_HANDLED;
9952f52a517SVinod Koul }
9962f52a517SVinod Koul EXPORT_SYMBOL(sdw_cdns_irq);
9972f52a517SVinod Koul
cdns_check_attached_status_dwork(struct work_struct * work)998*740a6059SPierre-Louis Bossart static void cdns_check_attached_status_dwork(struct work_struct *work)
999*740a6059SPierre-Louis Bossart {
1000*740a6059SPierre-Louis Bossart struct sdw_cdns *cdns =
1001*740a6059SPierre-Louis Bossart container_of(work, struct sdw_cdns, attach_dwork.work);
1002*740a6059SPierre-Louis Bossart enum sdw_slave_status status[SDW_MAX_DEVICES + 1];
1003*740a6059SPierre-Louis Bossart u32 val;
1004*740a6059SPierre-Louis Bossart int ret;
1005*740a6059SPierre-Louis Bossart int i;
1006*740a6059SPierre-Louis Bossart
1007*740a6059SPierre-Louis Bossart val = cdns_readl(cdns, CDNS_MCP_SLAVE_STAT);
1008*740a6059SPierre-Louis Bossart
1009*740a6059SPierre-Louis Bossart for (i = 0; i <= SDW_MAX_DEVICES; i++) {
1010*740a6059SPierre-Louis Bossart status[i] = val & 0x3;
1011*740a6059SPierre-Louis Bossart if (status[i])
1012*740a6059SPierre-Louis Bossart dev_dbg(cdns->dev, "Peripheral %d status: %d\n", i, status[i]);
1013*740a6059SPierre-Louis Bossart val >>= 2;
1014*740a6059SPierre-Louis Bossart }
1015*740a6059SPierre-Louis Bossart
1016*740a6059SPierre-Louis Bossart mutex_lock(&cdns->status_update_lock);
1017*740a6059SPierre-Louis Bossart ret = sdw_handle_slave_status(&cdns->bus, status);
1018*740a6059SPierre-Louis Bossart mutex_unlock(&cdns->status_update_lock);
1019*740a6059SPierre-Louis Bossart if (ret < 0)
1020*740a6059SPierre-Louis Bossart dev_err(cdns->dev, "%s: sdw_handle_slave_status failed: %d\n", __func__, ret);
1021*740a6059SPierre-Louis Bossart }
1022*740a6059SPierre-Louis Bossart
10232f52a517SVinod Koul /**
1024b76f3fbaSPierre-Louis Bossart * cdns_update_slave_status_work - update slave status in a work since we will need to handle
10254a98a6b2SBard Liao * other interrupts eg. CDNS_MCP_INT_RX_WL during the update slave
10264a98a6b2SBard Liao * process.
10274a98a6b2SBard Liao * @work: cdns worker thread
10282f52a517SVinod Koul */
cdns_update_slave_status_work(struct work_struct * work)10294a98a6b2SBard Liao static void cdns_update_slave_status_work(struct work_struct *work)
10302f52a517SVinod Koul {
10314a98a6b2SBard Liao struct sdw_cdns *cdns =
10324a98a6b2SBard Liao container_of(work, struct sdw_cdns, work);
10332f52a517SVinod Koul u32 slave0, slave1;
10346f206833SPierre-Louis Bossart u64 slave_intstat;
10353db50a99SPierre-Louis Bossart u32 device0_status;
10363db50a99SPierre-Louis Bossart int retry_count = 0;
10372f52a517SVinod Koul
10380c5e99c4SRichard Fitzgerald /*
10390c5e99c4SRichard Fitzgerald * Clear main interrupt first so we don't lose any assertions
10400c5e99c4SRichard Fitzgerald * that happen during this function.
10410c5e99c4SRichard Fitzgerald */
10420c5e99c4SRichard Fitzgerald cdns_writel(cdns, CDNS_MCP_INTSTAT, CDNS_MCP_INT_SLAVE_MASK);
10430c5e99c4SRichard Fitzgerald
10442f52a517SVinod Koul slave0 = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT0);
10452f52a517SVinod Koul slave1 = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT1);
10462f52a517SVinod Koul
10470c5e99c4SRichard Fitzgerald /*
10480c5e99c4SRichard Fitzgerald * Clear the bits before handling so we don't lose any
10490c5e99c4SRichard Fitzgerald * bits that re-assert.
10500c5e99c4SRichard Fitzgerald */
10510c5e99c4SRichard Fitzgerald cdns_writel(cdns, CDNS_MCP_SLAVE_INTSTAT0, slave0);
10520c5e99c4SRichard Fitzgerald cdns_writel(cdns, CDNS_MCP_SLAVE_INTSTAT1, slave1);
10530c5e99c4SRichard Fitzgerald
10546f206833SPierre-Louis Bossart /* combine the two status */
10556f206833SPierre-Louis Bossart slave_intstat = ((u64)slave1 << 32) | slave0;
10566f206833SPierre-Louis Bossart
10576f206833SPierre-Louis Bossart dev_dbg_ratelimited(cdns->dev, "Slave status change: 0x%llx\n", slave_intstat);
10586f206833SPierre-Louis Bossart
10593db50a99SPierre-Louis Bossart update_status:
10606f206833SPierre-Louis Bossart cdns_update_slave_status(cdns, slave_intstat);
10612f52a517SVinod Koul
10623db50a99SPierre-Louis Bossart /*
10633db50a99SPierre-Louis Bossart * When there is more than one peripheral per link, it's
10643db50a99SPierre-Louis Bossart * possible that a deviceB becomes attached after we deal with
10653db50a99SPierre-Louis Bossart * the attachment of deviceA. Since the hardware does a
10663db50a99SPierre-Louis Bossart * logical AND, the attachment of the second device does not
10673db50a99SPierre-Louis Bossart * change the status seen by the driver.
10683db50a99SPierre-Louis Bossart *
10693db50a99SPierre-Louis Bossart * In that case, clearing the registers above would result in
10703db50a99SPierre-Louis Bossart * the deviceB never being detected - until a change of status
10713db50a99SPierre-Louis Bossart * is observed on the bus.
10723db50a99SPierre-Louis Bossart *
10733db50a99SPierre-Louis Bossart * To avoid this race condition, re-check if any device0 needs
10743db50a99SPierre-Louis Bossart * attention with PING commands. There is no need to check for
10753db50a99SPierre-Louis Bossart * ALERTS since they are not allowed until a non-zero
10763db50a99SPierre-Louis Bossart * device_number is assigned.
10770c5e99c4SRichard Fitzgerald *
10780c5e99c4SRichard Fitzgerald * Do not clear the INTSTAT0/1. While looping to enumerate devices on
10790c5e99c4SRichard Fitzgerald * #0 there could be status changes on other devices - these must
10800c5e99c4SRichard Fitzgerald * be kept in the INTSTAT so they can be handled when all #0 devices
10810c5e99c4SRichard Fitzgerald * have been handled.
10823db50a99SPierre-Louis Bossart */
10833db50a99SPierre-Louis Bossart
10843db50a99SPierre-Louis Bossart device0_status = cdns_readl(cdns, CDNS_MCP_SLAVE_STAT);
10853db50a99SPierre-Louis Bossart device0_status &= 3;
10863db50a99SPierre-Louis Bossart
10873db50a99SPierre-Louis Bossart if (device0_status == SDW_SLAVE_ATTACHED) {
10883db50a99SPierre-Louis Bossart if (retry_count++ < SDW_MAX_DEVICES) {
10893db50a99SPierre-Louis Bossart dev_dbg_ratelimited(cdns->dev,
10903db50a99SPierre-Louis Bossart "Device0 detected after clearing status, iteration %d\n",
10913db50a99SPierre-Louis Bossart retry_count);
10923db50a99SPierre-Louis Bossart slave_intstat = CDNS_MCP_SLAVE_INTSTAT_ATTACHED;
10933db50a99SPierre-Louis Bossart goto update_status;
10943db50a99SPierre-Louis Bossart } else {
10953db50a99SPierre-Louis Bossart dev_err_ratelimited(cdns->dev,
10963db50a99SPierre-Louis Bossart "Device0 detected after %d iterations\n",
10973db50a99SPierre-Louis Bossart retry_count);
10983db50a99SPierre-Louis Bossart }
10993db50a99SPierre-Louis Bossart }
11003db50a99SPierre-Louis Bossart
11010c5e99c4SRichard Fitzgerald /* unmask Slave interrupt now */
11022f52a517SVinod Koul cdns_updatel(cdns, CDNS_MCP_INTMASK,
11032f52a517SVinod Koul CDNS_MCP_INT_SLAVE_MASK, CDNS_MCP_INT_SLAVE_MASK);
11042f52a517SVinod Koul
11052f52a517SVinod Koul }
11062f52a517SVinod Koul
1107ff560946SPierre-Louis Bossart /* paranoia check to make sure self-cleared bits are indeed cleared */
sdw_cdns_check_self_clearing_bits(struct sdw_cdns * cdns,const char * string,bool initial_delay,int reset_iterations)1108ff560946SPierre-Louis Bossart void sdw_cdns_check_self_clearing_bits(struct sdw_cdns *cdns, const char *string,
1109ff560946SPierre-Louis Bossart bool initial_delay, int reset_iterations)
1110ff560946SPierre-Louis Bossart {
11114dc953bcSPierre-Louis Bossart u32 ip_mcp_control;
1112ff560946SPierre-Louis Bossart u32 mcp_control;
1113ff560946SPierre-Louis Bossart u32 mcp_config_update;
1114ff560946SPierre-Louis Bossart int i;
1115ff560946SPierre-Louis Bossart
1116ff560946SPierre-Louis Bossart if (initial_delay)
1117ff560946SPierre-Louis Bossart usleep_range(1000, 1500);
1118ff560946SPierre-Louis Bossart
11194dc953bcSPierre-Louis Bossart ip_mcp_control = cdns_ip_readl(cdns, CDNS_IP_MCP_CONTROL);
11204dc953bcSPierre-Louis Bossart
11214dc953bcSPierre-Louis Bossart /* the following bits should be cleared immediately */
11224dc953bcSPierre-Louis Bossart if (ip_mcp_control & CDNS_IP_MCP_CONTROL_SW_RST)
11234dc953bcSPierre-Louis Bossart dev_err(cdns->dev, "%s failed: IP_MCP_CONTROL_SW_RST is not cleared\n", string);
11244dc953bcSPierre-Louis Bossart
1125ff560946SPierre-Louis Bossart mcp_control = cdns_readl(cdns, CDNS_MCP_CONTROL);
1126ff560946SPierre-Louis Bossart
1127ff560946SPierre-Louis Bossart /* the following bits should be cleared immediately */
1128ff560946SPierre-Louis Bossart if (mcp_control & CDNS_MCP_CONTROL_CMD_RST)
1129ff560946SPierre-Louis Bossart dev_err(cdns->dev, "%s failed: MCP_CONTROL_CMD_RST is not cleared\n", string);
1130ff560946SPierre-Louis Bossart if (mcp_control & CDNS_MCP_CONTROL_SOFT_RST)
1131ff560946SPierre-Louis Bossart dev_err(cdns->dev, "%s failed: MCP_CONTROL_SOFT_RST is not cleared\n", string);
1132ff560946SPierre-Louis Bossart if (mcp_control & CDNS_MCP_CONTROL_CLK_STOP_CLR)
1133ff560946SPierre-Louis Bossart dev_err(cdns->dev, "%s failed: MCP_CONTROL_CLK_STOP_CLR is not cleared\n", string);
11344dc953bcSPierre-Louis Bossart
1135ff560946SPierre-Louis Bossart mcp_config_update = cdns_readl(cdns, CDNS_MCP_CONFIG_UPDATE);
1136ff560946SPierre-Louis Bossart if (mcp_config_update & CDNS_MCP_CONFIG_UPDATE_BIT)
1137ff560946SPierre-Louis Bossart dev_err(cdns->dev, "%s failed: MCP_CONFIG_UPDATE_BIT is not cleared\n", string);
1138ff560946SPierre-Louis Bossart
1139ff560946SPierre-Louis Bossart i = 0;
1140ff560946SPierre-Louis Bossart while (mcp_control & CDNS_MCP_CONTROL_HW_RST) {
1141ff560946SPierre-Louis Bossart if (i == reset_iterations) {
1142ff560946SPierre-Louis Bossart dev_err(cdns->dev, "%s failed: MCP_CONTROL_HW_RST is not cleared\n", string);
1143ff560946SPierre-Louis Bossart break;
1144ff560946SPierre-Louis Bossart }
1145ff560946SPierre-Louis Bossart
1146ff560946SPierre-Louis Bossart dev_dbg(cdns->dev, "%s: MCP_CONTROL_HW_RST is not cleared at iteration %d\n", string, i);
1147ff560946SPierre-Louis Bossart i++;
1148ff560946SPierre-Louis Bossart
1149ff560946SPierre-Louis Bossart usleep_range(1000, 1500);
1150ff560946SPierre-Louis Bossart mcp_control = cdns_readl(cdns, CDNS_MCP_CONTROL);
1151ff560946SPierre-Louis Bossart }
1152ff560946SPierre-Louis Bossart
1153ff560946SPierre-Louis Bossart }
1154ff560946SPierre-Louis Bossart EXPORT_SYMBOL(sdw_cdns_check_self_clearing_bits);
1155ff560946SPierre-Louis Bossart
11562f52a517SVinod Koul /*
11572f52a517SVinod Koul * init routines
11582f52a517SVinod Koul */
115949ea07d3SPierre-Louis Bossart
116049ea07d3SPierre-Louis Bossart /**
116149ea07d3SPierre-Louis Bossart * sdw_cdns_exit_reset() - Program reset parameters and start bus operations
116249ea07d3SPierre-Louis Bossart * @cdns: Cadence instance
116349ea07d3SPierre-Louis Bossart */
sdw_cdns_exit_reset(struct sdw_cdns * cdns)116449ea07d3SPierre-Louis Bossart int sdw_cdns_exit_reset(struct sdw_cdns *cdns)
116549ea07d3SPierre-Louis Bossart {
11662564a2d4SPierre-Louis Bossart /* keep reset delay unchanged to 4096 cycles */
116749ea07d3SPierre-Louis Bossart
116849ea07d3SPierre-Louis Bossart /* use hardware generated reset */
116949ea07d3SPierre-Louis Bossart cdns_updatel(cdns, CDNS_MCP_CONTROL,
117049ea07d3SPierre-Louis Bossart CDNS_MCP_CONTROL_HW_RST,
117149ea07d3SPierre-Louis Bossart CDNS_MCP_CONTROL_HW_RST);
117249ea07d3SPierre-Louis Bossart
117349ea07d3SPierre-Louis Bossart /* commit changes */
1174ffc363d9SPierre-Louis Bossart return cdns_config_update(cdns);
117549ea07d3SPierre-Louis Bossart }
117649ea07d3SPierre-Louis Bossart EXPORT_SYMBOL(sdw_cdns_exit_reset);
117749ea07d3SPierre-Louis Bossart
117849ea07d3SPierre-Louis Bossart /**
1179b76f3fbaSPierre-Louis Bossart * cdns_enable_slave_interrupts() - Enable SDW slave interrupts
1180af4cc917SPierre-Louis Bossart * @cdns: Cadence instance
1181af4cc917SPierre-Louis Bossart * @state: boolean for true/false
1182af4cc917SPierre-Louis Bossart */
cdns_enable_slave_interrupts(struct sdw_cdns * cdns,bool state)1183af4cc917SPierre-Louis Bossart static void cdns_enable_slave_interrupts(struct sdw_cdns *cdns, bool state)
1184af4cc917SPierre-Louis Bossart {
1185af4cc917SPierre-Louis Bossart u32 mask;
1186af4cc917SPierre-Louis Bossart
1187af4cc917SPierre-Louis Bossart mask = cdns_readl(cdns, CDNS_MCP_INTMASK);
1188af4cc917SPierre-Louis Bossart if (state)
1189af4cc917SPierre-Louis Bossart mask |= CDNS_MCP_INT_SLAVE_MASK;
1190af4cc917SPierre-Louis Bossart else
1191af4cc917SPierre-Louis Bossart mask &= ~CDNS_MCP_INT_SLAVE_MASK;
1192af4cc917SPierre-Louis Bossart
1193af4cc917SPierre-Louis Bossart cdns_writel(cdns, CDNS_MCP_INTMASK, mask);
1194af4cc917SPierre-Louis Bossart }
1195af4cc917SPierre-Louis Bossart
1196af4cc917SPierre-Louis Bossart /**
1197ae478d6eSRander Wang * sdw_cdns_enable_interrupt() - Enable SDW interrupts
119849ea07d3SPierre-Louis Bossart * @cdns: Cadence instance
1199550f9052SPierre-Louis Bossart * @state: True if we are trying to enable interrupt.
120049ea07d3SPierre-Louis Bossart */
sdw_cdns_enable_interrupt(struct sdw_cdns * cdns,bool state)12019e3d47fbSPierre-Louis Bossart int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns, bool state)
1202956baa19SSanyog Kale {
12039e3d47fbSPierre-Louis Bossart u32 slave_intmask0 = 0;
12049e3d47fbSPierre-Louis Bossart u32 slave_intmask1 = 0;
12059e3d47fbSPierre-Louis Bossart u32 mask = 0;
1206956baa19SSanyog Kale
12079e3d47fbSPierre-Louis Bossart if (!state)
12089e3d47fbSPierre-Louis Bossart goto update_masks;
12099e3d47fbSPierre-Louis Bossart
12109e3d47fbSPierre-Louis Bossart slave_intmask0 = CDNS_MCP_SLAVE_INTMASK0_MASK;
12119e3d47fbSPierre-Louis Bossart slave_intmask1 = CDNS_MCP_SLAVE_INTMASK1_MASK;
1212956baa19SSanyog Kale
12139b5884a0SPierre-Louis Bossart /* enable detection of all slave state changes */
12149b5884a0SPierre-Louis Bossart mask = CDNS_MCP_INT_SLAVE_MASK;
12159b5884a0SPierre-Louis Bossart
12169b5884a0SPierre-Louis Bossart /* enable detection of bus issues */
12179b5884a0SPierre-Louis Bossart mask |= CDNS_MCP_INT_CTRL_CLASH | CDNS_MCP_INT_DATA_CLASH |
12189b5884a0SPierre-Louis Bossart CDNS_MCP_INT_PARITY;
12199b5884a0SPierre-Louis Bossart
12209e4e6019SPierre-Louis Bossart /* port interrupt limited to test modes for now */
12219e4e6019SPierre-Louis Bossart if (cdns->bus.params.m_data_mode != SDW_PORT_DATA_MODE_NORMAL)
12229e4e6019SPierre-Louis Bossart mask |= CDNS_MCP_INT_DPINT;
12239b5884a0SPierre-Louis Bossart
12249b5884a0SPierre-Louis Bossart /* enable detection of RX fifo level */
12259b5884a0SPierre-Louis Bossart mask |= CDNS_MCP_INT_RX_WL;
12269b5884a0SPierre-Louis Bossart
12279b5884a0SPierre-Louis Bossart /*
12289b5884a0SPierre-Louis Bossart * CDNS_MCP_INT_IRQ needs to be set otherwise all previous
12299b5884a0SPierre-Louis Bossart * settings are irrelevant
12309b5884a0SPierre-Louis Bossart */
12319b5884a0SPierre-Louis Bossart mask |= CDNS_MCP_INT_IRQ;
1232956baa19SSanyog Kale
123304592dceSPierre-Louis Bossart if (interrupt_mask) /* parameter override */
123404592dceSPierre-Louis Bossart mask = interrupt_mask;
1235956baa19SSanyog Kale
12369e3d47fbSPierre-Louis Bossart update_masks:
12375ebb0945SRander Wang /* clear slave interrupt status before enabling interrupt */
12385ebb0945SRander Wang if (state) {
12395ebb0945SRander Wang u32 slave_state;
12405ebb0945SRander Wang
12415ebb0945SRander Wang slave_state = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT0);
12425ebb0945SRander Wang cdns_writel(cdns, CDNS_MCP_SLAVE_INTSTAT0, slave_state);
12435ebb0945SRander Wang slave_state = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT1);
12445ebb0945SRander Wang cdns_writel(cdns, CDNS_MCP_SLAVE_INTSTAT1, slave_state);
12455ebb0945SRander Wang }
1246d2068da5SPierre-Louis Bossart cdns->interrupt_enabled = state;
1247d2068da5SPierre-Louis Bossart
1248d2068da5SPierre-Louis Bossart /*
1249d2068da5SPierre-Louis Bossart * Complete any on-going status updates before updating masks,
1250d2068da5SPierre-Louis Bossart * and cancel queued status updates.
1251d2068da5SPierre-Louis Bossart *
1252d2068da5SPierre-Louis Bossart * There could be a race with a new interrupt thrown before
1253d2068da5SPierre-Louis Bossart * the 3 mask updates below are complete, so in the interrupt
1254d2068da5SPierre-Louis Bossart * we use the 'interrupt_enabled' status to prevent new work
1255d2068da5SPierre-Louis Bossart * from being queued.
1256d2068da5SPierre-Louis Bossart */
1257d2068da5SPierre-Louis Bossart if (!state)
1258d2068da5SPierre-Louis Bossart cancel_work_sync(&cdns->work);
12595ebb0945SRander Wang
12609e3d47fbSPierre-Louis Bossart cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK0, slave_intmask0);
12619e3d47fbSPierre-Louis Bossart cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK1, slave_intmask1);
1262956baa19SSanyog Kale cdns_writel(cdns, CDNS_MCP_INTMASK, mask);
1263956baa19SSanyog Kale
1264ae478d6eSRander Wang return 0;
1265956baa19SSanyog Kale }
1266956baa19SSanyog Kale EXPORT_SYMBOL(sdw_cdns_enable_interrupt);
12672f52a517SVinod Koul
cdns_allocate_pdi(struct sdw_cdns * cdns,struct sdw_cdns_pdi ** stream,u32 num,u32 pdi_offset)126807abeff1SVinod Koul static int cdns_allocate_pdi(struct sdw_cdns *cdns,
126907abeff1SVinod Koul struct sdw_cdns_pdi **stream,
127007abeff1SVinod Koul u32 num, u32 pdi_offset)
127107abeff1SVinod Koul {
127207abeff1SVinod Koul struct sdw_cdns_pdi *pdi;
127307abeff1SVinod Koul int i;
127407abeff1SVinod Koul
127507abeff1SVinod Koul if (!num)
127607abeff1SVinod Koul return 0;
127707abeff1SVinod Koul
127807abeff1SVinod Koul pdi = devm_kcalloc(cdns->dev, num, sizeof(*pdi), GFP_KERNEL);
127907abeff1SVinod Koul if (!pdi)
128007abeff1SVinod Koul return -ENOMEM;
128107abeff1SVinod Koul
128207abeff1SVinod Koul for (i = 0; i < num; i++) {
128307abeff1SVinod Koul pdi[i].num = i + pdi_offset;
128407abeff1SVinod Koul }
128507abeff1SVinod Koul
128607abeff1SVinod Koul *stream = pdi;
128707abeff1SVinod Koul return 0;
128807abeff1SVinod Koul }
128907abeff1SVinod Koul
129007abeff1SVinod Koul /**
129107abeff1SVinod Koul * sdw_cdns_pdi_init() - PDI initialization routine
129207abeff1SVinod Koul *
129307abeff1SVinod Koul * @cdns: Cadence instance
129407abeff1SVinod Koul * @config: Stream configurations
129507abeff1SVinod Koul */
sdw_cdns_pdi_init(struct sdw_cdns * cdns,struct sdw_cdns_stream_config config)129607abeff1SVinod Koul int sdw_cdns_pdi_init(struct sdw_cdns *cdns,
129707abeff1SVinod Koul struct sdw_cdns_stream_config config)
129807abeff1SVinod Koul {
129907abeff1SVinod Koul struct sdw_cdns_streams *stream;
130057a34790SPierre-Louis Bossart int offset;
130157a34790SPierre-Louis Bossart int ret;
130207abeff1SVinod Koul
130307abeff1SVinod Koul cdns->pcm.num_bd = config.pcm_bd;
130407abeff1SVinod Koul cdns->pcm.num_in = config.pcm_in;
130507abeff1SVinod Koul cdns->pcm.num_out = config.pcm_out;
130607abeff1SVinod Koul
130707abeff1SVinod Koul /* Allocate PDIs for PCMs */
130807abeff1SVinod Koul stream = &cdns->pcm;
130907abeff1SVinod Koul
1310807c15bcSPierre-Louis Bossart /* we allocate PDI0 and PDI1 which are used for Bulk */
1311807c15bcSPierre-Louis Bossart offset = 0;
131207abeff1SVinod Koul
131307abeff1SVinod Koul ret = cdns_allocate_pdi(cdns, &stream->bd,
131407abeff1SVinod Koul stream->num_bd, offset);
131507abeff1SVinod Koul if (ret)
131607abeff1SVinod Koul return ret;
131707abeff1SVinod Koul
131807abeff1SVinod Koul offset += stream->num_bd;
131907abeff1SVinod Koul
132007abeff1SVinod Koul ret = cdns_allocate_pdi(cdns, &stream->in,
132107abeff1SVinod Koul stream->num_in, offset);
132207abeff1SVinod Koul if (ret)
132307abeff1SVinod Koul return ret;
132407abeff1SVinod Koul
132507abeff1SVinod Koul offset += stream->num_in;
132607abeff1SVinod Koul
132707abeff1SVinod Koul ret = cdns_allocate_pdi(cdns, &stream->out,
132807abeff1SVinod Koul stream->num_out, offset);
132907abeff1SVinod Koul if (ret)
133007abeff1SVinod Koul return ret;
133107abeff1SVinod Koul
133207abeff1SVinod Koul /* Update total number of PCM PDIs */
133307abeff1SVinod Koul stream->num_pdi = stream->num_bd + stream->num_in + stream->num_out;
133407abeff1SVinod Koul cdns->num_ports = stream->num_pdi;
133507abeff1SVinod Koul
133607abeff1SVinod Koul return 0;
133707abeff1SVinod Koul }
133807abeff1SVinod Koul EXPORT_SYMBOL(sdw_cdns_pdi_init);
133907abeff1SVinod Koul
cdns_set_initial_frame_shape(int n_rows,int n_cols)134005be59acSPierre-Louis Bossart static u32 cdns_set_initial_frame_shape(int n_rows, int n_cols)
134105be59acSPierre-Louis Bossart {
134205be59acSPierre-Louis Bossart u32 val;
134305be59acSPierre-Louis Bossart int c;
134405be59acSPierre-Louis Bossart int r;
134505be59acSPierre-Louis Bossart
134605be59acSPierre-Louis Bossart r = sdw_find_row_index(n_rows);
13473cf25d63SVinod Koul c = sdw_find_col_index(n_cols);
134805be59acSPierre-Louis Bossart
13493cf25d63SVinod Koul val = FIELD_PREP(CDNS_MCP_FRAME_SHAPE_ROW_MASK, r);
13503cf25d63SVinod Koul val |= FIELD_PREP(CDNS_MCP_FRAME_SHAPE_COL_MASK, c);
135105be59acSPierre-Louis Bossart
135205be59acSPierre-Louis Bossart return val;
135305be59acSPierre-Louis Bossart }
135405be59acSPierre-Louis Bossart
cdns_init_clock_ctrl(struct sdw_cdns * cdns)13550cdcdedcSPierre-Louis Bossart static void cdns_init_clock_ctrl(struct sdw_cdns *cdns)
13562f52a517SVinod Koul {
13573859872fSPierre-Louis Bossart struct sdw_bus *bus = &cdns->bus;
13583859872fSPierre-Louis Bossart struct sdw_master_prop *prop = &bus->prop;
13592f52a517SVinod Koul u32 val;
13601dd6a17fSPierre-Louis Bossart u32 ssp_interval;
13613859872fSPierre-Louis Bossart int divider;
13622f52a517SVinod Koul
13632f52a517SVinod Koul /* Set clock divider */
13643859872fSPierre-Louis Bossart divider = (prop->mclk_freq / prop->max_clk_freq) - 1;
13652f52a517SVinod Koul
1366a50954e2SRander Wang cdns_updatel(cdns, CDNS_MCP_CLK_CTRL0,
1367a50954e2SRander Wang CDNS_MCP_CLK_MCLKD_MASK, divider);
1368a50954e2SRander Wang cdns_updatel(cdns, CDNS_MCP_CLK_CTRL1,
1369a50954e2SRander Wang CDNS_MCP_CLK_MCLKD_MASK, divider);
13702f52a517SVinod Koul
137105be59acSPierre-Louis Bossart /*
137205be59acSPierre-Louis Bossart * Frame shape changes after initialization have to be done
137305be59acSPierre-Louis Bossart * with the bank switch mechanism
137405be59acSPierre-Louis Bossart */
137505be59acSPierre-Louis Bossart val = cdns_set_initial_frame_shape(prop->default_row,
137605be59acSPierre-Louis Bossart prop->default_col);
137705be59acSPierre-Louis Bossart cdns_writel(cdns, CDNS_MCP_FRAME_SHAPE_INIT, val);
13782f52a517SVinod Koul
13792f52a517SVinod Koul /* Set SSP interval to default value */
13801dd6a17fSPierre-Louis Bossart ssp_interval = prop->default_frame_rate / SDW_CADENCE_GSYNC_HZ;
13811dd6a17fSPierre-Louis Bossart cdns_writel(cdns, CDNS_MCP_SSP_CTRL0, ssp_interval);
13821dd6a17fSPierre-Louis Bossart cdns_writel(cdns, CDNS_MCP_SSP_CTRL1, ssp_interval);
13830cdcdedcSPierre-Louis Bossart }
13840cdcdedcSPierre-Louis Bossart
13850cdcdedcSPierre-Louis Bossart /**
13860cdcdedcSPierre-Louis Bossart * sdw_cdns_init() - Cadence initialization
13870cdcdedcSPierre-Louis Bossart * @cdns: Cadence instance
13880cdcdedcSPierre-Louis Bossart */
sdw_cdns_init(struct sdw_cdns * cdns)13890cdcdedcSPierre-Louis Bossart int sdw_cdns_init(struct sdw_cdns *cdns)
13900cdcdedcSPierre-Louis Bossart {
13910cdcdedcSPierre-Louis Bossart u32 val;
13920cdcdedcSPierre-Louis Bossart
13930cdcdedcSPierre-Louis Bossart cdns_init_clock_ctrl(cdns);
13942f52a517SVinod Koul
1395ff560946SPierre-Louis Bossart sdw_cdns_check_self_clearing_bits(cdns, __func__, false, 0);
1396ff560946SPierre-Louis Bossart
13970d667d01SRander Wang /* reset msg_count to default value of FIFOLEVEL */
13980d667d01SRander Wang cdns->msg_count = cdns_readl(cdns, CDNS_MCP_FIFOLEVEL);
13990d667d01SRander Wang
140049ea07d3SPierre-Louis Bossart /* flush command FIFOs */
140149ea07d3SPierre-Louis Bossart cdns_updatel(cdns, CDNS_MCP_CONTROL, CDNS_MCP_CONTROL_CMD_RST,
140249ea07d3SPierre-Louis Bossart CDNS_MCP_CONTROL_CMD_RST);
140349ea07d3SPierre-Louis Bossart
14042f52a517SVinod Koul /* Set cmd accept mode */
14054dc953bcSPierre-Louis Bossart cdns_ip_updatel(cdns, CDNS_IP_MCP_CONTROL, CDNS_IP_MCP_CONTROL_CMD_ACCEPT,
14064dc953bcSPierre-Louis Bossart CDNS_IP_MCP_CONTROL_CMD_ACCEPT);
14072f52a517SVinod Koul
14082f52a517SVinod Koul /* Configure mcp config */
14092f52a517SVinod Koul val = cdns_readl(cdns, CDNS_MCP_CONFIG);
14102f52a517SVinod Koul
1411b62e76cfSPierre-Louis Bossart /* Disable auto bus release */
1412b62e76cfSPierre-Louis Bossart val &= ~CDNS_MCP_CONFIG_BUS_REL;
1413b62e76cfSPierre-Louis Bossart
1414c5753714SPierre-Louis Bossart cdns_writel(cdns, CDNS_MCP_CONFIG, val);
1415c5753714SPierre-Louis Bossart
1416c5753714SPierre-Louis Bossart /* Configure IP mcp config */
1417c5753714SPierre-Louis Bossart val = cdns_ip_readl(cdns, CDNS_IP_MCP_CONFIG);
1418c5753714SPierre-Louis Bossart
1419c5753714SPierre-Louis Bossart /* enable bus operations with clock and data */
1420c5753714SPierre-Louis Bossart val &= ~CDNS_IP_MCP_CONFIG_OP;
1421c5753714SPierre-Louis Bossart val |= CDNS_IP_MCP_CONFIG_OP_NORMAL;
1422c5753714SPierre-Louis Bossart
1423c5753714SPierre-Louis Bossart /* Set cmd mode for Tx and Rx cmds */
1424c5753714SPierre-Louis Bossart val &= ~CDNS_IP_MCP_CONFIG_CMD;
1425c5753714SPierre-Louis Bossart
1426c5753714SPierre-Louis Bossart /* Disable sniffer mode */
1427c5753714SPierre-Louis Bossart val &= ~CDNS_IP_MCP_CONFIG_SNIFFER;
1428c5753714SPierre-Louis Bossart
14292c800e3bSPierre-Louis Bossart if (cdns->bus.multi_link)
14302c800e3bSPierre-Louis Bossart /* Set Multi-master mode to take gsync into account */
1431c5753714SPierre-Louis Bossart val |= CDNS_IP_MCP_CONFIG_MMASTER;
1432b62e76cfSPierre-Louis Bossart
143391080111SPierre-Louis Bossart /* leave frame delay to hardware default of 0x1F */
1434b62e76cfSPierre-Louis Bossart
1435ad473db4SPierre-Louis Bossart /* leave command retry to hardware default of 0 */
14362f52a517SVinod Koul
1437c5753714SPierre-Louis Bossart cdns_ip_writel(cdns, CDNS_IP_MCP_CONFIG, val);
14382f52a517SVinod Koul
1439b17350e4SPierre-Louis Bossart /* changes will be committed later */
1440b17350e4SPierre-Louis Bossart return 0;
14412f52a517SVinod Koul }
14422f52a517SVinod Koul EXPORT_SYMBOL(sdw_cdns_init);
14432f52a517SVinod Koul
cdns_bus_conf(struct sdw_bus * bus,struct sdw_bus_params * params)144407abeff1SVinod Koul int cdns_bus_conf(struct sdw_bus *bus, struct sdw_bus_params *params)
144507abeff1SVinod Koul {
14463859872fSPierre-Louis Bossart struct sdw_master_prop *prop = &bus->prop;
144707abeff1SVinod Koul struct sdw_cdns *cdns = bus_to_cdns(bus);
1448a50954e2SRander Wang int mcp_clkctrl_off;
144907abeff1SVinod Koul int divider;
145007abeff1SVinod Koul
145107abeff1SVinod Koul if (!params->curr_dr_freq) {
145217ed5befSPierre-Louis Bossart dev_err(cdns->dev, "NULL curr_dr_freq\n");
145307abeff1SVinod Koul return -EINVAL;
145407abeff1SVinod Koul }
145507abeff1SVinod Koul
14563859872fSPierre-Louis Bossart divider = prop->mclk_freq * SDW_DOUBLE_RATE_FACTOR /
14573859872fSPierre-Louis Bossart params->curr_dr_freq;
14583859872fSPierre-Louis Bossart divider--; /* divider is 1/(N+1) */
145907abeff1SVinod Koul
146007abeff1SVinod Koul if (params->next_bank)
146107abeff1SVinod Koul mcp_clkctrl_off = CDNS_MCP_CLK_CTRL1;
146207abeff1SVinod Koul else
146307abeff1SVinod Koul mcp_clkctrl_off = CDNS_MCP_CLK_CTRL0;
146407abeff1SVinod Koul
1465a50954e2SRander Wang cdns_updatel(cdns, mcp_clkctrl_off, CDNS_MCP_CLK_MCLKD_MASK, divider);
146607abeff1SVinod Koul
146707abeff1SVinod Koul return 0;
146807abeff1SVinod Koul }
146907abeff1SVinod Koul EXPORT_SYMBOL(cdns_bus_conf);
147007abeff1SVinod Koul
cdns_port_params(struct sdw_bus * bus,struct sdw_port_params * p_params,unsigned int bank)147107abeff1SVinod Koul static int cdns_port_params(struct sdw_bus *bus,
147207abeff1SVinod Koul struct sdw_port_params *p_params, unsigned int bank)
147307abeff1SVinod Koul {
147407abeff1SVinod Koul struct sdw_cdns *cdns = bus_to_cdns(bus);
1475dd81e7c3SPierre-Louis Bossart int dpn_config_off_source;
1476dd81e7c3SPierre-Louis Bossart int dpn_config_off_target;
1477dd81e7c3SPierre-Louis Bossart int target_num = p_params->num;
1478dd81e7c3SPierre-Louis Bossart int source_num = p_params->num;
1479dd81e7c3SPierre-Louis Bossart bool override = false;
1480dd81e7c3SPierre-Louis Bossart int dpn_config;
148107abeff1SVinod Koul
1482dd81e7c3SPierre-Louis Bossart if (target_num == cdns->pdi_loopback_target &&
1483dd81e7c3SPierre-Louis Bossart cdns->pdi_loopback_source != -1) {
1484dd81e7c3SPierre-Louis Bossart source_num = cdns->pdi_loopback_source;
1485dd81e7c3SPierre-Louis Bossart override = true;
1486dd81e7c3SPierre-Louis Bossart }
148707abeff1SVinod Koul
1488dd81e7c3SPierre-Louis Bossart if (bank) {
1489dd81e7c3SPierre-Louis Bossart dpn_config_off_source = CDNS_DPN_B1_CONFIG(source_num);
1490dd81e7c3SPierre-Louis Bossart dpn_config_off_target = CDNS_DPN_B1_CONFIG(target_num);
1491dd81e7c3SPierre-Louis Bossart } else {
1492dd81e7c3SPierre-Louis Bossart dpn_config_off_source = CDNS_DPN_B0_CONFIG(source_num);
1493dd81e7c3SPierre-Louis Bossart dpn_config_off_target = CDNS_DPN_B0_CONFIG(target_num);
1494dd81e7c3SPierre-Louis Bossart }
149507abeff1SVinod Koul
1496dd81e7c3SPierre-Louis Bossart dpn_config = cdns_readl(cdns, dpn_config_off_source);
1497dd81e7c3SPierre-Louis Bossart
1498dd81e7c3SPierre-Louis Bossart /* use port params if there is no loopback, otherwise use source as is */
1499dd81e7c3SPierre-Louis Bossart if (!override) {
1500dd81e7c3SPierre-Louis Bossart u32p_replace_bits(&dpn_config, p_params->bps - 1, CDNS_DPN_CONFIG_WL);
1501714db045SVinod Koul u32p_replace_bits(&dpn_config, p_params->flow_mode, CDNS_DPN_CONFIG_PORT_FLOW);
1502714db045SVinod Koul u32p_replace_bits(&dpn_config, p_params->data_mode, CDNS_DPN_CONFIG_PORT_DAT);
1503dd81e7c3SPierre-Louis Bossart }
150407abeff1SVinod Koul
1505dd81e7c3SPierre-Louis Bossart cdns_writel(cdns, dpn_config_off_target, dpn_config);
150607abeff1SVinod Koul
150707abeff1SVinod Koul return 0;
150807abeff1SVinod Koul }
150907abeff1SVinod Koul
cdns_transport_params(struct sdw_bus * bus,struct sdw_transport_params * t_params,enum sdw_reg_bank bank)151007abeff1SVinod Koul static int cdns_transport_params(struct sdw_bus *bus,
151107abeff1SVinod Koul struct sdw_transport_params *t_params,
151207abeff1SVinod Koul enum sdw_reg_bank bank)
151307abeff1SVinod Koul {
151407abeff1SVinod Koul struct sdw_cdns *cdns = bus_to_cdns(bus);
1515dd81e7c3SPierre-Louis Bossart int dpn_config;
1516dd81e7c3SPierre-Louis Bossart int dpn_config_off_source;
1517dd81e7c3SPierre-Louis Bossart int dpn_config_off_target;
1518dd81e7c3SPierre-Louis Bossart int dpn_hctrl;
1519dd81e7c3SPierre-Louis Bossart int dpn_hctrl_off_source;
1520dd81e7c3SPierre-Louis Bossart int dpn_hctrl_off_target;
1521dd81e7c3SPierre-Louis Bossart int dpn_offsetctrl;
1522dd81e7c3SPierre-Louis Bossart int dpn_offsetctrl_off_source;
1523dd81e7c3SPierre-Louis Bossart int dpn_offsetctrl_off_target;
1524dd81e7c3SPierre-Louis Bossart int dpn_samplectrl;
1525dd81e7c3SPierre-Louis Bossart int dpn_samplectrl_off_source;
1526dd81e7c3SPierre-Louis Bossart int dpn_samplectrl_off_target;
1527dd81e7c3SPierre-Louis Bossart int source_num = t_params->port_num;
1528dd81e7c3SPierre-Louis Bossart int target_num = t_params->port_num;
1529dd81e7c3SPierre-Louis Bossart bool override = false;
1530dd81e7c3SPierre-Louis Bossart
1531dd81e7c3SPierre-Louis Bossart if (target_num == cdns->pdi_loopback_target &&
1532dd81e7c3SPierre-Louis Bossart cdns->pdi_loopback_source != -1) {
1533dd81e7c3SPierre-Louis Bossart source_num = cdns->pdi_loopback_source;
1534dd81e7c3SPierre-Louis Bossart override = true;
1535dd81e7c3SPierre-Louis Bossart }
153607abeff1SVinod Koul
153707abeff1SVinod Koul /*
153807abeff1SVinod Koul * Note: Only full data port is supported on the Master side for
153907abeff1SVinod Koul * both PCM and PDM ports.
154007abeff1SVinod Koul */
154107abeff1SVinod Koul
154207abeff1SVinod Koul if (bank) {
1543dd81e7c3SPierre-Louis Bossart dpn_config_off_source = CDNS_DPN_B1_CONFIG(source_num);
1544dd81e7c3SPierre-Louis Bossart dpn_hctrl_off_source = CDNS_DPN_B1_HCTRL(source_num);
1545dd81e7c3SPierre-Louis Bossart dpn_offsetctrl_off_source = CDNS_DPN_B1_OFFSET_CTRL(source_num);
1546dd81e7c3SPierre-Louis Bossart dpn_samplectrl_off_source = CDNS_DPN_B1_SAMPLE_CTRL(source_num);
1547dd81e7c3SPierre-Louis Bossart
1548dd81e7c3SPierre-Louis Bossart dpn_config_off_target = CDNS_DPN_B1_CONFIG(target_num);
1549dd81e7c3SPierre-Louis Bossart dpn_hctrl_off_target = CDNS_DPN_B1_HCTRL(target_num);
1550dd81e7c3SPierre-Louis Bossart dpn_offsetctrl_off_target = CDNS_DPN_B1_OFFSET_CTRL(target_num);
1551dd81e7c3SPierre-Louis Bossart dpn_samplectrl_off_target = CDNS_DPN_B1_SAMPLE_CTRL(target_num);
1552dd81e7c3SPierre-Louis Bossart
155307abeff1SVinod Koul } else {
1554dd81e7c3SPierre-Louis Bossart dpn_config_off_source = CDNS_DPN_B0_CONFIG(source_num);
1555dd81e7c3SPierre-Louis Bossart dpn_hctrl_off_source = CDNS_DPN_B0_HCTRL(source_num);
1556dd81e7c3SPierre-Louis Bossart dpn_offsetctrl_off_source = CDNS_DPN_B0_OFFSET_CTRL(source_num);
1557dd81e7c3SPierre-Louis Bossart dpn_samplectrl_off_source = CDNS_DPN_B0_SAMPLE_CTRL(source_num);
1558dd81e7c3SPierre-Louis Bossart
1559dd81e7c3SPierre-Louis Bossart dpn_config_off_target = CDNS_DPN_B0_CONFIG(target_num);
1560dd81e7c3SPierre-Louis Bossart dpn_hctrl_off_target = CDNS_DPN_B0_HCTRL(target_num);
1561dd81e7c3SPierre-Louis Bossart dpn_offsetctrl_off_target = CDNS_DPN_B0_OFFSET_CTRL(target_num);
1562dd81e7c3SPierre-Louis Bossart dpn_samplectrl_off_target = CDNS_DPN_B0_SAMPLE_CTRL(target_num);
156307abeff1SVinod Koul }
156407abeff1SVinod Koul
1565dd81e7c3SPierre-Louis Bossart dpn_config = cdns_readl(cdns, dpn_config_off_source);
1566dd81e7c3SPierre-Louis Bossart if (!override) {
1567714db045SVinod Koul u32p_replace_bits(&dpn_config, t_params->blk_grp_ctrl, CDNS_DPN_CONFIG_BGC);
1568714db045SVinod Koul u32p_replace_bits(&dpn_config, t_params->blk_pkg_mode, CDNS_DPN_CONFIG_BPM);
1569dd81e7c3SPierre-Louis Bossart }
1570dd81e7c3SPierre-Louis Bossart cdns_writel(cdns, dpn_config_off_target, dpn_config);
157107abeff1SVinod Koul
1572dd81e7c3SPierre-Louis Bossart if (!override) {
1573dd81e7c3SPierre-Louis Bossart dpn_offsetctrl = 0;
1574714db045SVinod Koul u32p_replace_bits(&dpn_offsetctrl, t_params->offset1, CDNS_DPN_OFFSET_CTRL_1);
1575714db045SVinod Koul u32p_replace_bits(&dpn_offsetctrl, t_params->offset2, CDNS_DPN_OFFSET_CTRL_2);
1576dd81e7c3SPierre-Louis Bossart } else {
1577dd81e7c3SPierre-Louis Bossart dpn_offsetctrl = cdns_readl(cdns, dpn_offsetctrl_off_source);
1578dd81e7c3SPierre-Louis Bossart }
1579dd81e7c3SPierre-Louis Bossart cdns_writel(cdns, dpn_offsetctrl_off_target, dpn_offsetctrl);
158007abeff1SVinod Koul
1581dd81e7c3SPierre-Louis Bossart if (!override) {
1582dd81e7c3SPierre-Louis Bossart dpn_hctrl = 0;
1583714db045SVinod Koul u32p_replace_bits(&dpn_hctrl, t_params->hstart, CDNS_DPN_HCTRL_HSTART);
1584714db045SVinod Koul u32p_replace_bits(&dpn_hctrl, t_params->hstop, CDNS_DPN_HCTRL_HSTOP);
1585714db045SVinod Koul u32p_replace_bits(&dpn_hctrl, t_params->lane_ctrl, CDNS_DPN_HCTRL_LCTRL);
1586dd81e7c3SPierre-Louis Bossart } else {
1587dd81e7c3SPierre-Louis Bossart dpn_hctrl = cdns_readl(cdns, dpn_hctrl_off_source);
1588dd81e7c3SPierre-Louis Bossart }
1589dd81e7c3SPierre-Louis Bossart cdns_writel(cdns, dpn_hctrl_off_target, dpn_hctrl);
159007abeff1SVinod Koul
1591dd81e7c3SPierre-Louis Bossart if (!override)
1592dd81e7c3SPierre-Louis Bossart dpn_samplectrl = t_params->sample_interval - 1;
1593dd81e7c3SPierre-Louis Bossart else
1594dd81e7c3SPierre-Louis Bossart dpn_samplectrl = cdns_readl(cdns, dpn_samplectrl_off_source);
1595dd81e7c3SPierre-Louis Bossart cdns_writel(cdns, dpn_samplectrl_off_target, dpn_samplectrl);
159607abeff1SVinod Koul
159707abeff1SVinod Koul return 0;
159807abeff1SVinod Koul }
159907abeff1SVinod Koul
cdns_port_enable(struct sdw_bus * bus,struct sdw_enable_ch * enable_ch,unsigned int bank)160007abeff1SVinod Koul static int cdns_port_enable(struct sdw_bus *bus,
160107abeff1SVinod Koul struct sdw_enable_ch *enable_ch, unsigned int bank)
160207abeff1SVinod Koul {
160307abeff1SVinod Koul struct sdw_cdns *cdns = bus_to_cdns(bus);
160407abeff1SVinod Koul int dpn_chnen_off, ch_mask;
160507abeff1SVinod Koul
160607abeff1SVinod Koul if (bank)
160707abeff1SVinod Koul dpn_chnen_off = CDNS_DPN_B1_CH_EN(enable_ch->port_num);
160807abeff1SVinod Koul else
160907abeff1SVinod Koul dpn_chnen_off = CDNS_DPN_B0_CH_EN(enable_ch->port_num);
161007abeff1SVinod Koul
161107abeff1SVinod Koul ch_mask = enable_ch->ch_mask * enable_ch->enable;
161207abeff1SVinod Koul cdns_writel(cdns, dpn_chnen_off, ch_mask);
161307abeff1SVinod Koul
161407abeff1SVinod Koul return 0;
161507abeff1SVinod Koul }
161607abeff1SVinod Koul
161707abeff1SVinod Koul static const struct sdw_master_port_ops cdns_port_ops = {
161807abeff1SVinod Koul .dpn_set_port_params = cdns_port_params,
161907abeff1SVinod Koul .dpn_set_port_transport_params = cdns_transport_params,
162007abeff1SVinod Koul .dpn_port_enable_ch = cdns_port_enable,
162107abeff1SVinod Koul };
162207abeff1SVinod Koul
1623956baa19SSanyog Kale /**
16245a885c52SRander Wang * sdw_cdns_is_clock_stop: Check clock status
16255a885c52SRander Wang *
16265a885c52SRander Wang * @cdns: Cadence instance
16275a885c52SRander Wang */
sdw_cdns_is_clock_stop(struct sdw_cdns * cdns)16285a885c52SRander Wang bool sdw_cdns_is_clock_stop(struct sdw_cdns *cdns)
16295a885c52SRander Wang {
16305a885c52SRander Wang return !!(cdns_readl(cdns, CDNS_MCP_STAT) & CDNS_MCP_STAT_CLK_STOP);
16315a885c52SRander Wang }
16325a885c52SRander Wang EXPORT_SYMBOL(sdw_cdns_is_clock_stop);
16335a885c52SRander Wang
16345a885c52SRander Wang /**
16351032504fSRander Wang * sdw_cdns_clock_stop: Cadence clock stop configuration routine
16361032504fSRander Wang *
16371032504fSRander Wang * @cdns: Cadence instance
16381032504fSRander Wang * @block_wake: prevent wakes if required by the platform
16391032504fSRander Wang */
sdw_cdns_clock_stop(struct sdw_cdns * cdns,bool block_wake)16401032504fSRander Wang int sdw_cdns_clock_stop(struct sdw_cdns *cdns, bool block_wake)
16411032504fSRander Wang {
16421032504fSRander Wang bool slave_present = false;
16431032504fSRander Wang struct sdw_slave *slave;
16441032504fSRander Wang int ret;
16451032504fSRander Wang
1646ff560946SPierre-Louis Bossart sdw_cdns_check_self_clearing_bits(cdns, __func__, false, 0);
1647ff560946SPierre-Louis Bossart
16481032504fSRander Wang /* Check suspend status */
16491032504fSRander Wang if (sdw_cdns_is_clock_stop(cdns)) {
16501032504fSRander Wang dev_dbg(cdns->dev, "Clock is already stopped\n");
16511032504fSRander Wang return 0;
16521032504fSRander Wang }
16531032504fSRander Wang
16541032504fSRander Wang /*
1655af4cc917SPierre-Louis Bossart * Before entering clock stop we mask the Slave
1656af4cc917SPierre-Louis Bossart * interrupts. This helps avoid having to deal with e.g. a
1657af4cc917SPierre-Louis Bossart * Slave becoming UNATTACHED while the clock is being stopped
1658af4cc917SPierre-Louis Bossart */
1659af4cc917SPierre-Louis Bossart cdns_enable_slave_interrupts(cdns, false);
1660af4cc917SPierre-Louis Bossart
1661af4cc917SPierre-Louis Bossart /*
16621032504fSRander Wang * For specific platforms, it is required to be able to put
16631032504fSRander Wang * master into a state in which it ignores wake-up trials
16641032504fSRander Wang * in clock stop state
16651032504fSRander Wang */
16661032504fSRander Wang if (block_wake)
16674dc953bcSPierre-Louis Bossart cdns_ip_updatel(cdns, CDNS_IP_MCP_CONTROL,
16684dc953bcSPierre-Louis Bossart CDNS_IP_MCP_CONTROL_BLOCK_WAKEUP,
16694dc953bcSPierre-Louis Bossart CDNS_IP_MCP_CONTROL_BLOCK_WAKEUP);
16701032504fSRander Wang
16711032504fSRander Wang list_for_each_entry(slave, &cdns->bus.slaves, node) {
16721032504fSRander Wang if (slave->status == SDW_SLAVE_ATTACHED ||
16731032504fSRander Wang slave->status == SDW_SLAVE_ALERT) {
16741032504fSRander Wang slave_present = true;
16751032504fSRander Wang break;
16761032504fSRander Wang }
16771032504fSRander Wang }
16781032504fSRander Wang
16791032504fSRander Wang /* commit changes */
16801032504fSRander Wang ret = cdns_config_update(cdns);
16811032504fSRander Wang if (ret < 0) {
16821032504fSRander Wang dev_err(cdns->dev, "%s: config_update failed\n", __func__);
16831032504fSRander Wang return ret;
16841032504fSRander Wang }
16851032504fSRander Wang
16861032504fSRander Wang /* Prepare slaves for clock stop */
168758ef9356SPierre-Louis Bossart if (slave_present) {
16881032504fSRander Wang ret = sdw_bus_prep_clk_stop(&cdns->bus);
168958ef9356SPierre-Louis Bossart if (ret < 0 && ret != -ENODATA) {
169058ef9356SPierre-Louis Bossart dev_err(cdns->dev, "prepare clock stop failed %d\n", ret);
16911032504fSRander Wang return ret;
16921032504fSRander Wang }
169358ef9356SPierre-Louis Bossart }
16941032504fSRander Wang
16951032504fSRander Wang /*
16961032504fSRander Wang * Enter clock stop mode and only report errors if there are
16971032504fSRander Wang * Slave devices present (ALERT or ATTACHED)
16981032504fSRander Wang */
16991032504fSRander Wang ret = sdw_bus_clk_stop(&cdns->bus);
17001032504fSRander Wang if (ret < 0 && slave_present && ret != -ENODATA) {
17017dbdcd61SPierre-Louis Bossart dev_err(cdns->dev, "bus clock stop failed %d\n", ret);
17021032504fSRander Wang return ret;
17031032504fSRander Wang }
17041032504fSRander Wang
17051032504fSRander Wang ret = cdns_set_wait(cdns, CDNS_MCP_STAT,
17061032504fSRander Wang CDNS_MCP_STAT_CLK_STOP,
17071032504fSRander Wang CDNS_MCP_STAT_CLK_STOP);
17081032504fSRander Wang if (ret < 0)
17091032504fSRander Wang dev_err(cdns->dev, "Clock stop failed %d\n", ret);
17101032504fSRander Wang
17111032504fSRander Wang return ret;
17121032504fSRander Wang }
17131032504fSRander Wang EXPORT_SYMBOL(sdw_cdns_clock_stop);
17141032504fSRander Wang
17151032504fSRander Wang /**
17161032504fSRander Wang * sdw_cdns_clock_restart: Cadence PM clock restart configuration routine
17171032504fSRander Wang *
17181032504fSRander Wang * @cdns: Cadence instance
17191032504fSRander Wang * @bus_reset: context may be lost while in low power modes and the bus
17201032504fSRander Wang * may require a Severe Reset and re-enumeration after a wake.
17211032504fSRander Wang */
sdw_cdns_clock_restart(struct sdw_cdns * cdns,bool bus_reset)17221032504fSRander Wang int sdw_cdns_clock_restart(struct sdw_cdns *cdns, bool bus_reset)
17231032504fSRander Wang {
17241032504fSRander Wang int ret;
17251032504fSRander Wang
1726af4cc917SPierre-Louis Bossart /* unmask Slave interrupts that were masked when stopping the clock */
1727af4cc917SPierre-Louis Bossart cdns_enable_slave_interrupts(cdns, true);
1728af4cc917SPierre-Louis Bossart
17291032504fSRander Wang ret = cdns_clear_bit(cdns, CDNS_MCP_CONTROL,
17301032504fSRander Wang CDNS_MCP_CONTROL_CLK_STOP_CLR);
17311032504fSRander Wang if (ret < 0) {
17321032504fSRander Wang dev_err(cdns->dev, "Couldn't exit from clock stop\n");
17331032504fSRander Wang return ret;
17341032504fSRander Wang }
17351032504fSRander Wang
17361032504fSRander Wang ret = cdns_set_wait(cdns, CDNS_MCP_STAT, CDNS_MCP_STAT_CLK_STOP, 0);
17371032504fSRander Wang if (ret < 0) {
17381032504fSRander Wang dev_err(cdns->dev, "clock stop exit failed %d\n", ret);
17391032504fSRander Wang return ret;
17401032504fSRander Wang }
17411032504fSRander Wang
17424dc953bcSPierre-Louis Bossart cdns_ip_updatel(cdns, CDNS_IP_MCP_CONTROL,
17434dc953bcSPierre-Louis Bossart CDNS_IP_MCP_CONTROL_BLOCK_WAKEUP, 0);
17441032504fSRander Wang
17454dc953bcSPierre-Louis Bossart cdns_ip_updatel(cdns, CDNS_IP_MCP_CONTROL, CDNS_IP_MCP_CONTROL_CMD_ACCEPT,
17464dc953bcSPierre-Louis Bossart CDNS_IP_MCP_CONTROL_CMD_ACCEPT);
17471032504fSRander Wang
17481032504fSRander Wang if (!bus_reset) {
17491032504fSRander Wang
17501032504fSRander Wang /* enable bus operations with clock and data */
1751c5753714SPierre-Louis Bossart cdns_ip_updatel(cdns, CDNS_IP_MCP_CONFIG,
1752c5753714SPierre-Louis Bossart CDNS_IP_MCP_CONFIG_OP,
1753c5753714SPierre-Louis Bossart CDNS_IP_MCP_CONFIG_OP_NORMAL);
17541032504fSRander Wang
17551032504fSRander Wang ret = cdns_config_update(cdns);
17561032504fSRander Wang if (ret < 0) {
17571032504fSRander Wang dev_err(cdns->dev, "%s: config_update failed\n", __func__);
17581032504fSRander Wang return ret;
17591032504fSRander Wang }
17601032504fSRander Wang
17611032504fSRander Wang ret = sdw_bus_exit_clk_stop(&cdns->bus);
17621032504fSRander Wang if (ret < 0)
17631032504fSRander Wang dev_err(cdns->dev, "bus failed to exit clock stop %d\n", ret);
17641032504fSRander Wang }
17651032504fSRander Wang
17661032504fSRander Wang return ret;
17671032504fSRander Wang }
17681032504fSRander Wang EXPORT_SYMBOL(sdw_cdns_clock_restart);
17691032504fSRander Wang
17701032504fSRander Wang /**
1771956baa19SSanyog Kale * sdw_cdns_probe() - Cadence probe routine
1772956baa19SSanyog Kale * @cdns: Cadence instance
1773956baa19SSanyog Kale */
sdw_cdns_probe(struct sdw_cdns * cdns)1774956baa19SSanyog Kale int sdw_cdns_probe(struct sdw_cdns *cdns)
1775956baa19SSanyog Kale {
1776956baa19SSanyog Kale init_completion(&cdns->tx_complete);
177707abeff1SVinod Koul cdns->bus.port_ops = &cdns_port_ops;
1778956baa19SSanyog Kale
1779*740a6059SPierre-Louis Bossart mutex_init(&cdns->status_update_lock);
1780*740a6059SPierre-Louis Bossart
17814a98a6b2SBard Liao INIT_WORK(&cdns->work, cdns_update_slave_status_work);
1782*740a6059SPierre-Louis Bossart INIT_DELAYED_WORK(&cdns->attach_dwork, cdns_check_attached_status_dwork);
1783*740a6059SPierre-Louis Bossart
1784956baa19SSanyog Kale return 0;
1785956baa19SSanyog Kale }
1786956baa19SSanyog Kale EXPORT_SYMBOL(sdw_cdns_probe);
1787956baa19SSanyog Kale
cdns_set_sdw_stream(struct snd_soc_dai * dai,void * stream,int direction)17885d6b3c8bSVinod Koul int cdns_set_sdw_stream(struct snd_soc_dai *dai,
178963a6aa96SPierre-Louis Bossart void *stream, int direction)
17905d6b3c8bSVinod Koul {
17915d6b3c8bSVinod Koul struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
1792e0767e39SPierre-Louis Bossart struct sdw_cdns_dai_runtime *dai_runtime;
17935d6b3c8bSVinod Koul
17947dddead7SPierre-Louis Bossart dai_runtime = cdns->dai_runtime_array[dai->id];
17957dddead7SPierre-Louis Bossart
1796b5e9e687SPierre-Louis Bossart if (stream) {
1797b5e9e687SPierre-Louis Bossart /* first paranoia check */
1798e0767e39SPierre-Louis Bossart if (dai_runtime) {
1799b5e9e687SPierre-Louis Bossart dev_err(dai->dev,
1800e0767e39SPierre-Louis Bossart "dai_runtime already allocated for dai %s\n",
1801b5e9e687SPierre-Louis Bossart dai->name);
1802b5e9e687SPierre-Louis Bossart return -EINVAL;
1803b5e9e687SPierre-Louis Bossart }
1804b5e9e687SPierre-Louis Bossart
1805e0767e39SPierre-Louis Bossart /* allocate and set dai_runtime info */
1806e0767e39SPierre-Louis Bossart dai_runtime = kzalloc(sizeof(*dai_runtime), GFP_KERNEL);
1807e0767e39SPierre-Louis Bossart if (!dai_runtime)
18085d6b3c8bSVinod Koul return -ENOMEM;
18095d6b3c8bSVinod Koul
1810e0767e39SPierre-Louis Bossart dai_runtime->stream_type = SDW_STREAM_PCM;
18115d6b3c8bSVinod Koul
1812e0767e39SPierre-Louis Bossart dai_runtime->bus = &cdns->bus;
1813e0767e39SPierre-Louis Bossart dai_runtime->link_id = cdns->instance;
18145d6b3c8bSVinod Koul
1815e0767e39SPierre-Louis Bossart dai_runtime->stream = stream;
18167dddead7SPierre-Louis Bossart dai_runtime->direction = direction;
18175d6b3c8bSVinod Koul
18187dddead7SPierre-Louis Bossart cdns->dai_runtime_array[dai->id] = dai_runtime;
1819b5e9e687SPierre-Louis Bossart } else {
18207dddead7SPierre-Louis Bossart /* second paranoia check */
18217dddead7SPierre-Louis Bossart if (!dai_runtime) {
18227dddead7SPierre-Louis Bossart dev_err(dai->dev,
18237dddead7SPierre-Louis Bossart "dai_runtime not allocated for dai %s\n",
18247dddead7SPierre-Louis Bossart dai->name);
18257dddead7SPierre-Louis Bossart return -EINVAL;
1826b5e9e687SPierre-Louis Bossart }
18277dddead7SPierre-Louis Bossart
18287dddead7SPierre-Louis Bossart /* for NULL stream we release allocated dai_runtime */
18297dddead7SPierre-Louis Bossart kfree(dai_runtime);
18307dddead7SPierre-Louis Bossart cdns->dai_runtime_array[dai->id] = NULL;
1831b5e9e687SPierre-Louis Bossart }
18325d6b3c8bSVinod Koul return 0;
18335d6b3c8bSVinod Koul }
18345d6b3c8bSVinod Koul EXPORT_SYMBOL(cdns_set_sdw_stream);
18355d6b3c8bSVinod Koul
18365d6b3c8bSVinod Koul /**
18375d6b3c8bSVinod Koul * cdns_find_pdi() - Find a free PDI
18385d6b3c8bSVinod Koul *
18395d6b3c8bSVinod Koul * @cdns: Cadence instance
184039737a31SPierre-Louis Bossart * @offset: Starting offset
18415d6b3c8bSVinod Koul * @num: Number of PDIs
18425d6b3c8bSVinod Koul * @pdi: PDI instances
184339737a31SPierre-Louis Bossart * @dai_id: DAI id
18445d6b3c8bSVinod Koul *
18451b53385eSBard Liao * Find a PDI for a given PDI array. The PDI num and dai_id are
18461b53385eSBard Liao * expected to match, return NULL otherwise.
18475d6b3c8bSVinod Koul */
cdns_find_pdi(struct sdw_cdns * cdns,unsigned int offset,unsigned int num,struct sdw_cdns_pdi * pdi,int dai_id)18485d6b3c8bSVinod Koul static struct sdw_cdns_pdi *cdns_find_pdi(struct sdw_cdns *cdns,
1849807c15bcSPierre-Louis Bossart unsigned int offset,
1850bbb63817SPierre-Louis Bossart unsigned int num,
18511b53385eSBard Liao struct sdw_cdns_pdi *pdi,
18521b53385eSBard Liao int dai_id)
18535d6b3c8bSVinod Koul {
18545d6b3c8bSVinod Koul int i;
18555d6b3c8bSVinod Koul
18561b53385eSBard Liao for (i = offset; i < offset + num; i++)
18571b53385eSBard Liao if (pdi[i].num == dai_id)
18585d6b3c8bSVinod Koul return &pdi[i];
18595d6b3c8bSVinod Koul
18605d6b3c8bSVinod Koul return NULL;
18615d6b3c8bSVinod Koul }
18625d6b3c8bSVinod Koul
18635d6b3c8bSVinod Koul /**
18645d6b3c8bSVinod Koul * sdw_cdns_config_stream: Configure a stream
18655d6b3c8bSVinod Koul *
18665d6b3c8bSVinod Koul * @cdns: Cadence instance
18675d6b3c8bSVinod Koul * @ch: Channel count
18685d6b3c8bSVinod Koul * @dir: Data direction
18695d6b3c8bSVinod Koul * @pdi: PDI to be used
18705d6b3c8bSVinod Koul */
sdw_cdns_config_stream(struct sdw_cdns * cdns,u32 ch,u32 dir,struct sdw_cdns_pdi * pdi)18715d6b3c8bSVinod Koul void sdw_cdns_config_stream(struct sdw_cdns *cdns,
18725d6b3c8bSVinod Koul u32 ch, u32 dir, struct sdw_cdns_pdi *pdi)
18735d6b3c8bSVinod Koul {
18745d6b3c8bSVinod Koul u32 offset, val = 0;
18755d6b3c8bSVinod Koul
18769e4e6019SPierre-Louis Bossart if (dir == SDW_DATA_DIR_RX) {
18775d6b3c8bSVinod Koul val = CDNS_PORTCTRL_DIRN;
18785d6b3c8bSVinod Koul
18799e4e6019SPierre-Louis Bossart if (cdns->bus.params.m_data_mode != SDW_PORT_DATA_MODE_NORMAL)
18809e4e6019SPierre-Louis Bossart val |= CDNS_PORTCTRL_TEST_FAILED;
18819e4e6019SPierre-Louis Bossart }
188257a34790SPierre-Louis Bossart offset = CDNS_PORTCTRL + pdi->num * CDNS_PORT_OFFSET;
18839e4e6019SPierre-Louis Bossart cdns_updatel(cdns, offset,
18849e4e6019SPierre-Louis Bossart CDNS_PORTCTRL_DIRN | CDNS_PORTCTRL_TEST_FAILED,
18859e4e6019SPierre-Louis Bossart val);
18865d6b3c8bSVinod Koul
188757a34790SPierre-Louis Bossart val = pdi->num;
1888b468a785Sranderwang val |= CDNS_PDI_CONFIG_SOFT_RESET;
18893cf25d63SVinod Koul val |= FIELD_PREP(CDNS_PDI_CONFIG_CHANNEL, (1 << ch) - 1);
18905d6b3c8bSVinod Koul cdns_writel(cdns, CDNS_PDI_CONFIG(pdi->num), val);
18915d6b3c8bSVinod Koul }
18925d6b3c8bSVinod Koul EXPORT_SYMBOL(sdw_cdns_config_stream);
18935d6b3c8bSVinod Koul
18945d6b3c8bSVinod Koul /**
189557a34790SPierre-Louis Bossart * sdw_cdns_alloc_pdi() - Allocate a PDI
18965d6b3c8bSVinod Koul *
18975d6b3c8bSVinod Koul * @cdns: Cadence instance
18985d6b3c8bSVinod Koul * @stream: Stream to be allocated
18995d6b3c8bSVinod Koul * @ch: Channel count
19005d6b3c8bSVinod Koul * @dir: Data direction
190139737a31SPierre-Louis Bossart * @dai_id: DAI id
19025d6b3c8bSVinod Koul */
sdw_cdns_alloc_pdi(struct sdw_cdns * cdns,struct sdw_cdns_streams * stream,u32 ch,u32 dir,int dai_id)190357a34790SPierre-Louis Bossart struct sdw_cdns_pdi *sdw_cdns_alloc_pdi(struct sdw_cdns *cdns,
19045d6b3c8bSVinod Koul struct sdw_cdns_streams *stream,
19051b53385eSBard Liao u32 ch, u32 dir, int dai_id)
19065d6b3c8bSVinod Koul {
19075d6b3c8bSVinod Koul struct sdw_cdns_pdi *pdi = NULL;
19085d6b3c8bSVinod Koul
19095d6b3c8bSVinod Koul if (dir == SDW_DATA_DIR_RX)
19101b53385eSBard Liao pdi = cdns_find_pdi(cdns, 0, stream->num_in, stream->in,
19111b53385eSBard Liao dai_id);
19125d6b3c8bSVinod Koul else
19131b53385eSBard Liao pdi = cdns_find_pdi(cdns, 0, stream->num_out, stream->out,
19141b53385eSBard Liao dai_id);
19155d6b3c8bSVinod Koul
19165d6b3c8bSVinod Koul /* check if we found a PDI, else find in bi-directional */
19175d6b3c8bSVinod Koul if (!pdi)
19187eeef1e9SPierre-Louis Bossart pdi = cdns_find_pdi(cdns, 0, stream->num_bd, stream->bd,
19191b53385eSBard Liao dai_id);
19205d6b3c8bSVinod Koul
192157a34790SPierre-Louis Bossart if (pdi) {
19225d6b3c8bSVinod Koul pdi->l_ch_num = 0;
19235d6b3c8bSVinod Koul pdi->h_ch_num = ch - 1;
19245d6b3c8bSVinod Koul pdi->dir = dir;
19255d6b3c8bSVinod Koul pdi->ch_count = ch;
19265d6b3c8bSVinod Koul }
192757a34790SPierre-Louis Bossart
192857a34790SPierre-Louis Bossart return pdi;
192957a34790SPierre-Louis Bossart }
193057a34790SPierre-Louis Bossart EXPORT_SYMBOL(sdw_cdns_alloc_pdi);
19315d6b3c8bSVinod Koul
19322f52a517SVinod Koul MODULE_LICENSE("Dual BSD/GPL");
19332f52a517SVinod Koul MODULE_DESCRIPTION("Cadence Soundwire Library");
1934