diff options
author | Puja Gupta <pujag@codeaurora.org> | 2015-11-16 18:21:59 -0800 |
---|---|---|
committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-22 11:16:21 -0700 |
commit | 35012c464e303e89f2fdf72589b2ae4a6b993bfe (patch) | |
tree | 057211364d372672e612fd383baa4b147f0e8ae7 /drivers/soc/qcom | |
parent | 7581cb300a62a48dba58de74112177562e878e11 (diff) |
soc: qcom: Add generic irq handler for secure processor
This patch adds the code to handle watchdog, err_ready and other
interrupts from secure processor subsystem to the PIL driver.
CRs-Fixed: 972423
Change-Id: I65455229ee14bd4da357358ac3977f2137f3c07e
Signed-off-by: Puja Gupta <pujag@codeaurora.org>
Diffstat (limited to 'drivers/soc/qcom')
-rw-r--r-- | drivers/soc/qcom/subsys-pil-tz.c | 90 | ||||
-rw-r--r-- | drivers/soc/qcom/subsystem_restart.c | 39 |
2 files changed, 124 insertions, 5 deletions
diff --git a/drivers/soc/qcom/subsys-pil-tz.c b/drivers/soc/qcom/subsys-pil-tz.c index 5751b827ac58..5a7c6dd17b09 100644 --- a/drivers/soc/qcom/subsys-pil-tz.c +++ b/drivers/soc/qcom/subsys-pil-tz.c @@ -40,6 +40,15 @@ #define STOP_ACK_TIMEOUT_MS 1000 #define CRASH_STOP_ACK_TO_MS 200 +#define COLD_BOOT_DONE 0 +#define GDSC_DONE 1 +#define RAM_WIPE_DONE 2 +#define CPU_BOOT_DONE 3 +#define WDOG_BITE 4 +#define CLR_WDOG_BITE 5 +#define ERR_READY 6 +#define PBL_DONE 7 + #define desc_to_data(d) container_of(d, struct pil_tz_data, desc) #define subsys_to_data(d) container_of(d, struct pil_tz_data, subsys_desc) @@ -80,6 +89,7 @@ struct reg_info { * @desc: PIL descriptor * @subsys: subsystem device pointer * @subsys_desc: subsystem descriptor + * @u32 bits_arr[8]: array of bit positions in SCSR registers */ struct pil_tz_data { struct reg_info *regs; @@ -100,6 +110,11 @@ struct pil_tz_data { struct pil_desc desc; struct subsys_device *subsys; struct subsys_desc subsys_desc; + void __iomem *irq_status; + void __iomem *irq_clear; + void __iomem *irq_mask; + void __iomem *err_status; + u32 bits_arr[8]; }; enum scm_cmd { @@ -898,9 +913,54 @@ static irqreturn_t subsys_stop_ack_intr_handler(int irq, void *dev_id) return IRQ_HANDLED; } +static irqreturn_t subsys_generic_handler(int irq, void *dev_id) +{ + struct pil_tz_data *d = subsys_to_data(dev_id); + uint32_t status_val, clear_val, err_value; + + if (subsys_get_crash_status(d->subsys)) + return IRQ_HANDLED; + + /* Masking interrupts not handled by HLOS */ + clear_val = __raw_readl(d->irq_mask); + __raw_writel(clear_val | BIT(d->bits_arr[COLD_BOOT_DONE]) | + BIT(d->bits_arr[GDSC_DONE]) | BIT(d->bits_arr[RAM_WIPE_DONE]) | + BIT(d->bits_arr[CPU_BOOT_DONE]), d->irq_mask); + status_val = __raw_readl(d->irq_status); + + if (status_val & BIT(d->bits_arr[WDOG_BITE])) { + pr_err("wdog bite received from %s!\n", d->subsys_desc.name); + clear_val = __raw_readl(d->irq_clear); + __raw_writel(clear_val | BIT(d->bits_arr[CLR_WDOG_BITE]), + d->irq_clear); + subsys_set_crash_status(d->subsys, true); + log_failure_reason(d); + subsystem_restart_dev(d->subsys); + } else if (status_val & BIT(d->bits_arr[ERR_READY])) { + pr_debug("Subsystem error services up received from %s!\n", + d->subsys_desc.name); + clear_val = __raw_readl(d->irq_clear); + __raw_writel(clear_val | BIT(d->bits_arr[ERR_READY]), + d->irq_clear); + complete_err_ready(d->subsys); + } else if (status_val & BIT(d->bits_arr[PBL_DONE])) { + err_value = __raw_readl(d->err_status); + pr_debug("PBL_DONE received from %s!\n", + d->subsys_desc.name); + if (!err_value) { + clear_val = __raw_readl(d->irq_clear); + __raw_writel(clear_val | BIT(d->bits_arr[PBL_DONE]), + d->irq_clear); + } else + pr_err("SP-PBL rmb error status: 0x%08x\n", err_value); + } + return IRQ_HANDLED; +} + static int pil_tz_driver_probe(struct platform_device *pdev) { struct pil_tz_data *d; + struct resource *res; u32 proxy_timeout; int len, rc; @@ -971,10 +1031,32 @@ static int pil_tz_driver_probe(struct platform_device *pdev) d->subsys_desc.ramdump = subsys_ramdump; d->subsys_desc.free_memory = subsys_free_memory; d->subsys_desc.crash_shutdown = subsys_crash_shutdown; - d->subsys_desc.err_fatal_handler = subsys_err_fatal_intr_handler; - d->subsys_desc.wdog_bite_handler = subsys_wdog_bite_irq_handler; - d->subsys_desc.stop_ack_handler = subsys_stop_ack_intr_handler; - + if (of_property_read_bool(pdev->dev.of_node, + "qcom,pil-generic-irq-handler")) { + d->subsys_desc.generic_handler = subsys_generic_handler; + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "sp2soc_irq_status"); + d->irq_status = devm_ioremap_resource(&pdev->dev, res); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "sp2soc_irq_clr"); + d->irq_clear = devm_ioremap_resource(&pdev->dev, res); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "sp2soc_irq_mask"); + d->irq_mask = devm_ioremap_resource(&pdev->dev, res); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "rmb_err"); + d->err_status = devm_ioremap_resource(&pdev->dev, res); + rc = of_property_read_u32_array(pdev->dev.of_node, + "qcom,spss-scsr-bits", d->bits_arr, sizeof(d->bits_arr)/ + sizeof(d->bits_arr[0])); + if (rc) + dev_err(&pdev->dev, "Failed to read qcom,spss-scsr-bits"); + } else { + d->subsys_desc.err_fatal_handler = + subsys_err_fatal_intr_handler; + d->subsys_desc.wdog_bite_handler = subsys_wdog_bite_irq_handler; + d->subsys_desc.stop_ack_handler = subsys_stop_ack_intr_handler; + } d->ramdump_dev = create_ramdump_device(d->subsys_desc.name, &pdev->dev); if (!d->ramdump_dev) { diff --git a/drivers/soc/qcom/subsystem_restart.c b/drivers/soc/qcom/subsystem_restart.c index 4175c98c065a..5bf4cd051a56 100644 --- a/drivers/soc/qcom/subsystem_restart.c +++ b/drivers/soc/qcom/subsystem_restart.c @@ -183,6 +183,11 @@ static struct subsys_device *to_subsys(struct device *d) return container_of(d, struct subsys_device, dev); } +void complete_err_ready(struct subsys_device *subsys) +{ + complete(&subsys->err_ready); +} + static struct subsys_tracking *subsys_get_track(struct subsys_device *subsys) { struct subsys_soc_restart_order *order = subsys->restart_order; @@ -537,6 +542,10 @@ static void enable_all_irqs(struct subsys_device *dev) enable_irq(dev->desc->err_fatal_irq); if (dev->desc->stop_ack_irq && dev->desc->stop_ack_handler) enable_irq(dev->desc->stop_ack_irq); + if (dev->desc->generic_irq && dev->desc->generic_handler) { + enable_irq(dev->desc->generic_irq); + irq_set_irq_wake(dev->desc->generic_irq, 1); + } } static void disable_all_irqs(struct subsys_device *dev) @@ -551,6 +560,10 @@ static void disable_all_irqs(struct subsys_device *dev) disable_irq(dev->desc->err_fatal_irq); if (dev->desc->stop_ack_irq && dev->desc->stop_ack_handler) disable_irq(dev->desc->stop_ack_irq); + if (dev->desc->generic_irq && dev->desc->generic_handler) { + disable_irq(dev->desc->generic_irq); + irq_set_irq_wake(dev->desc->generic_irq, 0); + } } int wait_for_shutdown_ack(struct subsys_desc *desc) @@ -576,7 +589,12 @@ static int wait_for_err_ready(struct subsys_device *subsys) { int ret; - if (!subsys->desc->err_ready_irq || enable_debug == 1) + /* + * If subsys is using generic_irq in which case err_ready_irq will be 0, + * don't return. + */ + if ((subsys->desc->generic_irq <= 0 && !subsys->desc->err_ready_irq) + || enable_debug == 1) return 0; ret = wait_for_completion_timeout(&subsys->err_ready, @@ -1474,6 +1492,13 @@ static int subsys_parse_devicetree(struct subsys_desc *desc) if (ret > 0) desc->wdog_bite_irq = ret; + if (of_property_read_bool(pdev->dev.of_node, + "qcom,pil-generic-irq-handler")) { + ret = platform_get_irq(pdev, 0); + if (ret > 0) + desc->generic_irq = ret; + } + order = ssr_parse_restart_orders(desc); if (IS_ERR(order)) { pr_err("Could not initialize SSR restart order, err = %ld\n", @@ -1525,6 +1550,18 @@ static int subsys_setup_irqs(struct subsys_device *subsys) disable_irq(desc->wdog_bite_irq); } + if (desc->generic_irq && desc->generic_handler) { + ret = devm_request_irq(desc->dev, desc->generic_irq, + desc->generic_handler, + IRQF_TRIGGER_HIGH, desc->name, desc); + if (ret < 0) { + dev_err(desc->dev, "[%s]: Unable to register generic irq handler!: %d\n", + desc->name, ret); + return ret; + } + disable_irq(desc->generic_irq); + } + if (desc->err_ready_irq) { ret = devm_request_irq(desc->dev, desc->err_ready_irq, |