blob: f50a93130d12f2f054be3c1efb8308f4b054fd74 [file] [log] [blame]
Vinod Kould62a7d42017-12-14 11:19:44 +05301// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2// Copyright(c) 2015-17 Intel Corporation.
3
4/*
5 * SDW Intel Init Routines
6 *
7 * Initializes and creates SDW devices based on ACPI and Hardware values
8 */
9
10#include <linux/acpi.h>
Paul Gortmaker4abbd782019-04-13 11:12:52 -040011#include <linux/export.h>
Vinod Koul3fc40442019-10-22 10:03:08 +053012#include <linux/io.h>
Paul Gortmaker4abbd782019-04-13 11:12:52 -040013#include <linux/module.h>
Vinod Kould62a7d42017-12-14 11:19:44 +053014#include <linux/platform_device.h>
15#include <linux/soundwire/sdw_intel.h>
Pierre-Louis Bossartb6109dd2020-06-01 02:20:57 +080016#include "cadence_master.h"
Vinod Kould62a7d42017-12-14 11:19:44 +053017#include "intel.h"
18
Pierre-Louis Bossart6f115862019-05-22 14:47:17 -050019#define SDW_LINK_TYPE 4 /* from Intel ACPI documentation */
Vinod Kould62a7d42017-12-14 11:19:44 +053020#define SDW_MAX_LINKS 4
21#define SDW_SHIM_LCAP 0x0
22#define SDW_SHIM_BASE 0x2C000
23#define SDW_ALH_BASE 0x2C800
24#define SDW_LINK_BASE 0x30000
25#define SDW_LINK_SIZE 0x10000
26
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +080027static int ctrl_link_mask;
28module_param_named(sdw_link_mask, ctrl_link_mask, int, 0444);
Pierre-Louis Bossart50302fc2019-08-05 19:55:20 -050029MODULE_PARM_DESC(sdw_link_mask, "Intel link mask (one bit per link)");
30
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +080031static bool is_link_enabled(struct fwnode_handle *fw_node, int i)
32{
33 struct fwnode_handle *link;
34 char name[32];
35 u32 quirk_mask = 0;
36
37 /* Find master handle */
38 snprintf(name, sizeof(name),
39 "mipi-sdw-link-%d-subproperties", i);
40
41 link = fwnode_get_named_child_node(fw_node, name);
42 if (!link)
43 return false;
44
45 fwnode_property_read_u32(link,
46 "intel-quirk-mask",
47 &quirk_mask);
48
49 if (quirk_mask & SDW_INTEL_QUIRK_MASK_BUS_DISABLE)
50 return false;
51
52 return true;
53}
54
55static int sdw_intel_cleanup(struct sdw_intel_ctx *ctx)
Vinod Kould62a7d42017-12-14 11:19:44 +053056{
Pierre-Louis Bossartf98f6902019-12-11 19:45:01 -060057 struct sdw_intel_link_res *link = ctx->links;
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +080058 u32 link_mask;
Vinod Kould62a7d42017-12-14 11:19:44 +053059 int i;
60
61 if (!link)
62 return 0;
63
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +080064 link_mask = ctx->link_mask;
65
66 for (i = 0; i < ctx->count; i++, link++) {
67 if (!(link_mask & BIT(i)))
68 continue;
69
Vinod Kould62a7d42017-12-14 11:19:44 +053070 if (link->pdev)
71 platform_device_unregister(link->pdev);
Vinod Kould62a7d42017-12-14 11:19:44 +053072 }
73
Vinod Kould62a7d42017-12-14 11:19:44 +053074 return 0;
75}
76
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +080077static int
78sdw_intel_scan_controller(struct sdw_intel_acpi_info *info)
Vinod Kould62a7d42017-12-14 11:19:44 +053079{
Vinod Kould62a7d42017-12-14 11:19:44 +053080 struct acpi_device *adev;
81 int ret, i;
82 u8 count;
Vinod Kould62a7d42017-12-14 11:19:44 +053083
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +080084 if (acpi_bus_get_device(info->handle, &adev))
85 return -EINVAL;
Vinod Kould62a7d42017-12-14 11:19:44 +053086
87 /* Found controller, find links supported */
88 count = 0;
89 ret = fwnode_property_read_u8_array(acpi_fwnode_handle(adev),
Pierre-Louis Bossart505ccb02019-05-01 10:57:37 -050090 "mipi-sdw-master-count", &count, 1);
Vinod Kould62a7d42017-12-14 11:19:44 +053091
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +080092 /*
93 * In theory we could check the number of links supported in
94 * hardware, but in that step we cannot assume SoundWire IP is
95 * powered.
96 *
97 * In addition, if the BIOS doesn't even provide this
98 * 'master-count' property then all the inits based on link
99 * masks will fail as well.
100 *
101 * We will check the hardware capabilities in the startup() step
102 */
103
Vinod Kould62a7d42017-12-14 11:19:44 +0530104 if (ret) {
105 dev_err(&adev->dev,
106 "Failed to read mipi-sdw-master-count: %d\n", ret);
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +0800107 return -EINVAL;
Vinod Kould62a7d42017-12-14 11:19:44 +0530108 }
109
Vinod Kould62a7d42017-12-14 11:19:44 +0530110 /* Check count is within bounds */
111 if (count > SDW_MAX_LINKS) {
112 dev_err(&adev->dev, "Link count %d exceeds max %d\n",
Pierre-Louis Bossart505ccb02019-05-01 10:57:37 -0500113 count, SDW_MAX_LINKS);
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +0800114 return -EINVAL;
Guennadi Liakhovetski6f7219f2020-05-08 02:30:46 +0200115 }
116
117 if (!count) {
Pierre-Louis Bossart432732b2019-05-22 14:47:31 -0500118 dev_warn(&adev->dev, "No SoundWire links detected\n");
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +0800119 return -EINVAL;
120 }
121 dev_dbg(&adev->dev, "ACPI reports %d SDW Link devices\n", count);
122
123 info->count = count;
124 info->link_mask = 0;
125
126 for (i = 0; i < count; i++) {
127 if (ctrl_link_mask && !(ctrl_link_mask & BIT(i))) {
128 dev_dbg(&adev->dev,
129 "Link %d masked, will not be enabled\n", i);
130 continue;
131 }
132
133 if (!is_link_enabled(acpi_fwnode_handle(adev), i)) {
134 dev_dbg(&adev->dev,
135 "Link %d not selected in firmware\n", i);
136 continue;
137 }
138
139 info->link_mask |= BIT(i);
Vinod Kould62a7d42017-12-14 11:19:44 +0530140 }
141
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +0800142 return 0;
143}
144
145static struct sdw_intel_ctx
146*sdw_intel_probe_controller(struct sdw_intel_res *res)
147{
148 struct platform_device_info pdevinfo;
149 struct platform_device *pdev;
150 struct sdw_intel_link_res *link;
151 struct sdw_intel_ctx *ctx;
152 struct acpi_device *adev;
153 u32 link_mask;
154 int count;
155 int i;
156
157 if (!res)
158 return NULL;
159
160 if (acpi_bus_get_device(res->handle, &adev))
161 return NULL;
162
163 if (!res->count)
164 return NULL;
165
166 count = res->count;
Vinod Kould62a7d42017-12-14 11:19:44 +0530167 dev_dbg(&adev->dev, "Creating %d SDW Link devices\n", count);
168
Pierre-Louis Bossartdd906cc2020-06-01 02:21:00 +0800169 ctx = devm_kzalloc(&adev->dev, sizeof(*ctx), GFP_KERNEL);
Vinod Kould62a7d42017-12-14 11:19:44 +0530170 if (!ctx)
171 return NULL;
172
173 ctx->count = count;
Pierre-Louis Bossartdd906cc2020-06-01 02:21:00 +0800174 ctx->links = devm_kcalloc(&adev->dev, ctx->count,
175 sizeof(*ctx->links), GFP_KERNEL);
Vinod Kould62a7d42017-12-14 11:19:44 +0530176 if (!ctx->links)
Pierre-Louis Bossartdd906cc2020-06-01 02:21:00 +0800177 return NULL;
Vinod Kould62a7d42017-12-14 11:19:44 +0530178
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +0800179 ctx->count = count;
180 ctx->mmio_base = res->mmio_base;
181 ctx->link_mask = res->link_mask;
182 ctx->handle = res->handle;
Pierre-Louis Bossart4a17c442020-07-16 23:09:40 +0800183 mutex_init(&ctx->shim_lock);
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +0800184
Vinod Kould62a7d42017-12-14 11:19:44 +0530185 link = ctx->links;
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +0800186 link_mask = ctx->link_mask;
Vinod Kould62a7d42017-12-14 11:19:44 +0530187
188 /* Create SDW Master devices */
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +0800189 for (i = 0; i < count; i++, link++) {
Pierre-Louis Bossart9cd1c5a2020-06-01 02:20:59 +0800190 if (!(link_mask & BIT(i))) {
Pierre-Louis Bossart50302fc2019-08-05 19:55:20 -0500191 dev_dbg(&adev->dev,
192 "Link %d masked, will not be enabled\n", i);
Pierre-Louis Bossart50302fc2019-08-05 19:55:20 -0500193 continue;
194 }
195
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +0800196 link->mmio_base = res->mmio_base;
Pierre-Louis Bossartf98f6902019-12-11 19:45:01 -0600197 link->registers = res->mmio_base + SDW_LINK_BASE
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +0800198 + (SDW_LINK_SIZE * i);
Pierre-Louis Bossartf98f6902019-12-11 19:45:01 -0600199 link->shim = res->mmio_base + SDW_SHIM_BASE;
200 link->alh = res->mmio_base + SDW_ALH_BASE;
Vinod Kould62a7d42017-12-14 11:19:44 +0530201
Pierre-Louis Bossartf98f6902019-12-11 19:45:01 -0600202 link->ops = res->ops;
Rander Wang4b206d32019-12-11 19:45:02 -0600203 link->dev = res->dev;
Vinod Koulc46302e2018-04-26 18:39:05 +0530204
Pierre-Louis Bossart4a17c442020-07-16 23:09:40 +0800205 link->shim_lock = &ctx->shim_lock;
206 link->shim_mask = &ctx->shim_mask;
207
Vinod Kould62a7d42017-12-14 11:19:44 +0530208 memset(&pdevinfo, 0, sizeof(pdevinfo));
209
210 pdevinfo.parent = res->parent;
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +0800211 pdevinfo.name = "intel-sdw";
Vinod Kould62a7d42017-12-14 11:19:44 +0530212 pdevinfo.id = i;
213 pdevinfo.fwnode = acpi_fwnode_handle(adev);
Pierre-Louis Bossart4ab34412020-06-01 02:21:01 +0800214 pdevinfo.data = link;
215 pdevinfo.size_data = sizeof(*link);
Vinod Kould62a7d42017-12-14 11:19:44 +0530216
217 pdev = platform_device_register_full(&pdevinfo);
218 if (IS_ERR(pdev)) {
219 dev_err(&adev->dev,
220 "platform device creation failed: %ld\n",
221 PTR_ERR(pdev));
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +0800222 goto err;
Vinod Kould62a7d42017-12-14 11:19:44 +0530223 }
Vinod Kould62a7d42017-12-14 11:19:44 +0530224 link->pdev = pdev;
Vinod Kould62a7d42017-12-14 11:19:44 +0530225 }
226
227 return ctx;
228
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +0800229err:
Pierre-Louis Bossartdd906cc2020-06-01 02:21:00 +0800230 ctx->count = i;
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +0800231 sdw_intel_cleanup(ctx);
Vinod Kould62a7d42017-12-14 11:19:44 +0530232 return NULL;
233}
234
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +0800235static int
236sdw_intel_startup_controller(struct sdw_intel_ctx *ctx)
237{
238 struct acpi_device *adev;
239 struct sdw_intel_link_res *link;
240 u32 caps;
241 u32 link_mask;
242 int i;
243
244 if (acpi_bus_get_device(ctx->handle, &adev))
245 return -EINVAL;
246
247 /* Check SNDWLCAP.LCOUNT */
248 caps = ioread32(ctx->mmio_base + SDW_SHIM_BASE + SDW_SHIM_LCAP);
249 caps &= GENMASK(2, 0);
250
251 /* Check HW supported vs property value */
252 if (caps < ctx->count) {
253 dev_err(&adev->dev,
254 "BIOS master count is larger than hardware capabilities\n");
255 return -EINVAL;
256 }
257
258 if (!ctx->links)
259 return -EINVAL;
260
261 link = ctx->links;
262 link_mask = ctx->link_mask;
263
264 /* Startup SDW Master devices */
265 for (i = 0; i < ctx->count; i++, link++) {
266 if (!(link_mask & BIT(i)))
267 continue;
268
269 intel_master_startup(link->pdev);
270 }
271
272 return 0;
273}
274
Vinod Kould62a7d42017-12-14 11:19:44 +0530275static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level,
Pierre-Louis Bossart505ccb02019-05-01 10:57:37 -0500276 void *cdata, void **return_value)
Vinod Kould62a7d42017-12-14 11:19:44 +0530277{
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +0800278 struct sdw_intel_acpi_info *info = cdata;
Vinod Kould62a7d42017-12-14 11:19:44 +0530279 struct acpi_device *adev;
Pierre-Louis Bossart6f115862019-05-22 14:47:17 -0500280 acpi_status status;
281 u64 adr;
282
283 status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr);
284 if (ACPI_FAILURE(status))
285 return AE_OK; /* keep going */
Vinod Kould62a7d42017-12-14 11:19:44 +0530286
287 if (acpi_bus_get_device(handle, &adev)) {
Vinod Koule1c815f2018-08-07 11:54:50 +0530288 pr_err("%s: Couldn't find ACPI handle\n", __func__);
Vinod Kould62a7d42017-12-14 11:19:44 +0530289 return AE_NOT_FOUND;
290 }
291
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +0800292 info->handle = handle;
Pierre-Louis Bossart6f115862019-05-22 14:47:17 -0500293
294 /*
295 * On some Intel platforms, multiple children of the HDAS
296 * device can be found, but only one of them is the SoundWire
297 * controller. The SNDW device is always exposed with
298 * Name(_ADR, 0x40000000), with bits 31..28 representing the
299 * SoundWire link so filter accordingly
300 */
301 if ((adr & GENMASK(31, 28)) >> 28 != SDW_LINK_TYPE)
302 return AE_OK; /* keep going */
303
304 /* device found, stop namespace walk */
305 return AE_CTRL_TERMINATE;
Vinod Kould62a7d42017-12-14 11:19:44 +0530306}
307
308/**
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +0800309 * sdw_intel_acpi_scan() - SoundWire Intel init routine
Vinod Kould62a7d42017-12-14 11:19:44 +0530310 * @parent_handle: ACPI parent handle
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +0800311 * @info: description of what firmware/DSDT tables expose
Vinod Kould62a7d42017-12-14 11:19:44 +0530312 *
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +0800313 * This scans the namespace and queries firmware to figure out which
314 * links to enable. A follow-up use of sdw_intel_probe() and
315 * sdw_intel_startup() is required for creation of devices and bus
316 * startup
Vinod Kould62a7d42017-12-14 11:19:44 +0530317 */
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +0800318int sdw_intel_acpi_scan(acpi_handle *parent_handle,
319 struct sdw_intel_acpi_info *info)
Vinod Kould62a7d42017-12-14 11:19:44 +0530320{
321 acpi_status status;
322
323 status = acpi_walk_namespace(ACPI_TYPE_DEVICE,
Pierre-Louis Bossart505ccb02019-05-01 10:57:37 -0500324 parent_handle, 1,
325 sdw_intel_acpi_cb,
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +0800326 NULL, info, NULL);
Vinod Kould62a7d42017-12-14 11:19:44 +0530327 if (ACPI_FAILURE(status))
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +0800328 return -ENODEV;
Vinod Kould62a7d42017-12-14 11:19:44 +0530329
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +0800330 return sdw_intel_scan_controller(info);
Vinod Kould62a7d42017-12-14 11:19:44 +0530331}
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +0800332EXPORT_SYMBOL(sdw_intel_acpi_scan);
Vinod Kould62a7d42017-12-14 11:19:44 +0530333
334/**
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +0800335 * sdw_intel_probe() - SoundWire Intel probe routine
336 * @res: resource data
337 *
338 * This registers a platform device for each Master handled by the controller,
339 * and SoundWire Master and Slave devices will be created by the platform
340 * device probe. All the information necessary is stored in the context, and
341 * the res argument pointer can be freed after this step.
342 * This function will be called after sdw_intel_acpi_scan() by SOF probe.
343 */
344struct sdw_intel_ctx
345*sdw_intel_probe(struct sdw_intel_res *res)
346{
347 return sdw_intel_probe_controller(res);
348}
349EXPORT_SYMBOL(sdw_intel_probe);
350
351/**
352 * sdw_intel_startup() - SoundWire Intel startup
353 * @ctx: SoundWire context allocated in the probe
354 *
355 * Startup Intel SoundWire controller. This function will be called after
356 * Intel Audio DSP is powered up.
357 */
358int sdw_intel_startup(struct sdw_intel_ctx *ctx)
359{
360 return sdw_intel_startup_controller(ctx);
361}
362EXPORT_SYMBOL(sdw_intel_startup);
363/**
Vinod Kould62a7d42017-12-14 11:19:44 +0530364 * sdw_intel_exit() - SoundWire Intel exit
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +0800365 * @ctx: SoundWire context allocated in the probe
Vinod Kould62a7d42017-12-14 11:19:44 +0530366 *
367 * Delete the controller instances created and cleanup
368 */
Pierre-Louis Bossartf98f6902019-12-11 19:45:01 -0600369void sdw_intel_exit(struct sdw_intel_ctx *ctx)
Vinod Kould62a7d42017-12-14 11:19:44 +0530370{
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +0800371 sdw_intel_cleanup(ctx);
Vinod Kould62a7d42017-12-14 11:19:44 +0530372}
373EXPORT_SYMBOL(sdw_intel_exit);
374
375MODULE_LICENSE("Dual BSD/GPL");
376MODULE_DESCRIPTION("Intel Soundwire Init Library");