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