From bae74510179bc6d2c71168eeef33b7b157e244d0 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 1 Apr 2014 16:23:46 +0300 Subject: drivers: bus: omap_l3: Convert to use devm_kzalloc We can remove the kfree() calls from probe and remove. Signed-off-by: Peter Ujfalusi Reviewed-by: Santosh Shilimkar Acked-by: Tony Lindgren Signed-off-by: Nishanth Menon Tested-by: Sekhar Nori --- drivers/bus/omap_l3_noc.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers/bus') diff --git a/drivers/bus/omap_l3_noc.c b/drivers/bus/omap_l3_noc.c index feeecae623f6..d25d727e7cfb 100644 --- a/drivers/bus/omap_l3_noc.c +++ b/drivers/bus/omap_l3_noc.c @@ -134,7 +134,7 @@ static int omap4_l3_probe(struct platform_device *pdev) struct resource *res; int ret; - l3 = kzalloc(sizeof(*l3), GFP_KERNEL); + l3 = devm_kzalloc(&pdev->dev, sizeof(*l3), GFP_KERNEL); if (!l3) return -ENOMEM; @@ -142,15 +142,13 @@ static int omap4_l3_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "couldn't find resource 0\n"); - ret = -ENODEV; - goto err0; + return -ENODEV; } l3->l3_base[0] = ioremap(res->start, resource_size(res)); if (!l3->l3_base[0]) { dev_err(&pdev->dev, "ioremap failed\n"); - ret = -ENOMEM; - goto err0; + return -ENOMEM; } res = platform_get_resource(pdev, IORESOURCE_MEM, 1); @@ -214,8 +212,6 @@ err2: iounmap(l3->l3_base[1]); err1: iounmap(l3->l3_base[0]); -err0: - kfree(l3); return ret; } @@ -228,7 +224,6 @@ static int omap4_l3_remove(struct platform_device *pdev) iounmap(l3->l3_base[0]); iounmap(l3->l3_base[1]); iounmap(l3->l3_base[2]); - kfree(l3); return 0; } -- cgit From 56c4a0224add82ced3af81c3a898a228a0560720 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 1 Apr 2014 16:23:47 +0300 Subject: drivers: bus: omap_l3: Convert to use devm_ioremap_resource() We can then remove the iounmap() calls from probe and remove. Since the driver requests the resources via index we can do the mem resource request within a for loop. Signed-off-by: Peter Ujfalusi Reviewed-by: Santosh Shilimkar Acked-by: Tony Lindgren Signed-off-by: Nishanth Menon Tested-by: Sekhar Nori --- drivers/bus/omap_l3_noc.c | 59 +++++++++-------------------------------------- 1 file changed, 11 insertions(+), 48 deletions(-) (limited to 'drivers/bus') diff --git a/drivers/bus/omap_l3_noc.c b/drivers/bus/omap_l3_noc.c index d25d727e7cfb..6f58be3c2f76 100644 --- a/drivers/bus/omap_l3_noc.c +++ b/drivers/bus/omap_l3_noc.c @@ -131,52 +131,24 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) static int omap4_l3_probe(struct platform_device *pdev) { static struct omap4_l3 *l3; - struct resource *res; - int ret; + int ret, i; l3 = devm_kzalloc(&pdev->dev, sizeof(*l3), GFP_KERNEL); if (!l3) return -ENOMEM; platform_set_drvdata(pdev, l3); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "couldn't find resource 0\n"); - return -ENODEV; - } - - l3->l3_base[0] = ioremap(res->start, resource_size(res)); - if (!l3->l3_base[0]) { - dev_err(&pdev->dev, "ioremap failed\n"); - return -ENOMEM; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!res) { - dev_err(&pdev->dev, "couldn't find resource 1\n"); - ret = -ENODEV; - goto err1; - } - l3->l3_base[1] = ioremap(res->start, resource_size(res)); - if (!l3->l3_base[1]) { - dev_err(&pdev->dev, "ioremap failed\n"); - ret = -ENOMEM; - goto err1; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 2); - if (!res) { - dev_err(&pdev->dev, "couldn't find resource 2\n"); - ret = -ENODEV; - goto err2; - } + /* Get mem resources */ + for (i = 0; i < L3_MODULES; i++) { + struct resource *res = platform_get_resource(pdev, + IORESOURCE_MEM, i); - l3->l3_base[2] = ioremap(res->start, resource_size(res)); - if (!l3->l3_base[2]) { - dev_err(&pdev->dev, "ioremap failed\n"); - ret = -ENOMEM; - goto err2; + l3->l3_base[i] = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(l3->l3_base[i])) { + dev_err(&pdev->dev, "ioremap %d failed\n", i); + return PTR_ERR(l3->l3_base[i]); + } } /* @@ -189,7 +161,7 @@ static int omap4_l3_probe(struct platform_device *pdev) if (ret) { pr_crit("L3: request_irq failed to register for 0x%x\n", l3->debug_irq); - goto err3; + return ret; } l3->app_irq = platform_get_irq(pdev, 1); @@ -206,12 +178,6 @@ static int omap4_l3_probe(struct platform_device *pdev) err4: free_irq(l3->debug_irq, l3); -err3: - iounmap(l3->l3_base[2]); -err2: - iounmap(l3->l3_base[1]); -err1: - iounmap(l3->l3_base[0]); return ret; } @@ -221,9 +187,6 @@ static int omap4_l3_remove(struct platform_device *pdev) free_irq(l3->app_irq, l3); free_irq(l3->debug_irq, l3); - iounmap(l3->l3_base[0]); - iounmap(l3->l3_base[1]); - iounmap(l3->l3_base[2]); return 0; } -- cgit From a0ef78f353d6edc9f88d3247601f1dc5ad8f4b84 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 1 Apr 2014 16:23:48 +0300 Subject: drivers: bus: omap_l3: Convert to use devm_request_irq() With this we can remove the free_irq() calls from probe and remove. Signed-off-by: Peter Ujfalusi Reviewed-by: Santosh Shilimkar Acked-by: Tony Lindgren Signed-off-by: Nishanth Menon Tested-by: Sekhar Nori --- drivers/bus/omap_l3_noc.c | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) (limited to 'drivers/bus') diff --git a/drivers/bus/omap_l3_noc.c b/drivers/bus/omap_l3_noc.c index 6f58be3c2f76..25bcb60be880 100644 --- a/drivers/bus/omap_l3_noc.c +++ b/drivers/bus/omap_l3_noc.c @@ -155,9 +155,8 @@ static int omap4_l3_probe(struct platform_device *pdev) * Setup interrupt Handlers */ l3->debug_irq = platform_get_irq(pdev, 0); - ret = request_irq(l3->debug_irq, - l3_interrupt_handler, - IRQF_DISABLED, "l3-dbg-irq", l3); + ret = devm_request_irq(&pdev->dev, l3->debug_irq, l3_interrupt_handler, + IRQF_DISABLED, "l3-dbg-irq", l3); if (ret) { pr_crit("L3: request_irq failed to register for 0x%x\n", l3->debug_irq); @@ -165,29 +164,17 @@ static int omap4_l3_probe(struct platform_device *pdev) } l3->app_irq = platform_get_irq(pdev, 1); - ret = request_irq(l3->app_irq, - l3_interrupt_handler, - IRQF_DISABLED, "l3-app-irq", l3); - if (ret) { + ret = devm_request_irq(&pdev->dev, l3->app_irq, l3_interrupt_handler, + IRQF_DISABLED, "l3-app-irq", l3); + if (ret) pr_crit("L3: request_irq failed to register for 0x%x\n", l3->app_irq); - goto err4; - } - - return 0; -err4: - free_irq(l3->debug_irq, l3); return ret; } static int omap4_l3_remove(struct platform_device *pdev) { - struct omap4_l3 *l3 = platform_get_drvdata(pdev); - - free_irq(l3->app_irq, l3); - free_irq(l3->debug_irq, l3); - return 0; } -- cgit From 442a4da7cad64cf7270cbbbed9ad69dc4a1bc263 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 1 Apr 2014 16:23:49 +0300 Subject: drivers: bus: omap_l3: Remove the platform driver's remove function It is NOP after the devm_* conversion. Signed-off-by: Peter Ujfalusi Reviewed-by: Santosh Shilimkar Acked-by: Tony Lindgren Signed-off-by: Nishanth Menon Tested-by: Sekhar Nori --- drivers/bus/omap_l3_noc.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/bus') diff --git a/drivers/bus/omap_l3_noc.c b/drivers/bus/omap_l3_noc.c index 25bcb60be880..0eff48585ae3 100644 --- a/drivers/bus/omap_l3_noc.c +++ b/drivers/bus/omap_l3_noc.c @@ -173,11 +173,6 @@ static int omap4_l3_probe(struct platform_device *pdev) return ret; } -static int omap4_l3_remove(struct platform_device *pdev) -{ - return 0; -} - #if defined(CONFIG_OF) static const struct of_device_id l3_noc_match[] = { {.compatible = "ti,omap4-l3-noc", }, @@ -190,7 +185,6 @@ MODULE_DEVICE_TABLE(of, l3_noc_match); static struct platform_driver omap4_l3_driver = { .probe = omap4_l3_probe, - .remove = omap4_l3_remove, .driver = { .name = "omap_l3_noc", .owner = THIS_MODULE, -- cgit From ae22598a1199c1257b2de5643695221434ace1c3 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 1 Apr 2014 16:23:50 +0300 Subject: drivers: bus: omap_l3: Change pr_crit() to dev_err() when IRQ request fails Use dev_err() which will going to print the driver's name as well and the KERN_ERR level is sufficient in this case (we also print via dev_err when there is an error with the mem resources) Signed-off-by: Peter Ujfalusi Reviewed-by: Santosh Shilimkar Acked-by: Tony Lindgren Signed-off-by: Nishanth Menon Tested-by: Sekhar Nori --- drivers/bus/omap_l3_noc.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/bus') diff --git a/drivers/bus/omap_l3_noc.c b/drivers/bus/omap_l3_noc.c index 0eff48585ae3..972691a668a3 100644 --- a/drivers/bus/omap_l3_noc.c +++ b/drivers/bus/omap_l3_noc.c @@ -158,8 +158,8 @@ static int omap4_l3_probe(struct platform_device *pdev) ret = devm_request_irq(&pdev->dev, l3->debug_irq, l3_interrupt_handler, IRQF_DISABLED, "l3-dbg-irq", l3); if (ret) { - pr_crit("L3: request_irq failed to register for 0x%x\n", - l3->debug_irq); + dev_err(&pdev->dev, "request_irq failed for %d\n", + l3->debug_irq); return ret; } @@ -167,8 +167,7 @@ static int omap4_l3_probe(struct platform_device *pdev) ret = devm_request_irq(&pdev->dev, l3->app_irq, l3_interrupt_handler, IRQF_DISABLED, "l3-app-irq", l3); if (ret) - pr_crit("L3: request_irq failed to register for 0x%x\n", - l3->app_irq); + dev_err(&pdev->dev, "request_irq failed for %d\n", l3->app_irq); return ret; } -- cgit From c5f2aea0ef47b2934b46374abfac9015de79aecb Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Fri, 11 Apr 2014 13:15:43 -0500 Subject: bus: omap_l3_noc: Fix copyright information This is an embarrassing patch :(. Texas Corporation does not make OMAP. Texas Instruments Inc does. For that matter I dont seem to be able to find a Texas Corporation on the internet either. While at it, update coverage to the current year and update the template to remove redundant information and use the standard boiler plate licensing. Signed-off-by: Nishanth Menon Acked-by: Santosh Shilimkar Acked-by: Peter Ujfalusi Tested-by: Darren Etheridge Tested-by: Sekhar Nori --- drivers/bus/omap_l3_noc.c | 18 ++++++------------ drivers/bus/omap_l3_noc.h | 18 ++++++------------ 2 files changed, 12 insertions(+), 24 deletions(-) (limited to 'drivers/bus') diff --git a/drivers/bus/omap_l3_noc.c b/drivers/bus/omap_l3_noc.c index 972691a668a3..1eb6d85c19dc 100644 --- a/drivers/bus/omap_l3_noc.c +++ b/drivers/bus/omap_l3_noc.c @@ -1,24 +1,18 @@ /* * OMAP4XXX L3 Interconnect error handling driver * - * Copyright (C) 2011 Texas Corporation + * Copyright (C) 2011-2014 Texas Instruments Incorporated - http://www.ti.com/ * Santosh Shilimkar * Sricharan * * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA */ #include #include diff --git a/drivers/bus/omap_l3_noc.h b/drivers/bus/omap_l3_noc.h index a6ce34dc4814..cc4b1b1788f0 100644 --- a/drivers/bus/omap_l3_noc.h +++ b/drivers/bus/omap_l3_noc.h @@ -1,24 +1,18 @@ /* * OMAP4XXX L3 Interconnect error handling driver header * - * Copyright (C) 2011 Texas Corporation + * Copyright (C) 2011-2014 Texas Instruments Incorporated - http://www.ti.com/ * Santosh Shilimkar * sricharan * * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA */ #ifndef __ARCH_ARM_MACH_OMAP2_L3_INTERCONNECT_3XXX_H #define __ARCH_ARM_MACH_OMAP2_L3_INTERCONNECT_3XXX_H -- cgit From c10d5c9e1200e2b8c23329173f279caa86c6af45 Mon Sep 17 00:00:00 2001 From: Sricharan R Date: Fri, 11 Apr 2014 13:09:36 -0500 Subject: bus: omap_l3_noc: rename functions and data to omap_l3 Since omap_l3_noc driver is now being used for OMAP5 and reusable with DRA7 and AM437x, using omap4 specific naming is misleading. Signed-off-by: Sricharan R Signed-off-by: Nishanth Menon Acked-by: Santosh Shilimkar Acked-by: Peter Ujfalusi Tested-by: Darren Etheridge Tested-by: Sekhar Nori --- drivers/bus/omap_l3_noc.c | 24 ++++++++++++------------ drivers/bus/omap_l3_noc.h | 11 ++++++----- 2 files changed, 18 insertions(+), 17 deletions(-) (limited to 'drivers/bus') diff --git a/drivers/bus/omap_l3_noc.c b/drivers/bus/omap_l3_noc.c index 1eb6d85c19dc..800486c88cc3 100644 --- a/drivers/bus/omap_l3_noc.c +++ b/drivers/bus/omap_l3_noc.c @@ -1,5 +1,5 @@ /* - * OMAP4XXX L3 Interconnect error handling driver + * OMAP L3 Interconnect error handling driver * * Copyright (C) 2011-2014 Texas Instruments Incorporated - http://www.ti.com/ * Santosh Shilimkar @@ -50,7 +50,7 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) { - struct omap4_l3 *l3 = _l3; + struct omap_l3 *l3 = _l3; int inttype, i, k; int err_src = 0; u32 std_err_main, err_reg, clear, masterid; @@ -122,9 +122,9 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) return IRQ_HANDLED; } -static int omap4_l3_probe(struct platform_device *pdev) +static int omap_l3_probe(struct platform_device *pdev) { - static struct omap4_l3 *l3; + static struct omap_l3 *l3; int ret, i; l3 = devm_kzalloc(&pdev->dev, sizeof(*l3), GFP_KERNEL); @@ -176,8 +176,8 @@ MODULE_DEVICE_TABLE(of, l3_noc_match); #define l3_noc_match NULL #endif -static struct platform_driver omap4_l3_driver = { - .probe = omap4_l3_probe, +static struct platform_driver omap_l3_driver = { + .probe = omap_l3_probe, .driver = { .name = "omap_l3_noc", .owner = THIS_MODULE, @@ -185,14 +185,14 @@ static struct platform_driver omap4_l3_driver = { }, }; -static int __init omap4_l3_init(void) +static int __init omap_l3_init(void) { - return platform_driver_register(&omap4_l3_driver); + return platform_driver_register(&omap_l3_driver); } -postcore_initcall_sync(omap4_l3_init); +postcore_initcall_sync(omap_l3_init); -static void __exit omap4_l3_exit(void) +static void __exit omap_l3_exit(void) { - platform_driver_unregister(&omap4_l3_driver); + platform_driver_unregister(&omap_l3_driver); } -module_exit(omap4_l3_exit); +module_exit(omap_l3_exit); diff --git a/drivers/bus/omap_l3_noc.h b/drivers/bus/omap_l3_noc.h index cc4b1b1788f0..b3c81f2fe7a2 100644 --- a/drivers/bus/omap_l3_noc.h +++ b/drivers/bus/omap_l3_noc.h @@ -1,5 +1,5 @@ /* - * OMAP4XXX L3 Interconnect error handling driver header + * OMAP L3 Interconnect error handling driver header * * Copyright (C) 2011-2014 Texas Instruments Incorporated - http://www.ti.com/ * Santosh Shilimkar @@ -14,8 +14,8 @@ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ -#ifndef __ARCH_ARM_MACH_OMAP2_L3_INTERCONNECT_3XXX_H -#define __ARCH_ARM_MACH_OMAP2_L3_INTERCONNECT_3XXX_H +#ifndef __OMAP_L3_NOC_H +#define __OMAP_L3_NOC_H #define L3_MODULES 3 #define CLEAR_STDERR_LOG (1 << 31) @@ -157,7 +157,7 @@ static u32 *l3_targ[L3_MODULES] = { l3_targ_inst_clk3, }; -struct omap4_l3 { +struct omap_l3 { struct device *dev; struct clk *ick; @@ -167,4 +167,5 @@ struct omap4_l3 { int debug_irq; int app_irq; }; -#endif + +#endif /* __OMAP_L3_NOC_H */ -- cgit From 73cecc46dd3c3fc3fdf906f4de1448a4279cb1e2 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Fri, 11 Apr 2014 13:55:22 -0500 Subject: bus: omap_l3_noc: remove iclk from omap_l3 struct we do not use iclk directly anymore. And, even if we had to, we should be using pm_runtime APIs to do the same to be completely SoC independent. Signed-off-by: Nishanth Menon Acked-by: Santosh Shilimkar Acked-by: Peter Ujfalusi Tested-by: Darren Etheridge Tested-by: Sekhar Nori --- drivers/bus/omap_l3_noc.h | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/bus') diff --git a/drivers/bus/omap_l3_noc.h b/drivers/bus/omap_l3_noc.h index b3c81f2fe7a2..31984cf949cc 100644 --- a/drivers/bus/omap_l3_noc.h +++ b/drivers/bus/omap_l3_noc.h @@ -159,7 +159,6 @@ static u32 *l3_targ[L3_MODULES] = { struct omap_l3 { struct device *dev; - struct clk *ick; /* memory base */ void __iomem *l3_base[L3_MODULES]; -- cgit From ca6a34935c2c95482b901d76116f785ea356412c Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Fri, 11 Apr 2014 12:04:01 -0500 Subject: bus: omap_l3_noc: populate l3->dev and use it l3->dev is not populated, so populate it and use it to print information relevant to the device instead of using a generic pr_*. Signed-off-by: Nishanth Menon Acked-by: Santosh Shilimkar Acked-by: Peter Ujfalusi Tested-by: Darren Etheridge Tested-by: Sekhar Nori --- drivers/bus/omap_l3_noc.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/bus') diff --git a/drivers/bus/omap_l3_noc.c b/drivers/bus/omap_l3_noc.c index 800486c88cc3..37d71b715053 100644 --- a/drivers/bus/omap_l3_noc.c +++ b/drivers/bus/omap_l3_noc.c @@ -131,6 +131,7 @@ static int omap_l3_probe(struct platform_device *pdev) if (!l3) return -ENOMEM; + l3->dev = &pdev->dev; platform_set_drvdata(pdev, l3); /* Get mem resources */ @@ -140,7 +141,7 @@ static int omap_l3_probe(struct platform_device *pdev) l3->l3_base[i] = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(l3->l3_base[i])) { - dev_err(&pdev->dev, "ioremap %d failed\n", i); + dev_err(l3->dev, "ioremap %d failed\n", i); return PTR_ERR(l3->l3_base[i]); } } @@ -149,19 +150,19 @@ static int omap_l3_probe(struct platform_device *pdev) * Setup interrupt Handlers */ l3->debug_irq = platform_get_irq(pdev, 0); - ret = devm_request_irq(&pdev->dev, l3->debug_irq, l3_interrupt_handler, + ret = devm_request_irq(l3->dev, l3->debug_irq, l3_interrupt_handler, IRQF_DISABLED, "l3-dbg-irq", l3); if (ret) { - dev_err(&pdev->dev, "request_irq failed for %d\n", + dev_err(l3->dev, "request_irq failed for %d\n", l3->debug_irq); return ret; } l3->app_irq = platform_get_irq(pdev, 1); - ret = devm_request_irq(&pdev->dev, l3->app_irq, l3_interrupt_handler, + ret = devm_request_irq(l3->dev, l3->app_irq, l3_interrupt_handler, IRQF_DISABLED, "l3-app-irq", l3); if (ret) - dev_err(&pdev->dev, "request_irq failed for %d\n", l3->app_irq); + dev_err(l3->dev, "request_irq failed for %d\n", l3->app_irq); return ret; } -- cgit From 9e224c8ff19e4c4a9c9272171d5a0169d5cb1bef Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Fri, 11 Apr 2014 11:21:47 -0500 Subject: bus: omap_l3_noc: switch over to relaxed variants of readl/writel Currently we use __raw_readl and writel in this driver. Considering there is no specific need for a memory barrier, replacing writel with endian-neutral writel_relaxed and replacing __raw_readls with the corresponding endian-neutral readl_relaxed allows us to have a standard set of register operations for the driver. While at it, simplify address computation using variables for register. Signed-off-by: Nishanth Menon Acked-by: Santosh Shilimkar Acked-by: Felipe Balbi Acked-by: Peter Ujfalusi Tested-by: Darren Etheridge Tested-by: Sekhar Nori --- drivers/bus/omap_l3_noc.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'drivers/bus') diff --git a/drivers/bus/omap_l3_noc.c b/drivers/bus/omap_l3_noc.c index 37d71b715053..c8facb00bb53 100644 --- a/drivers/bus/omap_l3_noc.c +++ b/drivers/bus/omap_l3_noc.c @@ -55,6 +55,7 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) int err_src = 0; u32 std_err_main, err_reg, clear, masterid; void __iomem *base, *l3_targ_base; + void __iomem *l3_targ_stderr, *l3_targ_slvofslsb, *l3_targ_mstaddr; char *target_name, *master_name = "UN IDENTIFIED"; /* Get the Type of interrupt */ @@ -66,8 +67,8 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) * to determine the source */ base = l3->l3_base[i]; - err_reg = __raw_readl(base + l3_flagmux[i] + - + L3_FLAGMUX_REGERR0 + (inttype << 3)); + err_reg = readl_relaxed(base + l3_flagmux[i] + + L3_FLAGMUX_REGERR0 + (inttype << 3)); /* Get the corresponding error and analyse */ if (err_reg) { @@ -76,10 +77,14 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) /* Read the stderrlog_main_source from clk domain */ l3_targ_base = base + *(l3_targ[i] + err_src); - std_err_main = __raw_readl(l3_targ_base + - L3_TARG_STDERRLOG_MAIN); - masterid = __raw_readl(l3_targ_base + - L3_TARG_STDERRLOG_MSTADDR); + l3_targ_stderr = l3_targ_base + L3_TARG_STDERRLOG_MAIN; + l3_targ_slvofslsb = l3_targ_base + + L3_TARG_STDERRLOG_SLVOFSLSB; + l3_targ_mstaddr = l3_targ_base + + L3_TARG_STDERRLOG_MSTADDR; + + std_err_main = readl_relaxed(l3_targ_stderr); + masterid = readl_relaxed(l3_targ_mstaddr); switch (std_err_main & CUSTOM_ERROR) { case STANDARD_ERROR: @@ -87,12 +92,10 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) l3_targ_inst_name[i][err_src]; WARN(true, "L3 standard error: TARGET:%s at address 0x%x\n", target_name, - __raw_readl(l3_targ_base + - L3_TARG_STDERRLOG_SLVOFSLSB)); + readl_relaxed(l3_targ_slvofslsb)); /* clear the std error log*/ clear = std_err_main | CLEAR_STDERR_LOG; - writel(clear, l3_targ_base + - L3_TARG_STDERRLOG_MAIN); + writel_relaxed(clear, l3_targ_stderr); break; case CUSTOM_ERROR: @@ -107,8 +110,7 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) master_name, target_name); /* clear the std error log*/ clear = std_err_main | CLEAR_STDERR_LOG; - writel(clear, l3_targ_base + - L3_TARG_STDERRLOG_MAIN); + writel_relaxed(clear, l3_targ_stderr); break; default: -- cgit From add6f74b9baf6676c4465b99967c972c464e59cc Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Fri, 11 Apr 2014 11:24:42 -0500 Subject: bus: omap_l3_noc: un-obfuscate l3_targ address computation just simplify derefencing that is equivalent. Signed-off-by: Nishanth Menon Acked-by: Santosh Shilimkar Acked-by: Peter Ujfalusi Tested-by: Darren Etheridge Tested-by: Sekhar Nori --- drivers/bus/omap_l3_noc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/bus') diff --git a/drivers/bus/omap_l3_noc.c b/drivers/bus/omap_l3_noc.c index c8facb00bb53..f7d3bf4f7284 100644 --- a/drivers/bus/omap_l3_noc.c +++ b/drivers/bus/omap_l3_noc.c @@ -76,7 +76,7 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) err_src = __ffs(err_reg); /* Read the stderrlog_main_source from clk domain */ - l3_targ_base = base + *(l3_targ[i] + err_src); + l3_targ_base = base + l3_targ[i][err_src]; l3_targ_stderr = l3_targ_base + L3_TARG_STDERRLOG_MAIN; l3_targ_slvofslsb = l3_targ_base + L3_TARG_STDERRLOG_SLVOFSLSB; -- cgit From f0a6e654d8db2dfa3eb8b99380ad449d5e092c33 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Fri, 11 Apr 2014 10:11:59 -0500 Subject: bus: omap_l3_noc: move L3 master data structure out Move the L3 master structure out of the static definition to enable reuse for other SoCs. Signed-off-by: Nishanth Menon Acked-by: Santosh Shilimkar Acked-by: Peter Ujfalusi Tested-by: Darren Etheridge Tested-by: Sekhar Nori --- drivers/bus/omap_l3_noc.h | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'drivers/bus') diff --git a/drivers/bus/omap_l3_noc.h b/drivers/bus/omap_l3_noc.h index 31984cf949cc..059c707fdc84 100644 --- a/drivers/bus/omap_l3_noc.h +++ b/drivers/bus/omap_l3_noc.h @@ -33,6 +33,16 @@ #define NUM_OF_L3_MASTERS (sizeof(l3_masters)/sizeof(l3_masters[0])) +/** + * struct l3_masters_data - L3 Master information + * @id: ID of the L3 Master + * @name: master name + */ +struct l3_masters_data { + u32 id; + char *name; +}; + static u32 l3_flagmux[L3_MODULES] = { 0x500, 0x1000, @@ -80,10 +90,7 @@ static u32 l3_targ_inst_clk3[] = { 0x0 /* HOST CLK3 */ }; -static struct l3_masters_data { - u32 id; - char name[10]; -} l3_masters[] = { +static struct l3_masters_data l3_masters[] = { { 0x0 , "MPU"}, { 0x10, "CS_ADP"}, { 0x14, "xxx"}, -- cgit From 3ae9af7c90f8113365cf2600797115ee35e42d0d Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Fri, 11 Apr 2014 11:38:10 -0500 Subject: bus: omap_l3_noc: convert target information into a structure Currently the target instance information is organized indexed by bit field offset into multiple arrays. 1. We currently have offsets specific to each target associated with each clock domains are in seperate arrays: l3_targ_inst_clk1 l3_targ_inst_clk2 l3_targ_inst_clk3 2. Then they are organized per master index in l3_targ. 3. We have names in l3_targ_inst_name as an array to array of strings corresponding to the above with offsets. Simplify the same by defining a structure for information containing both target offset and name. this is then stored in arrays per domain and organized into an array indexed off domain. The array is still indexed based on bit field offset. Signed-off-by: Nishanth Menon Acked-by: Santosh Shilimkar Acked-by: Peter Ujfalusi Tested-by: Darren Etheridge Tested-by: Sekhar Nori --- drivers/bus/omap_l3_noc.c | 9 ++-- drivers/bus/omap_l3_noc.h | 129 ++++++++++++++++++---------------------------- 2 files changed, 54 insertions(+), 84 deletions(-) (limited to 'drivers/bus') diff --git a/drivers/bus/omap_l3_noc.c b/drivers/bus/omap_l3_noc.c index f7d3bf4f7284..343f002a06f7 100644 --- a/drivers/bus/omap_l3_noc.c +++ b/drivers/bus/omap_l3_noc.c @@ -57,6 +57,7 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) void __iomem *base, *l3_targ_base; void __iomem *l3_targ_stderr, *l3_targ_slvofslsb, *l3_targ_mstaddr; char *target_name, *master_name = "UN IDENTIFIED"; + struct l3_target_data *l3_targ_inst; /* Get the Type of interrupt */ inttype = irq == l3->app_irq ? L3_APPLICATION_ERROR : L3_DEBUG_ERROR; @@ -74,9 +75,11 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) if (err_reg) { /* Identify the source from control status register */ err_src = __ffs(err_reg); + l3_targ_inst = &l3_targ[i][err_src]; + target_name = l3_targ_inst->name; + l3_targ_base = base + l3_targ_inst->offset; /* Read the stderrlog_main_source from clk domain */ - l3_targ_base = base + l3_targ[i][err_src]; l3_targ_stderr = l3_targ_base + L3_TARG_STDERRLOG_MAIN; l3_targ_slvofslsb = l3_targ_base + L3_TARG_STDERRLOG_SLVOFSLSB; @@ -88,8 +91,6 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) switch (std_err_main & CUSTOM_ERROR) { case STANDARD_ERROR: - target_name = - l3_targ_inst_name[i][err_src]; WARN(true, "L3 standard error: TARGET:%s at address 0x%x\n", target_name, readl_relaxed(l3_targ_slvofslsb)); @@ -99,8 +100,6 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) break; case CUSTOM_ERROR: - target_name = - l3_targ_inst_name[i][err_src]; for (k = 0; k < NUM_OF_L3_MASTERS; k++) { if (masterid == l3_masters[k].id) master_name = diff --git a/drivers/bus/omap_l3_noc.h b/drivers/bus/omap_l3_noc.h index 059c707fdc84..ae2878464efa 100644 --- a/drivers/bus/omap_l3_noc.h +++ b/drivers/bus/omap_l3_noc.h @@ -43,51 +43,62 @@ struct l3_masters_data { char *name; }; +/** + * struct l3_target_data - L3 Target information + * @offset: Offset from base for L3 Target + * @name: Target name + * + * Target information is organized indexed by bit field definitions. + */ +struct l3_target_data { + u32 offset; + char *name; +}; + static u32 l3_flagmux[L3_MODULES] = { 0x500, 0x1000, 0X0200 }; -/* L3 Target standard Error register offsets */ -static u32 l3_targ_inst_clk1[] = { - 0x100, /* DMM1 */ - 0x200, /* DMM2 */ - 0x300, /* ABE */ - 0x400, /* L4CFG */ - 0x600, /* CLK2 PWR DISC */ - 0x0, /* Host CLK1 */ - 0x900 /* L4 Wakeup */ +static struct l3_target_data l3_target_inst_data_clk1[] = { + {0x100, "DMM1",}, + {0x200, "DMM2",}, + {0x300, "ABE",}, + {0x400, "L4CFG",}, + {0x600, "CLK2PWRDISC",}, + {0x0, "HOSTCLK1",}, + {0x900, "L4WAKEUP",}, }; -static u32 l3_targ_inst_clk2[] = { - 0x500, /* CORTEX M3 */ - 0x300, /* DSS */ - 0x100, /* GPMC */ - 0x400, /* ISS */ - 0x700, /* IVAHD */ - 0xD00, /* missing in TRM corresponds to AES1*/ - 0x900, /* L4 PER0*/ - 0x200, /* OCMRAM */ - 0x100, /* missing in TRM corresponds to GPMC sERROR*/ - 0x600, /* SGX */ - 0x800, /* SL2 */ - 0x1600, /* C2C */ - 0x1100, /* missing in TRM corresponds PWR DISC CLK1*/ - 0xF00, /* missing in TRM corrsponds to SHA1*/ - 0xE00, /* missing in TRM corresponds to AES2*/ - 0xC00, /* L4 PER3 */ - 0xA00, /* L4 PER1*/ - 0xB00, /* L4 PER2*/ - 0x0, /* HOST CLK2 */ - 0x1800, /* CAL */ - 0x1700 /* LLI */ +static struct l3_target_data l3_target_inst_data_clk2[] = { + {0x500, "CORTEXM3",}, + {0x300, "DSS",}, + {0x100, "GPMC",}, + {0x400, "ISS",}, + {0x700, "IVAHD",}, + {0xD00, "AES1",}, + {0x900, "L4PER0",}, + {0x200, "OCMRAM",}, + {0x100, "GPMCsERROR",}, + {0x600, "SGX",}, + {0x800, "SL2",}, + {0x1600, "C2C",}, + {0x1100, "PWRDISCCLK1",}, + {0xF00, "SHA1",}, + {0xE00, "AES2",}, + {0xC00, "L4PER3",}, + {0xA00, "L4PER1",}, + {0xB00, "L4PER2",}, + {0x0, "HOSTCLK2",}, + {0x1800, "CAL",}, + {0x1700, "LLI",}, }; -static u32 l3_targ_inst_clk3[] = { - 0x0100 /* EMUSS */, - 0x0300, /* DEBUGSS_CT_TBR */ - 0x0 /* HOST CLK3 */ +static struct l3_target_data l3_target_inst_data_clk3[] = { + {0x0100, "EMUSS",}, + {0x0300, "DEBUG SOURCE",}, + {0x0, "HOST CLK3",}, }; static struct l3_masters_data l3_masters[] = { @@ -118,50 +129,10 @@ static struct l3_masters_data l3_masters[] = { { 0xC8, "USBHOSTFS"} }; -static char *l3_targ_inst_name[L3_MODULES][21] = { - { - "DMM1", - "DMM2", - "ABE", - "L4CFG", - "CLK2 PWR DISC", - "HOST CLK1", - "L4 WAKEUP" - }, - { - "CORTEX M3" , - "DSS ", - "GPMC ", - "ISS ", - "IVAHD ", - "AES1", - "L4 PER0", - "OCMRAM ", - "GPMC sERROR", - "SGX ", - "SL2 ", - "C2C ", - "PWR DISC CLK1", - "SHA1", - "AES2", - "L4 PER3", - "L4 PER1", - "L4 PER2", - "HOST CLK2", - "CAL", - "LLI" - }, - { - "EMUSS", - "DEBUG SOURCE", - "HOST CLK3" - }, -}; - -static u32 *l3_targ[L3_MODULES] = { - l3_targ_inst_clk1, - l3_targ_inst_clk2, - l3_targ_inst_clk3, +static struct l3_target_data *l3_targ[L3_MODULES] = { + l3_target_inst_data_clk1, + l3_target_inst_data_clk2, + l3_target_inst_data_clk3, }; struct omap_l3 { -- cgit From 3340d739f8e1273abd408c59ad1843ea2ac35566 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Thu, 10 Apr 2014 11:31:33 -0500 Subject: bus: omap_l3_noc: Add support for discountinous flag mux input numbers On DRA7, unlike on OMAP4 and OMAP5, the flag mux input numbers used to indicate the source of errors are not continous. Have a way in the driver to catch these and WARN the user of the flag mux input thats either undocumented or wrong. In the similar vein, Timeout errors in AM43x can't be cleared per h/w team, neither does it have a STDERRLOG_MAIN to clear the error. Further, the mux bit offset might not even be indexed into our array of known mux input description, in which case we'd have a abort. So, define a static range check for bit description and any definition which has target_name set to NULL (the ones that are not populated or ones that are specifically marked in the case of discontinous input numbers), can handle the same gracefully. Upon occurance of error from such sources, mask it. Otherwise, we'd have an infinite interrupt source without any means to clear it. NOTE: follow on patch ensures that these masked bits are ignored. [nm@ti.com: rebase, squash and improve] Signed-off-by: Rajendra Nayak Signed-off-by: Afzal Mohammed Signed-off-by: Nishanth Menon Acked-by: Santosh Shilimkar Acked-by: Peter Ujfalusi Tested-by: Darren Etheridge Tested-by: Sekhar Nori --- drivers/bus/omap_l3_noc.c | 31 +++++++++++++++++++++++++++++++ drivers/bus/omap_l3_noc.h | 11 ++++++++--- 2 files changed, 39 insertions(+), 3 deletions(-) (limited to 'drivers/bus') diff --git a/drivers/bus/omap_l3_noc.c b/drivers/bus/omap_l3_noc.c index 343f002a06f7..7743e86e88b1 100644 --- a/drivers/bus/omap_l3_noc.c +++ b/drivers/bus/omap_l3_noc.c @@ -75,10 +75,41 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) if (err_reg) { /* Identify the source from control status register */ err_src = __ffs(err_reg); + + /* We DONOT expect err_src to go out of bounds */ + BUG_ON(err_src > MAX_CLKDM_TARGETS); + l3_targ_inst = &l3_targ[i][err_src]; target_name = l3_targ_inst->name; l3_targ_base = base + l3_targ_inst->offset; + /* + * If we do not know of a register offset to decode + * and clear, then mask. + */ + if (target_name == L3_TARGET_NOT_SUPPORTED) { + u32 mask_val; + void __iomem *mask_reg; + + /* + * Certain plaforms may have "undocumented" + * status pending on boot.. So dont generate + * a severe warning here. + */ + dev_err(l3->dev, + "L3 %s error: target %d mod:%d %s\n", + inttype ? "debug" : "application", + err_src, i, "(unclearable)"); + + mask_reg = base + l3_flagmux[i] + + L3_FLAGMUX_MASK0 + (inttype << 3); + mask_val = readl_relaxed(mask_reg); + mask_val &= ~(1 << err_src); + writel_relaxed(mask_val, mask_reg); + + break; + } + /* Read the stderrlog_main_source from clk domain */ l3_targ_stderr = l3_targ_base + L3_TARG_STDERRLOG_MAIN; l3_targ_slvofslsb = l3_targ_base + diff --git a/drivers/bus/omap_l3_noc.h b/drivers/bus/omap_l3_noc.h index ae2878464efa..66caeceaf123 100644 --- a/drivers/bus/omap_l3_noc.h +++ b/drivers/bus/omap_l3_noc.h @@ -30,6 +30,11 @@ #define L3_TARG_STDERRLOG_SLVOFSLSB 0x5c #define L3_TARG_STDERRLOG_MSTADDR 0x68 #define L3_FLAGMUX_REGERR0 0xc +#define L3_FLAGMUX_MASK0 0x8 + +#define L3_TARGET_NOT_SUPPORTED NULL + +#define MAX_CLKDM_TARGETS 31 #define NUM_OF_L3_MASTERS (sizeof(l3_masters)/sizeof(l3_masters[0])) @@ -61,7 +66,7 @@ static u32 l3_flagmux[L3_MODULES] = { 0X0200 }; -static struct l3_target_data l3_target_inst_data_clk1[] = { +static struct l3_target_data l3_target_inst_data_clk1[MAX_CLKDM_TARGETS] = { {0x100, "DMM1",}, {0x200, "DMM2",}, {0x300, "ABE",}, @@ -71,7 +76,7 @@ static struct l3_target_data l3_target_inst_data_clk1[] = { {0x900, "L4WAKEUP",}, }; -static struct l3_target_data l3_target_inst_data_clk2[] = { +static struct l3_target_data l3_target_inst_data_clk2[MAX_CLKDM_TARGETS] = { {0x500, "CORTEXM3",}, {0x300, "DSS",}, {0x100, "GPMC",}, @@ -95,7 +100,7 @@ static struct l3_target_data l3_target_inst_data_clk2[] = { {0x1700, "LLI",}, }; -static struct l3_target_data l3_target_inst_data_clk3[] = { +static struct l3_target_data l3_target_inst_data_clk3[MAX_CLKDM_TARGETS] = { {0x0100, "EMUSS",}, {0x0300, "DEBUG SOURCE",}, {0x0, "HOST CLK3",}, -- cgit From 0659452dd2b2602058b80cfdcc673e98f2a67184 Mon Sep 17 00:00:00 2001 From: Sricharan R Date: Tue, 26 Nov 2013 07:38:23 -0600 Subject: bus: omap_l3_noc: use of_match_data to pick up SoC information DRA7xx SoC has the same l3-noc interconnect ip (as OMAP4 and OMAP5), but AM437x SoC has just 2 modules instead of 3 which other SoCs have. So, stop using direct access of array indices and use of->match data and simplify implementation to benefit future usage. While at it, rename a few very generic variables to make them omap specific. This helps us differentiate from DRA7 and AM43xx data in the future. NOTE: None of the platforms that use omap_l3_noc are non-device tree anymore. So, it is safe to assume OF match here. Signed-off-by: Sricharan R Signed-off-by: Rajendra Nayak [nm@ti.com: split, refactor and optimize logic] Signed-off-by: Nishanth Menon Acked-by: Santosh Shilimkar Acked-by: Peter Ujfalusi Tested-by: Darren Etheridge Tested-by: Sekhar Nori --- drivers/bus/omap_l3_noc.c | 55 +++++++++++++++++++++--------------- drivers/bus/omap_l3_noc.h | 72 ++++++++++++++++++++++++++++++++++------------- 2 files changed, 84 insertions(+), 43 deletions(-) (limited to 'drivers/bus') diff --git a/drivers/bus/omap_l3_noc.c b/drivers/bus/omap_l3_noc.c index 7743e86e88b1..7e0a988ad579 100644 --- a/drivers/bus/omap_l3_noc.c +++ b/drivers/bus/omap_l3_noc.c @@ -14,12 +14,14 @@ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ -#include #include -#include -#include #include +#include #include +#include +#include +#include +#include #include #include "omap_l3_noc.h" @@ -58,17 +60,18 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) void __iomem *l3_targ_stderr, *l3_targ_slvofslsb, *l3_targ_mstaddr; char *target_name, *master_name = "UN IDENTIFIED"; struct l3_target_data *l3_targ_inst; + struct l3_masters_data *master; /* Get the Type of interrupt */ inttype = irq == l3->app_irq ? L3_APPLICATION_ERROR : L3_DEBUG_ERROR; - for (i = 0; i < L3_MODULES; i++) { + for (i = 0; i < l3->num_modules; i++) { /* * Read the regerr register of the clock domain * to determine the source */ base = l3->l3_base[i]; - err_reg = readl_relaxed(base + l3_flagmux[i] + + err_reg = readl_relaxed(base + l3->l3_flagmux[i] + L3_FLAGMUX_REGERR0 + (inttype << 3)); /* Get the corresponding error and analyse */ @@ -79,7 +82,7 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) /* We DONOT expect err_src to go out of bounds */ BUG_ON(err_src > MAX_CLKDM_TARGETS); - l3_targ_inst = &l3_targ[i][err_src]; + l3_targ_inst = &l3->l3_targ[i][err_src]; target_name = l3_targ_inst->name; l3_targ_base = base + l3_targ_inst->offset; @@ -101,7 +104,7 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) inttype ? "debug" : "application", err_src, i, "(unclearable)"); - mask_reg = base + l3_flagmux[i] + + mask_reg = base + l3->l3_flagmux[i] + L3_FLAGMUX_MASK0 + (inttype << 3); mask_val = readl_relaxed(mask_reg); mask_val &= ~(1 << err_src); @@ -131,10 +134,12 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) break; case CUSTOM_ERROR: - for (k = 0; k < NUM_OF_L3_MASTERS; k++) { - if (masterid == l3_masters[k].id) - master_name = - l3_masters[k].name; + for (k = 0, master = l3->l3_masters; + k < l3->num_masters; k++, master++) { + if (masterid == master->id) { + master_name = master->name; + break; + } } WARN(true, "L3 custom error: MASTER:%s TARGET:%s\n", master_name, target_name); @@ -154,20 +159,34 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) return IRQ_HANDLED; } +static const struct of_device_id l3_noc_match[] = { + {.compatible = "ti,omap4-l3-noc", .data = &omap_l3_data}, + {}, +}; +MODULE_DEVICE_TABLE(of, l3_noc_match); + static int omap_l3_probe(struct platform_device *pdev) { + const struct of_device_id *of_id; static struct omap_l3 *l3; int ret, i; + of_id = of_match_device(l3_noc_match, &pdev->dev); + if (!of_id) { + dev_err(&pdev->dev, "OF data missing\n"); + return -EINVAL; + } + l3 = devm_kzalloc(&pdev->dev, sizeof(*l3), GFP_KERNEL); if (!l3) return -ENOMEM; + memcpy(l3, of_id->data, sizeof(*l3)); l3->dev = &pdev->dev; platform_set_drvdata(pdev, l3); /* Get mem resources */ - for (i = 0; i < L3_MODULES; i++) { + for (i = 0; i < l3->num_modules; i++) { struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, i); @@ -199,22 +218,12 @@ static int omap_l3_probe(struct platform_device *pdev) return ret; } -#if defined(CONFIG_OF) -static const struct of_device_id l3_noc_match[] = { - {.compatible = "ti,omap4-l3-noc", }, - {}, -}; -MODULE_DEVICE_TABLE(of, l3_noc_match); -#else -#define l3_noc_match NULL -#endif - static struct platform_driver omap_l3_driver = { .probe = omap_l3_probe, .driver = { .name = "omap_l3_noc", .owner = THIS_MODULE, - .of_match_table = l3_noc_match, + .of_match_table = of_match_ptr(l3_noc_match), }, }; diff --git a/drivers/bus/omap_l3_noc.h b/drivers/bus/omap_l3_noc.h index 66caeceaf123..e60865fe5965 100644 --- a/drivers/bus/omap_l3_noc.h +++ b/drivers/bus/omap_l3_noc.h @@ -17,7 +17,9 @@ #ifndef __OMAP_L3_NOC_H #define __OMAP_L3_NOC_H -#define L3_MODULES 3 +#define OMAP_L3_MODULES 3 +#define MAX_L3_MODULES 3 + #define CLEAR_STDERR_LOG (1 << 31) #define CUSTOM_ERROR 0x2 #define STANDARD_ERROR 0x0 @@ -36,8 +38,6 @@ #define MAX_CLKDM_TARGETS 31 -#define NUM_OF_L3_MASTERS (sizeof(l3_masters)/sizeof(l3_masters[0])) - /** * struct l3_masters_data - L3 Master information * @id: ID of the L3 Master @@ -60,13 +60,47 @@ struct l3_target_data { char *name; }; -static u32 l3_flagmux[L3_MODULES] = { + +/** + * struct omap_l3 - Description of data relevant for L3 bus. + * @dev: device representing the bus (populated runtime) + * @l3_base: base addresses of modules (populated runtime) + * @l3_flag_mux: array containing offsets to flag mux per module + * offset from corresponding module base indexed per + * module. + * @num_modules: number of clock domains / modules. + * @l3_masters: array pointing to master data containing name and register + * offset for the master. + * @num_master: number of masters + * @l3_targ: array indexed by flagmux index (bit offset) pointing to the + * target data. unsupported ones are marked with + * L3_TARGET_NOT_SUPPORTED + * @debug_irq: irq number of the debug interrupt (populated runtime) + * @app_irq: irq number of the application interrupt (populated runtime) + */ +struct omap_l3 { + struct device *dev; + + void __iomem *l3_base[MAX_L3_MODULES]; + u32 *l3_flagmux; + int num_modules; + + struct l3_masters_data *l3_masters; + int num_masters; + + struct l3_target_data **l3_targ; + + int debug_irq; + int app_irq; +}; + +static u32 omap_l3_flagmux[OMAP_L3_MODULES] = { 0x500, 0x1000, 0X0200 }; -static struct l3_target_data l3_target_inst_data_clk1[MAX_CLKDM_TARGETS] = { +static struct l3_target_data omap_l3_target_data_clk1[MAX_CLKDM_TARGETS] = { {0x100, "DMM1",}, {0x200, "DMM2",}, {0x300, "ABE",}, @@ -76,7 +110,7 @@ static struct l3_target_data l3_target_inst_data_clk1[MAX_CLKDM_TARGETS] = { {0x900, "L4WAKEUP",}, }; -static struct l3_target_data l3_target_inst_data_clk2[MAX_CLKDM_TARGETS] = { +static struct l3_target_data omap_l3_target_data_clk2[MAX_CLKDM_TARGETS] = { {0x500, "CORTEXM3",}, {0x300, "DSS",}, {0x100, "GPMC",}, @@ -100,13 +134,13 @@ static struct l3_target_data l3_target_inst_data_clk2[MAX_CLKDM_TARGETS] = { {0x1700, "LLI",}, }; -static struct l3_target_data l3_target_inst_data_clk3[MAX_CLKDM_TARGETS] = { +static struct l3_target_data omap_l3_target_data_clk3[MAX_CLKDM_TARGETS] = { {0x0100, "EMUSS",}, {0x0300, "DEBUG SOURCE",}, {0x0, "HOST CLK3",}, }; -static struct l3_masters_data l3_masters[] = { +static struct l3_masters_data omap_l3_masters[] = { { 0x0 , "MPU"}, { 0x10, "CS_ADP"}, { 0x14, "xxx"}, @@ -134,20 +168,18 @@ static struct l3_masters_data l3_masters[] = { { 0xC8, "USBHOSTFS"} }; -static struct l3_target_data *l3_targ[L3_MODULES] = { - l3_target_inst_data_clk1, - l3_target_inst_data_clk2, - l3_target_inst_data_clk3, +static struct l3_target_data *omap_l3_targ[OMAP_L3_MODULES] = { + omap_l3_target_data_clk1, + omap_l3_target_data_clk2, + omap_l3_target_data_clk3, }; -struct omap_l3 { - struct device *dev; - - /* memory base */ - void __iomem *l3_base[L3_MODULES]; - - int debug_irq; - int app_irq; +static const struct omap_l3 omap_l3_data = { + .l3_flagmux = omap_l3_flagmux, + .num_modules = OMAP_L3_MODULES, + .l3_masters = omap_l3_masters, + .num_masters = ARRAY_SIZE(omap_l3_masters), + .l3_targ = omap_l3_targ, }; #endif /* __OMAP_L3_NOC_H */ -- cgit From 97708c08c9955306742872ff7f2e47faec864ee7 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Mon, 14 Apr 2014 09:57:50 -0500 Subject: bus: omap_l3_noc: convert flagmux information into a structure This allows us to encompass target information and flag mux offset that points to the target information into a singular structure. This saves us the need to look up two different arrays indexed by module ID for information. This allows us to reduce the static target information allocation to just the ones that are documented. Signed-off-by: Nishanth Menon Acked-by: Santosh Shilimkar Acked-by: Peter Ujfalusi Tested-by: Darren Etheridge Tested-by: Sekhar Nori --- drivers/bus/omap_l3_noc.c | 16 +++++++---- drivers/bus/omap_l3_noc.h | 70 ++++++++++++++++++++++++++++++----------------- 2 files changed, 56 insertions(+), 30 deletions(-) (limited to 'drivers/bus') diff --git a/drivers/bus/omap_l3_noc.c b/drivers/bus/omap_l3_noc.c index 7e0a988ad579..9524452ee12c 100644 --- a/drivers/bus/omap_l3_noc.c +++ b/drivers/bus/omap_l3_noc.c @@ -60,6 +60,7 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) void __iomem *l3_targ_stderr, *l3_targ_slvofslsb, *l3_targ_mstaddr; char *target_name, *master_name = "UN IDENTIFIED"; struct l3_target_data *l3_targ_inst; + struct l3_flagmux_data *flag_mux; struct l3_masters_data *master; /* Get the Type of interrupt */ @@ -71,7 +72,8 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) * to determine the source */ base = l3->l3_base[i]; - err_reg = readl_relaxed(base + l3->l3_flagmux[i] + + flag_mux = l3->l3_flagmux[i]; + err_reg = readl_relaxed(base + flag_mux->offset + L3_FLAGMUX_REGERR0 + (inttype << 3)); /* Get the corresponding error and analyse */ @@ -82,9 +84,13 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) /* We DONOT expect err_src to go out of bounds */ BUG_ON(err_src > MAX_CLKDM_TARGETS); - l3_targ_inst = &l3->l3_targ[i][err_src]; - target_name = l3_targ_inst->name; - l3_targ_base = base + l3_targ_inst->offset; + if (err_src < flag_mux->num_targ_data) { + l3_targ_inst = &flag_mux->l3_targ[err_src]; + target_name = l3_targ_inst->name; + l3_targ_base = base + l3_targ_inst->offset; + } else { + target_name = L3_TARGET_NOT_SUPPORTED; + } /* * If we do not know of a register offset to decode @@ -104,7 +110,7 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) inttype ? "debug" : "application", err_src, i, "(unclearable)"); - mask_reg = base + l3->l3_flagmux[i] + + mask_reg = base + flag_mux->offset + L3_FLAGMUX_MASK0 + (inttype << 3); mask_val = readl_relaxed(mask_reg); mask_val &= ~(1 << err_src); diff --git a/drivers/bus/omap_l3_noc.h b/drivers/bus/omap_l3_noc.h index e60865fe5965..64869fe656e5 100644 --- a/drivers/bus/omap_l3_noc.h +++ b/drivers/bus/omap_l3_noc.h @@ -17,8 +17,8 @@ #ifndef __OMAP_L3_NOC_H #define __OMAP_L3_NOC_H -#define OMAP_L3_MODULES 3 #define MAX_L3_MODULES 3 +#define MAX_CLKDM_TARGETS 31 #define CLEAR_STDERR_LOG (1 << 31) #define CUSTOM_ERROR 0x2 @@ -36,8 +36,6 @@ #define L3_TARGET_NOT_SUPPORTED NULL -#define MAX_CLKDM_TARGETS 31 - /** * struct l3_masters_data - L3 Master information * @id: ID of the L3 Master @@ -60,21 +58,32 @@ struct l3_target_data { char *name; }; +/** + * struct l3_flagmux_data - Flag Mux information + * @offset: offset from base for flagmux register + * @l3_targ: array indexed by flagmux index (bit offset) pointing to the + * target data. unsupported ones are marked with + * L3_TARGET_NOT_SUPPORTED + * @num_targ_data: number of entries in target data + */ +struct l3_flagmux_data { + u32 offset; + struct l3_target_data *l3_targ; + u8 num_targ_data; +}; + /** * struct omap_l3 - Description of data relevant for L3 bus. * @dev: device representing the bus (populated runtime) * @l3_base: base addresses of modules (populated runtime) - * @l3_flag_mux: array containing offsets to flag mux per module + * @l3_flag_mux: array containing flag mux data per module * offset from corresponding module base indexed per * module. * @num_modules: number of clock domains / modules. * @l3_masters: array pointing to master data containing name and register * offset for the master. * @num_master: number of masters - * @l3_targ: array indexed by flagmux index (bit offset) pointing to the - * target data. unsupported ones are marked with - * L3_TARGET_NOT_SUPPORTED * @debug_irq: irq number of the debug interrupt (populated runtime) * @app_irq: irq number of the application interrupt (populated runtime) */ @@ -82,25 +91,17 @@ struct omap_l3 { struct device *dev; void __iomem *l3_base[MAX_L3_MODULES]; - u32 *l3_flagmux; + struct l3_flagmux_data **l3_flagmux; int num_modules; struct l3_masters_data *l3_masters; int num_masters; - struct l3_target_data **l3_targ; - int debug_irq; int app_irq; }; -static u32 omap_l3_flagmux[OMAP_L3_MODULES] = { - 0x500, - 0x1000, - 0X0200 -}; - -static struct l3_target_data omap_l3_target_data_clk1[MAX_CLKDM_TARGETS] = { +static struct l3_target_data omap_l3_target_data_clk1[] = { {0x100, "DMM1",}, {0x200, "DMM2",}, {0x300, "ABE",}, @@ -110,7 +111,14 @@ static struct l3_target_data omap_l3_target_data_clk1[MAX_CLKDM_TARGETS] = { {0x900, "L4WAKEUP",}, }; -static struct l3_target_data omap_l3_target_data_clk2[MAX_CLKDM_TARGETS] = { +static struct l3_flagmux_data omap_l3_flagmux_clk1 = { + .offset = 0x500, + .l3_targ = omap_l3_target_data_clk1, + .num_targ_data = ARRAY_SIZE(omap_l3_target_data_clk1), +}; + + +static struct l3_target_data omap_l3_target_data_clk2[] = { {0x500, "CORTEXM3",}, {0x300, "DSS",}, {0x100, "GPMC",}, @@ -134,12 +142,25 @@ static struct l3_target_data omap_l3_target_data_clk2[MAX_CLKDM_TARGETS] = { {0x1700, "LLI",}, }; -static struct l3_target_data omap_l3_target_data_clk3[MAX_CLKDM_TARGETS] = { +static struct l3_flagmux_data omap_l3_flagmux_clk2 = { + .offset = 0x1000, + .l3_targ = omap_l3_target_data_clk2, + .num_targ_data = ARRAY_SIZE(omap_l3_target_data_clk2), +}; + + +static struct l3_target_data omap_l3_target_data_clk3[] = { {0x0100, "EMUSS",}, {0x0300, "DEBUG SOURCE",}, {0x0, "HOST CLK3",}, }; +static struct l3_flagmux_data omap_l3_flagmux_clk3 = { + .offset = 0x0200, + .l3_targ = omap_l3_target_data_clk3, + .num_targ_data = ARRAY_SIZE(omap_l3_target_data_clk3), +}; + static struct l3_masters_data omap_l3_masters[] = { { 0x0 , "MPU"}, { 0x10, "CS_ADP"}, @@ -168,18 +189,17 @@ static struct l3_masters_data omap_l3_masters[] = { { 0xC8, "USBHOSTFS"} }; -static struct l3_target_data *omap_l3_targ[OMAP_L3_MODULES] = { - omap_l3_target_data_clk1, - omap_l3_target_data_clk2, - omap_l3_target_data_clk3, +static struct l3_flagmux_data *omap_l3_flagmux[] = { + &omap_l3_flagmux_clk1, + &omap_l3_flagmux_clk2, + &omap_l3_flagmux_clk3, }; static const struct omap_l3 omap_l3_data = { .l3_flagmux = omap_l3_flagmux, - .num_modules = OMAP_L3_MODULES, + .num_modules = ARRAY_SIZE(omap_l3_flagmux), .l3_masters = omap_l3_masters, .num_masters = ARRAY_SIZE(omap_l3_masters), - .l3_targ = omap_l3_targ, }; #endif /* __OMAP_L3_NOC_H */ -- cgit From d4d8819e205854cc102e366f30b8eadd60a58e97 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Wed, 16 Apr 2014 11:01:02 -0500 Subject: bus: omap_l3_noc: fix masterid detection As per Documentation (OMAP4+), then masterid is infact encoded as follows: "L3_TARG_STDERRLOG_MSTADDR[7:0] STDERRLOG_MSTADDR stores the NTTP master address. The master address is the concatenation of Prefix & Initiator ConnID. It is defined on 8 bits. The 6 MSBs are used to distinguish the different initiators." So, when we matchup currently with the master ID list, we never get a proper match other than when MPU is the master (thanks to 0). Now, on other platforms such as AM437x, this tends to be bits[5:0]. Fix this by using the relevant 6MSBits to identify the master ID for standard and custom errors. Reported-by: Darren Etheridge Signed-off-by: Nishanth Menon Acked-by: Santosh Shilimkar Acked-by: Peter Ujfalusi Tested-by: Darren Etheridge Tested-by: Sekhar Nori --- drivers/bus/omap_l3_noc.c | 6 +++++- drivers/bus/omap_l3_noc.h | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers/bus') diff --git a/drivers/bus/omap_l3_noc.c b/drivers/bus/omap_l3_noc.c index 9524452ee12c..8a1926daacd7 100644 --- a/drivers/bus/omap_l3_noc.c +++ b/drivers/bus/omap_l3_noc.c @@ -127,7 +127,11 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) L3_TARG_STDERRLOG_MSTADDR; std_err_main = readl_relaxed(l3_targ_stderr); - masterid = readl_relaxed(l3_targ_mstaddr); + + /* STDERRLOG_MSTADDR Stores the NTTP master address. */ + masterid = (readl_relaxed(l3_targ_mstaddr) & + l3->mst_addr_mask) >> + __ffs(l3->mst_addr_mask); switch (std_err_main & CUSTOM_ERROR) { case STANDARD_ERROR: diff --git a/drivers/bus/omap_l3_noc.h b/drivers/bus/omap_l3_noc.h index 64869fe656e5..ba8692444665 100644 --- a/drivers/bus/omap_l3_noc.h +++ b/drivers/bus/omap_l3_noc.h @@ -84,6 +84,7 @@ struct l3_flagmux_data { * @l3_masters: array pointing to master data containing name and register * offset for the master. * @num_master: number of masters + * @mst_addr_mask: Mask representing MSTADDR information of NTTP packet * @debug_irq: irq number of the debug interrupt (populated runtime) * @app_irq: irq number of the application interrupt (populated runtime) */ @@ -96,6 +97,7 @@ struct omap_l3 { struct l3_masters_data *l3_masters; int num_masters; + u32 mst_addr_mask; int debug_irq; int app_irq; @@ -200,6 +202,8 @@ static const struct omap_l3 omap_l3_data = { .num_modules = ARRAY_SIZE(omap_l3_flagmux), .l3_masters = omap_l3_masters, .num_masters = ARRAY_SIZE(omap_l3_masters), + /* The 6 MSBs of register field used to distinguish initiator */ + .mst_addr_mask = 0xFC, }; #endif /* __OMAP_L3_NOC_H */ -- cgit From c98aa7aaa24b7687a170b93c4bf3111a6d166069 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Fri, 11 Apr 2014 12:24:56 -0500 Subject: bus: omap_l3_noc: make error reporting and handling common The logic between handling CUSTOM_ERROR and STANDARD_ERROR is just the reporting style. So make it generic, simplify and standardize the reporting with both master and target information printed to log. Handle the register address difference for master code for standard error and custom error as well. While at it, fix a minor indentation error. Signed-off-by: Nishanth Menon Acked-by: Santosh Shilimkar Acked-by: Peter Ujfalusi Tested-by: Darren Etheridge Tested-by: Sekhar Nori --- drivers/bus/omap_l3_noc.c | 72 +++++++++++++++++++++++++++++------------------ drivers/bus/omap_l3_noc.h | 3 +- 2 files changed, 47 insertions(+), 28 deletions(-) (limited to 'drivers/bus') diff --git a/drivers/bus/omap_l3_noc.c b/drivers/bus/omap_l3_noc.c index 8a1926daacd7..42e411457494 100644 --- a/drivers/bus/omap_l3_noc.c +++ b/drivers/bus/omap_l3_noc.c @@ -62,6 +62,8 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) struct l3_target_data *l3_targ_inst; struct l3_flagmux_data *flag_mux; struct l3_masters_data *master; + char *err_description; + char err_string[30] = { 0 }; /* Get the Type of interrupt */ inttype = irq == l3->app_irq ? L3_APPLICATION_ERROR : L3_DEBUG_ERROR; @@ -78,6 +80,8 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) /* Get the corresponding error and analyse */ if (err_reg) { + bool std_err = true; + /* Identify the source from control status register */ err_src = __ffs(err_reg); @@ -123,47 +127,61 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) l3_targ_stderr = l3_targ_base + L3_TARG_STDERRLOG_MAIN; l3_targ_slvofslsb = l3_targ_base + L3_TARG_STDERRLOG_SLVOFSLSB; - l3_targ_mstaddr = l3_targ_base + - L3_TARG_STDERRLOG_MSTADDR; std_err_main = readl_relaxed(l3_targ_stderr); - /* STDERRLOG_MSTADDR Stores the NTTP master address. */ - masterid = (readl_relaxed(l3_targ_mstaddr) & - l3->mst_addr_mask) >> - __ffs(l3->mst_addr_mask); - switch (std_err_main & CUSTOM_ERROR) { case STANDARD_ERROR: - WARN(true, "L3 standard error: TARGET:%s at address 0x%x\n", - target_name, - readl_relaxed(l3_targ_slvofslsb)); - /* clear the std error log*/ - clear = std_err_main | CLEAR_STDERR_LOG; - writel_relaxed(clear, l3_targ_stderr); + err_description = "Standard"; + snprintf(err_string, sizeof(err_string), + ": At Address: 0x%08X ", + readl_relaxed(l3_targ_slvofslsb)); + + l3_targ_mstaddr = l3_targ_base + + L3_TARG_STDERRLOG_MSTADDR; break; case CUSTOM_ERROR: - for (k = 0, master = l3->l3_masters; - k < l3->num_masters; k++, master++) { - if (masterid == master->id) { - master_name = master->name; - break; - } - } - WARN(true, "L3 custom error: MASTER:%s TARGET:%s\n", - master_name, target_name); - /* clear the std error log*/ - clear = std_err_main | CLEAR_STDERR_LOG; - writel_relaxed(clear, l3_targ_stderr); + err_description = "Custom"; + + l3_targ_mstaddr = l3_targ_base + + L3_TARG_STDERRLOG_CINFO_MSTADDR; break; default: + std_err = false; /* Nothing to be handled here as of now */ break; } - /* Error found so break the for loop */ - break; + + if (!std_err) + break; + + /* STDERRLOG_MSTADDR Stores the NTTP master address. */ + masterid = (readl_relaxed(l3_targ_mstaddr) & + l3->mst_addr_mask) >> + __ffs(l3->mst_addr_mask); + + for (k = 0, master = l3->l3_masters; + k < l3->num_masters; k++, master++) { + if (masterid == master->id) { + master_name = master->name; + break; + } + } + + WARN(true, + "%s:L3 %s Error: MASTER %s TARGET %s%s\n", + dev_name(l3->dev), + err_description, + master_name, target_name, + err_string); + /* clear the std error log*/ + clear = std_err_main | CLEAR_STDERR_LOG; + writel_relaxed(clear, l3_targ_stderr); + + /* Error found so break the for loop */ + break; } } return IRQ_HANDLED; diff --git a/drivers/bus/omap_l3_noc.h b/drivers/bus/omap_l3_noc.h index ba8692444665..ea2f51c984f1 100644 --- a/drivers/bus/omap_l3_noc.h +++ b/drivers/bus/omap_l3_noc.h @@ -29,8 +29,9 @@ /* L3 TARG register offsets */ #define L3_TARG_STDERRLOG_MAIN 0x48 +#define L3_TARG_STDERRLOG_MSTADDR 0x50 #define L3_TARG_STDERRLOG_SLVOFSLSB 0x5c -#define L3_TARG_STDERRLOG_MSTADDR 0x68 +#define L3_TARG_STDERRLOG_CINFO_MSTADDR 0x68 #define L3_FLAGMUX_REGERR0 0xc #define L3_FLAGMUX_MASK0 0x8 -- cgit From e4be3f3a040432398225d3634d44fc21f4807b7a Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Thu, 17 Apr 2014 12:33:50 -0500 Subject: bus: omap_l3_noc: improve readability by using helper for slave event parsing Current interrupt handler does the first level parse to identify the slave and then handles the slave even identification, reporting and clearing of event as well. It is hence logical to split the handler into two where the primary handler just parses the flagmux till it identifies a slave and the slave handling, reporting and clearing is done in a helper function. While at it update the documentation in kerneldoc style. Signed-off-by: Nishanth Menon Acked-by: Santosh Shilimkar Acked-by: Peter Ujfalusi Tested-by: Darren Etheridge Tested-by: Sekhar Nori --- drivers/bus/omap_l3_noc.c | 211 +++++++++++++++++++++++++--------------------- 1 file changed, 113 insertions(+), 98 deletions(-) (limited to 'drivers/bus') diff --git a/drivers/bus/omap_l3_noc.c b/drivers/bus/omap_l3_noc.c index 42e411457494..0691e6d9c1e4 100644 --- a/drivers/bus/omap_l3_noc.c +++ b/drivers/bus/omap_l3_noc.c @@ -26,14 +26,20 @@ #include "omap_l3_noc.h" -/* - * Interrupt Handler for L3 error detection. - * 1) Identify the L3 clockdomain partition to which the error belongs to. - * 2) Identify the slave where the error information is logged - * 3) Print the logged information. - * 4) Add dump stack to provide kernel trace. +/** + * l3_handle_target() - Handle Target specific parse and reporting + * @l3: pointer to l3 struct + * @base: base address of clkdm + * @flag_mux: flagmux corresponding to the event + * @err_src: error source index of the slave (target) * - * Two Types of errors : + * This does the second part of the error interrupt handling: + * 3) Parse in the slave information + * 4) Print the logged information. + * 5) Add dump stack to provide kernel trace. + * 6) Clear the source if known. + * + * This handles two types of errors: * 1) Custom errors in L3 : * Target like DMM/FW/EMIF generates SRESP=ERR error * 2) Standard L3 error: @@ -49,22 +55,107 @@ * can be trapped as well. But the trapping is implemented as part * secure software and hence need not be implemented here. */ -static irqreturn_t l3_interrupt_handler(int irq, void *_l3) +static int l3_handle_target(struct omap_l3 *l3, void __iomem *base, + struct l3_flagmux_data *flag_mux, int err_src) { - - struct omap_l3 *l3 = _l3; - int inttype, i, k; - int err_src = 0; - u32 std_err_main, err_reg, clear, masterid; - void __iomem *base, *l3_targ_base; + int k; + u32 std_err_main, clear, masterid; + void __iomem *l3_targ_base; void __iomem *l3_targ_stderr, *l3_targ_slvofslsb, *l3_targ_mstaddr; - char *target_name, *master_name = "UN IDENTIFIED"; struct l3_target_data *l3_targ_inst; - struct l3_flagmux_data *flag_mux; struct l3_masters_data *master; + char *target_name, *master_name = "UN IDENTIFIED"; char *err_description; char err_string[30] = { 0 }; + /* We DONOT expect err_src to go out of bounds */ + BUG_ON(err_src > MAX_CLKDM_TARGETS); + + if (err_src < flag_mux->num_targ_data) { + l3_targ_inst = &flag_mux->l3_targ[err_src]; + target_name = l3_targ_inst->name; + l3_targ_base = base + l3_targ_inst->offset; + } else { + target_name = L3_TARGET_NOT_SUPPORTED; + } + + if (target_name == L3_TARGET_NOT_SUPPORTED) + return -ENODEV; + + /* Read the stderrlog_main_source from clk domain */ + l3_targ_stderr = l3_targ_base + L3_TARG_STDERRLOG_MAIN; + l3_targ_slvofslsb = l3_targ_base + L3_TARG_STDERRLOG_SLVOFSLSB; + + std_err_main = readl_relaxed(l3_targ_stderr); + + switch (std_err_main & CUSTOM_ERROR) { + case STANDARD_ERROR: + err_description = "Standard"; + snprintf(err_string, sizeof(err_string), + ": At Address: 0x%08X ", + readl_relaxed(l3_targ_slvofslsb)); + + l3_targ_mstaddr = l3_targ_base + L3_TARG_STDERRLOG_MSTADDR; + break; + + case CUSTOM_ERROR: + err_description = "Custom"; + + l3_targ_mstaddr = l3_targ_base + + L3_TARG_STDERRLOG_CINFO_MSTADDR; + break; + + default: + /* Nothing to be handled here as of now */ + return 0; + } + + /* STDERRLOG_MSTADDR Stores the NTTP master address. */ + masterid = (readl_relaxed(l3_targ_mstaddr) & + l3->mst_addr_mask) >> __ffs(l3->mst_addr_mask); + + for (k = 0, master = l3->l3_masters; k < l3->num_masters; + k++, master++) { + if (masterid == master->id) { + master_name = master->name; + break; + } + } + + WARN(true, + "%s:L3 %s Error: MASTER %s TARGET %s%s\n", + dev_name(l3->dev), + err_description, + master_name, target_name, + err_string); + + /* clear the std error log*/ + clear = std_err_main | CLEAR_STDERR_LOG; + writel_relaxed(clear, l3_targ_stderr); + + return 0; +} + +/** + * l3_interrupt_handler() - interrupt handler for l3 events + * @irq: irq number + * @_l3: pointer to l3 structure + * + * Interrupt Handler for L3 error detection. + * 1) Identify the L3 clockdomain partition to which the error belongs to. + * 2) Identify the slave where the error information is logged + * ... handle the slave event.. + * 7) if the slave is unknown, mask out the slave. + */ +static irqreturn_t l3_interrupt_handler(int irq, void *_l3) +{ + struct omap_l3 *l3 = _l3; + int inttype, i, ret; + int err_src = 0; + u32 err_reg, mask_val; + void __iomem *base, *mask_reg; + struct l3_flagmux_data *flag_mux; + /* Get the Type of interrupt */ inttype = irq == l3->app_irq ? L3_APPLICATION_ERROR : L3_DEBUG_ERROR; @@ -80,35 +171,18 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) /* Get the corresponding error and analyse */ if (err_reg) { - bool std_err = true; - /* Identify the source from control status register */ err_src = __ffs(err_reg); - /* We DONOT expect err_src to go out of bounds */ - BUG_ON(err_src > MAX_CLKDM_TARGETS); - - if (err_src < flag_mux->num_targ_data) { - l3_targ_inst = &flag_mux->l3_targ[err_src]; - target_name = l3_targ_inst->name; - l3_targ_base = base + l3_targ_inst->offset; - } else { - target_name = L3_TARGET_NOT_SUPPORTED; - } + ret = l3_handle_target(l3, base, flag_mux, err_src); /* - * If we do not know of a register offset to decode - * and clear, then mask. + * Certain plaforms may have "undocumented" status + * pending on boot. So dont generate a severe warning + * here. Just mask it off to prevent the error from + * reoccuring and locking up the system. */ - if (target_name == L3_TARGET_NOT_SUPPORTED) { - u32 mask_val; - void __iomem *mask_reg; - - /* - * Certain plaforms may have "undocumented" - * status pending on boot.. So dont generate - * a severe warning here. - */ + if (ret) { dev_err(l3->dev, "L3 %s error: target %d mod:%d %s\n", inttype ? "debug" : "application", @@ -119,67 +193,8 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) mask_val = readl_relaxed(mask_reg); mask_val &= ~(1 << err_src); writel_relaxed(mask_val, mask_reg); - - break; } - /* Read the stderrlog_main_source from clk domain */ - l3_targ_stderr = l3_targ_base + L3_TARG_STDERRLOG_MAIN; - l3_targ_slvofslsb = l3_targ_base + - L3_TARG_STDERRLOG_SLVOFSLSB; - - std_err_main = readl_relaxed(l3_targ_stderr); - - switch (std_err_main & CUSTOM_ERROR) { - case STANDARD_ERROR: - err_description = "Standard"; - snprintf(err_string, sizeof(err_string), - ": At Address: 0x%08X ", - readl_relaxed(l3_targ_slvofslsb)); - - l3_targ_mstaddr = l3_targ_base + - L3_TARG_STDERRLOG_MSTADDR; - break; - - case CUSTOM_ERROR: - err_description = "Custom"; - - l3_targ_mstaddr = l3_targ_base + - L3_TARG_STDERRLOG_CINFO_MSTADDR; - break; - - default: - std_err = false; - /* Nothing to be handled here as of now */ - break; - } - - if (!std_err) - break; - - /* STDERRLOG_MSTADDR Stores the NTTP master address. */ - masterid = (readl_relaxed(l3_targ_mstaddr) & - l3->mst_addr_mask) >> - __ffs(l3->mst_addr_mask); - - for (k = 0, master = l3->l3_masters; - k < l3->num_masters; k++, master++) { - if (masterid == master->id) { - master_name = master->name; - break; - } - } - - WARN(true, - "%s:L3 %s Error: MASTER %s TARGET %s%s\n", - dev_name(l3->dev), - err_description, - master_name, target_name, - err_string); - /* clear the std error log*/ - clear = std_err_main | CLEAR_STDERR_LOG; - writel_relaxed(clear, l3_targ_stderr); - /* Error found so break the for loop */ break; } -- cgit From 2100b595b756db29a0b71de49c3bf73ae76c679b Mon Sep 17 00:00:00 2001 From: Afzal Mohammed Date: Fri, 25 Apr 2014 17:38:11 -0500 Subject: bus: omap_l3_noc: ignore masked out unclearable targets Errors that cannot be cleared (determined by reading REGERR register) are currently handled by masking it. Documentation states that REGERR "Checks which application/debug error sources are active" - it does not indicate that this is "interrupt status" - masked out status represented eventually in the irq line to MPU. For example: Lets say module 0 bit 8(0x100) was unclearable, we do the mask it from generating further errors. However in the following cases: a) bit 9 of Module 0 OR b) any bit of Module 1+ occur, the interrupt handler wrongly assumes that the raw interrupt status of module 0 bit 8 is the root cause of the interrupt, and returns. This causes unhandled interrupt and resultant infinite interrupts. Fix this scenario by storing the events we masked out and masking raw status with masked ones before identifying and handling the error. Reported-by: Vaibhav Hiremath Signed-off-by: Afzal Mohammed Tested-by: Vaibhav Hiremath Signed-off-by: Sekhar Nori Signed-off-by: Nishanth Menon Tested-by: Sekhar Nori --- drivers/bus/omap_l3_noc.c | 9 +++++++++ drivers/bus/omap_l3_noc.h | 4 ++++ 2 files changed, 13 insertions(+) (limited to 'drivers/bus') diff --git a/drivers/bus/omap_l3_noc.c b/drivers/bus/omap_l3_noc.c index 0691e6d9c1e4..00e4fed4a39b 100644 --- a/drivers/bus/omap_l3_noc.c +++ b/drivers/bus/omap_l3_noc.c @@ -169,6 +169,9 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) err_reg = readl_relaxed(base + flag_mux->offset + L3_FLAGMUX_REGERR0 + (inttype << 3)); + err_reg &= ~(inttype ? flag_mux->mask_app_bits : + flag_mux->mask_dbg_bits); + /* Get the corresponding error and analyse */ if (err_reg) { /* Identify the source from control status register */ @@ -193,6 +196,12 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) mask_val = readl_relaxed(mask_reg); mask_val &= ~(1 << err_src); writel_relaxed(mask_val, mask_reg); + + /* Mark these bits as to be ignored */ + if (inttype) + flag_mux->mask_app_bits |= 1 << err_src; + else + flag_mux->mask_dbg_bits |= 1 << err_src; } /* Error found so break the for loop */ diff --git a/drivers/bus/omap_l3_noc.h b/drivers/bus/omap_l3_noc.h index ea2f51c984f1..4e18307470f6 100644 --- a/drivers/bus/omap_l3_noc.h +++ b/drivers/bus/omap_l3_noc.h @@ -66,11 +66,15 @@ struct l3_target_data { * target data. unsupported ones are marked with * L3_TARGET_NOT_SUPPORTED * @num_targ_data: number of entries in target data + * @mask_app_bits: ignore these from raw application irq status + * @mask_dbg_bits: ignore these from raw debug irq status */ struct l3_flagmux_data { u32 offset; struct l3_target_data *l3_targ; u8 num_targ_data; + u32 mask_app_bits; + u32 mask_dbg_bits; }; -- cgit From 7f9de02d603c439890c4c94631a326c73e2b5b4c Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Wed, 16 Apr 2014 15:47:28 -0500 Subject: bus: omap_l3_noc: add information about the type of operation Today we get error such as L3 Custom Error: MASTER MPU TARGET L4PER2 But since the actual instruction triggerring the error Vs the point at which we report error may not be aligned, it makes sense to try and provide additional information - example the type of operation that was attempted to being performed can help narrow the debug down further. This helps provide log such as: L3 Custom Error: MASTER MPU TARGET L4PER2 (Read) Signed-off-by: Nishanth Menon Acked-by: Santosh Shilimkar Acked-by: Peter Ujfalusi Tested-by: Darren Etheridge Tested-by: Sekhar Nori --- drivers/bus/omap_l3_noc.c | 9 ++++++++- drivers/bus/omap_l3_noc.h | 13 +++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) (limited to 'drivers/bus') diff --git a/drivers/bus/omap_l3_noc.c b/drivers/bus/omap_l3_noc.c index 00e4fed4a39b..9d021d002bec 100644 --- a/drivers/bus/omap_l3_noc.c +++ b/drivers/bus/omap_l3_noc.c @@ -60,8 +60,10 @@ static int l3_handle_target(struct omap_l3 *l3, void __iomem *base, { int k; u32 std_err_main, clear, masterid; + u8 op_code; void __iomem *l3_targ_base; void __iomem *l3_targ_stderr, *l3_targ_slvofslsb, *l3_targ_mstaddr; + void __iomem *l3_targ_hdr; struct l3_target_data *l3_targ_inst; struct l3_masters_data *master; char *target_name, *master_name = "UN IDENTIFIED"; @@ -96,6 +98,7 @@ static int l3_handle_target(struct omap_l3 *l3, void __iomem *base, readl_relaxed(l3_targ_slvofslsb)); l3_targ_mstaddr = l3_targ_base + L3_TARG_STDERRLOG_MSTADDR; + l3_targ_hdr = l3_targ_base + L3_TARG_STDERRLOG_HDR; break; case CUSTOM_ERROR: @@ -103,6 +106,7 @@ static int l3_handle_target(struct omap_l3 *l3, void __iomem *base, l3_targ_mstaddr = l3_targ_base + L3_TARG_STDERRLOG_CINFO_MSTADDR; + l3_targ_hdr = l3_targ_base + L3_TARG_STDERRLOG_CINFO_OPCODE; break; default: @@ -122,11 +126,14 @@ static int l3_handle_target(struct omap_l3 *l3, void __iomem *base, } } + op_code = readl_relaxed(l3_targ_hdr) & 0x7; + WARN(true, - "%s:L3 %s Error: MASTER %s TARGET %s%s\n", + "%s:L3 %s Error: MASTER %s TARGET %s (%s)%s\n", dev_name(l3->dev), err_description, master_name, target_name, + l3_transaction_type[op_code], err_string); /* clear the std error log*/ diff --git a/drivers/bus/omap_l3_noc.h b/drivers/bus/omap_l3_noc.h index 4e18307470f6..6670fd98ce7c 100644 --- a/drivers/bus/omap_l3_noc.h +++ b/drivers/bus/omap_l3_noc.h @@ -29,14 +29,27 @@ /* L3 TARG register offsets */ #define L3_TARG_STDERRLOG_MAIN 0x48 +#define L3_TARG_STDERRLOG_HDR 0x4c #define L3_TARG_STDERRLOG_MSTADDR 0x50 #define L3_TARG_STDERRLOG_SLVOFSLSB 0x5c #define L3_TARG_STDERRLOG_CINFO_MSTADDR 0x68 +#define L3_TARG_STDERRLOG_CINFO_OPCODE 0x6c #define L3_FLAGMUX_REGERR0 0xc #define L3_FLAGMUX_MASK0 0x8 #define L3_TARGET_NOT_SUPPORTED NULL +static const char * const l3_transaction_type[] = { + /* 0 0 0 */ "Idle", + /* 0 0 1 */ "Write", + /* 0 1 0 */ "Read", + /* 0 1 1 */ "ReadEx", + /* 1 0 0 */ "Read Link", + /* 1 0 1 */ "Write Non-Posted", + /* 1 1 0 */ "Write Conditional", + /* 1 1 1 */ "Write Broadcast", +}; + /** * struct l3_masters_data - L3 Master information * @id: ID of the L3 Master -- cgit From cf52b2ecd719ca7acb19c0fd74bcfcce9dc6a362 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Wed, 16 Apr 2014 17:23:33 -0500 Subject: bus: omap_l3_noc: Add information about the context of operation L3 error may be triggered using Debug interface (example JTAG) or due to other errors, for example an opcode fetch (due to function pointer or stack corruption) or a data access (due to some other failure). NOC registers contain additional information to help aid debug information. With this, we can enhance the error information to more detailed form: " L3 Custom Error: MASTER MPU TARGET L4PER2 (Read): Data Access in User mode during Functional access " Signed-off-by: Nishanth Menon Acked-by: Santosh Shilimkar Acked-by: Peter Ujfalusi Tested-by: Darren Etheridge Tested-by: Sekhar Nori --- drivers/bus/omap_l3_noc.c | 18 ++++++++++++++---- drivers/bus/omap_l3_noc.h | 2 ++ 2 files changed, 16 insertions(+), 4 deletions(-) (limited to 'drivers/bus') diff --git a/drivers/bus/omap_l3_noc.c b/drivers/bus/omap_l3_noc.c index 9d021d002bec..08344b03fda6 100644 --- a/drivers/bus/omap_l3_noc.c +++ b/drivers/bus/omap_l3_noc.c @@ -60,15 +60,16 @@ static int l3_handle_target(struct omap_l3 *l3, void __iomem *base, { int k; u32 std_err_main, clear, masterid; - u8 op_code; + u8 op_code, m_req_info; void __iomem *l3_targ_base; void __iomem *l3_targ_stderr, *l3_targ_slvofslsb, *l3_targ_mstaddr; - void __iomem *l3_targ_hdr; + void __iomem *l3_targ_hdr, *l3_targ_info; struct l3_target_data *l3_targ_inst; struct l3_masters_data *master; char *target_name, *master_name = "UN IDENTIFIED"; char *err_description; char err_string[30] = { 0 }; + char info_string[60] = { 0 }; /* We DONOT expect err_src to go out of bounds */ BUG_ON(err_src > MAX_CLKDM_TARGETS); @@ -99,6 +100,7 @@ static int l3_handle_target(struct omap_l3 *l3, void __iomem *base, l3_targ_mstaddr = l3_targ_base + L3_TARG_STDERRLOG_MSTADDR; l3_targ_hdr = l3_targ_base + L3_TARG_STDERRLOG_HDR; + l3_targ_info = l3_targ_base + L3_TARG_STDERRLOG_INFO; break; case CUSTOM_ERROR: @@ -107,6 +109,7 @@ static int l3_handle_target(struct omap_l3 *l3, void __iomem *base, l3_targ_mstaddr = l3_targ_base + L3_TARG_STDERRLOG_CINFO_MSTADDR; l3_targ_hdr = l3_targ_base + L3_TARG_STDERRLOG_CINFO_OPCODE; + l3_targ_info = l3_targ_base + L3_TARG_STDERRLOG_CINFO_INFO; break; default: @@ -128,13 +131,20 @@ static int l3_handle_target(struct omap_l3 *l3, void __iomem *base, op_code = readl_relaxed(l3_targ_hdr) & 0x7; + m_req_info = readl_relaxed(l3_targ_info) & 0xF; + snprintf(info_string, sizeof(info_string), + ": %s in %s mode during %s access", + (m_req_info & BIT(0)) ? "Opcode Fetch" : "Data Access", + (m_req_info & BIT(1)) ? "Supervisor" : "User", + (m_req_info & BIT(3)) ? "Debug" : "Functional"); + WARN(true, - "%s:L3 %s Error: MASTER %s TARGET %s (%s)%s\n", + "%s:L3 %s Error: MASTER %s TARGET %s (%s)%s%s\n", dev_name(l3->dev), err_description, master_name, target_name, l3_transaction_type[op_code], - err_string); + err_string, info_string); /* clear the std error log*/ clear = std_err_main | CLEAR_STDERR_LOG; diff --git a/drivers/bus/omap_l3_noc.h b/drivers/bus/omap_l3_noc.h index 6670fd98ce7c..36dc48b3dc00 100644 --- a/drivers/bus/omap_l3_noc.h +++ b/drivers/bus/omap_l3_noc.h @@ -31,7 +31,9 @@ #define L3_TARG_STDERRLOG_MAIN 0x48 #define L3_TARG_STDERRLOG_HDR 0x4c #define L3_TARG_STDERRLOG_MSTADDR 0x50 +#define L3_TARG_STDERRLOG_INFO 0x58 #define L3_TARG_STDERRLOG_SLVOFSLSB 0x5c +#define L3_TARG_STDERRLOG_CINFO_INFO 0x64 #define L3_TARG_STDERRLOG_CINFO_MSTADDR 0x68 #define L3_TARG_STDERRLOG_CINFO_OPCODE 0x6c #define L3_FLAGMUX_REGERR0 0xc -- cgit From f33ddf745cbcd4145fcb2f8239f5dbba089fb8ff Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Fri, 11 Apr 2014 14:37:03 -0500 Subject: bus: omap_l3_noc: introduce concept of submodule While OMAP4 and OMAP5 had 3 separate clock domains, DRA7 has only 2 and the first one then is internally divided into 2 sub clock domains. To better represent this in the driver, we use the concept of submodule. The address defintions in the devicetree is as per the high level clock domain(module) base, the sub clockdomain/subdomain which shares the same register space of a clockdomain is marked in the SoC data as L3_BASE_IS_SUBMODULE. L3_BASE_IS_SUBMODULE is used as an indication that it's base address is the same as the parent module and offsets are considered from the same base address as they are usually intermingled. Other than the base address, the submodule is same as a module as it is functionally so. Signed-off-by: Nishanth Menon Acked-by: Santosh Shilimkar Acked-by: Peter Ujfalusi Tested-by: Darren Etheridge Tested-by: Sekhar Nori --- drivers/bus/omap_l3_noc.c | 17 ++++++++++++----- drivers/bus/omap_l3_noc.h | 6 +++++- 2 files changed, 17 insertions(+), 6 deletions(-) (limited to 'drivers/bus') diff --git a/drivers/bus/omap_l3_noc.c b/drivers/bus/omap_l3_noc.c index 08344b03fda6..0eba07ac6008 100644 --- a/drivers/bus/omap_l3_noc.c +++ b/drivers/bus/omap_l3_noc.c @@ -238,7 +238,7 @@ static int omap_l3_probe(struct platform_device *pdev) { const struct of_device_id *of_id; static struct omap_l3 *l3; - int ret, i; + int ret, i, res_idx; of_id = of_match_device(l3_noc_match, &pdev->dev); if (!of_id) { @@ -255,15 +255,22 @@ static int omap_l3_probe(struct platform_device *pdev) platform_set_drvdata(pdev, l3); /* Get mem resources */ - for (i = 0; i < l3->num_modules; i++) { - struct resource *res = platform_get_resource(pdev, - IORESOURCE_MEM, i); - + for (i = 0, res_idx = 0; i < l3->num_modules; i++) { + struct resource *res; + + if (l3->l3_base[i] == L3_BASE_IS_SUBMODULE) { + /* First entry cannot be submodule */ + BUG_ON(i == 0); + l3->l3_base[i] = l3->l3_base[i - 1]; + continue; + } + res = platform_get_resource(pdev, IORESOURCE_MEM, res_idx); l3->l3_base[i] = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(l3->l3_base[i])) { dev_err(l3->dev, "ioremap %d failed\n", i); return PTR_ERR(l3->l3_base[i]); } + res_idx++; } /* diff --git a/drivers/bus/omap_l3_noc.h b/drivers/bus/omap_l3_noc.h index 36dc48b3dc00..aced4c546783 100644 --- a/drivers/bus/omap_l3_noc.h +++ b/drivers/bus/omap_l3_noc.h @@ -41,6 +41,8 @@ #define L3_TARGET_NOT_SUPPORTED NULL +#define L3_BASE_IS_SUBMODULE ((void __iomem *)(1 << 0)) + static const char * const l3_transaction_type[] = { /* 0 0 0 */ "Idle", /* 0 0 1 */ "Write", @@ -96,7 +98,9 @@ struct l3_flagmux_data { /** * struct omap_l3 - Description of data relevant for L3 bus. * @dev: device representing the bus (populated runtime) - * @l3_base: base addresses of modules (populated runtime) + * @l3_base: base addresses of modules (populated runtime if 0) + * if set to L3_BASE_IS_SUBMODULE, then uses previous + * module index as the base address * @l3_flag_mux: array containing flag mux data per module * offset from corresponding module base indexed per * module. -- cgit From 53a848be0a65c6fb105eb5ecb8b8b3edfa0f91ad Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Thu, 10 Apr 2014 11:33:13 -0500 Subject: bus: omap_l3_noc: Add DRA7 interconnect error data DRA7 is distinctly different from OMAP4 in terms of masters and clock domain organization. There two main clock domains which is divided as follows: <0x44000000 0x1000000> is clk1 and clk2 is the sub clock domain <0x45000000 0x1000> is clk3 Add all the data needed to handle L3 error handling on DRA7 devices and mark clk2 as subdomain and provide a compatible flag for functionality. Other than the data difference the hardware blocks involved are essentially the same. Signed-off-by: Rajendra Nayak [nm@ti.com: bugfixes and generic improvements, documentation] Signed-off-by: Nishanth Menon Acked-by: Santosh Shilimkar Acked-by: Peter Ujfalusi Tested-by: Darren Etheridge Tested-by: Sekhar Nori --- drivers/bus/omap_l3_noc.c | 1 + drivers/bus/omap_l3_noc.h | 151 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 152 insertions(+) (limited to 'drivers/bus') diff --git a/drivers/bus/omap_l3_noc.c b/drivers/bus/omap_l3_noc.c index 0eba07ac6008..6cdd02ef0909 100644 --- a/drivers/bus/omap_l3_noc.c +++ b/drivers/bus/omap_l3_noc.c @@ -230,6 +230,7 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) static const struct of_device_id l3_noc_match[] = { {.compatible = "ti,omap4-l3-noc", .data = &omap_l3_data}, + {.compatible = "ti,dra7-l3-noc", .data = &dra_l3_data}, {}, }; MODULE_DEVICE_TABLE(of, l3_noc_match); diff --git a/drivers/bus/omap_l3_noc.h b/drivers/bus/omap_l3_noc.h index aced4c546783..9562a75259c8 100644 --- a/drivers/bus/omap_l3_noc.h +++ b/drivers/bus/omap_l3_noc.h @@ -230,4 +230,155 @@ static const struct omap_l3 omap_l3_data = { .mst_addr_mask = 0xFC, }; +/* DRA7 data */ +static struct l3_target_data dra_l3_target_data_clk1[] = { + {0x2a00, "AES1",}, + {0x0200, "DMM_P1",}, + {0x0600, "DSP2_SDMA",}, + {0x0b00, "EVE2",}, + {0x1300, "DMM_P2",}, + {0x2c00, "AES2",}, + {0x0300, "DSP1_SDMA",}, + {0x0a00, "EVE1",}, + {0x0c00, "EVE3",}, + {0x0d00, "EVE4",}, + {0x2900, "DSS",}, + {0x0100, "GPMC",}, + {0x3700, "PCIE1",}, + {0x1600, "IVA_CONFIG",}, + {0x1800, "IVA_SL2IF",}, + {0x0500, "L4_CFG",}, + {0x1d00, "L4_WKUP",}, + {0x3800, "PCIE2",}, + {0x3300, "SHA2_1",}, + {0x1200, "GPU",}, + {0x1000, "IPU1",}, + {0x1100, "IPU2",}, + {0x2000, "TPCC_EDMA",}, + {0x2e00, "TPTC1_EDMA",}, + {0x2b00, "TPTC2_EDMA",}, + {0x0700, "VCP1",}, + {0x2500, "L4_PER2_P3",}, + {0x0e00, "L4_PER3_P3",}, + {0x2200, "MMU1",}, + {0x1400, "PRUSS1",}, + {0x1500, "PRUSS2"}, + {0x0800, "VCP1",}, +}; + +static struct l3_flagmux_data dra_l3_flagmux_clk1 = { + .offset = 0x803500, + .l3_targ = dra_l3_target_data_clk1, + .num_targ_data = ARRAY_SIZE(dra_l3_target_data_clk1), +}; + +static struct l3_target_data dra_l3_target_data_clk2[] = { + {0x0, "HOST CLK1",}, + {0x0, "HOST CLK2",}, + {0xdead, L3_TARGET_NOT_SUPPORTED,}, + {0x3400, "SHA2_2",}, + {0x0900, "BB2D",}, + {0xdead, L3_TARGET_NOT_SUPPORTED,}, + {0x2100, "L4_PER1_P3",}, + {0x1c00, "L4_PER1_P1",}, + {0x1f00, "L4_PER1_P2",}, + {0x2300, "L4_PER2_P1",}, + {0x2400, "L4_PER2_P2",}, + {0x2600, "L4_PER3_P1",}, + {0x2700, "L4_PER3_P2",}, + {0x2f00, "MCASP1",}, + {0x3000, "MCASP2",}, + {0x3100, "MCASP3",}, + {0x2800, "MMU2",}, + {0x0f00, "OCMC_RAM1",}, + {0x1700, "OCMC_RAM2",}, + {0x1900, "OCMC_RAM3",}, + {0x1e00, "OCMC_ROM",}, + {0x3900, "QSPI",}, +}; + +static struct l3_flagmux_data dra_l3_flagmux_clk2 = { + .offset = 0x803600, + .l3_targ = dra_l3_target_data_clk2, + .num_targ_data = ARRAY_SIZE(dra_l3_target_data_clk2), +}; + +static struct l3_target_data dra_l3_target_data_clk3[] = { + {0x0100, "L3_INSTR"}, + {0x0300, "DEBUGSS_CT_TBR"}, + {0x0, "HOST CLK3"}, +}; + +static struct l3_flagmux_data dra_l3_flagmux_clk3 = { + .offset = 0x200, + .l3_targ = dra_l3_target_data_clk3, + .num_targ_data = ARRAY_SIZE(dra_l3_target_data_clk3), +}; + +static struct l3_masters_data dra_l3_masters[] = { + { 0x0, "MPU" }, + { 0x4, "CS_DAP" }, + { 0x5, "IEEE1500_2_OCP" }, + { 0x8, "DSP1_MDMA" }, + { 0x9, "DSP1_CFG" }, + { 0xA, "DSP1_DMA" }, + { 0xB, "DSP2_MDMA" }, + { 0xC, "DSP2_CFG" }, + { 0xD, "DSP2_DMA" }, + { 0xE, "IVA" }, + { 0x10, "EVE1_P1" }, + { 0x11, "EVE2_P1" }, + { 0x12, "EVE3_P1" }, + { 0x13, "EVE4_P1" }, + { 0x14, "PRUSS1 PRU1" }, + { 0x15, "PRUSS1 PRU2" }, + { 0x16, "PRUSS2 PRU1" }, + { 0x17, "PRUSS2 PRU2" }, + { 0x18, "IPU1" }, + { 0x19, "IPU2" }, + { 0x1A, "SDMA" }, + { 0x1B, "CDMA" }, + { 0x1C, "TC1_EDMA" }, + { 0x1D, "TC2_EDMA" }, + { 0x20, "DSS" }, + { 0x21, "MMU1" }, + { 0x22, "PCIE1" }, + { 0x23, "MMU2" }, + { 0x24, "VIP1" }, + { 0x25, "VIP2" }, + { 0x26, "VIP3" }, + { 0x27, "VPE" }, + { 0x28, "GPU_P1" }, + { 0x29, "BB2D" }, + { 0x29, "GPU_P2" }, + { 0x2B, "GMAC_SW" }, + { 0x2C, "USB3" }, + { 0x2D, "USB2_SS" }, + { 0x2E, "USB2_ULPI_SS1" }, + { 0x2F, "USB2_ULPI_SS2" }, + { 0x30, "CSI2_1" }, + { 0x31, "CSI2_2" }, + { 0x33, "SATA" }, + { 0x34, "EVE1_P2" }, + { 0x35, "EVE2_P2" }, + { 0x36, "EVE3_P2" }, + { 0x37, "EVE4_P2" } +}; + +static struct l3_flagmux_data *dra_l3_flagmux[] = { + &dra_l3_flagmux_clk1, + &dra_l3_flagmux_clk2, + &dra_l3_flagmux_clk3, +}; + +static const struct omap_l3 dra_l3_data = { + .l3_base = { [1] = L3_BASE_IS_SUBMODULE }, + .l3_flagmux = dra_l3_flagmux, + .num_modules = ARRAY_SIZE(dra_l3_flagmux), + .l3_masters = dra_l3_masters, + .num_masters = ARRAY_SIZE(dra_l3_masters), + /* The 6 MSBs of register field used to distinguish initiator */ + .mst_addr_mask = 0xFC, +}; + #endif /* __OMAP_L3_NOC_H */ -- cgit From 27b7d5f3cc49f2e5cd6c005d73696058b7140c5c Mon Sep 17 00:00:00 2001 From: Afzal Mohammed Date: Mon, 2 Dec 2013 17:48:57 +0530 Subject: bus: omap_l3_noc: Add AM4372 interconnect error data Add AM4372 information to handle L3 error. AM4372 has two clk domains 100f and 200s. Provide flagmux and data associated with it. NOTE: Timeout doesn't have STDERRLOG_MAIN register. And per hardware team, L3 timeout error cannot be cleared the normal way (by setting bit 31 in STDERRLOG_MAIN), instead it may be required to do system reset. L3 error handler can't help in such scenarios. Hence indicate timeout target offset as L3_TARGET_NOT_SUPPORTED as done for undocumented bits. Signed-off-by: Dave Gerlach Signed-off-by: Afzal Mohammed Signed-off-by: Sekhar Nori Signed-off-by: Nishanth Menon Acked-by: Santosh Shilimkar Acked-by: Peter Ujfalusi Tested-by: Darren Etheridge Tested-by: Sekhar Nori --- drivers/bus/omap_l3_noc.c | 1 + drivers/bus/omap_l3_noc.h | 91 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) (limited to 'drivers/bus') diff --git a/drivers/bus/omap_l3_noc.c b/drivers/bus/omap_l3_noc.c index 6cdd02ef0909..531ae591783b 100644 --- a/drivers/bus/omap_l3_noc.c +++ b/drivers/bus/omap_l3_noc.c @@ -231,6 +231,7 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) static const struct of_device_id l3_noc_match[] = { {.compatible = "ti,omap4-l3-noc", .data = &omap_l3_data}, {.compatible = "ti,dra7-l3-noc", .data = &dra_l3_data}, + {.compatible = "ti,am4372-l3-noc", .data = &am4372_l3_data}, {}, }; MODULE_DEVICE_TABLE(of, l3_noc_match); diff --git a/drivers/bus/omap_l3_noc.h b/drivers/bus/omap_l3_noc.h index 9562a75259c8..551e01061434 100644 --- a/drivers/bus/omap_l3_noc.h +++ b/drivers/bus/omap_l3_noc.h @@ -381,4 +381,95 @@ static const struct omap_l3 dra_l3_data = { .mst_addr_mask = 0xFC, }; +/* AM4372 data */ +static struct l3_target_data am4372_l3_target_data_200f[] = { + {0xf00, "EMIF",}, + {0x1200, "DES",}, + {0x400, "OCMCRAM",}, + {0x700, "TPTC0",}, + {0x800, "TPTC1",}, + {0x900, "TPTC2"}, + {0xb00, "TPCC",}, + {0xd00, "DEBUGSS",}, + {0xdead, L3_TARGET_NOT_SUPPORTED,}, + {0x200, "SHA",}, + {0xc00, "SGX530",}, + {0x500, "AES0",}, + {0xa00, "L4_FAST",}, + {0x300, "MPUSS_L2_RAM",}, + {0x100, "ICSS",}, +}; + +static struct l3_flagmux_data am4372_l3_flagmux_200f = { + .offset = 0x1000, + .l3_targ = am4372_l3_target_data_200f, + .num_targ_data = ARRAY_SIZE(am4372_l3_target_data_200f), +}; + +static struct l3_target_data am4372_l3_target_data_100s[] = { + {0x100, "L4_PER_0",}, + {0x200, "L4_PER_1",}, + {0x300, "L4_PER_2",}, + {0x400, "L4_PER_3",}, + {0x800, "McASP0",}, + {0x900, "McASP1",}, + {0xC00, "MMCHS2",}, + {0x700, "GPMC",}, + {0xD00, "L4_FW",}, + {0xdead, L3_TARGET_NOT_SUPPORTED,}, + {0x500, "ADCTSC",}, + {0xE00, "L4_WKUP",}, + {0xA00, "MAG_CARD",}, +}; + +static struct l3_flagmux_data am4372_l3_flagmux_100s = { + .offset = 0x600, + .l3_targ = am4372_l3_target_data_100s, + .num_targ_data = ARRAY_SIZE(am4372_l3_target_data_100s), +}; + +static struct l3_masters_data am4372_l3_masters[] = { + { 0x0, "M1 (128-bit)"}, + { 0x1, "M2 (64-bit)"}, + { 0x4, "DAP"}, + { 0x5, "P1500"}, + { 0xC, "ICSS0"}, + { 0xD, "ICSS1"}, + { 0x14, "Wakeup Processor"}, + { 0x18, "TPTC0 Read"}, + { 0x19, "TPTC0 Write"}, + { 0x1A, "TPTC1 Read"}, + { 0x1B, "TPTC1 Write"}, + { 0x1C, "TPTC2 Read"}, + { 0x1D, "TPTC2 Write"}, + { 0x20, "SGX530"}, + { 0x21, "OCP WP Traffic Probe"}, + { 0x22, "OCP WP DMA Profiling"}, + { 0x23, "OCP WP Event Trace"}, + { 0x25, "DSS"}, + { 0x28, "Crypto DMA RD"}, + { 0x29, "Crypto DMA WR"}, + { 0x2C, "VPFE0"}, + { 0x2D, "VPFE1"}, + { 0x30, "GEMAC"}, + { 0x34, "USB0 RD"}, + { 0x35, "USB0 WR"}, + { 0x36, "USB1 RD"}, + { 0x37, "USB1 WR"}, +}; + +static struct l3_flagmux_data *am4372_l3_flagmux[] = { + &am4372_l3_flagmux_200f, + &am4372_l3_flagmux_100s, +}; + +static const struct omap_l3 am4372_l3_data = { + .l3_flagmux = am4372_l3_flagmux, + .num_modules = ARRAY_SIZE(am4372_l3_flagmux), + .l3_masters = am4372_l3_masters, + .num_masters = ARRAY_SIZE(am4372_l3_masters), + /* All 6 bits of register field used to distinguish initiator */ + .mst_addr_mask = 0x3F, +}; + #endif /* __OMAP_L3_NOC_H */ -- cgit From 44127b771d9c31dcb5ab90d9093a4d48877738bc Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 19 May 2014 13:05:59 -0700 Subject: bus: add Broadcom GISB bus arbiter timeout/error handler This patch adds support for the Broadcom GISB arbiter bus timeout/error handler. GISB is a proprietary bus used by Broadcom Set Top Box System-on-a-chip devices (BCM7xxx) which allows multiple masters and clients to be interfaced with each other. The bus arbiter offers support for generating two interrupts towards the host CPU, thus allowing us to "catch" clock gated masters, or masters being volontarily blocked for powersaving purposes, or do general system troubleshooting. We also register a hook with the ARM fault exception handling to allow printing a more informative message than "imprecise external abort at 0x00000000" for instance. Signed-off-by: Florian Fainelli Signed-off-by: Arnd Bergmann --- drivers/bus/Kconfig | 8 ++ drivers/bus/Makefile | 1 + drivers/bus/brcmstb_gisb.c | 289 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 298 insertions(+) create mode 100644 drivers/bus/brcmstb_gisb.c (limited to 'drivers/bus') diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig index 552373c4e362..d40d155f4234 100644 --- a/drivers/bus/Kconfig +++ b/drivers/bus/Kconfig @@ -4,6 +4,14 @@ menu "Bus devices" +config BRCMSTB_GISB_ARB + bool "Broadcom STB GISB bus arbiter" + depends on ARM + help + Driver for the Broadcom Set Top Box System-on-a-chip internal bus + arbiter. This driver provides timeout and target abort error handling + and internal bus master decoding. + config IMX_WEIM bool "Freescale EIM DRIVER" depends on ARCH_MXC diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index 8947bdd0de8b..41fa45b3f061 100644 --- a/drivers/bus/Makefile +++ b/drivers/bus/Makefile @@ -2,6 +2,7 @@ # Makefile for the bus drivers. # +obj-$(CONFIG_BRCMSTB_GISB_ARB) += brcmstb_gisb.o obj-$(CONFIG_IMX_WEIM) += imx-weim.o obj-$(CONFIG_MVEBU_MBUS) += mvebu-mbus.o obj-$(CONFIG_OMAP_OCP2SCP) += omap-ocp2scp.o diff --git a/drivers/bus/brcmstb_gisb.c b/drivers/bus/brcmstb_gisb.c new file mode 100644 index 000000000000..6159b7752a64 --- /dev/null +++ b/drivers/bus/brcmstb_gisb.c @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2014 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define ARB_TIMER 0x008 +#define ARB_ERR_CAP_CLR 0x7e4 +#define ARB_ERR_CAP_CLEAR (1 << 0) +#define ARB_ERR_CAP_HI_ADDR 0x7e8 +#define ARB_ERR_CAP_ADDR 0x7ec +#define ARB_ERR_CAP_DATA 0x7f0 +#define ARB_ERR_CAP_STATUS 0x7f4 +#define ARB_ERR_CAP_STATUS_TIMEOUT (1 << 12) +#define ARB_ERR_CAP_STATUS_TEA (1 << 11) +#define ARB_ERR_CAP_STATUS_BS_SHIFT (1 << 2) +#define ARB_ERR_CAP_STATUS_BS_MASK 0x3c +#define ARB_ERR_CAP_STATUS_WRITE (1 << 1) +#define ARB_ERR_CAP_STATUS_VALID (1 << 0) +#define ARB_ERR_CAP_MASTER 0x7f8 + +struct brcmstb_gisb_arb_device { + void __iomem *base; + struct mutex lock; + struct list_head next; + u32 valid_mask; + const char *master_names[sizeof(u32) * BITS_PER_BYTE]; +}; + +static LIST_HEAD(brcmstb_gisb_arb_device_list); + +static ssize_t gisb_arb_get_timeout(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct brcmstb_gisb_arb_device *gdev = platform_get_drvdata(pdev); + u32 timeout; + + mutex_lock(&gdev->lock); + timeout = ioread32(gdev->base + ARB_TIMER); + mutex_unlock(&gdev->lock); + + return sprintf(buf, "%d", timeout); +} + +static ssize_t gisb_arb_set_timeout(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct platform_device *pdev = to_platform_device(dev); + struct brcmstb_gisb_arb_device *gdev = platform_get_drvdata(pdev); + int val, ret; + + ret = kstrtoint(buf, 10, &val); + if (ret < 0) + return ret; + + if (val == 0 || val >= 0xffffffff) + return -EINVAL; + + mutex_lock(&gdev->lock); + iowrite32(val, gdev->base + ARB_TIMER); + mutex_unlock(&gdev->lock); + + return count; +} + +static const char * +brcmstb_gisb_master_to_str(struct brcmstb_gisb_arb_device *gdev, + u32 masters) +{ + u32 mask = gdev->valid_mask & masters; + + if (hweight_long(mask) != 1) + return NULL; + + return gdev->master_names[ffs(mask) - 1]; +} + +static int brcmstb_gisb_arb_decode_addr(struct brcmstb_gisb_arb_device *gdev, + const char *reason) +{ + u32 cap_status; + unsigned long arb_addr; + u32 master; + const char *m_name; + char m_fmt[11]; + + cap_status = ioread32(gdev->base + ARB_ERR_CAP_STATUS); + + /* Invalid captured address, bail out */ + if (!(cap_status & ARB_ERR_CAP_STATUS_VALID)) + return 1; + + /* Read the address and master */ + arb_addr = ioread32(gdev->base + ARB_ERR_CAP_ADDR) & 0xffffffff; +#if (IS_ENABLED(CONFIG_PHYS_ADDR_T_64BIT)) + arb_addr |= (u64)ioread32(gdev->base + ARB_ERR_CAP_HI_ADDR) << 32; +#endif + master = ioread32(gdev->base + ARB_ERR_CAP_MASTER); + + m_name = brcmstb_gisb_master_to_str(gdev, master); + if (!m_name) { + snprintf(m_fmt, sizeof(m_fmt), "0x%08x", master); + m_name = m_fmt; + } + + pr_crit("%s: %s at 0x%lx [%c %s], core: %s\n", + __func__, reason, arb_addr, + cap_status & ARB_ERR_CAP_STATUS_WRITE ? 'W' : 'R', + cap_status & ARB_ERR_CAP_STATUS_TIMEOUT ? "timeout" : "", + m_name); + + /* clear the GISB error */ + iowrite32(ARB_ERR_CAP_CLEAR, gdev->base + ARB_ERR_CAP_CLR); + + return 0; +} + +static int brcmstb_bus_error_handler(unsigned long addr, unsigned int fsr, + struct pt_regs *regs) +{ + int ret = 0; + struct brcmstb_gisb_arb_device *gdev; + + /* iterate over each GISB arb registered handlers */ + list_for_each_entry(gdev, &brcmstb_gisb_arb_device_list, next) + ret |= brcmstb_gisb_arb_decode_addr(gdev, "bus error"); + /* + * If it was an imprecise abort, then we need to correct the + * return address to be _after_ the instruction. + */ + if (fsr & (1 << 10)) + regs->ARM_pc += 4; + + return ret; +} + +void __init brcmstb_hook_fault_code(void) +{ + hook_fault_code(22, brcmstb_bus_error_handler, SIGBUS, 0, + "imprecise external abort"); +} + +static irqreturn_t brcmstb_gisb_timeout_handler(int irq, void *dev_id) +{ + brcmstb_gisb_arb_decode_addr(dev_id, "timeout"); + + return IRQ_HANDLED; +} + +static irqreturn_t brcmstb_gisb_tea_handler(int irq, void *dev_id) +{ + brcmstb_gisb_arb_decode_addr(dev_id, "target abort"); + + return IRQ_HANDLED; +} + +static DEVICE_ATTR(gisb_arb_timeout, S_IWUSR | S_IRUGO, + gisb_arb_get_timeout, gisb_arb_set_timeout); + +static struct attribute *gisb_arb_sysfs_attrs[] = { + &dev_attr_gisb_arb_timeout.attr, + NULL, +}; + +static struct attribute_group gisb_arb_sysfs_attr_group = { + .attrs = gisb_arb_sysfs_attrs, +}; + +static int brcmstb_gisb_arb_probe(struct platform_device *pdev) +{ + struct device_node *dn = pdev->dev.of_node; + struct brcmstb_gisb_arb_device *gdev; + struct resource *r; + int err, timeout_irq, tea_irq; + unsigned int num_masters, j = 0; + int i, first, last; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + timeout_irq = platform_get_irq(pdev, 0); + tea_irq = platform_get_irq(pdev, 1); + + gdev = devm_kzalloc(&pdev->dev, sizeof(*gdev), GFP_KERNEL); + if (!gdev) + return -ENOMEM; + + mutex_init(&gdev->lock); + INIT_LIST_HEAD(&gdev->next); + + gdev->base = devm_request_and_ioremap(&pdev->dev, r); + if (!gdev->base) + return -ENOMEM; + + err = devm_request_irq(&pdev->dev, timeout_irq, + brcmstb_gisb_timeout_handler, 0, pdev->name, + gdev); + if (err < 0) + return err; + + err = devm_request_irq(&pdev->dev, tea_irq, + brcmstb_gisb_tea_handler, 0, pdev->name, + gdev); + if (err < 0) + return err; + + /* If we do not have a valid mask, assume all masters are enabled */ + if (of_property_read_u32(dn, "brcm,gisb-arb-master-mask", + &gdev->valid_mask)) + gdev->valid_mask = 0xffffffff; + + /* Proceed with reading the litteral names if we agree on the + * number of masters + */ + num_masters = of_property_count_strings(dn, + "brcm,gisb-arb-master-names"); + if (hweight_long(gdev->valid_mask) == num_masters) { + first = ffs(gdev->valid_mask) - 1; + last = fls(gdev->valid_mask) - 1; + + for (i = first; i < last; i++) { + if (!(gdev->valid_mask & BIT(i))) + continue; + + of_property_read_string_index(dn, + "brcm,gisb-arb-master-names", j, + &gdev->master_names[i]); + j++; + } + } + + err = sysfs_create_group(&pdev->dev.kobj, &gisb_arb_sysfs_attr_group); + if (err) + return err; + + platform_set_drvdata(pdev, gdev); + + list_add_tail(&gdev->next, &brcmstb_gisb_arb_device_list); + + dev_info(&pdev->dev, "registered mem: %p, irqs: %d, %d\n", + gdev->base, timeout_irq, tea_irq); + + return 0; +} + +static const struct of_device_id brcmstb_gisb_arb_of_match[] = { + { .compatible = "brcm,gisb-arb" }, + { }, +}; + +static struct platform_driver brcmstb_gisb_arb_driver = { + .probe = brcmstb_gisb_arb_probe, + .driver = { + .name = "brcm-gisb-arb", + .owner = THIS_MODULE, + .of_match_table = brcmstb_gisb_arb_of_match, + }, +}; + +static int __init brcm_gisb_driver_init(void) +{ + return platform_driver_register(&brcmstb_gisb_arb_driver); +} + +module_init(brcm_gisb_driver_init); -- cgit