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");
238