Linux Audio

Check our new training course

Loading...
v5.9
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Intel SST loader on ACPI systems
  4 *
  5 * Copyright (C) 2013, Intel Corporation. All rights reserved.
 
 
 
 
 
 
 
 
 
 
  6 */
  7
  8#include <linux/acpi.h>
  9#include <linux/device.h>
 10#include <linux/firmware.h>
 11#include <linux/module.h>
 12#include <linux/platform_device.h>
 13
 14#include "sst-dsp.h"
 15#include <sound/soc-acpi.h>
 16#include <sound/soc-acpi-intel-match.h>
 17
 18#define SST_LPT_DSP_DMA_ADDR_OFFSET	0x0F0000
 19#define SST_WPT_DSP_DMA_ADDR_OFFSET	0x0FE000
 20#define SST_LPT_DSP_DMA_SIZE		(1024 - 1)
 21
 22/* Descriptor for setting up SST platform data */
 23struct sst_acpi_desc {
 24	const char *drv_name;
 25	struct snd_soc_acpi_mach *machines;
 26	/* Platform resource indexes. Must set to -1 if not used */
 27	int resindex_lpe_base;
 28	int resindex_pcicfg_base;
 29	int resindex_fw_base;
 30	int irqindex_host_ipc;
 31	int resindex_dma_base;
 32	/* Unique number identifying the SST core on platform */
 33	int sst_id;
 34	/* DMA only valid when resindex_dma_base != -1*/
 35	int dma_engine;
 36	int dma_size;
 37};
 38
 39struct sst_acpi_priv {
 40	struct platform_device *pdev_mach;
 41	struct platform_device *pdev_pcm;
 42	struct sst_pdata sst_pdata;
 43	struct sst_acpi_desc *desc;
 44	struct snd_soc_acpi_mach *mach;
 45};
 46
 47static void sst_acpi_fw_cb(const struct firmware *fw, void *context)
 48{
 49	struct platform_device *pdev = context;
 50	struct device *dev = &pdev->dev;
 51	struct sst_acpi_priv *sst_acpi = platform_get_drvdata(pdev);
 52	struct sst_pdata *sst_pdata = &sst_acpi->sst_pdata;
 53	struct sst_acpi_desc *desc = sst_acpi->desc;
 54	struct snd_soc_acpi_mach *mach = sst_acpi->mach;
 55
 56	sst_pdata->fw = fw;
 57	if (!fw) {
 58		dev_err(dev, "Cannot load firmware %s\n", mach->fw_filename);
 59		return;
 60	}
 61
 62	/* register PCM and DAI driver */
 63	sst_acpi->pdev_pcm =
 64		platform_device_register_data(dev, desc->drv_name, -1,
 65					      sst_pdata, sizeof(*sst_pdata));
 66	if (IS_ERR(sst_acpi->pdev_pcm)) {
 67		dev_err(dev, "Cannot register device %s. Error %d\n",
 68			desc->drv_name, (int)PTR_ERR(sst_acpi->pdev_pcm));
 69	}
 70
 71	return;
 72}
 73
 74static int sst_acpi_probe(struct platform_device *pdev)
 75{
 76	const struct acpi_device_id *id;
 77	struct device *dev = &pdev->dev;
 78	struct sst_acpi_priv *sst_acpi;
 79	struct sst_pdata *sst_pdata;
 80	struct snd_soc_acpi_mach *mach;
 81	struct sst_acpi_desc *desc;
 82	struct resource *mmio;
 83	int ret = 0;
 84
 85	sst_acpi = devm_kzalloc(dev, sizeof(*sst_acpi), GFP_KERNEL);
 86	if (sst_acpi == NULL)
 87		return -ENOMEM;
 88
 89	id = acpi_match_device(dev->driver->acpi_match_table, dev);
 90	if (!id)
 91		return -ENODEV;
 92
 93	desc = (struct sst_acpi_desc *)id->driver_data;
 94	mach = snd_soc_acpi_find_machine(desc->machines);
 95	if (mach == NULL) {
 96		dev_err(dev, "No matching ASoC machine driver found\n");
 97		return -ENODEV;
 98	}
 99
100	sst_pdata = &sst_acpi->sst_pdata;
101	sst_pdata->id = desc->sst_id;
102	sst_pdata->dma_dev = dev;
103	sst_acpi->desc = desc;
104	sst_acpi->mach = mach;
105
106	sst_pdata->resindex_dma_base = desc->resindex_dma_base;
107	if (desc->resindex_dma_base >= 0) {
108		sst_pdata->dma_engine = desc->dma_engine;
109		sst_pdata->dma_base = desc->resindex_dma_base;
110		sst_pdata->dma_size = desc->dma_size;
111	}
112
113	if (desc->irqindex_host_ipc >= 0)
114		sst_pdata->irq = platform_get_irq(pdev, desc->irqindex_host_ipc);
115
116	if (desc->resindex_lpe_base >= 0) {
117		mmio = platform_get_resource(pdev, IORESOURCE_MEM,
118					     desc->resindex_lpe_base);
119		if (mmio) {
120			sst_pdata->lpe_base = mmio->start;
121			sst_pdata->lpe_size = resource_size(mmio);
122		}
123	}
124
125	if (desc->resindex_pcicfg_base >= 0) {
126		mmio = platform_get_resource(pdev, IORESOURCE_MEM,
127					     desc->resindex_pcicfg_base);
128		if (mmio) {
129			sst_pdata->pcicfg_base = mmio->start;
130			sst_pdata->pcicfg_size = resource_size(mmio);
131		}
132	}
133
134	if (desc->resindex_fw_base >= 0) {
135		mmio = platform_get_resource(pdev, IORESOURCE_MEM,
136					     desc->resindex_fw_base);
137		if (mmio) {
138			sst_pdata->fw_base = mmio->start;
139			sst_pdata->fw_size = resource_size(mmio);
140		}
141	}
142
143	platform_set_drvdata(pdev, sst_acpi);
144	mach->pdata = sst_pdata;
145
146	/* register machine driver */
147	sst_acpi->pdev_mach =
148		platform_device_register_data(dev, mach->drv_name, -1,
149					      mach, sizeof(*mach));
150	if (IS_ERR(sst_acpi->pdev_mach))
151		return PTR_ERR(sst_acpi->pdev_mach);
152
153	/* continue SST probing after firmware is loaded */
154	ret = request_firmware_nowait(THIS_MODULE, true, mach->fw_filename,
155				      dev, GFP_KERNEL, pdev, sst_acpi_fw_cb);
156	if (ret)
157		platform_device_unregister(sst_acpi->pdev_mach);
158
159	return ret;
160}
161
162static int sst_acpi_remove(struct platform_device *pdev)
163{
164	struct sst_acpi_priv *sst_acpi = platform_get_drvdata(pdev);
165	struct sst_pdata *sst_pdata = &sst_acpi->sst_pdata;
166
167	platform_device_unregister(sst_acpi->pdev_mach);
168	if (!IS_ERR_OR_NULL(sst_acpi->pdev_pcm))
169		platform_device_unregister(sst_acpi->pdev_pcm);
170	release_firmware(sst_pdata->fw);
171
172	return 0;
173}
174
175static struct sst_acpi_desc sst_acpi_haswell_desc = {
176	.drv_name = "haswell-pcm-audio",
177	.machines = snd_soc_acpi_intel_haswell_machines,
178	.resindex_lpe_base = 0,
179	.resindex_pcicfg_base = 1,
180	.resindex_fw_base = -1,
181	.irqindex_host_ipc = 0,
182	.sst_id = SST_DEV_ID_LYNX_POINT,
183	.dma_engine = SST_DMA_TYPE_DW,
184	.resindex_dma_base = SST_LPT_DSP_DMA_ADDR_OFFSET,
185	.dma_size = SST_LPT_DSP_DMA_SIZE,
186};
187
188static struct sst_acpi_desc sst_acpi_broadwell_desc = {
189	.drv_name = "haswell-pcm-audio",
190	.machines = snd_soc_acpi_intel_broadwell_machines,
191	.resindex_lpe_base = 0,
192	.resindex_pcicfg_base = 1,
193	.resindex_fw_base = -1,
194	.irqindex_host_ipc = 0,
195	.sst_id = SST_DEV_ID_WILDCAT_POINT,
196	.dma_engine = SST_DMA_TYPE_DW,
197	.resindex_dma_base = SST_WPT_DSP_DMA_ADDR_OFFSET,
198	.dma_size = SST_LPT_DSP_DMA_SIZE,
199};
200
201#if !IS_ENABLED(CONFIG_SND_SST_IPC_ACPI)
202static struct sst_acpi_desc sst_acpi_baytrail_desc = {
203	.drv_name = "baytrail-pcm-audio",
204	.machines = snd_soc_acpi_intel_baytrail_legacy_machines,
205	.resindex_lpe_base = 0,
206	.resindex_pcicfg_base = 1,
207	.resindex_fw_base = 2,
208	.irqindex_host_ipc = 5,
209	.sst_id = SST_DEV_ID_BYT,
210	.resindex_dma_base = -1,
211};
212#endif
213
214static const struct acpi_device_id sst_acpi_match[] = {
215	{ "INT33C8", (unsigned long)&sst_acpi_haswell_desc },
216	{ "INT3438", (unsigned long)&sst_acpi_broadwell_desc },
217#if !IS_ENABLED(CONFIG_SND_SST_IPC_ACPI)
218	{ "80860F28", (unsigned long)&sst_acpi_baytrail_desc },
219#endif
220	{ }
221};
222MODULE_DEVICE_TABLE(acpi, sst_acpi_match);
223
224static struct platform_driver sst_acpi_driver = {
225	.probe = sst_acpi_probe,
226	.remove = sst_acpi_remove,
227	.driver = {
228		.name = "sst-acpi",
229		.acpi_match_table = ACPI_PTR(sst_acpi_match),
230	},
231};
232module_platform_driver(sst_acpi_driver);
233
234MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@linux.intel.com>");
235MODULE_DESCRIPTION("Intel SST loader on ACPI systems");
236MODULE_LICENSE("GPL v2");
v4.17
 
  1/*
  2 * Intel SST loader on ACPI systems
  3 *
  4 * Copyright (C) 2013, Intel Corporation. All rights reserved.
  5 *
  6 * This program is free software; you can redistribute it and/or
  7 * modify it under the terms of the GNU General Public License version
  8 * 2 as published by the Free Software Foundation.
  9 *
 10 * This program is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 13 * GNU General Public License for more details.
 14 *
 15 */
 16
 17#include <linux/acpi.h>
 18#include <linux/device.h>
 19#include <linux/firmware.h>
 20#include <linux/module.h>
 21#include <linux/platform_device.h>
 22
 23#include "sst-dsp.h"
 24#include <sound/soc-acpi.h>
 25#include <sound/soc-acpi-intel-match.h>
 26
 27#define SST_LPT_DSP_DMA_ADDR_OFFSET	0x0F0000
 28#define SST_WPT_DSP_DMA_ADDR_OFFSET	0x0FE000
 29#define SST_LPT_DSP_DMA_SIZE		(1024 - 1)
 30
 31/* Descriptor for setting up SST platform data */
 32struct sst_acpi_desc {
 33	const char *drv_name;
 34	struct snd_soc_acpi_mach *machines;
 35	/* Platform resource indexes. Must set to -1 if not used */
 36	int resindex_lpe_base;
 37	int resindex_pcicfg_base;
 38	int resindex_fw_base;
 39	int irqindex_host_ipc;
 40	int resindex_dma_base;
 41	/* Unique number identifying the SST core on platform */
 42	int sst_id;
 43	/* DMA only valid when resindex_dma_base != -1*/
 44	int dma_engine;
 45	int dma_size;
 46};
 47
 48struct sst_acpi_priv {
 49	struct platform_device *pdev_mach;
 50	struct platform_device *pdev_pcm;
 51	struct sst_pdata sst_pdata;
 52	struct sst_acpi_desc *desc;
 53	struct snd_soc_acpi_mach *mach;
 54};
 55
 56static void sst_acpi_fw_cb(const struct firmware *fw, void *context)
 57{
 58	struct platform_device *pdev = context;
 59	struct device *dev = &pdev->dev;
 60	struct sst_acpi_priv *sst_acpi = platform_get_drvdata(pdev);
 61	struct sst_pdata *sst_pdata = &sst_acpi->sst_pdata;
 62	struct sst_acpi_desc *desc = sst_acpi->desc;
 63	struct snd_soc_acpi_mach *mach = sst_acpi->mach;
 64
 65	sst_pdata->fw = fw;
 66	if (!fw) {
 67		dev_err(dev, "Cannot load firmware %s\n", mach->fw_filename);
 68		return;
 69	}
 70
 71	/* register PCM and DAI driver */
 72	sst_acpi->pdev_pcm =
 73		platform_device_register_data(dev, desc->drv_name, -1,
 74					      sst_pdata, sizeof(*sst_pdata));
 75	if (IS_ERR(sst_acpi->pdev_pcm)) {
 76		dev_err(dev, "Cannot register device %s. Error %d\n",
 77			desc->drv_name, (int)PTR_ERR(sst_acpi->pdev_pcm));
 78	}
 79
 80	return;
 81}
 82
 83static int sst_acpi_probe(struct platform_device *pdev)
 84{
 85	const struct acpi_device_id *id;
 86	struct device *dev = &pdev->dev;
 87	struct sst_acpi_priv *sst_acpi;
 88	struct sst_pdata *sst_pdata;
 89	struct snd_soc_acpi_mach *mach;
 90	struct sst_acpi_desc *desc;
 91	struct resource *mmio;
 92	int ret = 0;
 93
 94	sst_acpi = devm_kzalloc(dev, sizeof(*sst_acpi), GFP_KERNEL);
 95	if (sst_acpi == NULL)
 96		return -ENOMEM;
 97
 98	id = acpi_match_device(dev->driver->acpi_match_table, dev);
 99	if (!id)
100		return -ENODEV;
101
102	desc = (struct sst_acpi_desc *)id->driver_data;
103	mach = snd_soc_acpi_find_machine(desc->machines);
104	if (mach == NULL) {
105		dev_err(dev, "No matching ASoC machine driver found\n");
106		return -ENODEV;
107	}
108
109	sst_pdata = &sst_acpi->sst_pdata;
110	sst_pdata->id = desc->sst_id;
111	sst_pdata->dma_dev = dev;
112	sst_acpi->desc = desc;
113	sst_acpi->mach = mach;
114
115	sst_pdata->resindex_dma_base = desc->resindex_dma_base;
116	if (desc->resindex_dma_base >= 0) {
117		sst_pdata->dma_engine = desc->dma_engine;
118		sst_pdata->dma_base = desc->resindex_dma_base;
119		sst_pdata->dma_size = desc->dma_size;
120	}
121
122	if (desc->irqindex_host_ipc >= 0)
123		sst_pdata->irq = platform_get_irq(pdev, desc->irqindex_host_ipc);
124
125	if (desc->resindex_lpe_base >= 0) {
126		mmio = platform_get_resource(pdev, IORESOURCE_MEM,
127					     desc->resindex_lpe_base);
128		if (mmio) {
129			sst_pdata->lpe_base = mmio->start;
130			sst_pdata->lpe_size = resource_size(mmio);
131		}
132	}
133
134	if (desc->resindex_pcicfg_base >= 0) {
135		mmio = platform_get_resource(pdev, IORESOURCE_MEM,
136					     desc->resindex_pcicfg_base);
137		if (mmio) {
138			sst_pdata->pcicfg_base = mmio->start;
139			sst_pdata->pcicfg_size = resource_size(mmio);
140		}
141	}
142
143	if (desc->resindex_fw_base >= 0) {
144		mmio = platform_get_resource(pdev, IORESOURCE_MEM,
145					     desc->resindex_fw_base);
146		if (mmio) {
147			sst_pdata->fw_base = mmio->start;
148			sst_pdata->fw_size = resource_size(mmio);
149		}
150	}
151
152	platform_set_drvdata(pdev, sst_acpi);
 
153
154	/* register machine driver */
155	sst_acpi->pdev_mach =
156		platform_device_register_data(dev, mach->drv_name, -1,
157					      sst_pdata, sizeof(*sst_pdata));
158	if (IS_ERR(sst_acpi->pdev_mach))
159		return PTR_ERR(sst_acpi->pdev_mach);
160
161	/* continue SST probing after firmware is loaded */
162	ret = request_firmware_nowait(THIS_MODULE, true, mach->fw_filename,
163				      dev, GFP_KERNEL, pdev, sst_acpi_fw_cb);
164	if (ret)
165		platform_device_unregister(sst_acpi->pdev_mach);
166
167	return ret;
168}
169
170static int sst_acpi_remove(struct platform_device *pdev)
171{
172	struct sst_acpi_priv *sst_acpi = platform_get_drvdata(pdev);
173	struct sst_pdata *sst_pdata = &sst_acpi->sst_pdata;
174
175	platform_device_unregister(sst_acpi->pdev_mach);
176	if (!IS_ERR_OR_NULL(sst_acpi->pdev_pcm))
177		platform_device_unregister(sst_acpi->pdev_pcm);
178	release_firmware(sst_pdata->fw);
179
180	return 0;
181}
182
183static struct sst_acpi_desc sst_acpi_haswell_desc = {
184	.drv_name = "haswell-pcm-audio",
185	.machines = snd_soc_acpi_intel_haswell_machines,
186	.resindex_lpe_base = 0,
187	.resindex_pcicfg_base = 1,
188	.resindex_fw_base = -1,
189	.irqindex_host_ipc = 0,
190	.sst_id = SST_DEV_ID_LYNX_POINT,
191	.dma_engine = SST_DMA_TYPE_DW,
192	.resindex_dma_base = SST_LPT_DSP_DMA_ADDR_OFFSET,
193	.dma_size = SST_LPT_DSP_DMA_SIZE,
194};
195
196static struct sst_acpi_desc sst_acpi_broadwell_desc = {
197	.drv_name = "haswell-pcm-audio",
198	.machines = snd_soc_acpi_intel_broadwell_machines,
199	.resindex_lpe_base = 0,
200	.resindex_pcicfg_base = 1,
201	.resindex_fw_base = -1,
202	.irqindex_host_ipc = 0,
203	.sst_id = SST_DEV_ID_WILDCAT_POINT,
204	.dma_engine = SST_DMA_TYPE_DW,
205	.resindex_dma_base = SST_WPT_DSP_DMA_ADDR_OFFSET,
206	.dma_size = SST_LPT_DSP_DMA_SIZE,
207};
208
209#if !IS_ENABLED(CONFIG_SND_SST_IPC_ACPI)
210static struct sst_acpi_desc sst_acpi_baytrail_desc = {
211	.drv_name = "baytrail-pcm-audio",
212	.machines = snd_soc_acpi_intel_baytrail_legacy_machines,
213	.resindex_lpe_base = 0,
214	.resindex_pcicfg_base = 1,
215	.resindex_fw_base = 2,
216	.irqindex_host_ipc = 5,
217	.sst_id = SST_DEV_ID_BYT,
218	.resindex_dma_base = -1,
219};
220#endif
221
222static const struct acpi_device_id sst_acpi_match[] = {
223	{ "INT33C8", (unsigned long)&sst_acpi_haswell_desc },
224	{ "INT3438", (unsigned long)&sst_acpi_broadwell_desc },
225#if !IS_ENABLED(CONFIG_SND_SST_IPC_ACPI)
226	{ "80860F28", (unsigned long)&sst_acpi_baytrail_desc },
227#endif
228	{ }
229};
230MODULE_DEVICE_TABLE(acpi, sst_acpi_match);
231
232static struct platform_driver sst_acpi_driver = {
233	.probe = sst_acpi_probe,
234	.remove = sst_acpi_remove,
235	.driver = {
236		.name = "sst-acpi",
237		.acpi_match_table = ACPI_PTR(sst_acpi_match),
238	},
239};
240module_platform_driver(sst_acpi_driver);
241
242MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@linux.intel.com>");
243MODULE_DESCRIPTION("Intel SST loader on ACPI systems");
244MODULE_LICENSE("GPL v2");