blob: 55d9812870a450bbb00129643b261d38c584961b [file] [log] [blame]
YC Hung32d7e032021-11-18 12:07:42 +02001// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2//
3// Copyright(c) 2021 Mediatek Inc. All rights reserved.
4//
5// Author: YC Hung <yc.hung@mediatek.com>
6//
7
8/*
9 * Hardware interface for audio DSP on mt8195
10 */
11
12#include <linux/delay.h>
13#include <linux/firmware.h>
14#include <linux/io.h>
15#include <linux/of_address.h>
16#include <linux/of_irq.h>
17#include <linux/of_platform.h>
18#include <linux/of_reserved_mem.h>
19#include <linux/module.h>
20
21#include <sound/sof.h>
22#include <sound/sof/xtensa.h>
23#include "../../ops.h"
24#include "../../sof-audio.h"
25#include "../adsp_helper.h"
26#include "../mediatek-ops.h"
27#include "mt8195.h"
YC Hung424d6d12021-11-18 12:07:48 +020028#include "mt8195-clk.h"
YC Hung32d7e032021-11-18 12:07:42 +020029
30static int platform_parse_resource(struct platform_device *pdev, void *data)
31{
32 struct resource *mmio;
33 struct resource res;
34 struct device_node *mem_region;
35 struct device *dev = &pdev->dev;
36 struct mtk_adsp_chip_info *adsp = data;
37 int ret;
38
39 mem_region = of_parse_phandle(dev->of_node, "memory-region", 0);
40 if (!mem_region) {
41 dev_err(dev, "no dma memory-region phandle\n");
42 return -ENODEV;
43 }
44
45 ret = of_address_to_resource(mem_region, 0, &res);
Yang Yingliangfc6c62c2021-11-25 15:16:08 +080046 of_node_put(mem_region);
YC Hung32d7e032021-11-18 12:07:42 +020047 if (ret) {
48 dev_err(dev, "of_address_to_resource dma failed\n");
49 return ret;
50 }
51
52 dev_dbg(dev, "DMA pbase=0x%llx, size=0x%llx\n",
53 (phys_addr_t)res.start, resource_size(&res));
54
55 ret = of_reserved_mem_device_init(dev);
56 if (ret) {
57 dev_err(dev, "of_reserved_mem_device_init failed\n");
58 return ret;
59 }
60
61 mem_region = of_parse_phandle(dev->of_node, "memory-region", 1);
62 if (!mem_region) {
63 dev_err(dev, "no memory-region sysmem phandle\n");
64 return -ENODEV;
65 }
66
67 ret = of_address_to_resource(mem_region, 0, &res);
Yang Yingliangfc6c62c2021-11-25 15:16:08 +080068 of_node_put(mem_region);
YC Hung32d7e032021-11-18 12:07:42 +020069 if (ret) {
70 dev_err(dev, "of_address_to_resource sysmem failed\n");
71 return ret;
72 }
73
74 adsp->pa_dram = (phys_addr_t)res.start;
75 adsp->dramsize = resource_size(&res);
76 if (adsp->pa_dram & DRAM_REMAP_MASK) {
77 dev_err(dev, "adsp memory(%#x) is not 4K-aligned\n",
78 (u32)adsp->pa_dram);
79 return -EINVAL;
80 }
81
82 if (adsp->dramsize < TOTAL_SIZE_SHARED_DRAM_FROM_TAIL) {
83 dev_err(dev, "adsp memory(%#x) is not enough for share\n",
84 adsp->dramsize);
85 return -EINVAL;
86 }
87
88 dev_dbg(dev, "dram pbase=%pa, dramsize=%#x\n",
89 &adsp->pa_dram, adsp->dramsize);
90
91 /* Parse CFG base */
92 mmio = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg");
93 if (!mmio) {
94 dev_err(dev, "no ADSP-CFG register resource\n");
95 return -ENXIO;
96 }
97 /* remap for DSP register accessing */
98 adsp->va_cfgreg = devm_ioremap_resource(dev, mmio);
99 if (IS_ERR(adsp->va_cfgreg))
100 return PTR_ERR(adsp->va_cfgreg);
101
102 adsp->pa_cfgreg = (phys_addr_t)mmio->start;
103 adsp->cfgregsize = resource_size(mmio);
104
105 dev_dbg(dev, "cfgreg-vbase=%p, cfgregsize=%#x\n",
106 adsp->va_cfgreg, adsp->cfgregsize);
107
108 /* Parse SRAM */
109 mmio = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sram");
110 if (!mmio) {
111 dev_err(dev, "no SRAM resource\n");
112 return -ENXIO;
113 }
114
115 adsp->pa_sram = (phys_addr_t)mmio->start;
116 adsp->sramsize = resource_size(mmio);
117 if (adsp->sramsize < TOTAL_SIZE_SHARED_SRAM_FROM_TAIL) {
118 dev_err(dev, "adsp SRAM(%#x) is not enough for share\n",
119 adsp->sramsize);
120 return -EINVAL;
121 }
122
123 dev_dbg(dev, "sram pbase=%pa,%#x\n", &adsp->pa_sram, adsp->sramsize);
124
125 return ret;
126}
127
128static int adsp_sram_power_on(struct device *dev, bool on)
129{
130 void __iomem *va_dspsysreg;
131 u32 srampool_con;
132
133 va_dspsysreg = ioremap(ADSP_SRAM_POOL_CON, 0x4);
134 if (!va_dspsysreg) {
135 dev_err(dev, "failed to ioremap sram pool base %#x\n",
136 ADSP_SRAM_POOL_CON);
137 return -ENOMEM;
138 }
139
140 srampool_con = readl(va_dspsysreg);
141 if (on)
142 writel(srampool_con & ~DSP_SRAM_POOL_PD_MASK, va_dspsysreg);
143 else
144 writel(srampool_con | DSP_SRAM_POOL_PD_MASK, va_dspsysreg);
145
146 iounmap(va_dspsysreg);
147 return 0;
148}
149
150/* Init the basic DSP DRAM address */
151static int adsp_memory_remap_init(struct device *dev, struct mtk_adsp_chip_info *adsp)
152{
153 void __iomem *vaddr_emi_map;
154 int offset;
155
156 if (!adsp)
157 return -ENXIO;
158
159 vaddr_emi_map = devm_ioremap(dev, DSP_EMI_MAP_ADDR, 0x4);
160 if (!vaddr_emi_map) {
161 dev_err(dev, "failed to ioremap emi map base %#x\n",
162 DSP_EMI_MAP_ADDR);
163 return -ENOMEM;
164 }
165
166 offset = adsp->pa_dram - DRAM_PHYS_BASE_FROM_DSP_VIEW;
167 adsp->dram_offset = offset;
168 offset >>= DRAM_REMAP_SHIFT;
169 dev_dbg(dev, "adsp->pa_dram %llx, offset %#x\n", adsp->pa_dram, offset);
170 writel(offset, vaddr_emi_map);
171 if (offset != readl(vaddr_emi_map)) {
172 dev_err(dev, "write emi map fail : %#x\n", readl(vaddr_emi_map));
173 return -EIO;
174 }
175
176 return 0;
177}
178
179static int adsp_shared_base_ioremap(struct platform_device *pdev, void *data)
180{
181 struct device *dev = &pdev->dev;
182 struct mtk_adsp_chip_info *adsp = data;
183 u32 shared_size;
184
185 /* remap shared-dram base to be non-cachable */
186 shared_size = TOTAL_SIZE_SHARED_DRAM_FROM_TAIL;
187 adsp->pa_shared_dram = adsp->pa_dram + adsp->dramsize - shared_size;
188 if (adsp->va_dram) {
189 adsp->shared_dram = adsp->va_dram + DSP_DRAM_SIZE - shared_size;
190 } else {
191 adsp->shared_dram = devm_ioremap(dev, adsp->pa_shared_dram,
192 shared_size);
193 if (!adsp->shared_dram) {
194 dev_err(dev, "ioremap failed for shared DRAM\n");
195 return -ENOMEM;
196 }
197 }
198 dev_dbg(dev, "shared-dram vbase=%p, phy addr :%llx, size=%#x\n",
199 adsp->shared_dram, adsp->pa_shared_dram, shared_size);
200
201 return 0;
202}
203
YC Hungb7f65032021-11-18 12:07:45 +0200204static int mt8195_run(struct snd_sof_dev *sdev)
205{
206 u32 adsp_bootup_addr;
207
208 adsp_bootup_addr = SRAM_PHYS_BASE_FROM_DSP_VIEW;
209 dev_dbg(sdev->dev, "HIFIxDSP boot from base : 0x%08X\n", adsp_bootup_addr);
210 sof_hifixdsp_boot_sequence(sdev, adsp_bootup_addr);
211
212 return 0;
213}
214
YC Hung32d7e032021-11-18 12:07:42 +0200215static int mt8195_dsp_probe(struct snd_sof_dev *sdev)
216{
217 struct platform_device *pdev = container_of(sdev->dev, struct platform_device, dev);
218 struct adsp_priv *priv;
219 int ret;
220
221 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
222 if (!priv)
223 return -ENOMEM;
224
225 sdev->pdata->hw_pdata = priv;
226 priv->dev = sdev->dev;
227 priv->sdev = sdev;
228
229 priv->adsp = devm_kzalloc(&pdev->dev, sizeof(struct mtk_adsp_chip_info), GFP_KERNEL);
230 if (!priv->adsp)
231 return -ENOMEM;
232
233 ret = platform_parse_resource(pdev, priv->adsp);
234 if (ret)
235 return ret;
236
YC Hung424d6d12021-11-18 12:07:48 +0200237 ret = mt8195_adsp_init_clock(sdev);
238 if (ret) {
239 dev_err(sdev->dev, "mt8195_adsp_init_clock failed\n");
240 return -EINVAL;
241 }
242
243 ret = adsp_clock_on(sdev);
244 if (ret) {
245 dev_err(sdev->dev, "adsp_clock_on fail!\n");
246 return -EINVAL;
247 }
248
YC Hung32d7e032021-11-18 12:07:42 +0200249 ret = adsp_sram_power_on(sdev->dev, true);
250 if (ret) {
251 dev_err(sdev->dev, "adsp_sram_power_on fail!\n");
YC Hung424d6d12021-11-18 12:07:48 +0200252 goto exit_clk_disable;
YC Hung32d7e032021-11-18 12:07:42 +0200253 }
254
255 ret = adsp_memory_remap_init(&pdev->dev, priv->adsp);
256 if (ret) {
257 dev_err(sdev->dev, "adsp_memory_remap_init fail!\n");
258 goto err_adsp_sram_power_off;
259 }
260
261 sdev->bar[SOF_FW_BLK_TYPE_IRAM] = devm_ioremap(sdev->dev,
262 priv->adsp->pa_sram,
263 priv->adsp->sramsize);
264 if (!sdev->bar[SOF_FW_BLK_TYPE_IRAM]) {
265 dev_err(sdev->dev, "failed to ioremap base %pa size %#x\n",
266 &priv->adsp->pa_sram, priv->adsp->sramsize);
267 ret = -EINVAL;
268 goto err_adsp_sram_power_off;
269 }
270
271 sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap_wc(sdev->dev,
272 priv->adsp->pa_dram,
273 priv->adsp->dramsize);
274 if (!sdev->bar[SOF_FW_BLK_TYPE_SRAM]) {
275 dev_err(sdev->dev, "failed to ioremap base %pa size %#x\n",
276 &priv->adsp->pa_dram, priv->adsp->dramsize);
277 ret = -EINVAL;
278 goto err_adsp_sram_power_off;
279 }
280 priv->adsp->va_dram = sdev->bar[SOF_FW_BLK_TYPE_SRAM];
281
282 ret = adsp_shared_base_ioremap(pdev, priv->adsp);
283 if (ret) {
284 dev_err(sdev->dev, "adsp_shared_base_ioremap fail!\n");
285 goto err_adsp_sram_power_off;
286 }
287
288 sdev->bar[DSP_REG_BAR] = priv->adsp->va_cfgreg;
289 sdev->bar[DSP_MBOX0_BAR] = priv->adsp->va_mboxreg[0];
290 sdev->bar[DSP_MBOX1_BAR] = priv->adsp->va_mboxreg[1];
291 sdev->bar[DSP_MBOX2_BAR] = priv->adsp->va_mboxreg[2];
292
293 sdev->mmio_bar = SOF_FW_BLK_TYPE_SRAM;
294 sdev->mailbox_bar = SOF_FW_BLK_TYPE_SRAM;
295
296 return 0;
297
298err_adsp_sram_power_off:
299 adsp_sram_power_on(&pdev->dev, false);
YC Hung424d6d12021-11-18 12:07:48 +0200300exit_clk_disable:
301 adsp_clock_off(sdev);
YC Hung32d7e032021-11-18 12:07:42 +0200302
303 return ret;
304}
305
306static int mt8195_dsp_remove(struct snd_sof_dev *sdev)
307{
308 struct platform_device *pdev = container_of(sdev->dev, struct platform_device, dev);
309
YC Hung424d6d12021-11-18 12:07:48 +0200310 adsp_sram_power_on(&pdev->dev, false);
311 adsp_clock_off(sdev);
312
313 return 0;
YC Hung32d7e032021-11-18 12:07:42 +0200314}
315
YC Hung163fa3a2021-11-18 12:07:49 +0200316static int mt8195_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state)
317{
318 struct platform_device *pdev = container_of(sdev->dev, struct platform_device, dev);
319 int ret;
320
321 /* stall and reset dsp */
322 sof_hifixdsp_shutdown(sdev);
323
324 /* power down adsp sram */
325 ret = adsp_sram_power_on(&pdev->dev, false);
326 if (ret) {
327 dev_err(sdev->dev, "adsp_sram_power_off fail!\n");
328 return ret;
329 }
330
331 /* turn off adsp clock */
332 return adsp_clock_off(sdev);
333}
334
335static int mt8195_dsp_resume(struct snd_sof_dev *sdev)
336{
337 int ret;
338
339 /* turn on adsp clock */
340 ret = adsp_clock_on(sdev);
341 if (ret) {
342 dev_err(sdev->dev, "adsp_clock_on fail!\n");
343 return ret;
344 }
345
346 /* power on adsp sram */
347 ret = adsp_sram_power_on(sdev->dev, true);
348 if (ret)
349 dev_err(sdev->dev, "adsp_sram_power_on fail!\n");
350
351 return ret;
352}
353
YC Hung32d7e032021-11-18 12:07:42 +0200354/* on mt8195 there is 1 to 1 match between type and BAR idx */
355static int mt8195_get_bar_index(struct snd_sof_dev *sdev, u32 type)
356{
357 return type;
358}
359
YC Hung24d75042021-11-18 12:07:47 +0200360static struct snd_soc_dai_driver mt8195_dai[] = {
361{
362 .name = "SOF_DL2",
363 .playback = {
364 .channels_min = 1,
365 .channels_max = 2,
366 },
367},
368{
369 .name = "SOF_DL3",
370 .playback = {
371 .channels_min = 1,
372 .channels_max = 2,
373 },
374},
375{
376 .name = "SOF_UL4",
377 .capture = {
378 .channels_min = 1,
379 .channels_max = 2,
380 },
381},
382{
383 .name = "SOF_UL5",
384 .capture = {
385 .channels_min = 1,
386 .channels_max = 2,
387 },
388},
389};
390
YC Hung32d7e032021-11-18 12:07:42 +0200391/* mt8195 ops */
392const struct snd_sof_dsp_ops sof_mt8195_ops = {
393 /* probe and remove */
394 .probe = mt8195_dsp_probe,
395 .remove = mt8195_dsp_remove,
396
YC Hungb7f65032021-11-18 12:07:45 +0200397 /* DSP core boot */
398 .run = mt8195_run,
399
YC Hung32d7e032021-11-18 12:07:42 +0200400 /* Block IO */
401 .block_read = sof_block_read,
402 .block_write = sof_block_write,
403
404 /* Register IO */
405 .write = sof_io_write,
406 .read = sof_io_read,
407 .write64 = sof_io_write64,
408 .read64 = sof_io_read64,
409
410 /* misc */
411 .get_bar_index = mt8195_get_bar_index,
412
YC Hungb7f65032021-11-18 12:07:45 +0200413 /* module loading */
414 .load_module = snd_sof_parse_module_memcpy,
415 /* firmware loading */
416 .load_firmware = snd_sof_load_firmware_memcpy,
417
YC Hung32d7e032021-11-18 12:07:42 +0200418 /* Firmware ops */
419 .dsp_arch_ops = &sof_xtensa_arch_ops,
420
YC Hung24d75042021-11-18 12:07:47 +0200421 /* DAI drivers */
422 .drv = mt8195_dai,
423 .num_drv = ARRAY_SIZE(mt8195_dai),
424
YC Hung163fa3a2021-11-18 12:07:49 +0200425 /* PM */
426 .suspend = mt8195_dsp_suspend,
427 .resume = mt8195_dsp_resume,
428
YC Hung32d7e032021-11-18 12:07:42 +0200429 /* ALSA HW info flags */
430 .hw_info = SNDRV_PCM_INFO_MMAP |
431 SNDRV_PCM_INFO_MMAP_VALID |
432 SNDRV_PCM_INFO_INTERLEAVED |
433 SNDRV_PCM_INFO_PAUSE |
434 SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
435};
436EXPORT_SYMBOL(sof_mt8195_ops);
437
438MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA);
439MODULE_LICENSE("Dual BSD/GPL");