1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include <linux/pci.h>
18#include <linux/delay.h>
19#include <linux/fs.h>
20#include <linux/sched.h>
21#include <linux/firmware.h>
22#include <linux/dmaengine.h>
23#include <linux/pm_runtime.h>
24#include <linux/pm_qos.h>
25#include <sound/core.h>
26#include <sound/pcm.h>
27#include <sound/soc.h>
28#include <sound/compress_driver.h>
29#include <asm/platform_sst_audio.h>
30#include "../sst-mfld-platform.h"
31#include "sst.h"
32
33void memcpy32_toio(void __iomem *dst, const void *src, int count)
34{
35
36
37
38 __iowrite32_copy(dst, src, count / 4);
39}
40
41void memcpy32_fromio(void *dst, const void __iomem *src, int count)
42{
43
44
45
46 __ioread32_copy(dst, src, count / 4);
47}
48
49
50
51
52
53
54
55int intel_sst_reset_dsp_mrfld(struct intel_sst_drv *sst_drv_ctx)
56{
57 union config_status_reg_mrfld csr;
58
59 dev_dbg(sst_drv_ctx->dev, "sst: Resetting the DSP in mrfld\n");
60 csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR);
61
62 dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full);
63
64 csr.full |= 0x7;
65 sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full);
66 csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR);
67
68 dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full);
69
70 csr.full &= ~(0x1);
71 sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full);
72
73 csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR);
74 dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full);
75 return 0;
76}
77
78
79
80
81
82
83
84int sst_start_mrfld(struct intel_sst_drv *sst_drv_ctx)
85{
86 union config_status_reg_mrfld csr;
87
88 dev_dbg(sst_drv_ctx->dev, "sst: Starting the DSP in mrfld LALALALA\n");
89 csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR);
90 dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full);
91
92 csr.full |= 0x7;
93 sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full);
94
95 csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR);
96 dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full);
97
98 csr.part.xt_snoop = 1;
99 csr.full &= ~(0x5);
100 sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full);
101
102 csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR);
103 dev_dbg(sst_drv_ctx->dev, "sst: Starting the DSP_merrifield:%llx\n",
104 csr.full);
105 return 0;
106}
107
108static int sst_validate_fw_image(struct intel_sst_drv *ctx, unsigned long size,
109 struct fw_module_header **module, u32 *num_modules)
110{
111 struct sst_fw_header *header;
112 const void *sst_fw_in_mem = ctx->fw_in_mem;
113
114 dev_dbg(ctx->dev, "Enter\n");
115
116
117 header = (struct sst_fw_header *)sst_fw_in_mem;
118 dev_dbg(ctx->dev,
119 "header sign=%s size=%x modules=%x fmt=%x size=%zx\n",
120 header->signature, header->file_size, header->modules,
121 header->file_format, sizeof(*header));
122
123
124 if ((strncmp(header->signature, SST_FW_SIGN, 4) != 0) ||
125 (size != header->file_size + sizeof(*header))) {
126
127 dev_err(ctx->dev, "InvalidFW sign/filesize mismatch\n");
128 return -EINVAL;
129 }
130 *num_modules = header->modules;
131 *module = (void *)sst_fw_in_mem + sizeof(*header);
132
133 return 0;
134}
135
136
137
138
139
140
141
142
143
144
145
146
147static int sst_fill_memcpy_list(struct list_head *memcpy_list,
148 void *destn, const void *src, u32 size, bool is_io)
149{
150 struct sst_memcpy_list *listnode;
151
152 listnode = kzalloc(sizeof(*listnode), GFP_KERNEL);
153 if (listnode == NULL)
154 return -ENOMEM;
155 listnode->dstn = destn;
156 listnode->src = src;
157 listnode->size = size;
158 listnode->is_io = is_io;
159 list_add_tail(&listnode->memcpylist, memcpy_list);
160
161 return 0;
162}
163
164
165
166
167
168
169
170
171
172
173static int sst_parse_module_memcpy(struct intel_sst_drv *sst_drv_ctx,
174 struct fw_module_header *module, struct list_head *memcpy_list)
175{
176 struct fw_block_info *block;
177 u32 count;
178 int ret_val = 0;
179 void __iomem *ram_iomem;
180
181 dev_dbg(sst_drv_ctx->dev, "module sign %s size %x blocks %x type %x\n",
182 module->signature, module->mod_size,
183 module->blocks, module->type);
184 dev_dbg(sst_drv_ctx->dev, "module entrypoint 0x%x\n", module->entry_point);
185
186 block = (void *)module + sizeof(*module);
187
188 for (count = 0; count < module->blocks; count++) {
189 if (block->size <= 0) {
190 dev_err(sst_drv_ctx->dev, "block size invalid\n");
191 return -EINVAL;
192 }
193 switch (block->type) {
194 case SST_IRAM:
195 ram_iomem = sst_drv_ctx->iram;
196 break;
197 case SST_DRAM:
198 ram_iomem = sst_drv_ctx->dram;
199 break;
200 case SST_DDR:
201 ram_iomem = sst_drv_ctx->ddr;
202 break;
203 case SST_CUSTOM_INFO:
204 block = (void *)block + sizeof(*block) + block->size;
205 continue;
206 default:
207 dev_err(sst_drv_ctx->dev, "wrong ram type0x%x in block0x%x\n",
208 block->type, count);
209 return -EINVAL;
210 }
211
212 ret_val = sst_fill_memcpy_list(memcpy_list,
213 ram_iomem + block->ram_offset,
214 (void *)block + sizeof(*block), block->size, 1);
215 if (ret_val)
216 return ret_val;
217
218 block = (void *)block + sizeof(*block) + block->size;
219 }
220 return 0;
221}
222
223
224
225
226
227
228
229
230
231
232static int sst_parse_fw_memcpy(struct intel_sst_drv *ctx, unsigned long size,
233 struct list_head *fw_list)
234{
235 struct fw_module_header *module;
236 u32 count, num_modules;
237 int ret_val;
238
239 ret_val = sst_validate_fw_image(ctx, size, &module, &num_modules);
240 if (ret_val)
241 return ret_val;
242
243 for (count = 0; count < num_modules; count++) {
244 ret_val = sst_parse_module_memcpy(ctx, module, fw_list);
245 if (ret_val)
246 return ret_val;
247 module = (void *)module + sizeof(*module) + module->mod_size;
248 }
249
250 return 0;
251}
252
253
254
255
256
257
258
259
260static void sst_do_memcpy(struct list_head *memcpy_list)
261{
262 struct sst_memcpy_list *listnode;
263
264 list_for_each_entry(listnode, memcpy_list, memcpylist) {
265 if (listnode->is_io)
266 memcpy32_toio((void __iomem *)listnode->dstn,
267 listnode->src, listnode->size);
268 else
269 memcpy(listnode->dstn, listnode->src, listnode->size);
270 }
271}
272
273void sst_memcpy_free_resources(struct intel_sst_drv *sst_drv_ctx)
274{
275 struct sst_memcpy_list *listnode, *tmplistnode;
276
277
278 list_for_each_entry_safe(listnode, tmplistnode,
279 &sst_drv_ctx->memcpy_list, memcpylist) {
280 list_del(&listnode->memcpylist);
281 kfree(listnode);
282 }
283}
284
285static int sst_cache_and_parse_fw(struct intel_sst_drv *sst,
286 const struct firmware *fw)
287{
288 int retval = 0;
289
290 sst->fw_in_mem = kzalloc(fw->size, GFP_KERNEL);
291 if (!sst->fw_in_mem) {
292 retval = -ENOMEM;
293 goto end_release;
294 }
295 dev_dbg(sst->dev, "copied fw to %p", sst->fw_in_mem);
296 dev_dbg(sst->dev, "phys: %lx", (unsigned long)virt_to_phys(sst->fw_in_mem));
297 memcpy(sst->fw_in_mem, fw->data, fw->size);
298 retval = sst_parse_fw_memcpy(sst, fw->size, &sst->memcpy_list);
299 if (retval) {
300 dev_err(sst->dev, "Failed to parse fw\n");
301 kfree(sst->fw_in_mem);
302 sst->fw_in_mem = NULL;
303 }
304
305end_release:
306 release_firmware(fw);
307 return retval;
308
309}
310
311void sst_firmware_load_cb(const struct firmware *fw, void *context)
312{
313 struct intel_sst_drv *ctx = context;
314
315 dev_dbg(ctx->dev, "Enter\n");
316
317 if (fw == NULL) {
318 dev_err(ctx->dev, "request fw failed\n");
319 return;
320 }
321
322 mutex_lock(&ctx->sst_lock);
323
324 if (ctx->sst_state != SST_RESET ||
325 ctx->fw_in_mem != NULL) {
326 release_firmware(fw);
327 mutex_unlock(&ctx->sst_lock);
328 return;
329 }
330
331 dev_dbg(ctx->dev, "Request Fw completed\n");
332 sst_cache_and_parse_fw(ctx, fw);
333 mutex_unlock(&ctx->sst_lock);
334}
335
336
337
338
339
340
341
342static int sst_request_fw(struct intel_sst_drv *sst)
343{
344 int retval = 0;
345 const struct firmware *fw;
346
347 retval = request_firmware(&fw, sst->firmware_name, sst->dev);
348 if (retval) {
349 dev_err(sst->dev, "request fw failed %d\n", retval);
350 return retval;
351 }
352 if (fw == NULL) {
353 dev_err(sst->dev, "fw is returning as null\n");
354 return -EINVAL;
355 }
356 mutex_lock(&sst->sst_lock);
357 retval = sst_cache_and_parse_fw(sst, fw);
358 mutex_unlock(&sst->sst_lock);
359
360 return retval;
361}
362
363
364
365
366
367static void sst_dccm_config_write(void __iomem *dram_base,
368 unsigned int ddr_base)
369{
370 void __iomem *addr;
371 u32 bss_reset = 0;
372
373 addr = (void __iomem *)(dram_base + MRFLD_FW_DDR_BASE_OFFSET);
374 memcpy32_toio(addr, (void *)&ddr_base, sizeof(u32));
375 bss_reset |= (1 << MRFLD_FW_BSS_RESET_BIT);
376 addr = (void __iomem *)(dram_base + MRFLD_FW_FEATURE_BASE_OFFSET);
377 memcpy32_toio(addr, &bss_reset, sizeof(u32));
378
379}
380
381void sst_post_download_mrfld(struct intel_sst_drv *ctx)
382{
383 sst_dccm_config_write(ctx->dram, ctx->ddr_base);
384 dev_dbg(ctx->dev, "config written to DCCM\n");
385}
386
387
388
389
390
391
392
393int sst_load_fw(struct intel_sst_drv *sst_drv_ctx)
394{
395 int ret_val = 0;
396 struct sst_block *block;
397
398 dev_dbg(sst_drv_ctx->dev, "sst_load_fw\n");
399
400 if (sst_drv_ctx->sst_state != SST_RESET)
401 return -EAGAIN;
402
403 if (!sst_drv_ctx->fw_in_mem) {
404 dev_dbg(sst_drv_ctx->dev, "sst: FW not in memory retry to download\n");
405 ret_val = sst_request_fw(sst_drv_ctx);
406 if (ret_val)
407 return ret_val;
408 }
409
410 block = sst_create_block(sst_drv_ctx, 0, FW_DWNL_ID);
411 if (block == NULL)
412 return -ENOMEM;
413
414
415 cpu_latency_qos_update_request(sst_drv_ctx->qos, 0);
416
417 sst_drv_ctx->sst_state = SST_FW_LOADING;
418
419 ret_val = sst_drv_ctx->ops->reset(sst_drv_ctx);
420 if (ret_val)
421 goto restore;
422
423 sst_do_memcpy(&sst_drv_ctx->memcpy_list);
424
425
426 if (sst_drv_ctx->ops->post_download)
427 sst_drv_ctx->ops->post_download(sst_drv_ctx);
428
429
430 ret_val = sst_drv_ctx->ops->start(sst_drv_ctx);
431 if (ret_val)
432 goto restore;
433
434 ret_val = sst_wait_timeout(sst_drv_ctx, block);
435 if (ret_val) {
436 dev_err(sst_drv_ctx->dev, "fw download failed %d\n" , ret_val);
437
438 ret_val = -EBUSY;
439
440 }
441
442
443restore:
444
445 cpu_latency_qos_update_request(sst_drv_ctx->qos, PM_QOS_DEFAULT_VALUE);
446 sst_free_block(sst_drv_ctx, block);
447 dev_dbg(sst_drv_ctx->dev, "fw load successful!!!\n");
448
449 if (sst_drv_ctx->ops->restore_dsp_context)
450 sst_drv_ctx->ops->restore_dsp_context();
451 sst_drv_ctx->sst_state = SST_FW_RUNNING;
452 return ret_val;
453}
454
455