soc: qcom: pil: Always assert and deassert restart signals on SDM845
SDM845 brings in new reset signal ALT_RESET which is part of the MSS
subsystem. New usage of boot IMEM means that modem is not in a complete
reset state at pil_boot and therefore full reset is needed at the start.
Change-Id: I9d6787422dd5e2971c4b484386efd51deea2027a
Signed-off-by: Kyle Yan <kyan@codeaurora.org>
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
index 868eee5..bc844de 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
@@ -18,6 +18,8 @@
"halt_nc" is required.
"pdc_sync" is the power domain register introduced in
sdm845 for power domain of subsystems.
+ If alternative reset is required, "alt_reset" maps to
+ mss_alt_ares.
- interrupts: The modem watchdog interrupt
- vdd_cx-supply: Reference to the regulator that supplies the vdd_cx domain.
- vdd_cx-voltage: Voltage corner/level(max) for cx rail.
diff --git a/drivers/soc/qcom/pil-msa.c b/drivers/soc/qcom/pil-msa.c
index a006a3a..8c4921f 100644
--- a/drivers/soc/qcom/pil-msa.c
+++ b/drivers/soc/qcom/pil-msa.c
@@ -225,6 +225,16 @@
}
}
+static void pil_mss_alt_reset(struct q6v5_data *drv, u32 val)
+{
+ if (drv->alt_reset) {
+ writel_relaxed(val, drv->alt_reset);
+ /* Ensure alt reset is written before restart reg */
+ wmb();
+ udelay(2);
+ }
+}
+
static int pil_mss_restart_reg(struct q6v5_data *drv, u32 mss_restart)
{
int ret = 0;
@@ -256,6 +266,32 @@
return ret;
}
+static int pil_mss_assert_resets(struct q6v5_data *drv)
+{
+ int ret = 0;
+
+ pil_mss_pdc_sync(drv, 1);
+ pil_mss_alt_reset(drv, 1);
+ ret = pil_mss_restart_reg(drv, true);
+
+ return ret;
+}
+
+static int pil_mss_deassert_resets(struct q6v5_data *drv)
+{
+ int ret = 0;
+
+ ret = pil_mss_restart_reg(drv, 0);
+ if (ret)
+ return ret;
+ /* Wait 6 32kHz sleep cycles for reset */
+ udelay(200);
+ pil_mss_alt_reset(drv, 0);
+ pil_mss_pdc_sync(drv, false);
+
+ return ret;
+}
+
static int pil_msa_wait_for_mba_ready(struct q6v5_data *drv)
{
struct device *dev = drv->desc.dev;
@@ -325,8 +361,10 @@
ret);
}
- pil_mss_pdc_sync(drv, 1);
- ret = pil_mss_restart_reg(drv, 1);
+ pil_mss_assert_resets(drv);
+ /* Wait 6 32kHz sleep cycles for reset */
+ udelay(200);
+ ret = pil_mss_deassert_resets(drv);
if (drv->is_booted) {
pil_mss_disable_clks(drv);
@@ -485,17 +523,18 @@
if (ret)
goto err_power;
- /* Deassert reset to subsystem and wait for propagation */
- ret = pil_mss_restart_reg(drv, 0);
- if (ret)
- goto err_restart;
-
- pil_mss_pdc_sync(drv, 0);
-
ret = pil_mss_enable_clks(drv);
if (ret)
goto err_clks;
+ /* Assert reset to subsystem */
+ pil_mss_assert_resets(drv);
+ /* Wait 6 32kHz sleep cycles for reset */
+ udelay(200);
+ ret = pil_mss_deassert_resets(drv);
+ if (ret)
+ goto err_restart;
+
if (modem_dbg_cfg)
writel_relaxed(modem_dbg_cfg, drv->reg_base + QDSP6SS_DBG_CFG);
@@ -543,13 +582,11 @@
err_q6v5_reset:
modem_log_rmb_regs(drv->rmb_base);
+err_restart:
pil_mss_disable_clks(drv);
if (drv->ahb_clk_vote)
clk_disable_unprepare(drv->ahb_clk);
err_clks:
- pil_mss_pdc_sync(drv, 1);
- pil_mss_restart_reg(drv, 1);
-err_restart:
pil_mss_power_down(drv);
err_power:
return ret;
diff --git a/drivers/soc/qcom/pil-q6v5-mss.c b/drivers/soc/qcom/pil-q6v5-mss.c
index c17d1a9..df0c609c 100644
--- a/drivers/soc/qcom/pil-q6v5-mss.c
+++ b/drivers/soc/qcom/pil-q6v5-mss.c
@@ -291,6 +291,13 @@
res->start, resource_size(res));
}
+ q6->alt_reset = NULL;
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "alt_reset");
+ if (res) {
+ q6->alt_reset = devm_ioremap(&pdev->dev,
+ res->start, resource_size(res));
+ }
+
q6->vreg = NULL;
prop = of_find_property(pdev->dev.of_node, "vdd_mss-supply", NULL);
diff --git a/drivers/soc/qcom/pil-q6v5.h b/drivers/soc/qcom/pil-q6v5.h
index afb591d..9b4c811 100644
--- a/drivers/soc/qcom/pil-q6v5.h
+++ b/drivers/soc/qcom/pil-q6v5.h
@@ -45,6 +45,7 @@
void __iomem *axi_halt_nc;
void __iomem *restart_reg;
void __iomem *pdc_sync;
+ void __iomem *alt_reset;
struct regulator *vreg;
struct regulator *vreg_cx;
struct regulator *vreg_mx;