summaryrefslogtreecommitdiff
path: root/drivers/soc/qcom
diff options
context:
space:
mode:
authorPuja Gupta <pujag@codeaurora.org>2015-11-16 18:21:59 -0800
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-22 11:16:21 -0700
commit35012c464e303e89f2fdf72589b2ae4a6b993bfe (patch)
tree057211364d372672e612fd383baa4b147f0e8ae7 /drivers/soc/qcom
parent7581cb300a62a48dba58de74112177562e878e11 (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.c90
-rw-r--r--drivers/soc/qcom/subsystem_restart.c39
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,