xref: /openbmc/linux/sound/soc/intel/atom/sst/sst_acpi.c (revision e5242c5f)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * sst_acpi.c - SST (LPE) driver init file for ACPI enumeration.
4  *
5  * Copyright (c) 2013, Intel Corporation.
6  *
7  *  Authors:	Ramesh Babu K V <Ramesh.Babu@intel.com>
8  *  Authors:	Omair Mohammed Abdullah <omair.m.abdullah@intel.com>
9  */
10 
11 #include <linux/module.h>
12 #include <linux/fs.h>
13 #include <linux/interrupt.h>
14 #include <linux/slab.h>
15 #include <linux/io.h>
16 #include <linux/platform_device.h>
17 #include <linux/firmware.h>
18 #include <linux/pm_qos.h>
19 #include <linux/dmi.h>
20 #include <linux/acpi.h>
21 #include <asm/platform_sst_audio.h>
22 #include <sound/core.h>
23 #include <sound/intel-dsp-config.h>
24 #include <sound/soc.h>
25 #include <sound/compress_driver.h>
26 #include <acpi/acbuffer.h>
27 #include <acpi/platform/acenv.h>
28 #include <acpi/platform/aclinux.h>
29 #include <acpi/actypes.h>
30 #include <acpi/acpi_bus.h>
31 #include <sound/soc-acpi.h>
32 #include <sound/soc-acpi-intel-match.h>
33 #include "../sst-mfld-platform.h"
34 #include "../../common/soc-intel-quirks.h"
35 #include "sst.h"
36 
37 /* LPE viewpoint addresses */
38 #define SST_BYT_IRAM_PHY_START	0xff2c0000
39 #define SST_BYT_IRAM_PHY_END	0xff2d4000
40 #define SST_BYT_DRAM_PHY_START	0xff300000
41 #define SST_BYT_DRAM_PHY_END	0xff320000
42 #define SST_BYT_IMR_VIRT_START	0xc0000000 /* virtual addr in LPE */
43 #define SST_BYT_IMR_VIRT_END	0xc01fffff
44 #define SST_BYT_SHIM_PHY_ADDR	0xff340000
45 #define SST_BYT_MBOX_PHY_ADDR	0xff344000
46 #define SST_BYT_DMA0_PHY_ADDR	0xff298000
47 #define SST_BYT_DMA1_PHY_ADDR	0xff29c000
48 #define SST_BYT_SSP0_PHY_ADDR	0xff2a0000
49 #define SST_BYT_SSP2_PHY_ADDR	0xff2a2000
50 
51 #define BYT_FW_MOD_TABLE_OFFSET	0x80000
52 #define BYT_FW_MOD_TABLE_SIZE	0x100
53 #define BYT_FW_MOD_OFFSET	(BYT_FW_MOD_TABLE_OFFSET + BYT_FW_MOD_TABLE_SIZE)
54 
55 static const struct sst_info byt_fwparse_info = {
56 	.use_elf	= false,
57 	.max_streams	= 25,
58 	.iram_start	= SST_BYT_IRAM_PHY_START,
59 	.iram_end	= SST_BYT_IRAM_PHY_END,
60 	.iram_use	= true,
61 	.dram_start	= SST_BYT_DRAM_PHY_START,
62 	.dram_end	= SST_BYT_DRAM_PHY_END,
63 	.dram_use	= true,
64 	.imr_start	= SST_BYT_IMR_VIRT_START,
65 	.imr_end	= SST_BYT_IMR_VIRT_END,
66 	.imr_use	= true,
67 	.mailbox_start	= SST_BYT_MBOX_PHY_ADDR,
68 	.num_probes	= 0,
69 	.lpe_viewpt_rqd  = true,
70 };
71 
72 static const struct sst_ipc_info byt_ipc_info = {
73 	.ipc_offset = 0,
74 	.mbox_recv_off = 0x400,
75 };
76 
77 static const struct sst_lib_dnld_info  byt_lib_dnld_info = {
78 	.mod_base           = SST_BYT_IMR_VIRT_START,
79 	.mod_end            = SST_BYT_IMR_VIRT_END,
80 	.mod_table_offset   = BYT_FW_MOD_TABLE_OFFSET,
81 	.mod_table_size     = BYT_FW_MOD_TABLE_SIZE,
82 	.mod_ddr_dnld       = false,
83 };
84 
85 static const struct sst_res_info byt_rvp_res_info = {
86 	.shim_offset = 0x140000,
87 	.shim_size = 0x000100,
88 	.shim_phy_addr = SST_BYT_SHIM_PHY_ADDR,
89 	.ssp0_offset = 0xa0000,
90 	.ssp0_size = 0x1000,
91 	.dma0_offset = 0x98000,
92 	.dma0_size = 0x4000,
93 	.dma1_offset = 0x9c000,
94 	.dma1_size = 0x4000,
95 	.iram_offset = 0x0c0000,
96 	.iram_size = 0x14000,
97 	.dram_offset = 0x100000,
98 	.dram_size = 0x28000,
99 	.mbox_offset = 0x144000,
100 	.mbox_size = 0x1000,
101 	.acpi_lpe_res_index = 0,
102 	.acpi_ddr_index = 2,
103 	.acpi_ipc_irq_index = 5,
104 };
105 
106 /* BYTCR has different BIOS from BYT */
107 static const struct sst_res_info bytcr_res_info = {
108 	.shim_offset = 0x140000,
109 	.shim_size = 0x000100,
110 	.shim_phy_addr = SST_BYT_SHIM_PHY_ADDR,
111 	.ssp0_offset = 0xa0000,
112 	.ssp0_size = 0x1000,
113 	.dma0_offset = 0x98000,
114 	.dma0_size = 0x4000,
115 	.dma1_offset = 0x9c000,
116 	.dma1_size = 0x4000,
117 	.iram_offset = 0x0c0000,
118 	.iram_size = 0x14000,
119 	.dram_offset = 0x100000,
120 	.dram_size = 0x28000,
121 	.mbox_offset = 0x144000,
122 	.mbox_size = 0x1000,
123 	.acpi_lpe_res_index = 0,
124 	.acpi_ddr_index = 2,
125 	.acpi_ipc_irq_index = 0
126 };
127 
128 /* For "LPE0F28" ACPI device found on some Android factory OS models */
129 static const struct sst_res_info lpe8086_res_info = {
130 	.shim_offset = 0x140000,
131 	.shim_size = 0x000100,
132 	.shim_phy_addr = SST_BYT_SHIM_PHY_ADDR,
133 	.ssp0_offset = 0xa0000,
134 	.ssp0_size = 0x1000,
135 	.dma0_offset = 0x98000,
136 	.dma0_size = 0x4000,
137 	.dma1_offset = 0x9c000,
138 	.dma1_size = 0x4000,
139 	.iram_offset = 0x0c0000,
140 	.iram_size = 0x14000,
141 	.dram_offset = 0x100000,
142 	.dram_size = 0x28000,
143 	.mbox_offset = 0x144000,
144 	.mbox_size = 0x1000,
145 	.acpi_lpe_res_index = 1,
146 	.acpi_ddr_index = 0,
147 	.acpi_ipc_irq_index = 0
148 };
149 
150 static struct sst_platform_info byt_rvp_platform_data = {
151 	.probe_data = &byt_fwparse_info,
152 	.ipc_info = &byt_ipc_info,
153 	.lib_info = &byt_lib_dnld_info,
154 	.res_info = &byt_rvp_res_info,
155 	.platform = "sst-mfld-platform",
156 	.streams_lost_on_suspend = true,
157 };
158 
159 /* Cherryview (Cherrytrail and Braswell) uses same mrfld dpcm fw as Baytrail,
160  * so pdata is same as Baytrail, minus the streams_lost_on_suspend quirk.
161  */
162 static struct sst_platform_info chv_platform_data = {
163 	.probe_data = &byt_fwparse_info,
164 	.ipc_info = &byt_ipc_info,
165 	.lib_info = &byt_lib_dnld_info,
166 	.res_info = &byt_rvp_res_info,
167 	.platform = "sst-mfld-platform",
168 };
169 
170 static int sst_platform_get_resources(struct intel_sst_drv *ctx)
171 {
172 	struct resource *rsrc;
173 	struct platform_device *pdev = to_platform_device(ctx->dev);
174 
175 	/* All ACPI resource request here */
176 	/* Get Shim addr */
177 	rsrc = platform_get_resource(pdev, IORESOURCE_MEM,
178 					ctx->pdata->res_info->acpi_lpe_res_index);
179 	if (!rsrc) {
180 		dev_err(ctx->dev, "Invalid SHIM base from IFWI\n");
181 		return -EIO;
182 	}
183 	dev_info(ctx->dev, "LPE base: %#x size:%#x", (unsigned int) rsrc->start,
184 					(unsigned int)resource_size(rsrc));
185 
186 	ctx->iram_base = rsrc->start + ctx->pdata->res_info->iram_offset;
187 	ctx->iram_end =  ctx->iram_base + ctx->pdata->res_info->iram_size - 1;
188 	dev_info(ctx->dev, "IRAM base: %#x", ctx->iram_base);
189 	ctx->iram = devm_ioremap(ctx->dev, ctx->iram_base,
190 					 ctx->pdata->res_info->iram_size);
191 	if (!ctx->iram) {
192 		dev_err(ctx->dev, "unable to map IRAM\n");
193 		return -EIO;
194 	}
195 
196 	ctx->dram_base = rsrc->start + ctx->pdata->res_info->dram_offset;
197 	ctx->dram_end = ctx->dram_base + ctx->pdata->res_info->dram_size - 1;
198 	dev_info(ctx->dev, "DRAM base: %#x", ctx->dram_base);
199 	ctx->dram = devm_ioremap(ctx->dev, ctx->dram_base,
200 					 ctx->pdata->res_info->dram_size);
201 	if (!ctx->dram) {
202 		dev_err(ctx->dev, "unable to map DRAM\n");
203 		return -EIO;
204 	}
205 
206 	ctx->shim_phy_add = rsrc->start + ctx->pdata->res_info->shim_offset;
207 	dev_info(ctx->dev, "SHIM base: %#x", ctx->shim_phy_add);
208 	ctx->shim = devm_ioremap(ctx->dev, ctx->shim_phy_add,
209 					ctx->pdata->res_info->shim_size);
210 	if (!ctx->shim) {
211 		dev_err(ctx->dev, "unable to map SHIM\n");
212 		return -EIO;
213 	}
214 
215 	/* reassign physical address to LPE viewpoint address */
216 	ctx->shim_phy_add = ctx->pdata->res_info->shim_phy_addr;
217 
218 	/* Get mailbox addr */
219 	ctx->mailbox_add = rsrc->start + ctx->pdata->res_info->mbox_offset;
220 	dev_info(ctx->dev, "Mailbox base: %#x", ctx->mailbox_add);
221 	ctx->mailbox = devm_ioremap(ctx->dev, ctx->mailbox_add,
222 					    ctx->pdata->res_info->mbox_size);
223 	if (!ctx->mailbox) {
224 		dev_err(ctx->dev, "unable to map mailbox\n");
225 		return -EIO;
226 	}
227 
228 	/* reassign physical address to LPE viewpoint address */
229 	ctx->mailbox_add = ctx->info.mailbox_start;
230 
231 	rsrc = platform_get_resource(pdev, IORESOURCE_MEM,
232 					ctx->pdata->res_info->acpi_ddr_index);
233 	if (!rsrc) {
234 		dev_err(ctx->dev, "Invalid DDR base from IFWI\n");
235 		return -EIO;
236 	}
237 	ctx->ddr_base = rsrc->start;
238 	ctx->ddr_end = rsrc->end;
239 	dev_info(ctx->dev, "DDR base: %#x", ctx->ddr_base);
240 	ctx->ddr = devm_ioremap(ctx->dev, ctx->ddr_base,
241 					resource_size(rsrc));
242 	if (!ctx->ddr) {
243 		dev_err(ctx->dev, "unable to map DDR\n");
244 		return -EIO;
245 	}
246 
247 	/* Find the IRQ */
248 	ctx->irq_num = platform_get_irq(pdev,
249 				ctx->pdata->res_info->acpi_ipc_irq_index);
250 	if (ctx->irq_num <= 0)
251 		return ctx->irq_num < 0 ? ctx->irq_num : -EIO;
252 
253 	return 0;
254 }
255 
256 static int sst_acpi_probe(struct platform_device *pdev)
257 {
258 	struct device *dev = &pdev->dev;
259 	int ret = 0;
260 	struct intel_sst_drv *ctx;
261 	const struct acpi_device_id *id;
262 	struct snd_soc_acpi_mach *mach;
263 	struct platform_device *mdev;
264 	struct platform_device *plat_dev;
265 	struct sst_platform_info *pdata;
266 	unsigned int dev_id;
267 
268 	id = acpi_match_device(dev->driver->acpi_match_table, dev);
269 	if (!id)
270 		return -ENODEV;
271 
272 	ret = snd_intel_acpi_dsp_driver_probe(dev, id->id);
273 	if (ret != SND_INTEL_DSP_DRIVER_ANY && ret != SND_INTEL_DSP_DRIVER_SST) {
274 		dev_dbg(dev, "SST ACPI driver not selected, aborting probe\n");
275 		return -ENODEV;
276 	}
277 
278 	dev_dbg(dev, "for %s\n", id->id);
279 
280 	mach = (struct snd_soc_acpi_mach *)id->driver_data;
281 	mach = snd_soc_acpi_find_machine(mach);
282 	if (mach == NULL) {
283 		dev_err(dev, "No matching machine driver found\n");
284 		return -ENODEV;
285 	}
286 
287 	if (soc_intel_is_byt())
288 		mach->pdata = &byt_rvp_platform_data;
289 	else
290 		mach->pdata = &chv_platform_data;
291 	pdata = mach->pdata;
292 
293 	if (!strcmp(id->id, "LPE0F28")) {
294 		struct resource *rsrc;
295 
296 		/* Use regular BYT SST PCI VID:PID */
297 		dev_id = 0x80860F28;
298 		byt_rvp_platform_data.res_info = &lpe8086_res_info;
299 
300 		/*
301 		 * The "LPE0F28" ACPI device has separate IO-mem resources for:
302 		 * DDR, SHIM, MBOX, IRAM, DRAM, CFG
303 		 * None of which covers the entire LPE base address range.
304 		 * lpe8086_res_info.acpi_lpe_res_index points to the SHIM.
305 		 * Patch this to cover the entire base address range as expected
306 		 * by sst_platform_get_resources().
307 		 */
308 		rsrc = platform_get_resource(pdev, IORESOURCE_MEM,
309 					     pdata->res_info->acpi_lpe_res_index);
310 		if (!rsrc) {
311 			dev_err(dev, "Invalid SHIM base\n");
312 			return -EIO;
313 		}
314 		rsrc->start -= pdata->res_info->shim_offset;
315 		rsrc->end = rsrc->start + 0x200000 - 1;
316 	} else {
317 		ret = kstrtouint(id->id, 16, &dev_id);
318 		if (ret < 0) {
319 			dev_err(dev, "Unique device id conversion error: %d\n", ret);
320 			return ret;
321 		}
322 
323 		if (soc_intel_is_byt_cr(pdev))
324 			byt_rvp_platform_data.res_info = &bytcr_res_info;
325 	}
326 
327 	dev_dbg(dev, "ACPI device id: %x\n", dev_id);
328 
329 	ret = sst_alloc_drv_context(&ctx, dev, dev_id);
330 	if (ret < 0)
331 		return ret;
332 
333 	/* update machine parameters */
334 	mach->mach_params.acpi_ipc_irq_index =
335 		pdata->res_info->acpi_ipc_irq_index;
336 
337 	plat_dev = platform_device_register_data(dev, pdata->platform, -1,
338 						NULL, 0);
339 	if (IS_ERR(plat_dev)) {
340 		dev_err(dev, "Failed to create machine device: %s\n",
341 			pdata->platform);
342 		return PTR_ERR(plat_dev);
343 	}
344 
345 	/*
346 	 * Create platform device for sst machine driver,
347 	 * pass machine info as pdata
348 	 */
349 	mdev = platform_device_register_data(dev, mach->drv_name, -1,
350 					(const void *)mach, sizeof(*mach));
351 	if (IS_ERR(mdev)) {
352 		dev_err(dev, "Failed to create machine device: %s\n",
353 			mach->drv_name);
354 		return PTR_ERR(mdev);
355 	}
356 
357 	/* Fill sst platform data */
358 	ctx->pdata = pdata;
359 	strcpy(ctx->firmware_name, mach->fw_filename);
360 
361 	ret = sst_platform_get_resources(ctx);
362 	if (ret)
363 		return ret;
364 
365 	ret = sst_context_init(ctx);
366 	if (ret < 0)
367 		return ret;
368 
369 	sst_configure_runtime_pm(ctx);
370 	platform_set_drvdata(pdev, ctx);
371 	return ret;
372 }
373 
374 /**
375 * sst_acpi_remove - remove function
376 *
377 * @pdev:	platform device structure
378 *
379 * This function is called by OS when a device is unloaded
380 * This frees the interrupt etc
381 */
382 static void sst_acpi_remove(struct platform_device *pdev)
383 {
384 	struct intel_sst_drv *ctx;
385 
386 	ctx = platform_get_drvdata(pdev);
387 	sst_context_cleanup(ctx);
388 	platform_set_drvdata(pdev, NULL);
389 }
390 
391 static const struct acpi_device_id sst_acpi_ids[] = {
392 	{ "LPE0F28", (unsigned long)&snd_soc_acpi_intel_baytrail_machines},
393 	{ "80860F28", (unsigned long)&snd_soc_acpi_intel_baytrail_machines},
394 	{ "808622A8", (unsigned long)&snd_soc_acpi_intel_cherrytrail_machines},
395 	{ },
396 };
397 
398 MODULE_DEVICE_TABLE(acpi, sst_acpi_ids);
399 
400 static struct platform_driver sst_acpi_driver = {
401 	.driver = {
402 		.name			= "intel_sst_acpi",
403 		.acpi_match_table	= ACPI_PTR(sst_acpi_ids),
404 		.pm			= &intel_sst_pm,
405 	},
406 	.probe	= sst_acpi_probe,
407 	.remove_new = sst_acpi_remove,
408 };
409 
410 module_platform_driver(sst_acpi_driver);
411 
412 MODULE_DESCRIPTION("Intel (R) SST(R) Audio Engine ACPI Driver");
413 MODULE_AUTHOR("Ramesh Babu K V");
414 MODULE_AUTHOR("Omair Mohammed Abdullah");
415 MODULE_LICENSE("GPL v2");
416 MODULE_ALIAS("sst");
417