projects/linux·blob master · refs

347 lines · 10.2 KiB

1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2//
3// This file is provided under a dual BSD/GPLv2 license. When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2021, 2023 Advanced Micro Devices, Inc.
7//
8// Authors: Ajit Kumar Pandey <[email protected]>
9
10/*
11 * Hardware interface for ACP DSP Firmware binaries loader
12 */
13
14#include <linux/firmware.h>
15#include <linux/module.h>
16#include <linux/pci.h>
17#include <linux/unaligned.h>
18
19#include "../ops.h"
20#include "acp-dsp-offset.h"
21#include "acp.h"
22
23#define FW_BIN 0
24#define FW_DATA_BIN 1
25#define FW_SRAM_DATA_BIN 2
26
27#define FW_BIN_PTE_OFFSET 0x00
28#define FW_DATA_BIN_PTE_OFFSET 0x08
29
30#define ACP_DSP_RUN 0x00
31
32int acp_dsp_block_read(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_type,
33 u32 offset, void *dest, size_t size)
34{
35 const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
36 switch (blk_type) {
37 case SOF_FW_BLK_TYPE_SRAM:
38 offset = offset - desc->sram_pte_offset;
39 memcpy_from_scratch(sdev, offset, dest, size);
40 break;
41 default:
42 dev_err(sdev->dev, "bad blk type 0x%x\n", blk_type);
43 return -EINVAL;
44 }
45
46 return 0;
47}
48EXPORT_SYMBOL_NS(acp_dsp_block_read, "SND_SOC_SOF_AMD_COMMON");
49
50int acp_dsp_block_write(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_type,
51 u32 offset, void *src, size_t size)
52{
53 struct pci_dev *pci = to_pci_dev(sdev->dev);
54 struct acp_dev_data *adata;
55 void *dest;
56 u32 dma_size, page_count;
57 unsigned int size_fw;
58
59 adata = sdev->pdata->hw_pdata;
60
61 switch (blk_type) {
62 case SOF_FW_BLK_TYPE_IRAM:
63 if (!adata->bin_buf) {
64 size_fw = sdev->basefw.fw->size;
65 page_count = PAGE_ALIGN(size_fw) >> PAGE_SHIFT;
66 dma_size = page_count * ACP_PAGE_SIZE;
67 adata->bin_buf = dma_alloc_coherent(&pci->dev, dma_size,
68 &adata->sha_dma_addr,
69 GFP_KERNEL);
70 if (!adata->bin_buf)
71 return -ENOMEM;
72 }
73 adata->fw_bin_size = size + offset;
74 dest = adata->bin_buf + offset;
75 break;
76 case SOF_FW_BLK_TYPE_DRAM:
77 if (!adata->data_buf) {
78 adata->data_buf = dma_alloc_coherent(&pci->dev,
79 ACP_DEFAULT_DRAM_LENGTH,
80 &adata->dma_addr,
81 GFP_KERNEL);
82 if (!adata->data_buf)
83 return -ENOMEM;
84 }
85 dest = adata->data_buf + offset;
86 adata->fw_data_bin_size = size + offset;
87 adata->is_dram_in_use = true;
88 break;
89 case SOF_FW_BLK_TYPE_SRAM:
90 if (!adata->sram_data_buf) {
91 adata->sram_data_buf = dma_alloc_coherent(&pci->dev,
92 ACP_DEFAULT_SRAM_LENGTH,
93 &adata->sram_dma_addr,
94 GFP_KERNEL);
95 if (!adata->sram_data_buf)
96 return -ENOMEM;
97 }
98 adata->fw_sram_data_bin_size = size + offset;
99 dest = adata->sram_data_buf + offset;
100 adata->is_sram_in_use = true;
101 break;
102 default:
103 dev_err(sdev->dev, "bad blk type 0x%x\n", blk_type);
104 return -EINVAL;
105 }
106
107 memcpy(dest, src, size);
108 return 0;
109}
110EXPORT_SYMBOL_NS(acp_dsp_block_write, "SND_SOC_SOF_AMD_COMMON");
111
112int acp_get_bar_index(struct snd_sof_dev *sdev, u32 type)
113{
114 return type;
115}
116EXPORT_SYMBOL_NS(acp_get_bar_index, "SND_SOC_SOF_AMD_COMMON");
117
118static void configure_pte_for_fw_loading(int type, int num_pages, struct acp_dev_data *adata)
119{
120 struct snd_sof_dev *sdev = adata->dev;
121 const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
122 unsigned int low, high;
123 dma_addr_t addr;
124 u16 page_idx;
125 u32 offset;
126
127 switch (type) {
128 case FW_BIN:
129 offset = FW_BIN_PTE_OFFSET;
130 addr = adata->sha_dma_addr;
131 break;
132 case FW_DATA_BIN:
133 offset = adata->fw_bin_page_count * 8;
134 addr = adata->dma_addr;
135 break;
136 case FW_SRAM_DATA_BIN:
137 offset = (adata->fw_bin_page_count + ACP_DRAM_PAGE_COUNT) * 8;
138 addr = adata->sram_dma_addr;
139 break;
140 default:
141 dev_err(sdev->dev, "Invalid data type %x\n", type);
142 return;
143 }
144
145 /* Group Enable */
146 snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACPAXI2AXI_ATU_BASE_ADDR_GRP_1,
147 desc->sram_pte_offset | BIT(31));
148 snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1,
149 PAGE_SIZE_4K_ENABLE);
150
151 for (page_idx = 0; page_idx < num_pages; page_idx++) {
152 low = lower_32_bits(addr);
153 high = upper_32_bits(addr);
154 snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + offset, low);
155 high |= BIT(31);
156 snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + offset + 4, high);
157 offset += 8;
158 addr += PAGE_SIZE;
159 }
160
161 /* Flush ATU Cache after PTE Update */
162 snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACPAXI2AXI_ATU_CTRL, ACP_ATU_CACHE_INVALID);
163}
164
165/* pre fw run operations */
166int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev)
167{
168 struct pci_dev *pci = to_pci_dev(sdev->dev);
169 const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
170 struct acp_dev_data *adata;
171 unsigned int src_addr, size_fw, dest_addr;
172 u32 page_count, dma_size;
173 int ret;
174
175 adata = sdev->pdata->hw_pdata;
176
177 if (adata->pci_rev >= ACP7B_PCI_ID) {
178 if (adata->acp_sof_signed_firmware_image) {
179 if (adata->fw_bin_size <= ACP_IMAGE_HEADER_SIZE) {
180 dev_err(sdev->dev, "Invalid signed firmware size %u\n",
181 adata->fw_bin_size);
182 return -EINVAL;
183 }
184 size_fw = get_unaligned_le32(adata->bin_buf +
185 ACP_IMAGE_HDR_SIZE_FW_SIGNED_OFF);
186 if (!size_fw ||
187 size_fw > adata->fw_bin_size - ACP_IMAGE_HEADER_SIZE) {
188 dev_err(sdev->dev,
189 "Invalid signed firmware payload size %u (max %u)\n",
190 size_fw, adata->fw_bin_size - ACP_IMAGE_HEADER_SIZE);
191 return -EINVAL;
192 }
193 size_fw += ACP_IMAGE_HEADER_SIZE;
194 } else {
195 size_fw = adata->fw_bin_size;
196 }
197 } else if (adata->quirks && adata->quirks->signed_fw_image) {
198 size_fw = adata->fw_bin_size - ACP_FIRMWARE_SIGNATURE;
199 } else {
200 size_fw = adata->fw_bin_size;
201 }
202
203 page_count = PAGE_ALIGN(size_fw) >> PAGE_SHIFT;
204 adata->fw_bin_page_count = page_count;
205
206 configure_pte_for_fw_loading(FW_BIN, page_count, adata);
207 ret = configure_and_run_sha_dma(adata, adata->bin_buf, ACP_SYSTEM_MEMORY_WINDOW,
208 ACP_IRAM_BASE_ADDRESS, size_fw);
209 if (ret < 0) {
210 dev_err(sdev->dev, "SHA DMA transfer failed status: %d\n", ret);
211 return ret;
212 }
213 if (adata->is_dram_in_use) {
214 configure_pte_for_fw_loading(FW_DATA_BIN, ACP_DRAM_PAGE_COUNT, adata);
215 src_addr = ACP_SYSTEM_MEMORY_WINDOW + (page_count * ACP_PAGE_SIZE);
216 dest_addr = ACP_DRAM_BASE_ADDRESS;
217
218 ret = configure_and_run_dma(adata, src_addr, dest_addr, adata->fw_data_bin_size);
219 if (ret < 0) {
220 dev_err(sdev->dev, "acp dma configuration failed: %d\n", ret);
221 return ret;
222 }
223 ret = acp_dma_status(adata, 0);
224 if (ret < 0)
225 dev_err(sdev->dev, "acp dma transfer status: %d\n", ret);
226 }
227 if (adata->is_sram_in_use) {
228 configure_pte_for_fw_loading(FW_SRAM_DATA_BIN, ACP_SRAM_PAGE_COUNT, adata);
229 src_addr = ACP_SYSTEM_MEMORY_WINDOW + ACP_DEFAULT_SRAM_LENGTH +
230 (page_count * ACP_PAGE_SIZE);
231 if (adata->pci_rev > ACP63_PCI_ID)
232 dest_addr = ACP7X_SRAM_BASE_ADDRESS;
233 else
234 dest_addr = ACP_SRAM_BASE_ADDRESS;
235
236 ret = configure_and_run_dma(adata, src_addr, dest_addr,
237 adata->fw_sram_data_bin_size);
238 if (ret < 0) {
239 dev_err(sdev->dev, "acp dma configuration failed: %d\n", ret);
240 return ret;
241 }
242 ret = acp_dma_status(adata, 0);
243 if (ret < 0)
244 dev_err(sdev->dev, "acp dma transfer status: %d\n", ret);
245 }
246
247 if (adata->pci_rev > ACP_RN_PCI_ID) {
248 /* Cache Window enable */
249 snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DSP0_CACHE_OFFSET0, desc->sram_pte_offset);
250 snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DSP0_CACHE_SIZE0, SRAM1_SIZE | BIT(31));
251 }
252
253 /* Free memory once DMA is complete */
254 dma_size = (PAGE_ALIGN(sdev->basefw.fw->size) >> PAGE_SHIFT) * ACP_PAGE_SIZE;
255 dma_free_coherent(&pci->dev, dma_size, adata->bin_buf, adata->sha_dma_addr);
256 adata->bin_buf = NULL;
257 if (adata->is_dram_in_use) {
258 dma_free_coherent(&pci->dev, ACP_DEFAULT_DRAM_LENGTH, adata->data_buf,
259 adata->dma_addr);
260 adata->data_buf = NULL;
261 }
262 if (adata->is_sram_in_use) {
263 dma_free_coherent(&pci->dev, ACP_DEFAULT_SRAM_LENGTH, adata->sram_data_buf,
264 adata->sram_dma_addr);
265 adata->sram_data_buf = NULL;
266 }
267 return ret;
268}
269EXPORT_SYMBOL_NS(acp_dsp_pre_fw_run, "SND_SOC_SOF_AMD_COMMON");
270
271int acp_sof_dsp_run(struct snd_sof_dev *sdev)
272{
273 struct acp_dev_data *adata = sdev->pdata->hw_pdata;
274 const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
275 int val;
276
277 snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DSP0_RUNSTALL, ACP_DSP_RUN);
278 val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_DSP0_RUNSTALL);
279 dev_dbg(sdev->dev, "ACP_DSP0_RUNSTALL : 0x%0x\n", val);
280
281 /* Some platforms won't support fusion DSP,keep offset zero for no support */
282 if (desc->fusion_dsp_offset && adata->enable_fw_debug) {
283 snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->fusion_dsp_offset, ACP_DSP_RUN);
284 val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->fusion_dsp_offset);
285 dev_dbg(sdev->dev, "ACP_DSP0_FUSION_RUNSTALL : 0x%0x\n", val);
286 }
287 return 0;
288}
289EXPORT_SYMBOL_NS(acp_sof_dsp_run, "SND_SOC_SOF_AMD_COMMON");
290
291int acp_sof_load_signed_firmware(struct snd_sof_dev *sdev)
292{
293 struct snd_sof_pdata *plat_data = sdev->pdata;
294 struct acp_dev_data *adata = plat_data->hw_pdata;
295 const char *fw_filename;
296 int ret;
297
298 fw_filename = kasprintf(GFP_KERNEL, "%s/%s",
299 plat_data->fw_filename_prefix,
300 adata->fw_code_bin);
301 if (!fw_filename)
302 return -ENOMEM;
303
304 ret = request_firmware(&sdev->basefw.fw, fw_filename, sdev->dev);
305 if (ret < 0) {
306 kfree(fw_filename);
307 dev_err(sdev->dev, "sof signed firmware code bin is missing\n");
308 return ret;
309 } else {
310 dev_dbg(sdev->dev, "request_firmware %s successful\n", fw_filename);
311 }
312 kfree(fw_filename);
313
314 ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_IRAM, 0,
315 (void *)sdev->basefw.fw->data,
316 sdev->basefw.fw->size);
317 if (ret < 0)
318 return ret;
319
320 fw_filename = kasprintf(GFP_KERNEL, "%s/%s",
321 plat_data->fw_filename_prefix,
322 adata->fw_data_bin);
323 if (!fw_filename)
324 return -ENOMEM;
325
326 ret = request_firmware(&adata->fw_dbin, fw_filename, sdev->dev);
327 if (ret < 0) {
328 kfree(fw_filename);
329 dev_err(sdev->dev, "sof signed firmware data bin is missing\n");
330 return ret;
331
332 } else {
333 dev_dbg(sdev->dev, "request_firmware %s successful\n", fw_filename);
334 }
335 kfree(fw_filename);
336
337 if (adata->pci_rev >= ACP7B_PCI_ID)
338 ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_SRAM, 0,
339 (void *)adata->fw_dbin->data,
340 adata->fw_dbin->size);
341 else
342 ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_DRAM, 0,
343 (void *)adata->fw_dbin->data,
344 adata->fw_dbin->size);
345 return ret;
346}
347EXPORT_SYMBOL_NS(acp_sof_load_signed_firmware, "SND_SOC_SOF_AMD_COMMON");