Blame view
drivers/soundwire/intel_init.c
11.4 KB
d62a7d41f soundwire: intel:... |
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. /* * SDW Intel Init Routines * * Initializes and creates SDW devices based on ACPI and Hardware values */ #include <linux/acpi.h> |
4abbd783d soundwire: intel:... |
11 |
#include <linux/export.h> |
4a98a6b2f soundwire: intel/... |
12 |
#include <linux/interrupt.h> |
3fc40449a soundwire: intel:... |
13 |
#include <linux/io.h> |
4abbd783d soundwire: intel:... |
14 |
#include <linux/module.h> |
d62a7d41f soundwire: intel:... |
15 |
#include <linux/platform_device.h> |
ebf878edd soundwire: intel:... |
16 |
#include <linux/pm_runtime.h> |
d62a7d41f soundwire: intel:... |
17 |
#include <linux/soundwire/sdw_intel.h> |
b6109dd6d soundwire: intel:... |
18 |
#include "cadence_master.h" |
d62a7d41f soundwire: intel:... |
19 |
#include "intel.h" |
6f11586f4 soundwire: intel:... |
20 |
#define SDW_LINK_TYPE 4 /* from Intel ACPI documentation */ |
d62a7d41f soundwire: intel:... |
21 22 23 24 25 26 |
#define SDW_MAX_LINKS 4 #define SDW_SHIM_LCAP 0x0 #define SDW_SHIM_BASE 0x2C000 #define SDW_ALH_BASE 0x2C800 #define SDW_LINK_BASE 0x30000 #define SDW_LINK_SIZE 0x10000 |
6d2c66695 soundwire: intel:... |
27 28 |
static int ctrl_link_mask; module_param_named(sdw_link_mask, ctrl_link_mask, int, 0444); |
50302fc7b soundwire: intel_... |
29 |
MODULE_PARM_DESC(sdw_link_mask, "Intel link mask (one bit per link)"); |
6d2c66695 soundwire: intel:... |
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
static bool is_link_enabled(struct fwnode_handle *fw_node, int i) { struct fwnode_handle *link; char name[32]; u32 quirk_mask = 0; /* Find master handle */ snprintf(name, sizeof(name), "mipi-sdw-link-%d-subproperties", i); link = fwnode_get_named_child_node(fw_node, name); if (!link) return false; fwnode_property_read_u32(link, "intel-quirk-mask", &quirk_mask); if (quirk_mask & SDW_INTEL_QUIRK_MASK_BUS_DISABLE) return false; return true; } static int sdw_intel_cleanup(struct sdw_intel_ctx *ctx) |
d62a7d41f soundwire: intel:... |
55 |
{ |
f98f690fb soundwire: intel:... |
56 |
struct sdw_intel_link_res *link = ctx->links; |
6d2c66695 soundwire: intel:... |
57 |
u32 link_mask; |
d62a7d41f soundwire: intel:... |
58 59 60 61 |
int i; if (!link) return 0; |
6d2c66695 soundwire: intel:... |
62 63 64 65 66 |
link_mask = ctx->link_mask; for (i = 0; i < ctx->count; i++, link++) { if (!(link_mask & BIT(i))) continue; |
ebf878edd soundwire: intel:... |
67 68 |
if (link->pdev) { pm_runtime_disable(&link->pdev->dev); |
d62a7d41f soundwire: intel:... |
69 |
platform_device_unregister(link->pdev); |
ebf878edd soundwire: intel:... |
70 |
} |
ab996b297 soundwire: intel_... |
71 72 73 |
if (!link->clock_stop_quirks) pm_runtime_put_noidle(link->dev); |
d62a7d41f soundwire: intel:... |
74 |
} |
d62a7d41f soundwire: intel:... |
75 76 |
return 0; } |
6d2c66695 soundwire: intel:... |
77 78 |
static int sdw_intel_scan_controller(struct sdw_intel_acpi_info *info) |
d62a7d41f soundwire: intel:... |
79 |
{ |
d62a7d41f soundwire: intel:... |
80 81 82 |
struct acpi_device *adev; int ret, i; u8 count; |
d62a7d41f soundwire: intel:... |
83 |
|
6d2c66695 soundwire: intel:... |
84 85 |
if (acpi_bus_get_device(info->handle, &adev)) return -EINVAL; |
d62a7d41f soundwire: intel:... |
86 87 88 89 |
/* Found controller, find links supported */ count = 0; ret = fwnode_property_read_u8_array(acpi_fwnode_handle(adev), |
505ccb006 soundwire: intel_... |
90 |
"mipi-sdw-master-count", &count, 1); |
d62a7d41f soundwire: intel:... |
91 |
|
6d2c66695 soundwire: intel:... |
92 93 94 95 96 97 98 99 100 101 102 |
/* * In theory we could check the number of links supported in * hardware, but in that step we cannot assume SoundWire IP is * powered. * * In addition, if the BIOS doesn't even provide this * 'master-count' property then all the inits based on link * masks will fail as well. * * We will check the hardware capabilities in the startup() step */ |
d62a7d41f soundwire: intel:... |
103 104 105 106 |
if (ret) { dev_err(&adev->dev, "Failed to read mipi-sdw-master-count: %d ", ret); |
6d2c66695 soundwire: intel:... |
107 |
return -EINVAL; |
d62a7d41f soundwire: intel:... |
108 |
} |
d62a7d41f soundwire: intel:... |
109 110 111 112 |
/* Check count is within bounds */ if (count > SDW_MAX_LINKS) { dev_err(&adev->dev, "Link count %d exceeds max %d ", |
505ccb006 soundwire: intel_... |
113 |
count, SDW_MAX_LINKS); |
6d2c66695 soundwire: intel:... |
114 |
return -EINVAL; |
6f7219fec soundwire: intel:... |
115 116 117 |
} if (!count) { |
432732b80 soundwire: intel_... |
118 119 |
dev_warn(&adev->dev, "No SoundWire links detected "); |
6d2c66695 soundwire: intel:... |
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
return -EINVAL; } dev_dbg(&adev->dev, "ACPI reports %d SDW Link devices ", count); info->count = count; info->link_mask = 0; for (i = 0; i < count; i++) { if (ctrl_link_mask && !(ctrl_link_mask & BIT(i))) { dev_dbg(&adev->dev, "Link %d masked, will not be enabled ", i); continue; } if (!is_link_enabled(acpi_fwnode_handle(adev), i)) { dev_dbg(&adev->dev, "Link %d not selected in firmware ", i); continue; } info->link_mask |= BIT(i); |
d62a7d41f soundwire: intel:... |
144 |
} |
6d2c66695 soundwire: intel:... |
145 146 |
return 0; } |
12b161468 soundwire: intel_... |
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
#define HDA_DSP_REG_ADSPIC2 (0x10) #define HDA_DSP_REG_ADSPIS2 (0x14) #define HDA_DSP_REG_ADSPIC2_SNDW BIT(5) /** * sdw_intel_enable_irq() - enable/disable Intel SoundWire IRQ * @mmio_base: The mmio base of the control register * @enable: true if enable */ void sdw_intel_enable_irq(void __iomem *mmio_base, bool enable) { u32 val; val = readl(mmio_base + HDA_DSP_REG_ADSPIC2); if (enable) val |= HDA_DSP_REG_ADSPIC2_SNDW; else val &= ~HDA_DSP_REG_ADSPIC2_SNDW; writel(val, mmio_base + HDA_DSP_REG_ADSPIC2); } |
8459cea75 soundwire: intel_... |
169 |
EXPORT_SYMBOL_NS(sdw_intel_enable_irq, SOUNDWIRE_INTEL_INIT); |
12b161468 soundwire: intel_... |
170 |
|
4a98a6b2f soundwire: intel/... |
171 172 173 174 175 176 177 178 179 180 181 182 |
irqreturn_t sdw_intel_thread(int irq, void *dev_id) { struct sdw_intel_ctx *ctx = dev_id; struct sdw_intel_link_res *link; list_for_each_entry(link, &ctx->link_list, list) sdw_cdns_irq(irq, link->cdns); sdw_intel_enable_irq(ctx->mmio_base, true); return IRQ_HANDLED; } EXPORT_SYMBOL_NS(sdw_intel_thread, SOUNDWIRE_INTEL_INIT); |
6d2c66695 soundwire: intel:... |
183 184 185 186 187 188 189 190 |
static struct sdw_intel_ctx *sdw_intel_probe_controller(struct sdw_intel_res *res) { struct platform_device_info pdevinfo; struct platform_device *pdev; struct sdw_intel_link_res *link; struct sdw_intel_ctx *ctx; struct acpi_device *adev; |
a81844034 Soundwire: intel_... |
191 192 193 |
struct sdw_slave *slave; struct list_head *node; struct sdw_bus *bus; |
6d2c66695 soundwire: intel:... |
194 |
u32 link_mask; |
a81844034 Soundwire: intel_... |
195 |
int num_slaves = 0; |
6d2c66695 soundwire: intel:... |
196 197 198 199 200 201 202 203 204 205 206 207 208 |
int count; int i; if (!res) return NULL; if (acpi_bus_get_device(res->handle, &adev)) return NULL; if (!res->count) return NULL; count = res->count; |
d62a7d41f soundwire: intel:... |
209 210 |
dev_dbg(&adev->dev, "Creating %d SDW Link devices ", count); |
dd906cc61 soundwire: intel_... |
211 |
ctx = devm_kzalloc(&adev->dev, sizeof(*ctx), GFP_KERNEL); |
d62a7d41f soundwire: intel:... |
212 213 214 215 |
if (!ctx) return NULL; ctx->count = count; |
dd906cc61 soundwire: intel_... |
216 217 |
ctx->links = devm_kcalloc(&adev->dev, ctx->count, sizeof(*ctx->links), GFP_KERNEL); |
d62a7d41f soundwire: intel:... |
218 |
if (!ctx->links) |
dd906cc61 soundwire: intel_... |
219 |
return NULL; |
d62a7d41f soundwire: intel:... |
220 |
|
6d2c66695 soundwire: intel:... |
221 222 223 224 |
ctx->count = count; ctx->mmio_base = res->mmio_base; ctx->link_mask = res->link_mask; ctx->handle = res->handle; |
4a17c441c soundwire: intel:... |
225 |
mutex_init(&ctx->shim_lock); |
6d2c66695 soundwire: intel:... |
226 |
|
d62a7d41f soundwire: intel:... |
227 |
link = ctx->links; |
6d2c66695 soundwire: intel:... |
228 |
link_mask = ctx->link_mask; |
d62a7d41f soundwire: intel:... |
229 |
|
4a98a6b2f soundwire: intel/... |
230 |
INIT_LIST_HEAD(&ctx->link_list); |
d62a7d41f soundwire: intel:... |
231 |
/* Create SDW Master devices */ |
6d2c66695 soundwire: intel:... |
232 |
for (i = 0; i < count; i++, link++) { |
9cd1c5a72 soundwire: intel_... |
233 |
if (!(link_mask & BIT(i))) { |
50302fc7b soundwire: intel_... |
234 235 236 |
dev_dbg(&adev->dev, "Link %d masked, will not be enabled ", i); |
50302fc7b soundwire: intel_... |
237 238 |
continue; } |
6d2c66695 soundwire: intel:... |
239 |
link->mmio_base = res->mmio_base; |
f98f690fb soundwire: intel:... |
240 |
link->registers = res->mmio_base + SDW_LINK_BASE |
6d2c66695 soundwire: intel:... |
241 |
+ (SDW_LINK_SIZE * i); |
f98f690fb soundwire: intel:... |
242 243 |
link->shim = res->mmio_base + SDW_SHIM_BASE; link->alh = res->mmio_base + SDW_ALH_BASE; |
d62a7d41f soundwire: intel:... |
244 |
|
f98f690fb soundwire: intel:... |
245 |
link->ops = res->ops; |
4b206d34b soundwire: intel:... |
246 |
link->dev = res->dev; |
c46302ec5 soundwire: intel:... |
247 |
|
a320f41ea soundwire: intel:... |
248 |
link->clock_stop_quirks = res->clock_stop_quirks; |
4a17c441c soundwire: intel:... |
249 250 |
link->shim_lock = &ctx->shim_lock; link->shim_mask = &ctx->shim_mask; |
de763fa88 soundwire: intel:... |
251 |
link->link_mask = link_mask; |
4a17c441c soundwire: intel:... |
252 |
|
d62a7d41f soundwire: intel:... |
253 254 255 |
memset(&pdevinfo, 0, sizeof(pdevinfo)); pdevinfo.parent = res->parent; |
6d2c66695 soundwire: intel:... |
256 |
pdevinfo.name = "intel-sdw"; |
d62a7d41f soundwire: intel:... |
257 258 |
pdevinfo.id = i; pdevinfo.fwnode = acpi_fwnode_handle(adev); |
4ab34412f soundwire: intel_... |
259 260 |
pdevinfo.data = link; pdevinfo.size_data = sizeof(*link); |
d62a7d41f soundwire: intel:... |
261 262 263 264 265 266 267 |
pdev = platform_device_register_full(&pdevinfo); if (IS_ERR(pdev)) { dev_err(&adev->dev, "platform device creation failed: %ld ", PTR_ERR(pdev)); |
6d2c66695 soundwire: intel:... |
268 |
goto err; |
d62a7d41f soundwire: intel:... |
269 |
} |
d62a7d41f soundwire: intel:... |
270 |
link->pdev = pdev; |
4a98a6b2f soundwire: intel/... |
271 272 273 |
link->cdns = platform_get_drvdata(pdev); list_add_tail(&link->list, &ctx->link_list); |
a81844034 Soundwire: intel_... |
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 |
bus = &link->cdns->bus; /* Calculate number of slaves */ list_for_each(node, &bus->slaves) num_slaves++; } ctx->ids = devm_kcalloc(&adev->dev, num_slaves, sizeof(*ctx->ids), GFP_KERNEL); if (!ctx->ids) goto err; ctx->num_slaves = num_slaves; i = 0; list_for_each_entry(link, &ctx->link_list, list) { bus = &link->cdns->bus; list_for_each_entry(slave, &bus->slaves, node) { ctx->ids[i].id = slave->id; ctx->ids[i].link_id = bus->link_id; i++; } |
d62a7d41f soundwire: intel:... |
294 295 296 |
} return ctx; |
6d2c66695 soundwire: intel:... |
297 |
err: |
dd906cc61 soundwire: intel_... |
298 |
ctx->count = i; |
6d2c66695 soundwire: intel:... |
299 |
sdw_intel_cleanup(ctx); |
d62a7d41f soundwire: intel:... |
300 301 |
return NULL; } |
6d2c66695 soundwire: intel:... |
302 303 304 305 306 307 308 309 310 311 312 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 |
static int sdw_intel_startup_controller(struct sdw_intel_ctx *ctx) { struct acpi_device *adev; struct sdw_intel_link_res *link; u32 caps; u32 link_mask; int i; if (acpi_bus_get_device(ctx->handle, &adev)) return -EINVAL; /* Check SNDWLCAP.LCOUNT */ caps = ioread32(ctx->mmio_base + SDW_SHIM_BASE + SDW_SHIM_LCAP); caps &= GENMASK(2, 0); /* Check HW supported vs property value */ if (caps < ctx->count) { dev_err(&adev->dev, "BIOS master count is larger than hardware capabilities "); return -EINVAL; } if (!ctx->links) return -EINVAL; link = ctx->links; link_mask = ctx->link_mask; /* Startup SDW Master devices */ for (i = 0; i < ctx->count; i++, link++) { if (!(link_mask & BIT(i))) continue; intel_master_startup(link->pdev); |
ab996b297 soundwire: intel_... |
338 339 340 341 342 343 344 345 346 347 |
if (!link->clock_stop_quirks) { /* * we need to prevent the parent PCI device * from entering pm_runtime suspend, so that * power rails to the SoundWire IP are not * turned off. */ pm_runtime_get_noresume(link->dev); } |
6d2c66695 soundwire: intel:... |
348 349 350 351 |
} return 0; } |
d62a7d41f soundwire: intel:... |
352 |
static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level, |
505ccb006 soundwire: intel_... |
353 |
void *cdata, void **return_value) |
d62a7d41f soundwire: intel:... |
354 |
{ |
6d2c66695 soundwire: intel:... |
355 |
struct sdw_intel_acpi_info *info = cdata; |
d62a7d41f soundwire: intel:... |
356 |
struct acpi_device *adev; |
6f11586f4 soundwire: intel:... |
357 358 359 360 361 362 |
acpi_status status; u64 adr; status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); if (ACPI_FAILURE(status)) return AE_OK; /* keep going */ |
d62a7d41f soundwire: intel:... |
363 364 |
if (acpi_bus_get_device(handle, &adev)) { |
e1c815f4b soundwire: intel:... |
365 366 |
pr_err("%s: Couldn't find ACPI handle ", __func__); |
d62a7d41f soundwire: intel:... |
367 368 |
return AE_NOT_FOUND; } |
6d2c66695 soundwire: intel:... |
369 |
info->handle = handle; |
6f11586f4 soundwire: intel:... |
370 371 372 373 374 375 376 377 |
/* * On some Intel platforms, multiple children of the HDAS * device can be found, but only one of them is the SoundWire * controller. The SNDW device is always exposed with * Name(_ADR, 0x40000000), with bits 31..28 representing the * SoundWire link so filter accordingly */ |
c30f92984 soundwire: intel_... |
378 |
if (FIELD_GET(GENMASK(31, 28), adr) != SDW_LINK_TYPE) |
6f11586f4 soundwire: intel:... |
379 380 381 382 |
return AE_OK; /* keep going */ /* device found, stop namespace walk */ return AE_CTRL_TERMINATE; |
d62a7d41f soundwire: intel:... |
383 384 385 |
} /** |
6d2c66695 soundwire: intel:... |
386 |
* sdw_intel_acpi_scan() - SoundWire Intel init routine |
d62a7d41f soundwire: intel:... |
387 |
* @parent_handle: ACPI parent handle |
6d2c66695 soundwire: intel:... |
388 |
* @info: description of what firmware/DSDT tables expose |
d62a7d41f soundwire: intel:... |
389 |
* |
6d2c66695 soundwire: intel:... |
390 391 392 393 |
* This scans the namespace and queries firmware to figure out which * links to enable. A follow-up use of sdw_intel_probe() and * sdw_intel_startup() is required for creation of devices and bus * startup |
d62a7d41f soundwire: intel:... |
394 |
*/ |
6d2c66695 soundwire: intel:... |
395 396 |
int sdw_intel_acpi_scan(acpi_handle *parent_handle, struct sdw_intel_acpi_info *info) |
d62a7d41f soundwire: intel:... |
397 398 399 400 |
{ acpi_status status; status = acpi_walk_namespace(ACPI_TYPE_DEVICE, |
505ccb006 soundwire: intel_... |
401 402 |
parent_handle, 1, sdw_intel_acpi_cb, |
6d2c66695 soundwire: intel:... |
403 |
NULL, info, NULL); |
d62a7d41f soundwire: intel:... |
404 |
if (ACPI_FAILURE(status)) |
6d2c66695 soundwire: intel:... |
405 |
return -ENODEV; |
d62a7d41f soundwire: intel:... |
406 |
|
6d2c66695 soundwire: intel:... |
407 |
return sdw_intel_scan_controller(info); |
d62a7d41f soundwire: intel:... |
408 |
} |
8459cea75 soundwire: intel_... |
409 |
EXPORT_SYMBOL_NS(sdw_intel_acpi_scan, SOUNDWIRE_INTEL_INIT); |
d62a7d41f soundwire: intel:... |
410 411 |
/** |
6d2c66695 soundwire: intel:... |
412 413 414 415 416 417 418 419 420 421 422 423 424 425 |
* sdw_intel_probe() - SoundWire Intel probe routine * @res: resource data * * This registers a platform device for each Master handled by the controller, * and SoundWire Master and Slave devices will be created by the platform * device probe. All the information necessary is stored in the context, and * the res argument pointer can be freed after this step. * This function will be called after sdw_intel_acpi_scan() by SOF probe. */ struct sdw_intel_ctx *sdw_intel_probe(struct sdw_intel_res *res) { return sdw_intel_probe_controller(res); } |
8459cea75 soundwire: intel_... |
426 |
EXPORT_SYMBOL_NS(sdw_intel_probe, SOUNDWIRE_INTEL_INIT); |
6d2c66695 soundwire: intel:... |
427 428 429 430 431 432 433 434 435 436 437 438 |
/** * sdw_intel_startup() - SoundWire Intel startup * @ctx: SoundWire context allocated in the probe * * Startup Intel SoundWire controller. This function will be called after * Intel Audio DSP is powered up. */ int sdw_intel_startup(struct sdw_intel_ctx *ctx) { return sdw_intel_startup_controller(ctx); } |
8459cea75 soundwire: intel_... |
439 |
EXPORT_SYMBOL_NS(sdw_intel_startup, SOUNDWIRE_INTEL_INIT); |
6d2c66695 soundwire: intel:... |
440 |
/** |
d62a7d41f soundwire: intel:... |
441 |
* sdw_intel_exit() - SoundWire Intel exit |
6d2c66695 soundwire: intel:... |
442 |
* @ctx: SoundWire context allocated in the probe |
d62a7d41f soundwire: intel:... |
443 444 445 |
* * Delete the controller instances created and cleanup */ |
f98f690fb soundwire: intel:... |
446 |
void sdw_intel_exit(struct sdw_intel_ctx *ctx) |
d62a7d41f soundwire: intel:... |
447 |
{ |
6d2c66695 soundwire: intel:... |
448 |
sdw_intel_cleanup(ctx); |
d62a7d41f soundwire: intel:... |
449 |
} |
8459cea75 soundwire: intel_... |
450 |
EXPORT_SYMBOL_NS(sdw_intel_exit, SOUNDWIRE_INTEL_INIT); |
d62a7d41f soundwire: intel:... |
451 |
|
ab2c91329 soundwire: intel:... |
452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 |
void sdw_intel_process_wakeen_event(struct sdw_intel_ctx *ctx) { struct sdw_intel_link_res *link; u32 link_mask; int i; if (!ctx->links) return; link = ctx->links; link_mask = ctx->link_mask; /* Startup SDW Master devices */ for (i = 0; i < ctx->count; i++, link++) { if (!(link_mask & BIT(i))) continue; intel_master_process_wakeen_event(link->pdev); } } EXPORT_SYMBOL_NS(sdw_intel_process_wakeen_event, SOUNDWIRE_INTEL_INIT); |
d62a7d41f soundwire: intel:... |
473 474 |
MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("Intel Soundwire Init Library"); |