diff options
| -rw-r--r-- | Documentation/devicetree/bindings/pil/subsys-pil-tz.txt | 3 | ||||
| -rw-r--r-- | drivers/soc/qcom/subsys-pil-tz.c | 90 | ||||
| -rw-r--r-- | drivers/soc/qcom/subsystem_restart.c | 39 | ||||
| -rw-r--r-- | include/soc/qcom/subsystem_restart.h | 3 |
4 files changed, 130 insertions, 5 deletions
diff --git a/Documentation/devicetree/bindings/pil/subsys-pil-tz.txt b/Documentation/devicetree/bindings/pil/subsys-pil-tz.txt index 8c60906741f7..a38eefcd4fb0 100644 --- a/Documentation/devicetree/bindings/pil/subsys-pil-tz.txt +++ b/Documentation/devicetree/bindings/pil/subsys-pil-tz.txt @@ -61,6 +61,9 @@ Optional properties: - qcom,sysmon-id: platform device id that sysmon is probed with for the subsystem. - qcom,pil-force-shutdown: Boolean. If set, the SSR framework will not trigger graceful shutdown on behalf of the subsystem driver. +- qcom,pil-generic-irq-handler: generic interrupt handler used for communication with subsytem + based on bit values in scsr registers. +- qcom,spss-scsr-bits: array of bit positions into the scsr registers used in generic handler. Example: qcom,venus@fdce0000 { 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, diff --git a/include/soc/qcom/subsystem_restart.h b/include/soc/qcom/subsystem_restart.h index 8b878bc897ef..0331c10f958e 100644 --- a/include/soc/qcom/subsystem_restart.h +++ b/include/soc/qcom/subsystem_restart.h @@ -66,12 +66,14 @@ struct subsys_desc { irqreturn_t (*err_fatal_handler) (int irq, void *dev_id); irqreturn_t (*stop_ack_handler) (int irq, void *dev_id); irqreturn_t (*wdog_bite_handler) (int irq, void *dev_id); + irqreturn_t (*generic_handler)(int irq, void *dev_id); int is_not_loadable; int err_fatal_gpio; unsigned int err_fatal_irq; unsigned int err_ready_irq; unsigned int stop_ack_irq; unsigned int wdog_bite_irq; + unsigned int generic_irq; int force_stop_gpio; int ramdump_disable_gpio; int shutdown_ack_gpio; @@ -120,6 +122,7 @@ extern void subsys_set_crash_status(struct subsys_device *dev, bool crashed); extern bool subsys_get_crash_status(struct subsys_device *dev); void notify_proxy_vote(struct device *device); void notify_proxy_unvote(struct device *device); +void complete_err_ready(struct subsys_device *subsys); extern int wait_for_shutdown_ack(struct subsys_desc *desc); #else |
