Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1723444 > unrolled thread
| Started by | Sricharan R <sricharan@codeaurora.org> |
|---|---|
| First post | 2017-08-30 17:20 +0200 |
| Last post | 2017-08-30 17:20 +0200 |
| Articles | 4 — 1 participant |
Back to article view | Back to linux.kernel
[PATCH v2 0/6] Add support for Hexagon q6v5-wcss integrated core Sricharan R <sricharan@codeaurora.org> - 2017-08-30 17:20 +0200
[PATCH v2 5/6] remoteproc: qcom: Add support for q6v5-wcss pil Sricharan R <sricharan@codeaurora.org> - 2017-08-30 17:20 +0200
[PATCH v2 2/6] remoteproc: Export rproc_elf_get_boot_addr Sricharan R <sricharan@codeaurora.org> - 2017-08-30 17:20 +0200
[PATCH v2 6/6] remoteproc: qcom: Add q6v5-wcss rproc ops Sricharan R <sricharan@codeaurora.org> - 2017-08-30 17:20 +0200
| From | Sricharan R <sricharan@codeaurora.org> |
|---|---|
| Date | 2017-08-30 17:20 +0200 |
| Subject | [PATCH v2 0/6] Add support for Hexagon q6v5-wcss integrated core |
| Message-ID | <ukcWB-1xz-5@gated-at.bofh.it> |
IPQ8074 has an integrated Hexagon dsp core Q6v5 and a wireless lan
(Lithium) IP. This series adds the remoteproc driver to reset, load
and boot Q6 firmware.
The first patch is to make the mdt_loader authenticate
the firmware only if required, so that the code can be reused for
self-authenticating firmware like the Q6v5 core in IPQ8074. The second
patch exports the elf header's get_boot_addr helper to reuse it.
The next couple of patches arranges the code in the original q6v5-mpss
rproc to add q6v5-wcss later. The last couple of patches add the relevant
bits for the q6v5-wcss core.
This is done on top of Avaneesh's msm8996 rproc support [1]
[1] https://lkml.org/lkml/2017/7/21/217
V2:
Last time introduced this a new rproc driver, but there is lot
of code that can be shared if it is added to the q6v5-mpss pil
driver.
Sricharan R (6):
remoteproc: qcom: mdt_loader: Make the firmware authentication
optional
remoteproc: Export rproc_elf_get_boot_addr
remoteproc: qcom: Push reset ops, fw ops, rproc ops in to of_match
data
remoteproc: qcom: Split the head and tail of the q6v5-pil rproc start
function
remoteproc: qcom: Add support for q6v5-wcss pil
remoteproc: qcom: Add q6v5-wcss rproc ops
.../devicetree/bindings/remoteproc/qcom,q6v5.txt | 7 +-
drivers/remoteproc/qcom_q6v5_pil.c | 468 +++++++++++++++++----
drivers/remoteproc/remoteproc_elf_loader.c | 2 +-
drivers/remoteproc/remoteproc_internal.h | 3 +
drivers/soc/qcom/mdt_loader.c | 70 ++-
include/linux/soc/qcom/mdt_loader.h | 3 +
6 files changed, 455 insertions(+), 98 deletions(-)
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
[toc] | [next] | [standalone]
| From | Sricharan R <sricharan@codeaurora.org> |
|---|---|
| Date | 2017-08-30 17:20 +0200 |
| Subject | [PATCH v2 5/6] remoteproc: qcom: Add support for q6v5-wcss pil |
| Message-ID | <ukcWB-1xz-19@gated-at.bofh.it> |
| In reply to | #1723444 |
IPQ8074 has an integrated Hexagon dsp core q6v5 and a wireless lan
(Lithium) IP. An mdt type single image format is used for the
firmware. So the mdt_load function can be directly used to load
the firmware. Also add the relevant resets required for this core.
Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
.../devicetree/bindings/remoteproc/qcom,q6v5.txt | 7 ++-
drivers/remoteproc/qcom_q6v5_pil.c | 53 +++++++++++++++++++++-
2 files changed, 58 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt b/Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt
index 87a8e51..a0a9ad3 100644
--- a/Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt
+++ b/Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt
@@ -12,6 +12,7 @@ on the Qualcomm Hexagon core.
"qcom,msm8974-mss-pil"
"qcom,msm8996-mss-pil"
+ "qcom,ipq8074-wcss-pil"
- reg:
Usage: required
Value type: <prop-encoded-array>
@@ -49,11 +50,15 @@ on the Qualcomm Hexagon core.
Usage: required
Value type: <phandle>
Definition: reference to the reset-controller for the modem sub-system
+ reference to the list of 3 reset-controllers for the
+ wcss sub-system
- reset-names:
Usage: required
Value type: <stringlist>
- Definition: must be "mss_restart"
+ Definition: must be "mss_restart" for the modem sub-system
+ Definition: must be "wcss_aon_reset", "wcss_reset", "wcss_q6_reset"
+ for the wcss syb-system
- cx-supply:
- mss-supply:
diff --git a/drivers/remoteproc/qcom_q6v5_pil.c b/drivers/remoteproc/qcom_q6v5_pil.c
index 232134c..8da1cc7 100644
--- a/drivers/remoteproc/qcom_q6v5_pil.c
+++ b/drivers/remoteproc/qcom_q6v5_pil.c
@@ -129,6 +129,9 @@ struct q6v5 {
u32 halt_nc;
struct reset_control *mss_restart;
+ struct reset_control *wcss_aon_reset;
+ struct reset_control *wcss_reset;
+ struct reset_control *wcss_q6_reset;
struct qcom_smem_state *state;
unsigned stop_bit;
@@ -178,6 +181,7 @@ enum {
MSS_MSM8916,
MSS_MSM8974,
MSS_MSM8996,
+ WCSS_IPQ8074,
};
static int q6v5_regulator_init(struct device *dev, struct reg_info *regs,
@@ -356,6 +360,21 @@ static int q6v5_load(struct rproc *rproc, const struct firmware *fw)
return 0;
}
+static int q6v5_wcss_load(struct rproc *rproc, const struct firmware *fw)
+{
+ struct q6v5 *qproc = rproc->priv;
+
+ return qcom_mdt_load_no_init(qproc->dev, fw, rproc->firmware,
+ 0, qproc->mba_region, qproc->mba_phys,
+ qproc->mba_size);
+}
+
+static const struct rproc_fw_ops q6v5_wcss_fw_ops = {
+ .find_rsc_table = q6v5_find_rsc_table,
+ .load = q6v5_wcss_load,
+ .get_boot_addr = rproc_elf_get_boot_addr,
+};
+
static const struct rproc_fw_ops q6v5_fw_ops = {
.find_rsc_table = q6v5_find_rsc_table,
.load = q6v5_load,
@@ -1055,6 +1074,26 @@ static int q6v5_init_clocks(struct device *dev, struct clk **clks,
return i;
}
+static int q6v5_wcss_init_reset(struct q6v5 *qproc)
+{
+ qproc->wcss_aon_reset = devm_reset_control_get(qproc->dev,
+ "wcss_aon_reset");
+ if (IS_ERR(qproc->wcss_aon_reset))
+ return PTR_ERR(qproc->wcss_aon_reset);
+
+ qproc->wcss_reset = devm_reset_control_get(qproc->dev,
+ "wcss_reset");
+ if (IS_ERR(qproc->wcss_reset))
+ return PTR_ERR(qproc->wcss_reset);
+
+ qproc->wcss_q6_reset = devm_reset_control_get(qproc->dev,
+ "wcss_q6_reset");
+ if (IS_ERR(qproc->wcss_q6_reset))
+ return PTR_ERR(qproc->wcss_q6_reset);
+
+ return 0;
+}
+
static int q6v5_init_reset(struct q6v5 *qproc)
{
qproc->mss_restart = devm_reset_control_get(qproc->dev, NULL);
@@ -1113,6 +1152,9 @@ static int q6v5_alloc_memory_region(struct q6v5 *qproc)
return -EBUSY;
}
+ if (qproc->version == WCSS_IPQ8074)
+ return 0;
+
child = of_get_child_by_name(qproc->dev->of_node, "mpss");
node = of_parse_phandle(child, "memory-region", 0);
ret = of_address_to_resource(node, 0, &r);
@@ -1156,6 +1198,7 @@ static int q6v5_probe(struct platform_device *pdev)
qproc = (struct q6v5 *)rproc->priv;
qproc->dev = &pdev->dev;
qproc->rproc = rproc;
+ qproc->version = desc->version;
platform_set_drvdata(pdev, qproc);
init_completion(&qproc->start_done);
@@ -1205,7 +1248,6 @@ static int q6v5_probe(struct platform_device *pdev)
if (ret)
goto free_rproc;
- qproc->version = desc->version;
qproc->need_mem_protection = desc->need_mem_protection;
ret = q6v5_request_irq(qproc, pdev, "wdog", q6v5_wdog_interrupt);
if (ret < 0)
@@ -1352,11 +1394,20 @@ static int q6v5_remove(struct platform_device *pdev)
.ops = &q6v5_ops,
};
+static const struct rproc_hexagon_res ipq8074_wcss = {
+ .hexagon_mba_image = "IPQ8074/q6_fw.mdt",
+ .need_mem_protection = false,
+ .version = WCSS_IPQ8074,
+ .init_reset = q6v5_wcss_init_reset,
+ .fw_ops = &q6v5_wcss_fw_ops,
+};
+
static const struct of_device_id q6v5_of_match[] = {
{ .compatible = "qcom,q6v5-pil", .data = &msm8916_mss},
{ .compatible = "qcom,msm8916-mss-pil", .data = &msm8916_mss},
{ .compatible = "qcom,msm8974-mss-pil", .data = &msm8974_mss},
{ .compatible = "qcom,msm8996-mss-pil", .data = &msm8996_mss},
+ { .compatible = "qcom,ipq8074-wcss-pil", .data = &ipq8074_wcss},
{ },
};
MODULE_DEVICE_TABLE(of, q6v5_of_match);
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
[toc] | [prev] | [next] | [standalone]
| From | Sricharan R <sricharan@codeaurora.org> |
|---|---|
| Date | 2017-08-30 17:20 +0200 |
| Subject | [PATCH v2 2/6] remoteproc: Export rproc_elf_get_boot_addr |
| Message-ID | <ukcWC-1xz-27@gated-at.bofh.it> |
| In reply to | #1723444 |
Export rproc_elf_get_boot_addr so that it can be
used by any remoteproc to get the bootaddr of the
elf type firmware images. This is used in the
subsequent patch by the q6v5 based remoteproc
while loading its elf based mdt type image.
Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
drivers/remoteproc/remoteproc_elf_loader.c | 2 +-
drivers/remoteproc/remoteproc_internal.h | 3 +++
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
index c523983..f6d07d9 100644
--- a/drivers/remoteproc/remoteproc_elf_loader.c
+++ b/drivers/remoteproc/remoteproc_elf_loader.c
@@ -110,13 +110,13 @@
* Note that the boot address is not a configurable property of all remote
* processors. Some will always boot at a specific hard-coded address.
*/
-static
u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
{
struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
return ehdr->e_entry;
}
+EXPORT_SYMBOL(rproc_elf_get_boot_addr);
/**
* rproc_elf_load_segments() - load firmware segments to memory
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
index 1e9e5b3..b898510 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -125,4 +125,7 @@ struct resource_table *rproc_find_loaded_rsc_table(struct rproc *rproc,
extern const struct rproc_fw_ops rproc_elf_fw_ops;
+/* from remoteproc_elf_loader.c */
+u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
+
#endif /* REMOTEPROC_INTERNAL_H */
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
[toc] | [prev] | [next] | [standalone]
| From | Sricharan R <sricharan@codeaurora.org> |
|---|---|
| Date | 2017-08-30 17:20 +0200 |
| Subject | [PATCH v2 6/6] remoteproc: qcom: Add q6v5-wcss rproc ops |
| Message-ID | <ukcWC-1xz-31@gated-at.bofh.it> |
| In reply to | #1723444 |
q6v5-wcss core's start function is mostly common
with the q6v5 of msm8996. So reuse that and add
the stop function.
Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
drivers/remoteproc/qcom_q6v5_pil.c | 212 +++++++++++++++++++++++++++++++++++++
1 file changed, 212 insertions(+)
diff --git a/drivers/remoteproc/qcom_q6v5_pil.c b/drivers/remoteproc/qcom_q6v5_pil.c
index 8da1cc7..5661487 100644
--- a/drivers/remoteproc/qcom_q6v5_pil.c
+++ b/drivers/remoteproc/qcom_q6v5_pil.c
@@ -104,6 +104,17 @@
#define QDSP6SS_XO_CBCR 0x0038
#define QDSP6SS_ACC_OVERRIDE_VAL 0x20
+/* QDSP6v5-WCSS config/status registers */
+#define TCSR_GLOBAL_CFG0 0x0
+#define TCSR_GLOBAL_CFG1 0x4
+#define SSCAON_CONFIG 0x8
+#define SSCAON_STATUS 0xc
+#define QDSP6SS_BHS_STATUS 0x78
+#define QDSP6SS_RST_EVB 0x10
+
+#define BHS_EN_REST_ACK BIT(0)
+#define SSCAON_ENABLE BIT(13)
+
struct reg_info {
struct regulator *reg;
int uV;
@@ -774,6 +785,61 @@ static int q6v5_mpss_load(struct q6v5 *qproc)
return ret < 0 ? ret : 0;
}
+static int q6v5_wcss_start(struct rproc *rproc)
+{
+ struct q6v5 *qproc = rproc->priv;
+ int ret = 0;
+
+ ret = q6v5_clk_enable(qproc->dev, qproc->active_clks,
+ qproc->active_clk_count);
+ if (ret) {
+ dev_err(qproc->dev, "failed to enable clocks\n");
+ return ret;
+ }
+
+ /* Release Q6 and WCSS reset */
+ ret = reset_control_deassert(qproc->wcss_reset);
+ if (ret)
+ dev_err(qproc->dev, "wcss_reset failed\n");
+
+ ret = reset_control_deassert(qproc->wcss_q6_reset);
+ if (ret)
+ dev_err(qproc->dev, "wcss_q6_reset failed\n");
+
+ /* Lithium configuration - clock gating and bus arbitration */
+ ret = regmap_update_bits(qproc->halt_map,
+ qproc->halt_nc + TCSR_GLOBAL_CFG0,
+ 0x1F, 0x14);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(qproc->halt_map,
+ qproc->halt_nc + TCSR_GLOBAL_CFG1,
+ 1, 0);
+ if (ret)
+ return ret;
+
+ /* Write bootaddr to EVB so that Q6WCSS will jump there after reset */
+ writel(rproc->bootaddr >> 4, qproc->reg_base + QDSP6SS_RST_EVB);
+
+ ret = q6v5_reset(qproc);
+ if (ret)
+ return ret;
+
+ q6v5_reset_rest(qproc);
+
+ ret = wait_for_completion_timeout(&qproc->start_done,
+ msecs_to_jiffies(5000));
+ if (ret == 0) {
+ dev_err(qproc->dev, "start timed out\n");
+ return -ETIMEDOUT;
+ }
+
+ qproc->running = true;
+
+ return 0;
+}
+
static int q6v5_start(struct rproc *rproc)
{
struct q6v5 *qproc = (struct q6v5 *)rproc->priv;
@@ -893,6 +959,146 @@ static int q6v5_start(struct rproc *rproc)
return ret;
}
+static int q6v5_wcss_powerdown(struct q6v5 *qproc)
+{
+ unsigned int val = 0;
+ int ret;
+
+ /* 1 - Assert WCSS/Q6 HALTREQ */
+ q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem);
+
+ /* 2 - Enable WCSSAON_CONFIG */
+ val = readl(qproc->rmb_base + SSCAON_CONFIG);
+ val |= SSCAON_ENABLE;
+ writel(val, qproc->rmb_base + SSCAON_CONFIG);
+
+ /* 3 - Set SSCAON_CONFIG */
+ val |= BIT(15);
+ val &= ~BIT(16);
+ val &= ~BIT(17);
+ val &= ~BIT(18);
+ writel(val, qproc->rmb_base + SSCAON_CONFIG);
+
+ /* 4 - SSCAON_CONFIG 1 */
+ val |= BIT(1);
+ writel(val, qproc->rmb_base + SSCAON_CONFIG);
+
+ /* 5 - wait for SSCAON_STATUS */
+ ret = readl_poll_timeout(qproc->rmb_base + SSCAON_STATUS,
+ val, (val & 0xffff) == 0x400, 1000,
+ HALT_CHECK_MAX_LOOPS);
+ if (ret) {
+ dev_err(qproc->dev,
+ "can't get SSCAON_STATUS rc:%d)\n", ret);
+ }
+
+ /* 6 - De-assert WCSS_AON reset */
+ reset_control_assert(qproc->wcss_aon_reset);
+
+ /* 7 - Disable WCSSAON_CONFIG 13 */
+ val = readl(qproc->rmb_base + SSCAON_CONFIG);
+ val &= ~SSCAON_ENABLE;
+ writel(val, qproc->rmb_base + SSCAON_CONFIG);
+
+ /* 8 - De-assert WCSS/Q6 HALTREQ */
+ reset_control_assert(qproc->wcss_reset);
+
+ return ret;
+}
+
+static int q6v5_q6_powerdown(struct q6v5 *qproc)
+{
+ int i = 0, ret;
+ unsigned int val = 0;
+
+ /* 1 - Halt Q6 bus interface */
+ q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_q6);
+
+ /* 2 - Disable Q6 Core clock */
+ val = readl(qproc->reg_base + QDSP6SS_GFMUX_CTL_REG);
+ val &= ~Q6SS_CLK_ENABLE;
+ writel(val, qproc->reg_base + QDSP6SS_GFMUX_CTL_REG);
+
+ /* 3 - Clamp I/O */
+ val = readl(qproc->reg_base + QDSP6SS_PWR_CTL_REG);
+ val |= Q6SS_CLAMP_IO;
+ writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
+
+ /* 4 - Clamp WL */
+ val |= QDSS_BHS_ON;
+ writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
+
+ /* 5 - Clear Erase standby */
+ val &= ~Q6SS_L2DATA_STBY_N;
+ writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
+
+ /* 6 - Clear Sleep RTN */
+ val &= ~Q6SS_SLP_RET_N;
+ writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
+
+ /* 7 - turn off QDSP6 memory foot/head switch one bank at a time */
+ for (i = 0; i < 20; i++) {
+ val = readl(qproc->reg_base + QDSP6SS_MEM_PWR_CTL);
+ val &= ~BIT(i);
+ writel(val, qproc->reg_base + QDSP6SS_MEM_PWR_CTL);
+ mdelay(1);
+ }
+ /* 8 - Assert QMC memory RTN */
+ val = readl(qproc->reg_base + QDSP6SS_PWR_CTL_REG);
+ val |= QDSP6v56_CLAMP_QMC_MEM;
+ writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
+
+ /* 9 - Turn off BHS */
+ val &= ~QDSP6v56_BHS_ON;
+ writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
+ udelay(1);
+ /* 10 - Wait till BHS Reset is done */
+ ret = readl_poll_timeout(qproc->reg_base + QDSP6SS_BHS_STATUS,
+ val, !(val & BHS_EN_REST_ACK), 1000,
+ HALT_CHECK_MAX_LOOPS);
+ if (ret) {
+ dev_err(qproc->dev,
+ "BHS_STATUS not OFF (rc:%d)\n", ret);
+ }
+
+ /* 11 - Enable Q6 Block reset */
+ reset_control_assert(qproc->wcss_q6_reset);
+
+ return 0;
+}
+
+static int q6v5_wcss_stop(struct rproc *rproc)
+{
+ struct q6v5 *qproc = rproc->priv;
+ int ret = 0;
+
+ qproc->running = false;
+
+ /* WCSS powerdown */
+ qcom_smem_state_update_bits(qproc->state, BIT(qproc->stop_bit),
+ BIT(qproc->stop_bit));
+
+ ret = wait_for_completion_timeout(&qproc->stop_done,
+ msecs_to_jiffies(5000));
+ if (ret == 0) {
+ dev_err(qproc->dev, "timed out on wait\n");
+ return -ETIMEDOUT;
+ }
+
+ qcom_smem_state_update_bits(qproc->state, BIT(qproc->stop_bit), 0);
+
+ ret = q6v5_wcss_powerdown(qproc);
+ if (ret)
+ return ret;
+
+ /* Q6 Power down */
+ ret = q6v5_q6_powerdown(qproc);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
static int q6v5_stop(struct rproc *rproc)
{
struct q6v5 *qproc = (struct q6v5 *)rproc->priv;
@@ -954,6 +1160,11 @@ static void *q6v5_da_to_va(struct rproc *rproc, u64 da, int len)
.da_to_va = q6v5_da_to_va,
};
+static const struct rproc_ops q6v5_wcss_ops = {
+ .start = q6v5_wcss_start,
+ .stop = q6v5_wcss_stop,
+};
+
static irqreturn_t q6v5_wdog_interrupt(int irq, void *dev)
{
struct q6v5 *qproc = dev;
@@ -1400,6 +1611,7 @@ static int q6v5_remove(struct platform_device *pdev)
.version = WCSS_IPQ8074,
.init_reset = q6v5_wcss_init_reset,
.fw_ops = &q6v5_wcss_fw_ops,
+ .ops = &q6v5_wcss_ops,
};
static const struct of_device_id q6v5_of_match[] = {
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web