]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/soundwire/intel_init.c
Merge branch 'cve-2019-3016' into kvm-next-5.6
[linux.git] / drivers / soundwire / intel_init.c
1 // 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>
11 #include <linux/export.h>
12 #include <linux/io.h>
13 #include <linux/module.h>
14 #include <linux/platform_device.h>
15 #include <linux/soundwire/sdw_intel.h>
16 #include "intel.h"
17
18 #define SDW_LINK_TYPE           4 /* from Intel ACPI documentation */
19 #define SDW_MAX_LINKS           4
20 #define SDW_SHIM_LCAP           0x0
21 #define SDW_SHIM_BASE           0x2C000
22 #define SDW_ALH_BASE            0x2C800
23 #define SDW_LINK_BASE           0x30000
24 #define SDW_LINK_SIZE           0x10000
25
26 static int link_mask;
27 module_param_named(sdw_link_mask, link_mask, int, 0444);
28 MODULE_PARM_DESC(sdw_link_mask, "Intel link mask (one bit per link)");
29
30 struct sdw_link_data {
31         struct sdw_intel_link_res res;
32         struct platform_device *pdev;
33 };
34
35 struct sdw_intel_ctx {
36         int count;
37         struct sdw_link_data *links;
38 };
39
40 static int sdw_intel_cleanup_pdev(struct sdw_intel_ctx *ctx)
41 {
42         struct sdw_link_data *link = ctx->links;
43         int i;
44
45         if (!link)
46                 return 0;
47
48         for (i = 0; i < ctx->count; i++) {
49                 if (link->pdev)
50                         platform_device_unregister(link->pdev);
51                 link++;
52         }
53
54         kfree(ctx->links);
55         ctx->links = NULL;
56
57         return 0;
58 }
59
60 static struct sdw_intel_ctx
61 *sdw_intel_add_controller(struct sdw_intel_res *res)
62 {
63         struct platform_device_info pdevinfo;
64         struct platform_device *pdev;
65         struct sdw_link_data *link;
66         struct sdw_intel_ctx *ctx;
67         struct acpi_device *adev;
68         int ret, i;
69         u8 count;
70         u32 caps;
71
72         if (acpi_bus_get_device(res->handle, &adev))
73                 return NULL;
74
75         /* Found controller, find links supported */
76         count = 0;
77         ret = fwnode_property_read_u8_array(acpi_fwnode_handle(adev),
78                                             "mipi-sdw-master-count", &count, 1);
79
80         /* Don't fail on error, continue and use hw value */
81         if (ret) {
82                 dev_err(&adev->dev,
83                         "Failed to read mipi-sdw-master-count: %d\n", ret);
84                 count = SDW_MAX_LINKS;
85         }
86
87         /* Check SNDWLCAP.LCOUNT */
88         caps = ioread32(res->mmio_base + SDW_SHIM_BASE + SDW_SHIM_LCAP);
89         caps &= GENMASK(2, 0);
90
91         /* Check HW supported vs property value and use min of two */
92         count = min_t(u8, caps, count);
93
94         /* Check count is within bounds */
95         if (count > SDW_MAX_LINKS) {
96                 dev_err(&adev->dev, "Link count %d exceeds max %d\n",
97                         count, SDW_MAX_LINKS);
98                 return NULL;
99         } else if (!count) {
100                 dev_warn(&adev->dev, "No SoundWire links detected\n");
101                 return NULL;
102         }
103
104         dev_dbg(&adev->dev, "Creating %d SDW Link devices\n", count);
105
106         ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
107         if (!ctx)
108                 return NULL;
109
110         ctx->count = count;
111         ctx->links = kcalloc(ctx->count, sizeof(*ctx->links), GFP_KERNEL);
112         if (!ctx->links)
113                 goto link_err;
114
115         link = ctx->links;
116
117         /* Create SDW Master devices */
118         for (i = 0; i < count; i++) {
119                 if (link_mask && !(link_mask & BIT(i))) {
120                         dev_dbg(&adev->dev,
121                                 "Link %d masked, will not be enabled\n", i);
122                         link++;
123                         continue;
124                 }
125
126                 link->res.irq = res->irq;
127                 link->res.registers = res->mmio_base + SDW_LINK_BASE
128                                         + (SDW_LINK_SIZE * i);
129                 link->res.shim = res->mmio_base + SDW_SHIM_BASE;
130                 link->res.alh = res->mmio_base + SDW_ALH_BASE;
131
132                 link->res.ops = res->ops;
133                 link->res.arg = res->arg;
134
135                 memset(&pdevinfo, 0, sizeof(pdevinfo));
136
137                 pdevinfo.parent = res->parent;
138                 pdevinfo.name = "int-sdw";
139                 pdevinfo.id = i;
140                 pdevinfo.fwnode = acpi_fwnode_handle(adev);
141                 pdevinfo.data = &link->res;
142                 pdevinfo.size_data = sizeof(link->res);
143
144                 pdev = platform_device_register_full(&pdevinfo);
145                 if (IS_ERR(pdev)) {
146                         dev_err(&adev->dev,
147                                 "platform device creation failed: %ld\n",
148                                 PTR_ERR(pdev));
149                         goto pdev_err;
150                 }
151
152                 link->pdev = pdev;
153                 link++;
154         }
155
156         return ctx;
157
158 pdev_err:
159         sdw_intel_cleanup_pdev(ctx);
160 link_err:
161         kfree(ctx);
162         return NULL;
163 }
164
165 static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level,
166                                      void *cdata, void **return_value)
167 {
168         struct sdw_intel_res *res = cdata;
169         struct acpi_device *adev;
170         acpi_status status;
171         u64 adr;
172
173         status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr);
174         if (ACPI_FAILURE(status))
175                 return AE_OK; /* keep going */
176
177         if (acpi_bus_get_device(handle, &adev)) {
178                 pr_err("%s: Couldn't find ACPI handle\n", __func__);
179                 return AE_NOT_FOUND;
180         }
181
182         res->handle = handle;
183
184         /*
185          * On some Intel platforms, multiple children of the HDAS
186          * device can be found, but only one of them is the SoundWire
187          * controller. The SNDW device is always exposed with
188          * Name(_ADR, 0x40000000), with bits 31..28 representing the
189          * SoundWire link so filter accordingly
190          */
191         if ((adr & GENMASK(31, 28)) >> 28 != SDW_LINK_TYPE)
192                 return AE_OK; /* keep going */
193
194         /* device found, stop namespace walk */
195         return AE_CTRL_TERMINATE;
196 }
197
198 /**
199  * sdw_intel_init() - SoundWire Intel init routine
200  * @parent_handle: ACPI parent handle
201  * @res: resource data
202  *
203  * This scans the namespace and creates SoundWire link controller devices
204  * based on the info queried.
205  */
206 void *sdw_intel_init(acpi_handle *parent_handle, struct sdw_intel_res *res)
207 {
208         acpi_status status;
209
210         status = acpi_walk_namespace(ACPI_TYPE_DEVICE,
211                                      parent_handle, 1,
212                                      sdw_intel_acpi_cb,
213                                      NULL, res, NULL);
214         if (ACPI_FAILURE(status))
215                 return NULL;
216
217         return sdw_intel_add_controller(res);
218 }
219 EXPORT_SYMBOL(sdw_intel_init);
220
221 /**
222  * sdw_intel_exit() - SoundWire Intel exit
223  * @arg: callback context
224  *
225  * Delete the controller instances created and cleanup
226  */
227 void sdw_intel_exit(void *arg)
228 {
229         struct sdw_intel_ctx *ctx = arg;
230
231         sdw_intel_cleanup_pdev(ctx);
232         kfree(ctx);
233 }
234 EXPORT_SYMBOL(sdw_intel_exit);
235
236 MODULE_LICENSE("Dual BSD/GPL");
237 MODULE_DESCRIPTION("Intel Soundwire Init Library");