1 // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2 // Copyright(c) 2015-17 Intel Corporation.
5 * Soundwire Intel Master Driver
8 #include <linux/acpi.h>
9 #include <linux/delay.h>
10 #include <linux/interrupt.h>
11 #include <linux/platform_device.h>
12 #include <linux/soundwire/sdw_registers.h>
13 #include <linux/soundwire/sdw.h>
14 #include <linux/soundwire/sdw_intel.h>
15 #include "cadence_master.h"
18 /* Intel SHIM Registers Definition */
19 #define SDW_SHIM_LCAP 0x0
20 #define SDW_SHIM_LCTL 0x4
21 #define SDW_SHIM_IPPTR 0x8
22 #define SDW_SHIM_SYNC 0xC
24 #define SDW_SHIM_CTLSCAP(x) (0x010 + 0x60 * x)
25 #define SDW_SHIM_CTLS0CM(x) (0x012 + 0x60 * x)
26 #define SDW_SHIM_CTLS1CM(x) (0x014 + 0x60 * x)
27 #define SDW_SHIM_CTLS2CM(x) (0x016 + 0x60 * x)
28 #define SDW_SHIM_CTLS3CM(x) (0x018 + 0x60 * x)
29 #define SDW_SHIM_PCMSCAP(x) (0x020 + 0x60 * x)
31 #define SDW_SHIM_PCMSYCHM(x, y) (0x022 + (0x60 * x) + (0x2 * y))
32 #define SDW_SHIM_PCMSYCHC(x, y) (0x042 + (0x60 * x) + (0x2 * y))
33 #define SDW_SHIM_PDMSCAP(x) (0x062 + 0x60 * x)
34 #define SDW_SHIM_IOCTL(x) (0x06C + 0x60 * x)
35 #define SDW_SHIM_CTMCTL(x) (0x06E + 0x60 * x)
37 #define SDW_SHIM_WAKEEN 0x190
38 #define SDW_SHIM_WAKESTS 0x192
40 #define SDW_SHIM_LCTL_SPA BIT(0)
41 #define SDW_SHIM_LCTL_CPA BIT(8)
43 #define SDW_SHIM_SYNC_SYNCPRD_VAL 0x176F
44 #define SDW_SHIM_SYNC_SYNCPRD GENMASK(14, 0)
45 #define SDW_SHIM_SYNC_SYNCCPU BIT(15)
46 #define SDW_SHIM_SYNC_CMDSYNC_MASK GENMASK(19, 16)
47 #define SDW_SHIM_SYNC_CMDSYNC BIT(16)
48 #define SDW_SHIM_SYNC_SYNCGO BIT(24)
50 #define SDW_SHIM_PCMSCAP_ISS GENMASK(3, 0)
51 #define SDW_SHIM_PCMSCAP_OSS GENMASK(7, 4)
52 #define SDW_SHIM_PCMSCAP_BSS GENMASK(12, 8)
54 #define SDW_SHIM_PCMSYCM_LCHN GENMASK(3, 0)
55 #define SDW_SHIM_PCMSYCM_HCHN GENMASK(7, 4)
56 #define SDW_SHIM_PCMSYCM_STREAM GENMASK(13, 8)
57 #define SDW_SHIM_PCMSYCM_DIR BIT(15)
59 #define SDW_SHIM_PDMSCAP_ISS GENMASK(3, 0)
60 #define SDW_SHIM_PDMSCAP_OSS GENMASK(7, 4)
61 #define SDW_SHIM_PDMSCAP_BSS GENMASK(12, 8)
62 #define SDW_SHIM_PDMSCAP_CPSS GENMASK(15, 13)
64 #define SDW_SHIM_IOCTL_MIF BIT(0)
65 #define SDW_SHIM_IOCTL_CO BIT(1)
66 #define SDW_SHIM_IOCTL_COE BIT(2)
67 #define SDW_SHIM_IOCTL_DO BIT(3)
68 #define SDW_SHIM_IOCTL_DOE BIT(4)
69 #define SDW_SHIM_IOCTL_BKE BIT(5)
70 #define SDW_SHIM_IOCTL_WPDD BIT(6)
71 #define SDW_SHIM_IOCTL_CIBD BIT(8)
72 #define SDW_SHIM_IOCTL_DIBD BIT(9)
74 #define SDW_SHIM_CTMCTL_DACTQE BIT(0)
75 #define SDW_SHIM_CTMCTL_DODS BIT(1)
76 #define SDW_SHIM_CTMCTL_DOAIS GENMASK(4, 3)
78 #define SDW_SHIM_WAKEEN_ENABLE BIT(0)
79 #define SDW_SHIM_WAKESTS_STATUS BIT(0)
81 /* Intel ALH Register definitions */
82 #define SDW_ALH_STRMZCFG(x) (0x000 + (0x4 * x))
84 #define SDW_ALH_STRMZCFG_DMAT_VAL 0x3
85 #define SDW_ALH_STRMZCFG_DMAT GENMASK(7, 0)
86 #define SDW_ALH_STRMZCFG_CHN GENMASK(19, 16)
91 struct sdw_intel_link_res
*res
;
94 #define cdns_to_intel(_cdns) container_of(_cdns, struct sdw_intel, cdns)
97 * Read, write helpers for HW registers
99 static inline int intel_readl(void __iomem
*base
, int offset
)
101 return readl(base
+ offset
);
104 static inline void intel_writel(void __iomem
*base
, int offset
, int value
)
106 writel(value
, base
+ offset
);
109 static inline u16
intel_readw(void __iomem
*base
, int offset
)
111 return readw(base
+ offset
);
114 static inline void intel_writew(void __iomem
*base
, int offset
, u16 value
)
116 writew(value
, base
+ offset
);
119 static int intel_clear_bit(void __iomem
*base
, int offset
, u32 value
, u32 mask
)
124 writel(value
, base
+ offset
);
126 reg_read
= readl(base
+ offset
);
127 if (!(reg_read
& mask
))
132 } while (timeout
!= 0);
137 static int intel_set_bit(void __iomem
*base
, int offset
, u32 value
, u32 mask
)
142 writel(value
, base
+ offset
);
144 reg_read
= readl(base
+ offset
);
150 } while (timeout
!= 0);
159 static int intel_link_power_up(struct sdw_intel
*sdw
)
161 unsigned int link_id
= sdw
->instance
;
162 void __iomem
*shim
= sdw
->res
->shim
;
163 int spa_mask
, cpa_mask
;
164 int link_control
, ret
;
166 /* Link power up sequence */
167 link_control
= intel_readl(shim
, SDW_SHIM_LCTL
);
168 spa_mask
= (SDW_SHIM_LCTL_SPA
<< link_id
);
169 cpa_mask
= (SDW_SHIM_LCTL_CPA
<< link_id
);
170 link_control
|= spa_mask
;
172 ret
= intel_set_bit(shim
, SDW_SHIM_LCTL
, link_control
, cpa_mask
);
176 sdw
->cdns
.link_up
= true;
180 static int intel_shim_init(struct sdw_intel
*sdw
)
182 void __iomem
*shim
= sdw
->res
->shim
;
183 unsigned int link_id
= sdw
->instance
;
185 u16 ioctl
= 0, act
= 0;
187 /* Initialize Shim */
188 ioctl
|= SDW_SHIM_IOCTL_BKE
;
189 intel_writew(shim
, SDW_SHIM_IOCTL(link_id
), ioctl
);
191 ioctl
|= SDW_SHIM_IOCTL_WPDD
;
192 intel_writew(shim
, SDW_SHIM_IOCTL(link_id
), ioctl
);
194 ioctl
|= SDW_SHIM_IOCTL_DO
;
195 intel_writew(shim
, SDW_SHIM_IOCTL(link_id
), ioctl
);
197 ioctl
|= SDW_SHIM_IOCTL_DOE
;
198 intel_writew(shim
, SDW_SHIM_IOCTL(link_id
), ioctl
);
200 /* Switch to MIP from Glue logic */
201 ioctl
= intel_readw(shim
, SDW_SHIM_IOCTL(link_id
));
203 ioctl
&= ~(SDW_SHIM_IOCTL_DOE
);
204 intel_writew(shim
, SDW_SHIM_IOCTL(link_id
), ioctl
);
206 ioctl
&= ~(SDW_SHIM_IOCTL_DO
);
207 intel_writew(shim
, SDW_SHIM_IOCTL(link_id
), ioctl
);
209 ioctl
|= (SDW_SHIM_IOCTL_MIF
);
210 intel_writew(shim
, SDW_SHIM_IOCTL(link_id
), ioctl
);
212 ioctl
&= ~(SDW_SHIM_IOCTL_BKE
);
213 ioctl
&= ~(SDW_SHIM_IOCTL_COE
);
215 intel_writew(shim
, SDW_SHIM_IOCTL(link_id
), ioctl
);
217 act
|= 0x1 << SDW_REG_SHIFT(SDW_SHIM_CTMCTL_DOAIS
);
218 act
|= SDW_SHIM_CTMCTL_DACTQE
;
219 act
|= SDW_SHIM_CTMCTL_DODS
;
220 intel_writew(shim
, SDW_SHIM_CTMCTL(link_id
), act
);
222 /* Now set SyncPRD period */
223 sync_reg
= intel_readl(shim
, SDW_SHIM_SYNC
);
224 sync_reg
|= (SDW_SHIM_SYNC_SYNCPRD_VAL
<<
225 SDW_REG_SHIFT(SDW_SHIM_SYNC_SYNCPRD
));
227 /* Set SyncCPU bit */
228 sync_reg
|= SDW_SHIM_SYNC_SYNCCPU
;
229 ret
= intel_clear_bit(shim
, SDW_SHIM_SYNC
, sync_reg
,
230 SDW_SHIM_SYNC_SYNCCPU
);
232 dev_err(sdw
->cdns
.dev
, "Failed to set sync period: %d", ret
);
237 static int intel_prop_read(struct sdw_bus
*bus
)
239 /* Initialize with default handler to read all DisCo properties */
240 sdw_master_read_prop(bus
);
242 /* BIOS is not giving some values correctly. So, lets override them */
243 bus
->prop
.num_freq
= 1;
244 bus
->prop
.freq
= devm_kcalloc(bus
->dev
, sizeof(*bus
->prop
.freq
),
245 bus
->prop
.num_freq
, GFP_KERNEL
);
249 bus
->prop
.freq
[0] = bus
->prop
.max_freq
;
250 bus
->prop
.err_threshold
= 5;
258 static int intel_probe(struct platform_device
*pdev
)
260 struct sdw_intel
*sdw
;
263 sdw
= devm_kzalloc(&pdev
->dev
, sizeof(*sdw
), GFP_KERNEL
);
267 sdw
->instance
= pdev
->id
;
268 sdw
->res
= dev_get_platdata(&pdev
->dev
);
269 sdw
->cdns
.dev
= &pdev
->dev
;
270 sdw
->cdns
.registers
= sdw
->res
->registers
;
271 sdw
->cdns
.instance
= sdw
->instance
;
272 sdw
->cdns
.msg_count
= 0;
273 sdw
->cdns
.bus
.dev
= &pdev
->dev
;
274 sdw
->cdns
.bus
.link_id
= pdev
->id
;
276 sdw_cdns_probe(&sdw
->cdns
);
278 /* Set property read ops */
279 sdw_cdns_master_ops
.read_prop
= intel_prop_read
;
280 sdw
->cdns
.bus
.ops
= &sdw_cdns_master_ops
;
282 platform_set_drvdata(pdev
, sdw
);
284 ret
= sdw_add_bus_master(&sdw
->cdns
.bus
);
286 dev_err(&pdev
->dev
, "sdw_add_bus_master fail: %d\n", ret
);
290 /* Initialize shim and controller */
291 intel_link_power_up(sdw
);
292 intel_shim_init(sdw
);
294 ret
= sdw_cdns_init(&sdw
->cdns
);
298 ret
= sdw_cdns_enable_interrupt(&sdw
->cdns
);
303 ret
= request_threaded_irq(sdw
->res
->irq
, sdw_cdns_irq
,
304 sdw_cdns_thread
, IRQF_SHARED
, KBUILD_MODNAME
,
307 dev_err(sdw
->cdns
.dev
, "unable to grab IRQ %d, disabling device\n",
315 sdw_delete_bus_master(&sdw
->cdns
.bus
);
320 static int intel_remove(struct platform_device
*pdev
)
322 struct sdw_intel
*sdw
;
324 sdw
= platform_get_drvdata(pdev
);
326 free_irq(sdw
->res
->irq
, sdw
);
327 sdw_delete_bus_master(&sdw
->cdns
.bus
);
332 static struct platform_driver sdw_intel_drv
= {
333 .probe
= intel_probe
,
334 .remove
= intel_remove
,
341 module_platform_driver(sdw_intel_drv
);
343 MODULE_LICENSE("Dual BSD/GPL");
344 MODULE_ALIAS("platform:int-sdw");
345 MODULE_DESCRIPTION("Intel Soundwire Master Driver");