Blame view

drivers/soundwire/cadence_master.c 42.7 KB
2f52a5177   Vinod Koul   soundwire: cdns: ...
1
2
3
4
5
6
7
8
9
10
  // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
  // Copyright(c) 2015-17 Intel Corporation.
  
  /*
   * Cadence SoundWire Master module
   * Used by Master driver
   */
  
  #include <linux/delay.h>
  #include <linux/device.h>
aa85066e5   Pierre-Louis Bossart   soundwire: cadenc...
11
  #include <linux/debugfs.h>
2f52a5177   Vinod Koul   soundwire: cdns: ...
12
  #include <linux/interrupt.h>
18de65d9e   Jan Kotas   soundwire: cdns: ...
13
  #include <linux/io.h>
2f52a5177   Vinod Koul   soundwire: cdns: ...
14
15
  #include <linux/module.h>
  #include <linux/mod_devicetable.h>
32d2a8935   Pierre-Louis Bossart   soundwire: cadenc...
16
  #include <linux/pm_runtime.h>
2f52a5177   Vinod Koul   soundwire: cdns: ...
17
18
  #include <linux/soundwire/sdw_registers.h>
  #include <linux/soundwire/sdw.h>
5d6b3c8ba   Vinod Koul   soundwire: cdns: ...
19
20
  #include <sound/pcm_params.h>
  #include <sound/soc.h>
4a98a6b2f   Bard Liao   soundwire: intel/...
21
  #include <linux/workqueue.h>
2f52a5177   Vinod Koul   soundwire: cdns: ...
22
23
  #include "bus.h"
  #include "cadence_master.h"
04592dced   Pierre-Louis Bossart   soundwire: cadenc...
24
25
26
  static int interrupt_mask;
  module_param_named(cnds_mcp_int_mask, interrupt_mask, int, 0444);
  MODULE_PARM_DESC(cdns_mcp_int_mask, "Cadence MCP IntMask");
2f52a5177   Vinod Koul   soundwire: cdns: ...
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
  #define CDNS_MCP_CONFIG				0x0
  
  #define CDNS_MCP_CONFIG_MCMD_RETRY		GENMASK(27, 24)
  #define CDNS_MCP_CONFIG_MPREQ_DELAY		GENMASK(20, 16)
  #define CDNS_MCP_CONFIG_MMASTER			BIT(7)
  #define CDNS_MCP_CONFIG_BUS_REL			BIT(6)
  #define CDNS_MCP_CONFIG_SNIFFER			BIT(5)
  #define CDNS_MCP_CONFIG_SSPMOD			BIT(4)
  #define CDNS_MCP_CONFIG_CMD			BIT(3)
  #define CDNS_MCP_CONFIG_OP			GENMASK(2, 0)
  #define CDNS_MCP_CONFIG_OP_NORMAL		0
  
  #define CDNS_MCP_CONTROL			0x4
  
  #define CDNS_MCP_CONTROL_RST_DELAY		GENMASK(10, 8)
  #define CDNS_MCP_CONTROL_CMD_RST		BIT(7)
  #define CDNS_MCP_CONTROL_SOFT_RST		BIT(6)
  #define CDNS_MCP_CONTROL_SW_RST			BIT(5)
  #define CDNS_MCP_CONTROL_HW_RST			BIT(4)
  #define CDNS_MCP_CONTROL_CLK_PAUSE		BIT(3)
  #define CDNS_MCP_CONTROL_CLK_STOP_CLR		BIT(2)
  #define CDNS_MCP_CONTROL_CMD_ACCEPT		BIT(1)
  #define CDNS_MCP_CONTROL_BLOCK_WAKEUP		BIT(0)
2f52a5177   Vinod Koul   soundwire: cdns: ...
50
  #define CDNS_MCP_CMDCTRL			0x8
32d2a8935   Pierre-Louis Bossart   soundwire: cadenc...
51
52
  
  #define CDNS_MCP_CMDCTRL_INSERT_PARITY_ERR	BIT(2)
2f52a5177   Vinod Koul   soundwire: cdns: ...
53
54
55
  #define CDNS_MCP_SSPSTAT			0xC
  #define CDNS_MCP_FRAME_SHAPE			0x10
  #define CDNS_MCP_FRAME_SHAPE_INIT		0x14
05be59ac4   Pierre-Louis Bossart   soundwire: cadenc...
56
  #define CDNS_MCP_FRAME_SHAPE_COL_MASK		GENMASK(2, 0)
3cf25d63b   Vinod Koul   soundwire: cadenc...
57
  #define CDNS_MCP_FRAME_SHAPE_ROW_MASK		GENMASK(7, 3)
2f52a5177   Vinod Koul   soundwire: cdns: ...
58
59
60
61
62
63
64
65
66
  
  #define CDNS_MCP_CONFIG_UPDATE			0x18
  #define CDNS_MCP_CONFIG_UPDATE_BIT		BIT(0)
  
  #define CDNS_MCP_PHYCTRL			0x1C
  #define CDNS_MCP_SSP_CTRL0			0x20
  #define CDNS_MCP_SSP_CTRL1			0x28
  #define CDNS_MCP_CLK_CTRL0			0x30
  #define CDNS_MCP_CLK_CTRL1			0x38
a50954e21   Rander Wang   soundwire: cadenc...
67
  #define CDNS_MCP_CLK_MCLKD_MASK		GENMASK(7, 0)
2f52a5177   Vinod Koul   soundwire: cdns: ...
68
69
70
71
72
73
74
75
76
77
  
  #define CDNS_MCP_STAT				0x40
  
  #define CDNS_MCP_STAT_ACTIVE_BANK		BIT(20)
  #define CDNS_MCP_STAT_CLK_STOP			BIT(16)
  
  #define CDNS_MCP_INTSTAT			0x44
  #define CDNS_MCP_INTMASK			0x48
  
  #define CDNS_MCP_INT_IRQ			BIT(31)
a2cff9ee4   Pierre-Louis Bossart   soundwire: cadenc...
78
  #define CDNS_MCP_INT_RESERVED1			GENMASK(30, 17)
2f52a5177   Vinod Koul   soundwire: cdns: ...
79
80
81
82
83
84
85
86
87
  #define CDNS_MCP_INT_WAKEUP			BIT(16)
  #define CDNS_MCP_INT_SLAVE_RSVD			BIT(15)
  #define CDNS_MCP_INT_SLAVE_ALERT		BIT(14)
  #define CDNS_MCP_INT_SLAVE_ATTACH		BIT(13)
  #define CDNS_MCP_INT_SLAVE_NATTACH		BIT(12)
  #define CDNS_MCP_INT_SLAVE_MASK			GENMASK(15, 12)
  #define CDNS_MCP_INT_DPINT			BIT(11)
  #define CDNS_MCP_INT_CTRL_CLASH			BIT(10)
  #define CDNS_MCP_INT_DATA_CLASH			BIT(9)
9b5884a0c   Pierre-Louis Bossart   soundwire: cadenc...
88
  #define CDNS_MCP_INT_PARITY			BIT(8)
2f52a5177   Vinod Koul   soundwire: cdns: ...
89
  #define CDNS_MCP_INT_CMD_ERR			BIT(7)
a2cff9ee4   Pierre-Louis Bossart   soundwire: cadenc...
90
  #define CDNS_MCP_INT_RESERVED2			GENMASK(6, 4)
9b5884a0c   Pierre-Louis Bossart   soundwire: cadenc...
91
  #define CDNS_MCP_INT_RX_NE			BIT(3)
2f52a5177   Vinod Koul   soundwire: cdns: ...
92
93
  #define CDNS_MCP_INT_RX_WL			BIT(2)
  #define CDNS_MCP_INT_TXE			BIT(1)
9b5884a0c   Pierre-Louis Bossart   soundwire: cadenc...
94
  #define CDNS_MCP_INT_TXF			BIT(0)
a2cff9ee4   Pierre-Louis Bossart   soundwire: cadenc...
95
  #define CDNS_MCP_INT_RESERVED (CDNS_MCP_INT_RESERVED1 | CDNS_MCP_INT_RESERVED2)
2f52a5177   Vinod Koul   soundwire: cdns: ...
96
97
  
  #define CDNS_MCP_INTSET				0x4C
b07dd9b40   Pierre-Louis Bossart   soundwire: cadenc...
98
99
  #define CDNS_MCP_SLAVE_STAT			0x50
  #define CDNS_MCP_SLAVE_STAT_MASK		GENMASK(1, 0)
2f52a5177   Vinod Koul   soundwire: cdns: ...
100
101
102
103
104
105
106
107
108
109
110
111
  
  #define CDNS_MCP_SLAVE_INTSTAT0			0x54
  #define CDNS_MCP_SLAVE_INTSTAT1			0x58
  #define CDNS_MCP_SLAVE_INTSTAT_NPRESENT		BIT(0)
  #define CDNS_MCP_SLAVE_INTSTAT_ATTACHED		BIT(1)
  #define CDNS_MCP_SLAVE_INTSTAT_ALERT		BIT(2)
  #define CDNS_MCP_SLAVE_INTSTAT_RESERVED		BIT(3)
  #define CDNS_MCP_SLAVE_STATUS_BITS		GENMASK(3, 0)
  #define CDNS_MCP_SLAVE_STATUS_NUM		4
  
  #define CDNS_MCP_SLAVE_INTMASK0			0x5C
  #define CDNS_MCP_SLAVE_INTMASK1			0x60
664b16589   Pierre-Louis Bossart   soundwire: cadenc...
112
113
  #define CDNS_MCP_SLAVE_INTMASK0_MASK		GENMASK(31, 0)
  #define CDNS_MCP_SLAVE_INTMASK1_MASK		GENMASK(15, 0)
2f52a5177   Vinod Koul   soundwire: cdns: ...
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
  
  #define CDNS_MCP_PORT_INTSTAT			0x64
  #define CDNS_MCP_PDI_STAT			0x6C
  
  #define CDNS_MCP_FIFOLEVEL			0x78
  #define CDNS_MCP_FIFOSTAT			0x7C
  #define CDNS_MCP_RX_FIFO_AVAIL			GENMASK(5, 0)
  
  #define CDNS_MCP_CMD_BASE			0x80
  #define CDNS_MCP_RESP_BASE			0x80
  #define CDNS_MCP_CMD_LEN			0x20
  #define CDNS_MCP_CMD_WORD_LEN			0x4
  
  #define CDNS_MCP_CMD_SSP_TAG			BIT(31)
  #define CDNS_MCP_CMD_COMMAND			GENMASK(30, 28)
  #define CDNS_MCP_CMD_DEV_ADDR			GENMASK(27, 24)
3cf25d63b   Vinod Koul   soundwire: cadenc...
130
  #define CDNS_MCP_CMD_REG_ADDR			GENMASK(23, 8)
2f52a5177   Vinod Koul   soundwire: cdns: ...
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
  #define CDNS_MCP_CMD_REG_DATA			GENMASK(7, 0)
  
  #define CDNS_MCP_CMD_READ			2
  #define CDNS_MCP_CMD_WRITE			3
  
  #define CDNS_MCP_RESP_RDATA			GENMASK(15, 8)
  #define CDNS_MCP_RESP_ACK			BIT(0)
  #define CDNS_MCP_RESP_NACK			BIT(1)
  
  #define CDNS_DP_SIZE				128
  
  #define CDNS_DPN_B0_CONFIG(n)			(0x100 + CDNS_DP_SIZE * (n))
  #define CDNS_DPN_B0_CH_EN(n)			(0x104 + CDNS_DP_SIZE * (n))
  #define CDNS_DPN_B0_SAMPLE_CTRL(n)		(0x108 + CDNS_DP_SIZE * (n))
  #define CDNS_DPN_B0_OFFSET_CTRL(n)		(0x10C + CDNS_DP_SIZE * (n))
  #define CDNS_DPN_B0_HCTRL(n)			(0x110 + CDNS_DP_SIZE * (n))
  #define CDNS_DPN_B0_ASYNC_CTRL(n)		(0x114 + CDNS_DP_SIZE * (n))
  
  #define CDNS_DPN_B1_CONFIG(n)			(0x118 + CDNS_DP_SIZE * (n))
  #define CDNS_DPN_B1_CH_EN(n)			(0x11C + CDNS_DP_SIZE * (n))
  #define CDNS_DPN_B1_SAMPLE_CTRL(n)		(0x120 + CDNS_DP_SIZE * (n))
  #define CDNS_DPN_B1_OFFSET_CTRL(n)		(0x124 + CDNS_DP_SIZE * (n))
  #define CDNS_DPN_B1_HCTRL(n)			(0x128 + CDNS_DP_SIZE * (n))
  #define CDNS_DPN_B1_ASYNC_CTRL(n)		(0x12C + CDNS_DP_SIZE * (n))
  
  #define CDNS_DPN_CONFIG_BPM			BIT(18)
  #define CDNS_DPN_CONFIG_BGC			GENMASK(17, 16)
  #define CDNS_DPN_CONFIG_WL			GENMASK(12, 8)
  #define CDNS_DPN_CONFIG_PORT_DAT		GENMASK(3, 2)
  #define CDNS_DPN_CONFIG_PORT_FLOW		GENMASK(1, 0)
  
  #define CDNS_DPN_SAMPLE_CTRL_SI			GENMASK(15, 0)
  
  #define CDNS_DPN_OFFSET_CTRL_1			GENMASK(7, 0)
  #define CDNS_DPN_OFFSET_CTRL_2			GENMASK(15, 8)
  
  #define CDNS_DPN_HCTRL_HSTOP			GENMASK(3, 0)
  #define CDNS_DPN_HCTRL_HSTART			GENMASK(7, 4)
  #define CDNS_DPN_HCTRL_LCTRL			GENMASK(10, 8)
  
  #define CDNS_PORTCTRL				0x130
9e4e6019e   Pierre-Louis Bossart   soundwire: cadenc...
172
  #define CDNS_PORTCTRL_TEST_FAILED		BIT(1)
2f52a5177   Vinod Koul   soundwire: cdns: ...
173
174
175
176
177
178
179
180
181
182
183
184
  #define CDNS_PORTCTRL_DIRN			BIT(7)
  #define CDNS_PORTCTRL_BANK_INVERT		BIT(8)
  
  #define CDNS_PORT_OFFSET			0x80
  
  #define CDNS_PDI_CONFIG(n)			(0x1100 + (n) * 16)
  
  #define CDNS_PDI_CONFIG_SOFT_RESET		BIT(24)
  #define CDNS_PDI_CONFIG_CHANNEL			GENMASK(15, 8)
  #define CDNS_PDI_CONFIG_PORT			GENMASK(4, 0)
  
  /* Driver defaults */
2f52a5177   Vinod Koul   soundwire: cdns: ...
185
  #define CDNS_TX_TIMEOUT				2000
2f52a5177   Vinod Koul   soundwire: cdns: ...
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
  #define CDNS_SCP_RX_FIFOLEVEL			0x2
  
  /*
   * register accessor helpers
   */
  static inline u32 cdns_readl(struct sdw_cdns *cdns, int offset)
  {
  	return readl(cdns->registers + offset);
  }
  
  static inline void cdns_writel(struct sdw_cdns *cdns, int offset, u32 value)
  {
  	writel(value, cdns->registers + offset);
  }
  
  static inline void cdns_updatel(struct sdw_cdns *cdns,
  				int offset, u32 mask, u32 val)
  {
  	u32 tmp;
  
  	tmp = cdns_readl(cdns, offset);
  	tmp = (tmp & ~mask) | val;
  	cdns_writel(cdns, offset, tmp);
  }
1032504f2   Rander Wang   soundwire: cadenc...
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
  static int cdns_set_wait(struct sdw_cdns *cdns, int offset, u32 mask, u32 value)
  {
  	int timeout = 10;
  	u32 reg_read;
  
  	/* Wait for bit to be set */
  	do {
  		reg_read = readl(cdns->registers + offset);
  		if ((reg_read & mask) == value)
  			return 0;
  
  		timeout--;
  		usleep_range(50, 100);
  	} while (timeout != 0);
  
  	return -ETIMEDOUT;
  }
12632459f   Pierre-Louis Bossart   soundwire: cadenc...
227
228
229
230
231
232
233
  static int cdns_clear_bit(struct sdw_cdns *cdns, int offset, u32 value)
  {
  	writel(value, cdns->registers + offset);
  
  	/* Wait for bit to be self cleared */
  	return cdns_set_wait(cdns, offset, value, 0);
  }
2f52a5177   Vinod Koul   soundwire: cdns: ...
234
  /*
49ea07d33   Pierre-Louis Bossart   soundwire: intel/...
235
236
237
   * all changes to the MCP_CONFIG, MCP_CONTROL, MCP_CMDCTRL and MCP_PHYCTRL
   * need to be confirmed with a write to MCP_CONFIG_UPDATE
   */
ce1acf019   Pierre-Louis Bossart   soundwire: cadenc...
238
  static int cdns_config_update(struct sdw_cdns *cdns)
49ea07d33   Pierre-Louis Bossart   soundwire: intel/...
239
240
  {
  	int ret;
9bc87cce9   Pierre-Louis Bossart   soundwire: cadenc...
241
242
243
244
245
  	if (sdw_cdns_is_clock_stop(cdns)) {
  		dev_err(cdns->dev, "Cannot program MCP_CONFIG_UPDATE in ClockStopMode
  ");
  		return -EINVAL;
  	}
49ea07d33   Pierre-Louis Bossart   soundwire: intel/...
246
247
248
249
250
251
252
253
254
255
  	ret = cdns_clear_bit(cdns, CDNS_MCP_CONFIG_UPDATE,
  			     CDNS_MCP_CONFIG_UPDATE_BIT);
  	if (ret < 0)
  		dev_err(cdns->dev, "Config update timedout
  ");
  
  	return ret;
  }
  
  /*
aa85066e5   Pierre-Louis Bossart   soundwire: cadenc...
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
   * debugfs
   */
  #ifdef CONFIG_DEBUG_FS
  
  #define RD_BUF (2 * PAGE_SIZE)
  
  static ssize_t cdns_sprintf(struct sdw_cdns *cdns,
  			    char *buf, size_t pos, unsigned int reg)
  {
  	return scnprintf(buf + pos, RD_BUF - pos,
  			 "%4x\t%8x
  ", reg, cdns_readl(cdns, reg));
  }
  
  static int cdns_reg_show(struct seq_file *s, void *data)
  {
  	struct sdw_cdns *cdns = s->private;
  	char *buf;
  	ssize_t ret;
  	int num_ports;
  	int i, j;
  
  	buf = kzalloc(RD_BUF, GFP_KERNEL);
  	if (!buf)
  		return -ENOMEM;
  
  	ret = scnprintf(buf, RD_BUF, "Register  Value
  ");
  	ret += scnprintf(buf + ret, RD_BUF - ret, "
  MCP Registers
  ");
  	/* 8 MCP registers */
  	for (i = CDNS_MCP_CONFIG; i <= CDNS_MCP_PHYCTRL; i += sizeof(u32))
  		ret += cdns_sprintf(cdns, buf, ret, i);
  
  	ret += scnprintf(buf + ret, RD_BUF - ret,
  			 "
  Status & Intr Registers
  ");
  	/* 13 Status & Intr registers (offsets 0x70 and 0x74 not defined) */
  	for (i = CDNS_MCP_STAT; i <=  CDNS_MCP_FIFOSTAT; i += sizeof(u32))
  		ret += cdns_sprintf(cdns, buf, ret, i);
  
  	ret += scnprintf(buf + ret, RD_BUF - ret,
  			 "
  SSP & Clk ctrl Registers
  ");
  	ret += cdns_sprintf(cdns, buf, ret, CDNS_MCP_SSP_CTRL0);
  	ret += cdns_sprintf(cdns, buf, ret, CDNS_MCP_SSP_CTRL1);
  	ret += cdns_sprintf(cdns, buf, ret, CDNS_MCP_CLK_CTRL0);
  	ret += cdns_sprintf(cdns, buf, ret, CDNS_MCP_CLK_CTRL1);
  
  	ret += scnprintf(buf + ret, RD_BUF - ret,
  			 "
  DPn B0 Registers
  ");
807c15bc7   Pierre-Louis Bossart   soundwire: intel:...
312
  	num_ports = cdns->num_ports;
aa85066e5   Pierre-Louis Bossart   soundwire: cadenc...
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
  
  	for (i = 0; i < num_ports; i++) {
  		ret += scnprintf(buf + ret, RD_BUF - ret,
  				 "
  DP-%d
  ", i);
  		for (j = CDNS_DPN_B0_CONFIG(i);
  		     j < CDNS_DPN_B0_ASYNC_CTRL(i); j += sizeof(u32))
  			ret += cdns_sprintf(cdns, buf, ret, j);
  	}
  
  	ret += scnprintf(buf + ret, RD_BUF - ret,
  			 "
  DPn B1 Registers
  ");
  	for (i = 0; i < num_ports; i++) {
  		ret += scnprintf(buf + ret, RD_BUF - ret,
  				 "
  DP-%d
  ", i);
  
  		for (j = CDNS_DPN_B1_CONFIG(i);
  		     j < CDNS_DPN_B1_ASYNC_CTRL(i); j += sizeof(u32))
  			ret += cdns_sprintf(cdns, buf, ret, j);
  	}
  
  	ret += scnprintf(buf + ret, RD_BUF - ret,
  			 "
  DPn Control Registers
  ");
  	for (i = 0; i < num_ports; i++)
  		ret += cdns_sprintf(cdns, buf, ret,
  				CDNS_PORTCTRL + i * CDNS_PORT_OFFSET);
  
  	ret += scnprintf(buf + ret, RD_BUF - ret,
  			 "
  PDIn Config Registers
  ");
  
  	/* number of PDI and ports is interchangeable */
  	for (i = 0; i < num_ports; i++)
  		ret += cdns_sprintf(cdns, buf, ret, CDNS_PDI_CONFIG(i));
  
  	seq_printf(s, "%s", buf);
  	kfree(buf);
  
  	return 0;
  }
  DEFINE_SHOW_ATTRIBUTE(cdns_reg);
675d4c9ab   Pierre-Louis Bossart   soundwire: cadenc...
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
  static int cdns_hw_reset(void *data, u64 value)
  {
  	struct sdw_cdns *cdns = data;
  	int ret;
  
  	if (value != 1)
  		return -EINVAL;
  
  	/* Userspace changed the hardware state behind the kernel's back */
  	add_taint(TAINT_USER, LOCKDEP_STILL_OK);
  
  	ret = sdw_cdns_exit_reset(cdns);
  
  	dev_dbg(cdns->dev, "link hw_reset done: %d
  ", ret);
  
  	return ret;
  }
  
  DEFINE_DEBUGFS_ATTRIBUTE(cdns_hw_reset_fops, NULL, cdns_hw_reset, "%llu
  ");
32d2a8935   Pierre-Louis Bossart   soundwire: cadenc...
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
  static int cdns_parity_error_injection(void *data, u64 value)
  {
  	struct sdw_cdns *cdns = data;
  	struct sdw_bus *bus;
  	int ret;
  
  	if (value != 1)
  		return -EINVAL;
  
  	bus = &cdns->bus;
  
  	/*
  	 * Resume Master device. If this results in a bus reset, the
  	 * Slave devices will re-attach and be re-enumerated.
  	 */
  	ret = pm_runtime_get_sync(bus->dev);
  	if (ret < 0 && ret != -EACCES) {
  		dev_err_ratelimited(cdns->dev,
  				    "pm_runtime_get_sync failed in %s, ret %d
  ",
  				    __func__, ret);
  		pm_runtime_put_noidle(bus->dev);
  		return ret;
  	}
  
  	/*
  	 * wait long enough for Slave(s) to be in steady state. This
  	 * does not need to be super precise.
  	 */
  	msleep(200);
  
  	/*
  	 * Take the bus lock here to make sure that any bus transactions
  	 * will be queued while we inject a parity error on a dummy read
  	 */
  	mutex_lock(&bus->bus_lock);
  
  	/* program hardware to inject parity error */
  	cdns_updatel(cdns, CDNS_MCP_CMDCTRL,
  		     CDNS_MCP_CMDCTRL_INSERT_PARITY_ERR,
  		     CDNS_MCP_CMDCTRL_INSERT_PARITY_ERR);
  
  	/* commit changes */
  	cdns_updatel(cdns, CDNS_MCP_CONFIG_UPDATE,
  		     CDNS_MCP_CONFIG_UPDATE_BIT,
  		     CDNS_MCP_CONFIG_UPDATE_BIT);
  
  	/* do a broadcast dummy read to avoid bus clashes */
  	ret = sdw_bread_no_pm_unlocked(&cdns->bus, 0xf, SDW_SCP_DEVID_0);
  	dev_info(cdns->dev, "parity error injection, read: %d
  ", ret);
  
  	/* program hardware to disable parity error */
  	cdns_updatel(cdns, CDNS_MCP_CMDCTRL,
  		     CDNS_MCP_CMDCTRL_INSERT_PARITY_ERR,
  		     0);
  
  	/* commit changes */
  	cdns_updatel(cdns, CDNS_MCP_CONFIG_UPDATE,
  		     CDNS_MCP_CONFIG_UPDATE_BIT,
  		     CDNS_MCP_CONFIG_UPDATE_BIT);
  
  	/* Continue bus operation with parity error injection disabled */
  	mutex_unlock(&bus->bus_lock);
  
  	/* Userspace changed the hardware state behind the kernel's back */
  	add_taint(TAINT_USER, LOCKDEP_STILL_OK);
  
  	/*
  	 * allow Master device to enter pm_runtime suspend. This may
  	 * also result in Slave devices suspending.
  	 */
  	pm_runtime_mark_last_busy(bus->dev);
  	pm_runtime_put_autosuspend(bus->dev);
  
  	return 0;
  }
  
  DEFINE_DEBUGFS_ATTRIBUTE(cdns_parity_error_fops, NULL,
  			 cdns_parity_error_injection, "%llu
  ");
aa85066e5   Pierre-Louis Bossart   soundwire: cadenc...
464
465
466
467
468
469
470
471
  /**
   * sdw_cdns_debugfs_init() - Cadence debugfs init
   * @cdns: Cadence instance
   * @root: debugfs root
   */
  void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root)
  {
  	debugfs_create_file("cdns-registers", 0400, root, cdns, &cdns_reg_fops);
675d4c9ab   Pierre-Louis Bossart   soundwire: cadenc...
472
473
474
  
  	debugfs_create_file("cdns-hw-reset", 0200, root, cdns,
  			    &cdns_hw_reset_fops);
32d2a8935   Pierre-Louis Bossart   soundwire: cadenc...
475
476
477
  
  	debugfs_create_file("cdns-parity-error-injection", 0200, root, cdns,
  			    &cdns_parity_error_fops);
aa85066e5   Pierre-Louis Bossart   soundwire: cadenc...
478
479
480
481
482
483
  }
  EXPORT_SYMBOL_GPL(sdw_cdns_debugfs_init);
  
  #endif /* CONFIG_DEBUG_FS */
  
  /*
956baa199   Sanyog Kale   soundwire: cdns: ...
484
485
   * IO Calls
   */
bbb638172   Pierre-Louis Bossart   soundwire: cadenc...
486
487
488
  static enum sdw_command_response
  cdns_fill_msg_resp(struct sdw_cdns *cdns,
  		   struct sdw_msg *msg, int count, int offset)
956baa199   Sanyog Kale   soundwire: cdns: ...
489
490
491
492
493
494
495
496
  {
  	int nack = 0, no_ack = 0;
  	int i;
  
  	/* check message response */
  	for (i = 0; i < count; i++) {
  		if (!(cdns->response_buf[i] & CDNS_MCP_RESP_ACK)) {
  			no_ack = 1;
eb7df4c86   Pierre-Louis Bossart   soundwire: cadenc...
497
498
  			dev_dbg_ratelimited(cdns->dev, "Msg Ack not received
  ");
956baa199   Sanyog Kale   soundwire: cdns: ...
499
500
  			if (cdns->response_buf[i] & CDNS_MCP_RESP_NACK) {
  				nack = 1;
eb7df4c86   Pierre-Louis Bossart   soundwire: cadenc...
501
502
  				dev_err_ratelimited(cdns->dev, "Msg NACK received
  ");
956baa199   Sanyog Kale   soundwire: cdns: ...
503
504
505
506
507
  			}
  		}
  	}
  
  	if (nack) {
eb7df4c86   Pierre-Louis Bossart   soundwire: cadenc...
508
509
  		dev_err_ratelimited(cdns->dev, "Msg NACKed for Slave %d
  ", msg->dev_num);
956baa199   Sanyog Kale   soundwire: cdns: ...
510
  		return SDW_CMD_FAIL;
6f7219fec   Guennadi Liakhovetski   soundwire: intel:...
511
512
513
  	}
  
  	if (no_ack) {
eb7df4c86   Pierre-Louis Bossart   soundwire: cadenc...
514
515
  		dev_dbg_ratelimited(cdns->dev, "Msg ignored for Slave %d
  ", msg->dev_num);
956baa199   Sanyog Kale   soundwire: cdns: ...
516
517
518
519
520
  		return SDW_CMD_IGNORED;
  	}
  
  	/* fill response */
  	for (i = 0; i < count; i++)
3cf25d63b   Vinod Koul   soundwire: cadenc...
521
  		msg->buf[i + offset] = FIELD_GET(CDNS_MCP_RESP_RDATA, cdns->response_buf[i]);
956baa199   Sanyog Kale   soundwire: cdns: ...
522
523
524
525
526
527
  
  	return SDW_CMD_OK;
  }
  
  static enum sdw_command_response
  _cdns_xfer_msg(struct sdw_cdns *cdns, struct sdw_msg *msg, int cmd,
bbb638172   Pierre-Louis Bossart   soundwire: cadenc...
528
  	       int offset, int count, bool defer)
956baa199   Sanyog Kale   soundwire: cdns: ...
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
  {
  	unsigned long time;
  	u32 base, i, data;
  	u16 addr;
  
  	/* Program the watermark level for RX FIFO */
  	if (cdns->msg_count != count) {
  		cdns_writel(cdns, CDNS_MCP_FIFOLEVEL, count);
  		cdns->msg_count = count;
  	}
  
  	base = CDNS_MCP_CMD_BASE;
  	addr = msg->addr;
  
  	for (i = 0; i < count; i++) {
3cf25d63b   Vinod Koul   soundwire: cadenc...
544
545
546
547
  		data = FIELD_PREP(CDNS_MCP_CMD_DEV_ADDR, msg->dev_num);
  		data |= FIELD_PREP(CDNS_MCP_CMD_COMMAND, cmd);
  		data |= FIELD_PREP(CDNS_MCP_CMD_REG_ADDR, addr);
  		addr++;
956baa199   Sanyog Kale   soundwire: cdns: ...
548
549
550
  
  		if (msg->flags == SDW_MSG_FLAG_WRITE)
  			data |= msg->buf[i + offset];
3cf25d63b   Vinod Koul   soundwire: cadenc...
551
  		data |= FIELD_PREP(CDNS_MCP_CMD_SSP_TAG, msg->ssp_sync);
956baa199   Sanyog Kale   soundwire: cdns: ...
552
553
554
555
556
557
558
559
560
  		cdns_writel(cdns, base, data);
  		base += CDNS_MCP_CMD_WORD_LEN;
  	}
  
  	if (defer)
  		return SDW_CMD_OK;
  
  	/* wait for timeout or response */
  	time = wait_for_completion_timeout(&cdns->tx_complete,
bbb638172   Pierre-Louis Bossart   soundwire: cadenc...
561
  					   msecs_to_jiffies(CDNS_TX_TIMEOUT));
956baa199   Sanyog Kale   soundwire: cdns: ...
562
  	if (!time) {
53ee95726   Pierre-Louis Bossart   soundwire: cadenc...
563
564
565
  		dev_err(cdns->dev, "IO transfer timed out, cmd %d device %d addr %x len %d
  ",
  			cmd, msg->dev_num, msg->addr, msg->len);
956baa199   Sanyog Kale   soundwire: cdns: ...
566
567
568
569
570
571
  		msg->len = 0;
  		return SDW_CMD_TIMEOUT;
  	}
  
  	return cdns_fill_msg_resp(cdns, msg, count, offset);
  }
bbb638172   Pierre-Louis Bossart   soundwire: cadenc...
572
573
  static enum sdw_command_response
  cdns_program_scp_addr(struct sdw_cdns *cdns, struct sdw_msg *msg)
956baa199   Sanyog Kale   soundwire: cdns: ...
574
575
576
577
578
579
580
581
582
583
584
  {
  	int nack = 0, no_ack = 0;
  	unsigned long time;
  	u32 data[2], base;
  	int i;
  
  	/* Program the watermark level for RX FIFO */
  	if (cdns->msg_count != CDNS_SCP_RX_FIFOLEVEL) {
  		cdns_writel(cdns, CDNS_MCP_FIFOLEVEL, CDNS_SCP_RX_FIFOLEVEL);
  		cdns->msg_count = CDNS_SCP_RX_FIFOLEVEL;
  	}
3cf25d63b   Vinod Koul   soundwire: cadenc...
585
586
  	data[0] = FIELD_PREP(CDNS_MCP_CMD_DEV_ADDR, msg->dev_num);
  	data[0] |= FIELD_PREP(CDNS_MCP_CMD_COMMAND, 0x3);
956baa199   Sanyog Kale   soundwire: cdns: ...
587
  	data[1] = data[0];
3cf25d63b   Vinod Koul   soundwire: cadenc...
588
589
  	data[0] |= FIELD_PREP(CDNS_MCP_CMD_REG_ADDR, SDW_SCP_ADDRPAGE1);
  	data[1] |= FIELD_PREP(CDNS_MCP_CMD_REG_ADDR, SDW_SCP_ADDRPAGE2);
956baa199   Sanyog Kale   soundwire: cdns: ...
590
591
592
593
594
595
596
597
598
599
  
  	data[0] |= msg->addr_page1;
  	data[1] |= msg->addr_page2;
  
  	base = CDNS_MCP_CMD_BASE;
  	cdns_writel(cdns, base, data[0]);
  	base += CDNS_MCP_CMD_WORD_LEN;
  	cdns_writel(cdns, base, data[1]);
  
  	time = wait_for_completion_timeout(&cdns->tx_complete,
bbb638172   Pierre-Louis Bossart   soundwire: cadenc...
600
  					   msecs_to_jiffies(CDNS_TX_TIMEOUT));
956baa199   Sanyog Kale   soundwire: cdns: ...
601
602
603
604
605
606
607
608
609
610
611
  	if (!time) {
  		dev_err(cdns->dev, "SCP Msg trf timed out
  ");
  		msg->len = 0;
  		return SDW_CMD_TIMEOUT;
  	}
  
  	/* check response the writes */
  	for (i = 0; i < 2; i++) {
  		if (!(cdns->response_buf[i] & CDNS_MCP_RESP_ACK)) {
  			no_ack = 1;
17ed5bef4   Pierre-Louis Bossart   soundwire: add mi...
612
613
  			dev_err(cdns->dev, "Program SCP Ack not received
  ");
956baa199   Sanyog Kale   soundwire: cdns: ...
614
615
  			if (cdns->response_buf[i] & CDNS_MCP_RESP_NACK) {
  				nack = 1;
17ed5bef4   Pierre-Louis Bossart   soundwire: add mi...
616
617
  				dev_err(cdns->dev, "Program SCP NACK received
  ");
956baa199   Sanyog Kale   soundwire: cdns: ...
618
619
620
621
622
623
  			}
  		}
  	}
  
  	/* For NACK, NO ack, don't return err if we are in Broadcast mode */
  	if (nack) {
eb7df4c86   Pierre-Louis Bossart   soundwire: cadenc...
624
625
626
  		dev_err_ratelimited(cdns->dev,
  				    "SCP_addrpage NACKed for Slave %d
  ", msg->dev_num);
956baa199   Sanyog Kale   soundwire: cdns: ...
627
  		return SDW_CMD_FAIL;
6f7219fec   Guennadi Liakhovetski   soundwire: intel:...
628
629
630
  	}
  
  	if (no_ack) {
eb7df4c86   Pierre-Louis Bossart   soundwire: cadenc...
631
632
633
  		dev_dbg_ratelimited(cdns->dev,
  				    "SCP_addrpage ignored for Slave %d
  ", msg->dev_num);
956baa199   Sanyog Kale   soundwire: cdns: ...
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
  		return SDW_CMD_IGNORED;
  	}
  
  	return SDW_CMD_OK;
  }
  
  static int cdns_prep_msg(struct sdw_cdns *cdns, struct sdw_msg *msg, int *cmd)
  {
  	int ret;
  
  	if (msg->page) {
  		ret = cdns_program_scp_addr(cdns, msg);
  		if (ret) {
  			msg->len = 0;
  			return ret;
  		}
  	}
  
  	switch (msg->flags) {
  	case SDW_MSG_FLAG_READ:
  		*cmd = CDNS_MCP_CMD_READ;
  		break;
  
  	case SDW_MSG_FLAG_WRITE:
  		*cmd = CDNS_MCP_CMD_WRITE;
  		break;
  
  	default:
  		dev_err(cdns->dev, "Invalid msg cmd: %d
  ", msg->flags);
  		return -EINVAL;
  	}
  
  	return 0;
  }
c91605f48   Shreyas NC   soundwire: Remove...
669
  enum sdw_command_response
956baa199   Sanyog Kale   soundwire: cdns: ...
670
671
672
673
674
675
676
677
678
679
680
  cdns_xfer_msg(struct sdw_bus *bus, struct sdw_msg *msg)
  {
  	struct sdw_cdns *cdns = bus_to_cdns(bus);
  	int cmd = 0, ret, i;
  
  	ret = cdns_prep_msg(cdns, msg, &cmd);
  	if (ret)
  		return SDW_CMD_FAIL_OTHER;
  
  	for (i = 0; i < msg->len / CDNS_MCP_CMD_LEN; i++) {
  		ret = _cdns_xfer_msg(cdns, msg, cmd, i * CDNS_MCP_CMD_LEN,
bbb638172   Pierre-Louis Bossart   soundwire: cadenc...
681
  				     CDNS_MCP_CMD_LEN, false);
956baa199   Sanyog Kale   soundwire: cdns: ...
682
683
684
685
686
687
688
689
  		if (ret < 0)
  			goto exit;
  	}
  
  	if (!(msg->len % CDNS_MCP_CMD_LEN))
  		goto exit;
  
  	ret = _cdns_xfer_msg(cdns, msg, cmd, i * CDNS_MCP_CMD_LEN,
bbb638172   Pierre-Louis Bossart   soundwire: cadenc...
690
  			     msg->len % CDNS_MCP_CMD_LEN, false);
956baa199   Sanyog Kale   soundwire: cdns: ...
691
692
693
694
  
  exit:
  	return ret;
  }
c91605f48   Shreyas NC   soundwire: Remove...
695
  EXPORT_SYMBOL(cdns_xfer_msg);
956baa199   Sanyog Kale   soundwire: cdns: ...
696

c91605f48   Shreyas NC   soundwire: Remove...
697
  enum sdw_command_response
956baa199   Sanyog Kale   soundwire: cdns: ...
698
  cdns_xfer_msg_defer(struct sdw_bus *bus,
bbb638172   Pierre-Louis Bossart   soundwire: cadenc...
699
  		    struct sdw_msg *msg, struct sdw_defer *defer)
956baa199   Sanyog Kale   soundwire: cdns: ...
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
  {
  	struct sdw_cdns *cdns = bus_to_cdns(bus);
  	int cmd = 0, ret;
  
  	/* for defer only 1 message is supported */
  	if (msg->len > 1)
  		return -ENOTSUPP;
  
  	ret = cdns_prep_msg(cdns, msg, &cmd);
  	if (ret)
  		return SDW_CMD_FAIL_OTHER;
  
  	cdns->defer = defer;
  	cdns->defer->length = msg->len;
  
  	return _cdns_xfer_msg(cdns, msg, cmd, 0, msg->len, true);
  }
c91605f48   Shreyas NC   soundwire: Remove...
717
  EXPORT_SYMBOL(cdns_xfer_msg_defer);
956baa199   Sanyog Kale   soundwire: cdns: ...
718

c91605f48   Shreyas NC   soundwire: Remove...
719
  enum sdw_command_response
956baa199   Sanyog Kale   soundwire: cdns: ...
720
721
722
723
724
725
726
727
728
729
730
  cdns_reset_page_addr(struct sdw_bus *bus, unsigned int dev_num)
  {
  	struct sdw_cdns *cdns = bus_to_cdns(bus);
  	struct sdw_msg msg;
  
  	/* Create dummy message with valid device number */
  	memset(&msg, 0, sizeof(msg));
  	msg.dev_num = dev_num;
  
  	return cdns_program_scp_addr(cdns, &msg);
  }
c91605f48   Shreyas NC   soundwire: Remove...
731
  EXPORT_SYMBOL(cdns_reset_page_addr);
956baa199   Sanyog Kale   soundwire: cdns: ...
732
733
  
  /*
2f52a5177   Vinod Koul   soundwire: cdns: ...
734
735
   * IRQ handling
   */
956baa199   Sanyog Kale   soundwire: cdns: ...
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
  static void cdns_read_response(struct sdw_cdns *cdns)
  {
  	u32 num_resp, cmd_base;
  	int i;
  
  	num_resp = cdns_readl(cdns, CDNS_MCP_FIFOSTAT);
  	num_resp &= CDNS_MCP_RX_FIFO_AVAIL;
  
  	cmd_base = CDNS_MCP_CMD_BASE;
  
  	for (i = 0; i < num_resp; i++) {
  		cdns->response_buf[i] = cdns_readl(cdns, cmd_base);
  		cmd_base += CDNS_MCP_CMD_WORD_LEN;
  	}
  }
2f52a5177   Vinod Koul   soundwire: cdns: ...
751
  static int cdns_update_slave_status(struct sdw_cdns *cdns,
bbb638172   Pierre-Louis Bossart   soundwire: cadenc...
752
  				    u32 slave0, u32 slave1)
2f52a5177   Vinod Koul   soundwire: cdns: ...
753
754
755
  {
  	enum sdw_slave_status status[SDW_MAX_DEVICES + 1];
  	bool is_slave = false;
a78b32d9c   Pierre-Louis Bossart   soundwire: cadenc...
756
757
  	u64 slave;
  	u32 mask;
2f52a5177   Vinod Koul   soundwire: cdns: ...
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
  	int i, set_status;
  
  	/* combine the two status */
  	slave = ((u64)slave1 << 32) | slave0;
  	memset(status, 0, sizeof(status));
  
  	for (i = 0; i <= SDW_MAX_DEVICES; i++) {
  		mask = (slave >> (i * CDNS_MCP_SLAVE_STATUS_NUM)) &
  				CDNS_MCP_SLAVE_STATUS_BITS;
  		if (!mask)
  			continue;
  
  		is_slave = true;
  		set_status = 0;
  
  		if (mask & CDNS_MCP_SLAVE_INTSTAT_RESERVED) {
  			status[i] = SDW_SLAVE_RESERVED;
  			set_status++;
  		}
  
  		if (mask & CDNS_MCP_SLAVE_INTSTAT_ATTACHED) {
  			status[i] = SDW_SLAVE_ATTACHED;
  			set_status++;
  		}
  
  		if (mask & CDNS_MCP_SLAVE_INTSTAT_ALERT) {
  			status[i] = SDW_SLAVE_ALERT;
  			set_status++;
  		}
  
  		if (mask & CDNS_MCP_SLAVE_INTSTAT_NPRESENT) {
  			status[i] = SDW_SLAVE_UNATTACHED;
  			set_status++;
  		}
  
  		/* first check if Slave reported multiple status */
  		if (set_status > 1) {
7181b1d41   Pierre-Louis Bossart   soundwire: cadenc...
795
  			u32 val;
eb7df4c86   Pierre-Louis Bossart   soundwire: cadenc...
796
  			dev_warn_ratelimited(cdns->dev,
7181b1d41   Pierre-Louis Bossart   soundwire: cadenc...
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
  					     "Slave %d reported multiple Status: %d
  ",
  					     i, mask);
  
  			/* check latest status extracted from PING commands */
  			val = cdns_readl(cdns, CDNS_MCP_SLAVE_STAT);
  			val >>= (i * 2);
  
  			switch (val & 0x3) {
  			case 0:
  				status[i] = SDW_SLAVE_UNATTACHED;
  				break;
  			case 1:
  				status[i] = SDW_SLAVE_ATTACHED;
  				break;
  			case 2:
  				status[i] = SDW_SLAVE_ALERT;
  				break;
  			case 3:
  			default:
  				status[i] = SDW_SLAVE_RESERVED;
  				break;
  			}
  
  			dev_warn_ratelimited(cdns->dev,
  					     "Slave %d status updated to %d
  ",
  					     i, status[i]);
2f52a5177   Vinod Koul   soundwire: cdns: ...
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
  		}
  	}
  
  	if (is_slave)
  		return sdw_handle_slave_status(&cdns->bus, status);
  
  	return 0;
  }
  
  /**
   * sdw_cdns_irq() - Cadence interrupt handler
   * @irq: irq number
   * @dev_id: irq context
   */
  irqreturn_t sdw_cdns_irq(int irq, void *dev_id)
  {
  	struct sdw_cdns *cdns = dev_id;
  	u32 int_status;
  	int ret = IRQ_HANDLED;
  
  	/* Check if the link is up */
  	if (!cdns->link_up)
  		return IRQ_NONE;
  
  	int_status = cdns_readl(cdns, CDNS_MCP_INTSTAT);
a2cff9ee4   Pierre-Louis Bossart   soundwire: cadenc...
850
851
852
  	/* check for reserved values read as zero */
  	if (int_status & CDNS_MCP_INT_RESERVED)
  		return IRQ_NONE;
2f52a5177   Vinod Koul   soundwire: cdns: ...
853
854
  	if (!(int_status & CDNS_MCP_INT_IRQ))
  		return IRQ_NONE;
956baa199   Sanyog Kale   soundwire: cdns: ...
855
856
857
858
859
  	if (int_status & CDNS_MCP_INT_RX_WL) {
  		cdns_read_response(cdns);
  
  		if (cdns->defer) {
  			cdns_fill_msg_resp(cdns, cdns->defer->msg,
bbb638172   Pierre-Louis Bossart   soundwire: cadenc...
860
  					   cdns->defer->length, 0);
956baa199   Sanyog Kale   soundwire: cdns: ...
861
862
  			complete(&cdns->defer->complete);
  			cdns->defer = NULL;
f6e20967d   Pierre-Louis Bossart   soundwire: cadenc...
863
  		} else {
956baa199   Sanyog Kale   soundwire: cdns: ...
864
  			complete(&cdns->tx_complete);
f6e20967d   Pierre-Louis Bossart   soundwire: cadenc...
865
  		}
956baa199   Sanyog Kale   soundwire: cdns: ...
866
  	}
9b5884a0c   Pierre-Louis Bossart   soundwire: cadenc...
867
868
869
870
871
  	if (int_status & CDNS_MCP_INT_PARITY) {
  		/* Parity error detected by Master */
  		dev_err_ratelimited(cdns->dev, "Parity error
  ");
  	}
2f52a5177   Vinod Koul   soundwire: cdns: ...
872
  	if (int_status & CDNS_MCP_INT_CTRL_CLASH) {
2f52a5177   Vinod Koul   soundwire: cdns: ...
873
874
875
  		/* Slave is driving bit slot during control word */
  		dev_err_ratelimited(cdns->dev, "Bus clash for control word
  ");
2f52a5177   Vinod Koul   soundwire: cdns: ...
876
877
878
879
880
881
882
883
884
  	}
  
  	if (int_status & CDNS_MCP_INT_DATA_CLASH) {
  		/*
  		 * Multiple slaves trying to drive bit slot, or issue with
  		 * ownership of data bits or Slave gone bonkers
  		 */
  		dev_err_ratelimited(cdns->dev, "Bus clash for data word
  ");
2f52a5177   Vinod Koul   soundwire: cdns: ...
885
  	}
9e4e6019e   Pierre-Louis Bossart   soundwire: cadenc...
886
887
888
889
890
891
892
893
894
895
896
897
898
  	if (cdns->bus.params.m_data_mode != SDW_PORT_DATA_MODE_NORMAL &&
  	    int_status & CDNS_MCP_INT_DPINT) {
  		u32 port_intstat;
  
  		/* just log which ports report an error */
  		port_intstat = cdns_readl(cdns, CDNS_MCP_PORT_INTSTAT);
  		dev_err_ratelimited(cdns->dev, "DP interrupt: PortIntStat %8x
  ",
  				    port_intstat);
  
  		/* clear status w/ write1 */
  		cdns_writel(cdns, CDNS_MCP_PORT_INTSTAT, port_intstat);
  	}
2f52a5177   Vinod Koul   soundwire: cdns: ...
899
900
901
  	if (int_status & CDNS_MCP_INT_SLAVE_MASK) {
  		/* Mask the Slave interrupt and wake thread */
  		cdns_updatel(cdns, CDNS_MCP_INTMASK,
bbb638172   Pierre-Louis Bossart   soundwire: cadenc...
902
  			     CDNS_MCP_INT_SLAVE_MASK, 0);
2f52a5177   Vinod Koul   soundwire: cdns: ...
903
904
  
  		int_status &= ~CDNS_MCP_INT_SLAVE_MASK;
d2068da5c   Pierre-Louis Bossart   soundwire: cadenc...
905
906
907
908
909
910
911
912
913
914
  
  		/*
  		 * Deal with possible race condition between interrupt
  		 * handling and disabling interrupts on suspend.
  		 *
  		 * If the master is in the process of disabling
  		 * interrupts, don't schedule a workqueue
  		 */
  		if (cdns->interrupt_enabled)
  			schedule_work(&cdns->work);
2f52a5177   Vinod Koul   soundwire: cdns: ...
915
916
917
918
919
920
921
922
  	}
  
  	cdns_writel(cdns, CDNS_MCP_INTSTAT, int_status);
  	return ret;
  }
  EXPORT_SYMBOL(sdw_cdns_irq);
  
  /**
4a98a6b2f   Bard Liao   soundwire: intel/...
923
924
925
926
   * To update slave status in a work since we will need to handle
   * other interrupts eg. CDNS_MCP_INT_RX_WL during the update slave
   * process.
   * @work: cdns worker thread
2f52a5177   Vinod Koul   soundwire: cdns: ...
927
   */
4a98a6b2f   Bard Liao   soundwire: intel/...
928
  static void cdns_update_slave_status_work(struct work_struct *work)
2f52a5177   Vinod Koul   soundwire: cdns: ...
929
  {
4a98a6b2f   Bard Liao   soundwire: intel/...
930
931
  	struct sdw_cdns *cdns =
  		container_of(work, struct sdw_cdns, work);
2f52a5177   Vinod Koul   soundwire: cdns: ...
932
  	u32 slave0, slave1;
eb7df4c86   Pierre-Louis Bossart   soundwire: cadenc...
933
934
  	dev_dbg_ratelimited(cdns->dev, "Slave status change
  ");
2f52a5177   Vinod Koul   soundwire: cdns: ...
935
936
937
938
939
940
941
942
943
944
945
  
  	slave0 = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT0);
  	slave1 = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT1);
  
  	cdns_update_slave_status(cdns, slave0, slave1);
  	cdns_writel(cdns, CDNS_MCP_SLAVE_INTSTAT0, slave0);
  	cdns_writel(cdns, CDNS_MCP_SLAVE_INTSTAT1, slave1);
  
  	/* clear and unmask Slave interrupt now */
  	cdns_writel(cdns, CDNS_MCP_INTSTAT, CDNS_MCP_INT_SLAVE_MASK);
  	cdns_updatel(cdns, CDNS_MCP_INTMASK,
bbb638172   Pierre-Louis Bossart   soundwire: cadenc...
946
  		     CDNS_MCP_INT_SLAVE_MASK, CDNS_MCP_INT_SLAVE_MASK);
2f52a5177   Vinod Koul   soundwire: cdns: ...
947

2f52a5177   Vinod Koul   soundwire: cdns: ...
948
  }
2f52a5177   Vinod Koul   soundwire: cdns: ...
949
950
951
952
  
  /*
   * init routines
   */
49ea07d33   Pierre-Louis Bossart   soundwire: intel/...
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
  
  /**
   * sdw_cdns_exit_reset() - Program reset parameters and start bus operations
   * @cdns: Cadence instance
   */
  int sdw_cdns_exit_reset(struct sdw_cdns *cdns)
  {
  	/* program maximum length reset to be safe */
  	cdns_updatel(cdns, CDNS_MCP_CONTROL,
  		     CDNS_MCP_CONTROL_RST_DELAY,
  		     CDNS_MCP_CONTROL_RST_DELAY);
  
  	/* use hardware generated reset */
  	cdns_updatel(cdns, CDNS_MCP_CONTROL,
  		     CDNS_MCP_CONTROL_HW_RST,
  		     CDNS_MCP_CONTROL_HW_RST);
49ea07d33   Pierre-Louis Bossart   soundwire: intel/...
969
  	/* commit changes */
2c800e3ba   Pierre-Louis Bossart   soundwire: cadenc...
970
971
972
973
974
975
  	cdns_updatel(cdns, CDNS_MCP_CONFIG_UPDATE,
  		     CDNS_MCP_CONFIG_UPDATE_BIT,
  		     CDNS_MCP_CONFIG_UPDATE_BIT);
  
  	/* don't wait here */
  	return 0;
49ea07d33   Pierre-Louis Bossart   soundwire: intel/...
976
977
978
979
  }
  EXPORT_SYMBOL(sdw_cdns_exit_reset);
  
  /**
af4cc9178   Pierre-Louis Bossart   soundwire: cadenc...
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
   * sdw_cdns_enable_slave_interrupt() - Enable SDW slave interrupts
   * @cdns: Cadence instance
   * @state: boolean for true/false
   */
  static void cdns_enable_slave_interrupts(struct sdw_cdns *cdns, bool state)
  {
  	u32 mask;
  
  	mask = cdns_readl(cdns, CDNS_MCP_INTMASK);
  	if (state)
  		mask |= CDNS_MCP_INT_SLAVE_MASK;
  	else
  		mask &= ~CDNS_MCP_INT_SLAVE_MASK;
  
  	cdns_writel(cdns, CDNS_MCP_INTMASK, mask);
  }
  
  /**
ae478d6e1   Rander Wang   soundwire: cadenc...
998
   * sdw_cdns_enable_interrupt() - Enable SDW interrupts
49ea07d33   Pierre-Louis Bossart   soundwire: intel/...
999
   * @cdns: Cadence instance
550f90520   Pierre-Louis Bossart   soundwire: cadenc...
1000
   * @state: True if we are trying to enable interrupt.
49ea07d33   Pierre-Louis Bossart   soundwire: intel/...
1001
   */
9e3d47fb2   Pierre-Louis Bossart   soundwire: intel/...
1002
  int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns, bool state)
956baa199   Sanyog Kale   soundwire: cdns: ...
1003
  {
9e3d47fb2   Pierre-Louis Bossart   soundwire: intel/...
1004
1005
1006
1007
1008
1009
  	u32 slave_intmask0 = 0;
  	u32 slave_intmask1 = 0;
  	u32 mask = 0;
  
  	if (!state)
  		goto update_masks;
956baa199   Sanyog Kale   soundwire: cdns: ...
1010

9e3d47fb2   Pierre-Louis Bossart   soundwire: intel/...
1011
1012
  	slave_intmask0 = CDNS_MCP_SLAVE_INTMASK0_MASK;
  	slave_intmask1 = CDNS_MCP_SLAVE_INTMASK1_MASK;
956baa199   Sanyog Kale   soundwire: cdns: ...
1013

9b5884a0c   Pierre-Louis Bossart   soundwire: cadenc...
1014
1015
1016
1017
1018
1019
  	/* enable detection of all slave state changes */
  	mask = CDNS_MCP_INT_SLAVE_MASK;
  
  	/* enable detection of bus issues */
  	mask |= CDNS_MCP_INT_CTRL_CLASH | CDNS_MCP_INT_DATA_CLASH |
  		CDNS_MCP_INT_PARITY;
9e4e6019e   Pierre-Louis Bossart   soundwire: cadenc...
1020
1021
1022
  	/* port interrupt limited to test modes for now */
  	if (cdns->bus.params.m_data_mode != SDW_PORT_DATA_MODE_NORMAL)
  		mask |= CDNS_MCP_INT_DPINT;
9b5884a0c   Pierre-Louis Bossart   soundwire: cadenc...
1023
1024
1025
1026
1027
1028
1029
1030
1031
  
  	/* enable detection of RX fifo level */
  	mask |= CDNS_MCP_INT_RX_WL;
  
  	/*
  	 * CDNS_MCP_INT_IRQ needs to be set otherwise all previous
  	 * settings are irrelevant
  	 */
  	mask |= CDNS_MCP_INT_IRQ;
956baa199   Sanyog Kale   soundwire: cdns: ...
1032

04592dced   Pierre-Louis Bossart   soundwire: cadenc...
1033
1034
  	if (interrupt_mask) /* parameter override */
  		mask = interrupt_mask;
956baa199   Sanyog Kale   soundwire: cdns: ...
1035

9e3d47fb2   Pierre-Louis Bossart   soundwire: intel/...
1036
  update_masks:
5ebb09454   Rander Wang   soundwire: cadenc...
1037
1038
1039
1040
1041
1042
1043
1044
1045
  	/* clear slave interrupt status before enabling interrupt */
  	if (state) {
  		u32 slave_state;
  
  		slave_state = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT0);
  		cdns_writel(cdns, CDNS_MCP_SLAVE_INTSTAT0, slave_state);
  		slave_state = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT1);
  		cdns_writel(cdns, CDNS_MCP_SLAVE_INTSTAT1, slave_state);
  	}
d2068da5c   Pierre-Louis Bossart   soundwire: cadenc...
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
  	cdns->interrupt_enabled = state;
  
  	/*
  	 * Complete any on-going status updates before updating masks,
  	 * and cancel queued status updates.
  	 *
  	 * There could be a race with a new interrupt thrown before
  	 * the 3 mask updates below are complete, so in the interrupt
  	 * we use the 'interrupt_enabled' status to prevent new work
  	 * from being queued.
  	 */
  	if (!state)
  		cancel_work_sync(&cdns->work);
5ebb09454   Rander Wang   soundwire: cadenc...
1059

9e3d47fb2   Pierre-Louis Bossart   soundwire: intel/...
1060
1061
  	cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK0, slave_intmask0);
  	cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK1, slave_intmask1);
956baa199   Sanyog Kale   soundwire: cdns: ...
1062
  	cdns_writel(cdns, CDNS_MCP_INTMASK, mask);
ae478d6e1   Rander Wang   soundwire: cadenc...
1063
  	return 0;
956baa199   Sanyog Kale   soundwire: cdns: ...
1064
1065
  }
  EXPORT_SYMBOL(sdw_cdns_enable_interrupt);
2f52a5177   Vinod Koul   soundwire: cdns: ...
1066

07abeff1e   Vinod Koul   soundwire: cdns: ...
1067
  static int cdns_allocate_pdi(struct sdw_cdns *cdns,
bbb638172   Pierre-Louis Bossart   soundwire: cadenc...
1068
1069
  			     struct sdw_cdns_pdi **stream,
  			     u32 num, u32 pdi_offset)
07abeff1e   Vinod Koul   soundwire: cdns: ...
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
  {
  	struct sdw_cdns_pdi *pdi;
  	int i;
  
  	if (!num)
  		return 0;
  
  	pdi = devm_kcalloc(cdns->dev, num, sizeof(*pdi), GFP_KERNEL);
  	if (!pdi)
  		return -ENOMEM;
  
  	for (i = 0; i < num; i++) {
  		pdi[i].num = i + pdi_offset;
07abeff1e   Vinod Koul   soundwire: cdns: ...
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
  	}
  
  	*stream = pdi;
  	return 0;
  }
  
  /**
   * sdw_cdns_pdi_init() - PDI initialization routine
   *
   * @cdns: Cadence instance
   * @config: Stream configurations
   */
  int sdw_cdns_pdi_init(struct sdw_cdns *cdns,
bbb638172   Pierre-Louis Bossart   soundwire: cadenc...
1096
  		      struct sdw_cdns_stream_config config)
07abeff1e   Vinod Koul   soundwire: cdns: ...
1097
1098
  {
  	struct sdw_cdns_streams *stream;
57a34790c   Pierre-Louis Bossart   soundwire: cadenc...
1099
1100
  	int offset;
  	int ret;
07abeff1e   Vinod Koul   soundwire: cdns: ...
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
  
  	cdns->pcm.num_bd = config.pcm_bd;
  	cdns->pcm.num_in = config.pcm_in;
  	cdns->pcm.num_out = config.pcm_out;
  	cdns->pdm.num_bd = config.pdm_bd;
  	cdns->pdm.num_in = config.pdm_in;
  	cdns->pdm.num_out = config.pdm_out;
  
  	/* Allocate PDIs for PCMs */
  	stream = &cdns->pcm;
807c15bc7   Pierre-Louis Bossart   soundwire: intel:...
1111
1112
  	/* we allocate PDI0 and PDI1 which are used for Bulk */
  	offset = 0;
07abeff1e   Vinod Koul   soundwire: cdns: ...
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
  
  	ret = cdns_allocate_pdi(cdns, &stream->bd,
  				stream->num_bd, offset);
  	if (ret)
  		return ret;
  
  	offset += stream->num_bd;
  
  	ret = cdns_allocate_pdi(cdns, &stream->in,
  				stream->num_in, offset);
  	if (ret)
  		return ret;
  
  	offset += stream->num_in;
  
  	ret = cdns_allocate_pdi(cdns, &stream->out,
  				stream->num_out, offset);
  	if (ret)
  		return ret;
  
  	/* Update total number of PCM PDIs */
  	stream->num_pdi = stream->num_bd + stream->num_in + stream->num_out;
  	cdns->num_ports = stream->num_pdi;
  
  	/* Allocate PDIs for PDMs */
  	stream = &cdns->pdm;
07abeff1e   Vinod Koul   soundwire: cdns: ...
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
  	ret = cdns_allocate_pdi(cdns, &stream->bd,
  				stream->num_bd, offset);
  	if (ret)
  		return ret;
  
  	offset += stream->num_bd;
  
  	ret = cdns_allocate_pdi(cdns, &stream->in,
  				stream->num_in, offset);
  	if (ret)
  		return ret;
  
  	offset += stream->num_in;
  
  	ret = cdns_allocate_pdi(cdns, &stream->out,
  				stream->num_out, offset);
807c15bc7   Pierre-Louis Bossart   soundwire: intel:...
1155

07abeff1e   Vinod Koul   soundwire: cdns: ...
1156
1157
1158
1159
1160
1161
  	if (ret)
  		return ret;
  
  	/* Update total number of PDM PDIs */
  	stream->num_pdi = stream->num_bd + stream->num_in + stream->num_out;
  	cdns->num_ports += stream->num_pdi;
07abeff1e   Vinod Koul   soundwire: cdns: ...
1162
1163
1164
  	return 0;
  }
  EXPORT_SYMBOL(sdw_cdns_pdi_init);
05be59ac4   Pierre-Louis Bossart   soundwire: cadenc...
1165
1166
1167
1168
1169
1170
1171
  static u32 cdns_set_initial_frame_shape(int n_rows, int n_cols)
  {
  	u32 val;
  	int c;
  	int r;
  
  	r = sdw_find_row_index(n_rows);
3cf25d63b   Vinod Koul   soundwire: cadenc...
1172
  	c = sdw_find_col_index(n_cols);
05be59ac4   Pierre-Louis Bossart   soundwire: cadenc...
1173

3cf25d63b   Vinod Koul   soundwire: cadenc...
1174
1175
  	val = FIELD_PREP(CDNS_MCP_FRAME_SHAPE_ROW_MASK, r);
  	val |= FIELD_PREP(CDNS_MCP_FRAME_SHAPE_COL_MASK, c);
05be59ac4   Pierre-Louis Bossart   soundwire: cadenc...
1176
1177
1178
  
  	return val;
  }
0cdcdedc1   Pierre-Louis Bossart   soundwire: cadenc...
1179
  static void cdns_init_clock_ctrl(struct sdw_cdns *cdns)
2f52a5177   Vinod Koul   soundwire: cdns: ...
1180
  {
3859872f4   Pierre-Louis Bossart   soundwire: cadenc...
1181
1182
  	struct sdw_bus *bus = &cdns->bus;
  	struct sdw_master_prop *prop = &bus->prop;
2f52a5177   Vinod Koul   soundwire: cdns: ...
1183
  	u32 val;
1dd6a17f3   Pierre-Louis Bossart   soundwire: cadenc...
1184
  	u32 ssp_interval;
3859872f4   Pierre-Louis Bossart   soundwire: cadenc...
1185
  	int divider;
2f52a5177   Vinod Koul   soundwire: cdns: ...
1186
1187
  
  	/* Set clock divider */
3859872f4   Pierre-Louis Bossart   soundwire: cadenc...
1188
  	divider	= (prop->mclk_freq / prop->max_clk_freq) - 1;
2f52a5177   Vinod Koul   soundwire: cdns: ...
1189

a50954e21   Rander Wang   soundwire: cadenc...
1190
1191
1192
1193
  	cdns_updatel(cdns, CDNS_MCP_CLK_CTRL0,
  		     CDNS_MCP_CLK_MCLKD_MASK, divider);
  	cdns_updatel(cdns, CDNS_MCP_CLK_CTRL1,
  		     CDNS_MCP_CLK_MCLKD_MASK, divider);
2f52a5177   Vinod Koul   soundwire: cdns: ...
1194

05be59ac4   Pierre-Louis Bossart   soundwire: cadenc...
1195
1196
1197
1198
1199
1200
1201
  	/*
  	 * Frame shape changes after initialization have to be done
  	 * with the bank switch mechanism
  	 */
  	val = cdns_set_initial_frame_shape(prop->default_row,
  					   prop->default_col);
  	cdns_writel(cdns, CDNS_MCP_FRAME_SHAPE_INIT, val);
2f52a5177   Vinod Koul   soundwire: cdns: ...
1202
1203
  
  	/* Set SSP interval to default value */
1dd6a17f3   Pierre-Louis Bossart   soundwire: cadenc...
1204
1205
1206
  	ssp_interval = prop->default_frame_rate / SDW_CADENCE_GSYNC_HZ;
  	cdns_writel(cdns, CDNS_MCP_SSP_CTRL0, ssp_interval);
  	cdns_writel(cdns, CDNS_MCP_SSP_CTRL1, ssp_interval);
0cdcdedc1   Pierre-Louis Bossart   soundwire: cadenc...
1207
1208
1209
1210
1211
1212
1213
1214
1215
  }
  
  /**
   * sdw_cdns_init() - Cadence initialization
   * @cdns: Cadence instance
   */
  int sdw_cdns_init(struct sdw_cdns *cdns)
  {
  	u32 val;
0cdcdedc1   Pierre-Louis Bossart   soundwire: cadenc...
1216
1217
  
  	cdns_init_clock_ctrl(cdns);
2f52a5177   Vinod Koul   soundwire: cdns: ...
1218

0d667d01c   Rander Wang   soundwire: cadenc...
1219
1220
  	/* reset msg_count to default value of FIFOLEVEL */
  	cdns->msg_count = cdns_readl(cdns, CDNS_MCP_FIFOLEVEL);
49ea07d33   Pierre-Louis Bossart   soundwire: intel/...
1221
1222
1223
  	/* flush command FIFOs */
  	cdns_updatel(cdns, CDNS_MCP_CONTROL, CDNS_MCP_CONTROL_CMD_RST,
  		     CDNS_MCP_CONTROL_CMD_RST);
2f52a5177   Vinod Koul   soundwire: cdns: ...
1224
1225
  	/* Set cmd accept mode */
  	cdns_updatel(cdns, CDNS_MCP_CONTROL, CDNS_MCP_CONTROL_CMD_ACCEPT,
bbb638172   Pierre-Louis Bossart   soundwire: cadenc...
1226
  		     CDNS_MCP_CONTROL_CMD_ACCEPT);
2f52a5177   Vinod Koul   soundwire: cdns: ...
1227
1228
1229
  
  	/* Configure mcp config */
  	val = cdns_readl(cdns, CDNS_MCP_CONFIG);
5c8f0f68a   Pierre-Louis Bossart   soundwire: cadenc...
1230
1231
1232
  	/* enable bus operations with clock and data */
  	val &= ~CDNS_MCP_CONFIG_OP;
  	val |= CDNS_MCP_CONFIG_OP_NORMAL;
b62e76cf3   Pierre-Louis Bossart   soundwire: cadenc...
1233
1234
  	/* Set cmd mode for Tx and Rx cmds */
  	val &= ~CDNS_MCP_CONFIG_CMD;
2f52a5177   Vinod Koul   soundwire: cdns: ...
1235

b62e76cf3   Pierre-Louis Bossart   soundwire: cadenc...
1236
1237
  	/* Disable sniffer mode */
  	val &= ~CDNS_MCP_CONFIG_SNIFFER;
2f52a5177   Vinod Koul   soundwire: cdns: ...
1238
1239
1240
  
  	/* Disable auto bus release */
  	val &= ~CDNS_MCP_CONFIG_BUS_REL;
2c800e3ba   Pierre-Louis Bossart   soundwire: cadenc...
1241
1242
1243
  	if (cdns->bus.multi_link)
  		/* Set Multi-master mode to take gsync into account */
  		val |= CDNS_MCP_CONFIG_MMASTER;
2f52a5177   Vinod Koul   soundwire: cdns: ...
1244

91080111f   Pierre-Louis Bossart   soundwire: cadenc...
1245
  	/* leave frame delay to hardware default of 0x1F */
b62e76cf3   Pierre-Louis Bossart   soundwire: cadenc...
1246

ad473db4e   Pierre-Louis Bossart   soundwire: cadenc...
1247
  	/* leave command retry to hardware default of 0 */
2f52a5177   Vinod Koul   soundwire: cdns: ...
1248

2f52a5177   Vinod Koul   soundwire: cdns: ...
1249
  	cdns_writel(cdns, CDNS_MCP_CONFIG, val);
b17350e40   Pierre-Louis Bossart   soundwire: cadenc...
1250
1251
  	/* changes will be committed later */
  	return 0;
2f52a5177   Vinod Koul   soundwire: cdns: ...
1252
1253
  }
  EXPORT_SYMBOL(sdw_cdns_init);
07abeff1e   Vinod Koul   soundwire: cdns: ...
1254
1255
  int cdns_bus_conf(struct sdw_bus *bus, struct sdw_bus_params *params)
  {
3859872f4   Pierre-Louis Bossart   soundwire: cadenc...
1256
  	struct sdw_master_prop *prop = &bus->prop;
07abeff1e   Vinod Koul   soundwire: cdns: ...
1257
  	struct sdw_cdns *cdns = bus_to_cdns(bus);
a50954e21   Rander Wang   soundwire: cadenc...
1258
  	int mcp_clkctrl_off;
07abeff1e   Vinod Koul   soundwire: cdns: ...
1259
1260
1261
  	int divider;
  
  	if (!params->curr_dr_freq) {
17ed5bef4   Pierre-Louis Bossart   soundwire: add mi...
1262
1263
  		dev_err(cdns->dev, "NULL curr_dr_freq
  ");
07abeff1e   Vinod Koul   soundwire: cdns: ...
1264
1265
  		return -EINVAL;
  	}
3859872f4   Pierre-Louis Bossart   soundwire: cadenc...
1266
1267
1268
  	divider	= prop->mclk_freq * SDW_DOUBLE_RATE_FACTOR /
  		params->curr_dr_freq;
  	divider--; /* divider is 1/(N+1) */
07abeff1e   Vinod Koul   soundwire: cdns: ...
1269
1270
1271
1272
1273
  
  	if (params->next_bank)
  		mcp_clkctrl_off = CDNS_MCP_CLK_CTRL1;
  	else
  		mcp_clkctrl_off = CDNS_MCP_CLK_CTRL0;
a50954e21   Rander Wang   soundwire: cadenc...
1274
  	cdns_updatel(cdns, mcp_clkctrl_off, CDNS_MCP_CLK_MCLKD_MASK, divider);
07abeff1e   Vinod Koul   soundwire: cdns: ...
1275
1276
1277
1278
1279
1280
  
  	return 0;
  }
  EXPORT_SYMBOL(cdns_bus_conf);
  
  static int cdns_port_params(struct sdw_bus *bus,
bbb638172   Pierre-Louis Bossart   soundwire: cadenc...
1281
  			    struct sdw_port_params *p_params, unsigned int bank)
07abeff1e   Vinod Koul   soundwire: cdns: ...
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
  {
  	struct sdw_cdns *cdns = bus_to_cdns(bus);
  	int dpn_config = 0, dpn_config_off;
  
  	if (bank)
  		dpn_config_off = CDNS_DPN_B1_CONFIG(p_params->num);
  	else
  		dpn_config_off = CDNS_DPN_B0_CONFIG(p_params->num);
  
  	dpn_config = cdns_readl(cdns, dpn_config_off);
714db045c   Vinod Koul   soundwire: cadenc...
1292
1293
1294
  	u32p_replace_bits(&dpn_config, (p_params->bps - 1), CDNS_DPN_CONFIG_WL);
  	u32p_replace_bits(&dpn_config, p_params->flow_mode, CDNS_DPN_CONFIG_PORT_FLOW);
  	u32p_replace_bits(&dpn_config, p_params->data_mode, CDNS_DPN_CONFIG_PORT_DAT);
07abeff1e   Vinod Koul   soundwire: cdns: ...
1295
1296
1297
1298
1299
1300
1301
  
  	cdns_writel(cdns, dpn_config_off, dpn_config);
  
  	return 0;
  }
  
  static int cdns_transport_params(struct sdw_bus *bus,
bbb638172   Pierre-Louis Bossart   soundwire: cadenc...
1302
1303
  				 struct sdw_transport_params *t_params,
  				 enum sdw_reg_bank bank)
07abeff1e   Vinod Koul   soundwire: cdns: ...
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
  {
  	struct sdw_cdns *cdns = bus_to_cdns(bus);
  	int dpn_offsetctrl = 0, dpn_offsetctrl_off;
  	int dpn_config = 0, dpn_config_off;
  	int dpn_hctrl = 0, dpn_hctrl_off;
  	int num = t_params->port_num;
  	int dpn_samplectrl_off;
  
  	/*
  	 * Note: Only full data port is supported on the Master side for
  	 * both PCM and PDM ports.
  	 */
  
  	if (bank) {
  		dpn_config_off = CDNS_DPN_B1_CONFIG(num);
  		dpn_samplectrl_off = CDNS_DPN_B1_SAMPLE_CTRL(num);
  		dpn_hctrl_off = CDNS_DPN_B1_HCTRL(num);
  		dpn_offsetctrl_off = CDNS_DPN_B1_OFFSET_CTRL(num);
  	} else {
  		dpn_config_off = CDNS_DPN_B0_CONFIG(num);
  		dpn_samplectrl_off = CDNS_DPN_B0_SAMPLE_CTRL(num);
  		dpn_hctrl_off = CDNS_DPN_B0_HCTRL(num);
  		dpn_offsetctrl_off = CDNS_DPN_B0_OFFSET_CTRL(num);
  	}
  
  	dpn_config = cdns_readl(cdns, dpn_config_off);
714db045c   Vinod Koul   soundwire: cadenc...
1330
1331
  	u32p_replace_bits(&dpn_config, t_params->blk_grp_ctrl, CDNS_DPN_CONFIG_BGC);
  	u32p_replace_bits(&dpn_config, t_params->blk_pkg_mode, CDNS_DPN_CONFIG_BPM);
07abeff1e   Vinod Koul   soundwire: cdns: ...
1332
  	cdns_writel(cdns, dpn_config_off, dpn_config);
714db045c   Vinod Koul   soundwire: cadenc...
1333
1334
  	u32p_replace_bits(&dpn_offsetctrl, t_params->offset1, CDNS_DPN_OFFSET_CTRL_1);
  	u32p_replace_bits(&dpn_offsetctrl, t_params->offset2, CDNS_DPN_OFFSET_CTRL_2);
07abeff1e   Vinod Koul   soundwire: cdns: ...
1335
  	cdns_writel(cdns, dpn_offsetctrl_off,  dpn_offsetctrl);
714db045c   Vinod Koul   soundwire: cadenc...
1336
1337
1338
  	u32p_replace_bits(&dpn_hctrl, t_params->hstart, CDNS_DPN_HCTRL_HSTART);
  	u32p_replace_bits(&dpn_hctrl, t_params->hstop, CDNS_DPN_HCTRL_HSTOP);
  	u32p_replace_bits(&dpn_hctrl, t_params->lane_ctrl, CDNS_DPN_HCTRL_LCTRL);
07abeff1e   Vinod Koul   soundwire: cdns: ...
1339
1340
1341
1342
1343
1344
1345
1346
  
  	cdns_writel(cdns, dpn_hctrl_off, dpn_hctrl);
  	cdns_writel(cdns, dpn_samplectrl_off, (t_params->sample_interval - 1));
  
  	return 0;
  }
  
  static int cdns_port_enable(struct sdw_bus *bus,
bbb638172   Pierre-Louis Bossart   soundwire: cadenc...
1347
  			    struct sdw_enable_ch *enable_ch, unsigned int bank)
07abeff1e   Vinod Koul   soundwire: cdns: ...
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
  {
  	struct sdw_cdns *cdns = bus_to_cdns(bus);
  	int dpn_chnen_off, ch_mask;
  
  	if (bank)
  		dpn_chnen_off = CDNS_DPN_B1_CH_EN(enable_ch->port_num);
  	else
  		dpn_chnen_off = CDNS_DPN_B0_CH_EN(enable_ch->port_num);
  
  	ch_mask = enable_ch->ch_mask * enable_ch->enable;
  	cdns_writel(cdns, dpn_chnen_off, ch_mask);
  
  	return 0;
  }
  
  static const struct sdw_master_port_ops cdns_port_ops = {
  	.dpn_set_port_params = cdns_port_params,
  	.dpn_set_port_transport_params = cdns_transport_params,
  	.dpn_port_enable_ch = cdns_port_enable,
  };
956baa199   Sanyog Kale   soundwire: cdns: ...
1368
  /**
5a885c52c   Rander Wang   soundwire: cadenc...
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
   * sdw_cdns_is_clock_stop: Check clock status
   *
   * @cdns: Cadence instance
   */
  bool sdw_cdns_is_clock_stop(struct sdw_cdns *cdns)
  {
  	return !!(cdns_readl(cdns, CDNS_MCP_STAT) & CDNS_MCP_STAT_CLK_STOP);
  }
  EXPORT_SYMBOL(sdw_cdns_is_clock_stop);
  
  /**
1032504f2   Rander Wang   soundwire: cadenc...
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
   * sdw_cdns_clock_stop: Cadence clock stop configuration routine
   *
   * @cdns: Cadence instance
   * @block_wake: prevent wakes if required by the platform
   */
  int sdw_cdns_clock_stop(struct sdw_cdns *cdns, bool block_wake)
  {
  	bool slave_present = false;
  	struct sdw_slave *slave;
  	int ret;
  
  	/* Check suspend status */
  	if (sdw_cdns_is_clock_stop(cdns)) {
  		dev_dbg(cdns->dev, "Clock is already stopped
  ");
  		return 0;
  	}
  
  	/*
af4cc9178   Pierre-Louis Bossart   soundwire: cadenc...
1399
1400
1401
1402
1403
1404
1405
  	 * Before entering clock stop we mask the Slave
  	 * interrupts. This helps avoid having to deal with e.g. a
  	 * Slave becoming UNATTACHED while the clock is being stopped
  	 */
  	cdns_enable_slave_interrupts(cdns, false);
  
  	/*
1032504f2   Rander Wang   soundwire: cadenc...
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
  	 * For specific platforms, it is required to be able to put
  	 * master into a state in which it ignores wake-up trials
  	 * in clock stop state
  	 */
  	if (block_wake)
  		cdns_updatel(cdns, CDNS_MCP_CONTROL,
  			     CDNS_MCP_CONTROL_BLOCK_WAKEUP,
  			     CDNS_MCP_CONTROL_BLOCK_WAKEUP);
  
  	list_for_each_entry(slave, &cdns->bus.slaves, node) {
  		if (slave->status == SDW_SLAVE_ATTACHED ||
  		    slave->status == SDW_SLAVE_ALERT) {
  			slave_present = true;
  			break;
  		}
  	}
  
  	/*
  	 * This CMD_ACCEPT should be used when there are no devices
  	 * attached on the link when entering clock stop mode. If this is
  	 * not set and there is a broadcast write then the command ignored
  	 * will be treated as a failure
  	 */
  	if (!slave_present)
  		cdns_updatel(cdns, CDNS_MCP_CONTROL,
  			     CDNS_MCP_CONTROL_CMD_ACCEPT,
  			     CDNS_MCP_CONTROL_CMD_ACCEPT);
  	else
  		cdns_updatel(cdns, CDNS_MCP_CONTROL,
  			     CDNS_MCP_CONTROL_CMD_ACCEPT, 0);
  
  	/* commit changes */
  	ret = cdns_config_update(cdns);
  	if (ret < 0) {
  		dev_err(cdns->dev, "%s: config_update failed
  ", __func__);
  		return ret;
  	}
  
  	/* Prepare slaves for clock stop */
  	ret = sdw_bus_prep_clk_stop(&cdns->bus);
  	if (ret < 0) {
  		dev_err(cdns->dev, "prepare clock stop failed %d", ret);
  		return ret;
  	}
  
  	/*
  	 * Enter clock stop mode and only report errors if there are
  	 * Slave devices present (ALERT or ATTACHED)
  	 */
  	ret = sdw_bus_clk_stop(&cdns->bus);
  	if (ret < 0 && slave_present && ret != -ENODATA) {
  		dev_err(cdns->dev, "bus clock stop failed %d", ret);
  		return ret;
  	}
  
  	ret = cdns_set_wait(cdns, CDNS_MCP_STAT,
  			    CDNS_MCP_STAT_CLK_STOP,
  			    CDNS_MCP_STAT_CLK_STOP);
  	if (ret < 0)
  		dev_err(cdns->dev, "Clock stop failed %d
  ", ret);
  
  	return ret;
  }
  EXPORT_SYMBOL(sdw_cdns_clock_stop);
  
  /**
   * sdw_cdns_clock_restart: Cadence PM clock restart configuration routine
   *
   * @cdns: Cadence instance
   * @bus_reset: context may be lost while in low power modes and the bus
   * may require a Severe Reset and re-enumeration after a wake.
   */
  int sdw_cdns_clock_restart(struct sdw_cdns *cdns, bool bus_reset)
  {
  	int ret;
af4cc9178   Pierre-Louis Bossart   soundwire: cadenc...
1483
1484
  	/* unmask Slave interrupts that were masked when stopping the clock */
  	cdns_enable_slave_interrupts(cdns, true);
1032504f2   Rander Wang   soundwire: cadenc...
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
  	ret = cdns_clear_bit(cdns, CDNS_MCP_CONTROL,
  			     CDNS_MCP_CONTROL_CLK_STOP_CLR);
  	if (ret < 0) {
  		dev_err(cdns->dev, "Couldn't exit from clock stop
  ");
  		return ret;
  	}
  
  	ret = cdns_set_wait(cdns, CDNS_MCP_STAT, CDNS_MCP_STAT_CLK_STOP, 0);
  	if (ret < 0) {
  		dev_err(cdns->dev, "clock stop exit failed %d
  ", ret);
  		return ret;
  	}
  
  	cdns_updatel(cdns, CDNS_MCP_CONTROL,
  		     CDNS_MCP_CONTROL_BLOCK_WAKEUP, 0);
  
  	/*
  	 * clear CMD_ACCEPT so that the command ignored
  	 * will be treated as a failure during a broadcast write
  	 */
  	cdns_updatel(cdns, CDNS_MCP_CONTROL, CDNS_MCP_CONTROL_CMD_ACCEPT, 0);
  
  	if (!bus_reset) {
  
  		/* enable bus operations with clock and data */
  		cdns_updatel(cdns, CDNS_MCP_CONFIG,
  			     CDNS_MCP_CONFIG_OP,
  			     CDNS_MCP_CONFIG_OP_NORMAL);
  
  		ret = cdns_config_update(cdns);
  		if (ret < 0) {
  			dev_err(cdns->dev, "%s: config_update failed
  ", __func__);
  			return ret;
  		}
  
  		ret = sdw_bus_exit_clk_stop(&cdns->bus);
  		if (ret < 0)
  			dev_err(cdns->dev, "bus failed to exit clock stop %d
  ", ret);
  	}
  
  	return ret;
  }
  EXPORT_SYMBOL(sdw_cdns_clock_restart);
  
  /**
956baa199   Sanyog Kale   soundwire: cdns: ...
1534
1535
1536
1537
1538
1539
   * sdw_cdns_probe() - Cadence probe routine
   * @cdns: Cadence instance
   */
  int sdw_cdns_probe(struct sdw_cdns *cdns)
  {
  	init_completion(&cdns->tx_complete);
07abeff1e   Vinod Koul   soundwire: cdns: ...
1540
  	cdns->bus.port_ops = &cdns_port_ops;
956baa199   Sanyog Kale   soundwire: cdns: ...
1541

4a98a6b2f   Bard Liao   soundwire: intel/...
1542
  	INIT_WORK(&cdns->work, cdns_update_slave_status_work);
956baa199   Sanyog Kale   soundwire: cdns: ...
1543
1544
1545
  	return 0;
  }
  EXPORT_SYMBOL(sdw_cdns_probe);
5d6b3c8ba   Vinod Koul   soundwire: cdns: ...
1546
  int cdns_set_sdw_stream(struct snd_soc_dai *dai,
bbb638172   Pierre-Louis Bossart   soundwire: cadenc...
1547
  			void *stream, bool pcm, int direction)
5d6b3c8ba   Vinod Koul   soundwire: cdns: ...
1548
1549
1550
  {
  	struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
  	struct sdw_cdns_dma_data *dma;
b5e9e687d   Pierre-Louis Bossart   soundwire: cadenc...
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
  	if (stream) {
  		/* first paranoia check */
  		if (direction == SNDRV_PCM_STREAM_PLAYBACK)
  			dma = dai->playback_dma_data;
  		else
  			dma = dai->capture_dma_data;
  
  		if (dma) {
  			dev_err(dai->dev,
  				"dma_data already allocated for dai %s
  ",
  				dai->name);
  			return -EINVAL;
  		}
5d6b3c8ba   Vinod Koul   soundwire: cdns: ...
1565

b5e9e687d   Pierre-Louis Bossart   soundwire: cadenc...
1566
1567
1568
1569
  		/* allocate and set dma info */
  		dma = kzalloc(sizeof(*dma), GFP_KERNEL);
  		if (!dma)
  			return -ENOMEM;
5d6b3c8ba   Vinod Koul   soundwire: cdns: ...
1570

b5e9e687d   Pierre-Louis Bossart   soundwire: cadenc...
1571
1572
1573
1574
  		if (pcm)
  			dma->stream_type = SDW_STREAM_PCM;
  		else
  			dma->stream_type = SDW_STREAM_PDM;
5d6b3c8ba   Vinod Koul   soundwire: cdns: ...
1575

b5e9e687d   Pierre-Louis Bossart   soundwire: cadenc...
1576
1577
  		dma->bus = &cdns->bus;
  		dma->link_id = cdns->instance;
5d6b3c8ba   Vinod Koul   soundwire: cdns: ...
1578

b5e9e687d   Pierre-Louis Bossart   soundwire: cadenc...
1579
  		dma->stream = stream;
5d6b3c8ba   Vinod Koul   soundwire: cdns: ...
1580

b5e9e687d   Pierre-Louis Bossart   soundwire: cadenc...
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
  		if (direction == SNDRV_PCM_STREAM_PLAYBACK)
  			dai->playback_dma_data = dma;
  		else
  			dai->capture_dma_data = dma;
  	} else {
  		/* for NULL stream we release allocated dma_data */
  		if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
  			kfree(dai->playback_dma_data);
  			dai->playback_dma_data = NULL;
  		} else {
  			kfree(dai->capture_dma_data);
  			dai->capture_dma_data = NULL;
  		}
  	}
5d6b3c8ba   Vinod Koul   soundwire: cdns: ...
1595
1596
1597
1598
1599
1600
1601
1602
  	return 0;
  }
  EXPORT_SYMBOL(cdns_set_sdw_stream);
  
  /**
   * cdns_find_pdi() - Find a free PDI
   *
   * @cdns: Cadence instance
39737a313   Pierre-Louis Bossart   soundwire: cadenc...
1603
   * @offset: Starting offset
5d6b3c8ba   Vinod Koul   soundwire: cdns: ...
1604
1605
   * @num: Number of PDIs
   * @pdi: PDI instances
39737a313   Pierre-Louis Bossart   soundwire: cadenc...
1606
   * @dai_id: DAI id
5d6b3c8ba   Vinod Koul   soundwire: cdns: ...
1607
   *
1b53385e7   Bard Liao   soundwire: cadenc...
1608
1609
   * Find a PDI for a given PDI array. The PDI num and dai_id are
   * expected to match, return NULL otherwise.
5d6b3c8ba   Vinod Koul   soundwire: cdns: ...
1610
1611
   */
  static struct sdw_cdns_pdi *cdns_find_pdi(struct sdw_cdns *cdns,
807c15bc7   Pierre-Louis Bossart   soundwire: intel:...
1612
  					  unsigned int offset,
bbb638172   Pierre-Louis Bossart   soundwire: cadenc...
1613
  					  unsigned int num,
1b53385e7   Bard Liao   soundwire: cadenc...
1614
1615
  					  struct sdw_cdns_pdi *pdi,
  					  int dai_id)
5d6b3c8ba   Vinod Koul   soundwire: cdns: ...
1616
1617
  {
  	int i;
1b53385e7   Bard Liao   soundwire: cadenc...
1618
1619
1620
  	for (i = offset; i < offset + num; i++)
  		if (pdi[i].num == dai_id)
  			return &pdi[i];
5d6b3c8ba   Vinod Koul   soundwire: cdns: ...
1621
1622
1623
1624
1625
1626
1627
1628
  
  	return NULL;
  }
  
  /**
   * sdw_cdns_config_stream: Configure a stream
   *
   * @cdns: Cadence instance
5d6b3c8ba   Vinod Koul   soundwire: cdns: ...
1629
1630
1631
1632
1633
   * @ch: Channel count
   * @dir: Data direction
   * @pdi: PDI to be used
   */
  void sdw_cdns_config_stream(struct sdw_cdns *cdns,
bbb638172   Pierre-Louis Bossart   soundwire: cadenc...
1634
  			    u32 ch, u32 dir, struct sdw_cdns_pdi *pdi)
5d6b3c8ba   Vinod Koul   soundwire: cdns: ...
1635
1636
  {
  	u32 offset, val = 0;
9e4e6019e   Pierre-Louis Bossart   soundwire: cadenc...
1637
  	if (dir == SDW_DATA_DIR_RX) {
5d6b3c8ba   Vinod Koul   soundwire: cdns: ...
1638
  		val = CDNS_PORTCTRL_DIRN;
9e4e6019e   Pierre-Louis Bossart   soundwire: cadenc...
1639
1640
1641
  		if (cdns->bus.params.m_data_mode != SDW_PORT_DATA_MODE_NORMAL)
  			val |= CDNS_PORTCTRL_TEST_FAILED;
  	}
57a34790c   Pierre-Louis Bossart   soundwire: cadenc...
1642
  	offset = CDNS_PORTCTRL + pdi->num * CDNS_PORT_OFFSET;
9e4e6019e   Pierre-Louis Bossart   soundwire: cadenc...
1643
1644
1645
  	cdns_updatel(cdns, offset,
  		     CDNS_PORTCTRL_DIRN | CDNS_PORTCTRL_TEST_FAILED,
  		     val);
5d6b3c8ba   Vinod Koul   soundwire: cdns: ...
1646

57a34790c   Pierre-Louis Bossart   soundwire: cadenc...
1647
  	val = pdi->num;
b468a785b   randerwang   soundwire: cadenc...
1648
  	val |= CDNS_PDI_CONFIG_SOFT_RESET;
3cf25d63b   Vinod Koul   soundwire: cadenc...
1649
  	val |= FIELD_PREP(CDNS_PDI_CONFIG_CHANNEL, (1 << ch) - 1);
5d6b3c8ba   Vinod Koul   soundwire: cdns: ...
1650
1651
1652
1653
1654
  	cdns_writel(cdns, CDNS_PDI_CONFIG(pdi->num), val);
  }
  EXPORT_SYMBOL(sdw_cdns_config_stream);
  
  /**
57a34790c   Pierre-Louis Bossart   soundwire: cadenc...
1655
   * sdw_cdns_alloc_pdi() - Allocate a PDI
5d6b3c8ba   Vinod Koul   soundwire: cdns: ...
1656
1657
1658
   *
   * @cdns: Cadence instance
   * @stream: Stream to be allocated
5d6b3c8ba   Vinod Koul   soundwire: cdns: ...
1659
1660
   * @ch: Channel count
   * @dir: Data direction
39737a313   Pierre-Louis Bossart   soundwire: cadenc...
1661
   * @dai_id: DAI id
5d6b3c8ba   Vinod Koul   soundwire: cdns: ...
1662
   */
57a34790c   Pierre-Louis Bossart   soundwire: cadenc...
1663
1664
  struct sdw_cdns_pdi *sdw_cdns_alloc_pdi(struct sdw_cdns *cdns,
  					struct sdw_cdns_streams *stream,
1b53385e7   Bard Liao   soundwire: cadenc...
1665
  					u32 ch, u32 dir, int dai_id)
5d6b3c8ba   Vinod Koul   soundwire: cdns: ...
1666
1667
1668
1669
  {
  	struct sdw_cdns_pdi *pdi = NULL;
  
  	if (dir == SDW_DATA_DIR_RX)
1b53385e7   Bard Liao   soundwire: cadenc...
1670
1671
  		pdi = cdns_find_pdi(cdns, 0, stream->num_in, stream->in,
  				    dai_id);
5d6b3c8ba   Vinod Koul   soundwire: cdns: ...
1672
  	else
1b53385e7   Bard Liao   soundwire: cadenc...
1673
1674
  		pdi = cdns_find_pdi(cdns, 0, stream->num_out, stream->out,
  				    dai_id);
5d6b3c8ba   Vinod Koul   soundwire: cdns: ...
1675
1676
1677
  
  	/* check if we found a PDI, else find in bi-directional */
  	if (!pdi)
1b53385e7   Bard Liao   soundwire: cadenc...
1678
1679
  		pdi = cdns_find_pdi(cdns, 2, stream->num_bd, stream->bd,
  				    dai_id);
5d6b3c8ba   Vinod Koul   soundwire: cdns: ...
1680

57a34790c   Pierre-Louis Bossart   soundwire: cadenc...
1681
1682
1683
1684
1685
1686
  	if (pdi) {
  		pdi->l_ch_num = 0;
  		pdi->h_ch_num = ch - 1;
  		pdi->dir = dir;
  		pdi->ch_count = ch;
  	}
5d6b3c8ba   Vinod Koul   soundwire: cdns: ...
1687

57a34790c   Pierre-Louis Bossart   soundwire: cadenc...
1688
  	return pdi;
5d6b3c8ba   Vinod Koul   soundwire: cdns: ...
1689
  }
57a34790c   Pierre-Louis Bossart   soundwire: cadenc...
1690
  EXPORT_SYMBOL(sdw_cdns_alloc_pdi);
5d6b3c8ba   Vinod Koul   soundwire: cdns: ...
1691

2f52a5177   Vinod Koul   soundwire: cdns: ...
1692
1693
  MODULE_LICENSE("Dual BSD/GPL");
  MODULE_DESCRIPTION("Cadence Soundwire Library");