aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjorn Andersson <bjorn.andersson@linaro.org>2017-01-26 16:58:35 -0500
committerBjorn Andersson <bjorn.andersson@linaro.org>2017-02-06 11:57:19 -0500
commite7fd25226295270cc248254e7406d1e19181aea9 (patch)
treebada9c05a57974f4158355926b809dfc5f49179e
parent2bb5d9069999a2c2195a05f4aa3da7f14ea3102d (diff)
remoteproc: qcom: q6v5: Decouple driver from MDT loader
Rather than duplicating half of the MDT loader in the validation step move the entire MDT parser into the q6v5 driver. This allows us to make the shared MDT-loader call the SCM PAS operations directly which simplifies the client code and allows for better reuse of the code. Cc: Avaneesh Kumar Dwivedi <akdwived@codeaurora.org> Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
-rw-r--r--drivers/remoteproc/Kconfig1
-rw-r--r--drivers/remoteproc/qcom_q6v5_pil.c146
2 files changed, 90 insertions, 57 deletions
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index a5e888043f1f..454fd9a4dd96 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -92,7 +92,6 @@ config QCOM_Q6V5_PIL
92 depends on QCOM_SMEM 92 depends on QCOM_SMEM
93 depends on REMOTEPROC 93 depends on REMOTEPROC
94 select MFD_SYSCON 94 select MFD_SYSCON
95 select QCOM_MDT_LOADER
96 select QCOM_SCM 95 select QCOM_SCM
97 help 96 help
98 Say y here to support the Qualcomm Peripherial Image Loader for the 97 Say y here to support the Qualcomm Peripherial Image Loader for the
diff --git a/drivers/remoteproc/qcom_q6v5_pil.c b/drivers/remoteproc/qcom_q6v5_pil.c
index b9ce66e28f8b..83a78daf55ef 100644
--- a/drivers/remoteproc/qcom_q6v5_pil.c
+++ b/drivers/remoteproc/qcom_q6v5_pil.c
@@ -37,8 +37,6 @@
37 37
38#include <linux/qcom_scm.h> 38#include <linux/qcom_scm.h>
39 39
40#define MPSS_FIRMWARE_NAME "modem.mdt"
41
42#define MPSS_CRASH_REASON_SMEM 421 40#define MPSS_CRASH_REASON_SMEM 421
43 41
44/* RMB Status Register Values */ 42/* RMB Status Register Values */
@@ -277,6 +275,16 @@ static void q6v5_clk_disable(struct device *dev,
277 clk_disable_unprepare(clks[i]); 275 clk_disable_unprepare(clks[i]);
278} 276}
279 277
278static struct resource_table *q6v5_find_rsc_table(struct rproc *rproc,
279 const struct firmware *fw,
280 int *tablesz)
281{
282 static struct resource_table table = { .ver = 1, };
283
284 *tablesz = sizeof(table);
285 return &table;
286}
287
280static int q6v5_load(struct rproc *rproc, const struct firmware *fw) 288static int q6v5_load(struct rproc *rproc, const struct firmware *fw)
281{ 289{
282 struct q6v5 *qproc = rproc->priv; 290 struct q6v5 *qproc = rproc->priv;
@@ -287,7 +295,7 @@ static int q6v5_load(struct rproc *rproc, const struct firmware *fw)
287} 295}
288 296
289static const struct rproc_fw_ops q6v5_fw_ops = { 297static const struct rproc_fw_ops q6v5_fw_ops = {
290 .find_rsc_table = qcom_mdt_find_rsc_table, 298 .find_rsc_table = q6v5_find_rsc_table,
291 .load = q6v5_load, 299 .load = q6v5_load,
292}; 300};
293 301
@@ -464,45 +472,109 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw)
464 return ret < 0 ? ret : 0; 472 return ret < 0 ? ret : 0;
465} 473}
466 474
467static int q6v5_mpss_validate(struct q6v5 *qproc, const struct firmware *fw) 475static bool q6v5_phdr_valid(const struct elf32_phdr *phdr)
476{
477 if (phdr->p_type != PT_LOAD)
478 return false;
479
480 if ((phdr->p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH)
481 return false;
482
483 if (!phdr->p_memsz)
484 return false;
485
486 return true;
487}
488
489static int q6v5_mpss_load(struct q6v5 *qproc)
468{ 490{
469 const struct elf32_phdr *phdrs; 491 const struct elf32_phdr *phdrs;
470 const struct elf32_phdr *phdr; 492 const struct elf32_phdr *phdr;
493 const struct firmware *seg_fw;
494 const struct firmware *fw;
471 struct elf32_hdr *ehdr; 495 struct elf32_hdr *ehdr;
496 phys_addr_t mpss_reloc;
472 phys_addr_t boot_addr; 497 phys_addr_t boot_addr;
473 phys_addr_t fw_addr; 498 phys_addr_t min_addr = (phys_addr_t)ULLONG_MAX;
474 bool relocate; 499 phys_addr_t max_addr = 0;
500 bool relocate = false;
501 char seg_name[10];
502 size_t offset;
475 size_t size; 503 size_t size;
504 void *ptr;
476 int ret; 505 int ret;
477 int i; 506 int i;
478 507
479 ret = qcom_mdt_parse(fw, &fw_addr, NULL, &relocate); 508 ret = request_firmware(&fw, "modem.mdt", qproc->dev);
480 if (ret) { 509 if (ret < 0) {
481 dev_err(qproc->dev, "failed to parse mdt header\n"); 510 dev_err(qproc->dev, "unable to load modem.mdt\n");
482 return ret; 511 return ret;
483 } 512 }
484 513
485 if (relocate) 514 /* Initialize the RMB validator */
486 boot_addr = qproc->mpss_phys; 515 writel(0, qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG);
487 else 516
488 boot_addr = fw_addr; 517 ret = q6v5_mpss_init_image(qproc, fw);
518 if (ret)
519 goto release_firmware;
489 520
490 ehdr = (struct elf32_hdr *)fw->data; 521 ehdr = (struct elf32_hdr *)fw->data;
491 phdrs = (struct elf32_phdr *)(ehdr + 1); 522 phdrs = (struct elf32_phdr *)(ehdr + 1);
492 for (i = 0; i < ehdr->e_phnum; i++, phdr++) { 523
524 for (i = 0; i < ehdr->e_phnum; i++) {
493 phdr = &phdrs[i]; 525 phdr = &phdrs[i];
494 526
495 if (phdr->p_type != PT_LOAD) 527 if (!q6v5_phdr_valid(phdr))
496 continue; 528 continue;
497 529
498 if ((phdr->p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH) 530 if (phdr->p_flags & QCOM_MDT_RELOCATABLE)
499 continue; 531 relocate = true;
532
533 if (phdr->p_paddr < min_addr)
534 min_addr = phdr->p_paddr;
500 535
501 if (!phdr->p_memsz) 536 if (phdr->p_paddr + phdr->p_memsz > max_addr)
537 max_addr = ALIGN(phdr->p_paddr + phdr->p_memsz, SZ_4K);
538 }
539
540 mpss_reloc = relocate ? min_addr : qproc->mpss_phys;
541
542 for (i = 0; i < ehdr->e_phnum; i++) {
543 phdr = &phdrs[i];
544
545 if (!q6v5_phdr_valid(phdr))
502 continue; 546 continue;
503 547
548 offset = phdr->p_paddr - mpss_reloc;
549 if (offset < 0 || offset + phdr->p_memsz > qproc->mpss_size) {
550 dev_err(qproc->dev, "segment outside memory range\n");
551 ret = -EINVAL;
552 goto release_firmware;
553 }
554
555 ptr = qproc->mpss_region + offset;
556
557 if (phdr->p_filesz) {
558 snprintf(seg_name, sizeof(seg_name), "modem.b%02d", i);
559 ret = request_firmware(&seg_fw, seg_name, qproc->dev);
560 if (ret) {
561 dev_err(qproc->dev, "failed to load %s\n", seg_name);
562 goto release_firmware;
563 }
564
565 memcpy(ptr, seg_fw->data, seg_fw->size);
566
567 release_firmware(seg_fw);
568 }
569
570 if (phdr->p_memsz > phdr->p_filesz) {
571 memset(ptr + phdr->p_filesz, 0,
572 phdr->p_memsz - phdr->p_filesz);
573 }
574
504 size = readl(qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG); 575 size = readl(qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG);
505 if (!size) { 576 if (!size) {
577 boot_addr = relocate ? qproc->mpss_phys : min_addr;
506 writel(boot_addr, qproc->rmb_base + RMB_PMI_CODE_START_REG); 578 writel(boot_addr, qproc->rmb_base + RMB_PMI_CODE_START_REG);
507 writel(RMB_CMD_LOAD_READY, qproc->rmb_base + RMB_MBA_COMMAND_REG); 579 writel(RMB_CMD_LOAD_READY, qproc->rmb_base + RMB_MBA_COMMAND_REG);
508 } 580 }
@@ -517,44 +589,6 @@ static int q6v5_mpss_validate(struct q6v5 *qproc, const struct firmware *fw)
517 else if (ret < 0) 589 else if (ret < 0)
518 dev_err(qproc->dev, "MPSS authentication failed: %d\n", ret); 590 dev_err(qproc->dev, "MPSS authentication failed: %d\n", ret);
519 591
520 return ret < 0 ? ret : 0;
521}
522
523static int q6v5_mpss_load(struct q6v5 *qproc)
524{
525 const struct firmware *fw;
526 phys_addr_t fw_addr;
527 bool relocate;
528 int ret;
529
530 ret = request_firmware(&fw, MPSS_FIRMWARE_NAME, qproc->dev);
531 if (ret < 0) {
532 dev_err(qproc->dev, "unable to load " MPSS_FIRMWARE_NAME "\n");
533 return ret;
534 }
535
536 ret = qcom_mdt_parse(fw, &fw_addr, NULL, &relocate);
537 if (ret) {
538 dev_err(qproc->dev, "failed to parse mdt header\n");
539 goto release_firmware;
540 }
541
542 if (relocate)
543 qproc->mpss_reloc = fw_addr;
544
545 /* Initialize the RMB validator */
546 writel(0, qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG);
547
548 ret = q6v5_mpss_init_image(qproc, fw);
549 if (ret)
550 goto release_firmware;
551
552 ret = qcom_mdt_load(qproc->rproc, fw, MPSS_FIRMWARE_NAME);
553 if (ret)
554 goto release_firmware;
555
556 ret = q6v5_mpss_validate(qproc, fw);
557
558release_firmware: 592release_firmware:
559 release_firmware(fw); 593 release_firmware(fw);
560 594