diff options
-rw-r--r-- | arch/arm/mach-tegra/board-ardbeg.c | 1 | ||||
-rw-r--r-- | arch/arm/mach-tegra/devices.c | 27 | ||||
-rw-r--r-- | arch/arm/mach-tegra/devices.h | 7 | ||||
-rw-r--r-- | arch/arm/mach-tegra/iomap.h | 9 | ||||
-rw-r--r-- | drivers/platform/tegra/Makefile | 2 | ||||
-rw-r--r-- | drivers/platform/tegra/hier_ictlr/Makefile | 8 | ||||
-rw-r--r-- | drivers/platform/tegra/hier_ictlr/hier_ictlr.c | 192 |
7 files changed, 244 insertions, 2 deletions
diff --git a/arch/arm/mach-tegra/board-ardbeg.c b/arch/arm/mach-tegra/board-ardbeg.c index e84103527c54..dedadf0d8975 100644 --- a/arch/arm/mach-tegra/board-ardbeg.c +++ b/arch/arm/mach-tegra/board-ardbeg.c @@ -467,6 +467,7 @@ static struct platform_device *ardbeg_devices[] __initdata = { #if defined(CONFIG_CRYPTO_DEV_TEGRA_AES) &tegra_aes_device, #endif + &tegra_hier_ictlr_device, }; static struct tegra_usb_platform_data tegra_udc_pdata = { diff --git a/arch/arm/mach-tegra/devices.c b/arch/arm/mach-tegra/devices.c index c5968260cd5d..429b553b7cc6 100644 --- a/arch/arm/mach-tegra/devices.c +++ b/arch/arm/mach-tegra/devices.c @@ -2942,3 +2942,30 @@ void __init tegra_init_debug_uart_rate(void) debug_uarte_platform_data[0].uartclk = uartclk; #endif } + +#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC) +static struct resource tegra_hier_ictlr_resource[] = { + [0] = { + .start = TEGRA_HIER2_ICTLR1_BASE, + .end = TEGRA_HIER2_ICTLR1_BASE + TEGRA_HIER2_ICTLR1_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = TEGRA_MSELECT_BASE, + .end = TEGRA_MSELECT_BASE + TEGRA_MSELECT_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [2] = { + .start = INT_HIER_GROUP1_CPU, + .end = INT_HIER_GROUP1_CPU, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device tegra_hier_ictlr_device = { + .name = "tegra-hier-ictlr", + .id = -1, + .resource = tegra_hier_ictlr_resource, + .num_resources = ARRAY_SIZE(tegra_hier_ictlr_resource), +}; +#endif diff --git a/arch/arm/mach-tegra/devices.h b/arch/arm/mach-tegra/devices.h index c293abd70db0..c0c53300ee8b 100644 --- a/arch/arm/mach-tegra/devices.h +++ b/arch/arm/mach-tegra/devices.h @@ -1,5 +1,6 @@ /* - * Copyright (C) 2010,2011 Google, Inc. + * Copyright (C) 2010,2014 Google, Inc. + * Copyright (C) 2014, NVIDIA Corporation. All rights reserved. * * Author: * Colin Cross <ccross@android.com> @@ -195,6 +196,10 @@ extern struct platform_device tegra12_i2c_device5; extern struct platform_device tegra12_i2c_device6; #endif +#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC) +extern struct platform_device tegra_hier_ictlr_device; +#endif + void __init tegra_init_debug_uart_rate(void); #endif diff --git a/arch/arm/mach-tegra/iomap.h b/arch/arm/mach-tegra/iomap.h index 5c72ae514213..25ebdb55201b 100644 --- a/arch/arm/mach-tegra/iomap.h +++ b/arch/arm/mach-tegra/iomap.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2010 Google, Inc. - * Copyright (C) 2011-2013, NVIDIA Corporation. All rights reserved. + * Copyright (C) 2011-2014, NVIDIA Corporation. All rights reserved. * * Author: * Colin Cross <ccross@google.com> @@ -201,6 +201,13 @@ #endif +#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC) + +#define TEGRA_HIER2_ICTLR1_BASE 0x60004800 +#define TEGRA_HIER2_ICTLR1_SIZE SZ_256 + +#endif + #define TEGRA_TMR1_BASE 0x60005000 #define TEGRA_TMR1_SIZE SZ_8 diff --git a/drivers/platform/tegra/Makefile b/drivers/platform/tegra/Makefile index 5f5888a2bbbd..ee9f7e05aafb 100644 --- a/drivers/platform/tegra/Makefile +++ b/drivers/platform/tegra/Makefile @@ -105,3 +105,5 @@ else # --- CONFIG_ARM64 --- # obj-y += dummy.o # generate a built-in.o endif + +obj-y += hier_ictlr/ diff --git a/drivers/platform/tegra/hier_ictlr/Makefile b/drivers/platform/tegra/hier_ictlr/Makefile new file mode 100644 index 000000000000..bfcbe36455c6 --- /dev/null +++ b/drivers/platform/tegra/hier_ictlr/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for tegra ... +# + +subdir-ccflags-y = -Werror + +obj-y += hier_ictlr.o + diff --git a/drivers/platform/tegra/hier_ictlr/hier_ictlr.c b/drivers/platform/tegra/hier_ictlr/hier_ictlr.c new file mode 100644 index 000000000000..5e565d0aa090 --- /dev/null +++ b/drivers/platform/tegra/hier_ictlr/hier_ictlr.c @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved. + * + * 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. + * + * 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. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/err.h> +#include <linux/io.h> + +#define HIER_GROUP_CPU_ENABLE 0x00000000 +#define HIER_GROUP_CPU_STATUS 0x00000004 +#define HIER_GROUP1_MSELECT_ERROR 15 + +#define MSELECT_CONFIG_0 0x0 +#define MSELECT_CONFIG_0_READ_TIMEOUT_EN_SLAVE0_SHIFT 16 +#define MSELECT_CONFIG_0_WRITE_TIMEOUT_EN_SLAVE0_SHIFT 17 +#define MSELECT_CONFIG_0_READ_TIMEOUT_EN_SLAVE1_SHIFT 18 +#define MSELECT_CONFIG_0_WRITE_TIMEOUT_EN_SLAVE1_SHIFT 19 +#define MSELECT_CONFIG_0_READ_TIMEOUT_EN_SLAVE2_SHIFT 20 +#define MSELECT_CONFIG_0_WRITE_TIMEOUT_EN_SLAVE2_SHIFT 21 +#define MSELECT_CONFIG_0_ERR_RESP_EN_SLAVE1_SHIFT 24 +#define MSELECT_CONFIG_0_ERR_RESP_EN_SLAVE2_SHIFT 25 + +#define MSELECT_TIMEOUT_TIMER_0 0x5c +#define MSELECT_ERROR_STATUS_0 0x60 + +struct tegra_hier_ictlr { + u32 irq; + void __iomem *hier_ictlr_base; + void __iomem *mselect_base; +}; + +static irqreturn_t tegra_hier_ictlr_irq_handler(int irq, void *data) +{ + struct device *dev = data; + struct tegra_hier_ictlr *ictlr = dev_get_drvdata(dev); + unsigned long status; + + status = readl(ictlr->mselect_base + MSELECT_ERROR_STATUS_0); + if (status != 0) { + pr_err("MSELECT error detected! status=0x%x\n", + (unsigned int)status); + BUG(); + } + + return IRQ_HANDLED; +} + +static int tegra_hier_ictlr_map_memory(struct platform_device *pdev, + struct tegra_hier_ictlr *ictlr) +{ + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, + "Unable to allocate resources (hier-ictlr).\n"); + return -EBUSY; + } + + ictlr->hier_ictlr_base = devm_request_and_ioremap(&pdev->dev, res); + if (!ictlr->hier_ictlr_base) { + dev_err(&pdev->dev, "Unable to map memory (hier-ictlr).\n"); + return -EBUSY; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res) { + dev_err(&pdev->dev, + "Unable to allocate resources (mselect).\n"); + return -EBUSY; + } + + ictlr->mselect_base = devm_request_and_ioremap(&pdev->dev, res); + if (!ictlr->mselect_base) { + dev_err(&pdev->dev, "Unable to map memory (mselect).\n"); + return -EBUSY; + } + + return 0; +} + +static int tegra_hier_ictlr_irq_init(struct platform_device *pdev, + struct tegra_hier_ictlr *ictlr) +{ + unsigned long reg; + int ret; + + ictlr->irq = platform_get_irq(pdev, 0); + if (ictlr->irq <= 0) + return -EBUSY; + + ret = devm_request_irq(&pdev->dev, ictlr->irq, + tegra_hier_ictlr_irq_handler, IRQF_TRIGGER_HIGH, + "hier_ictlr_irq", &pdev->dev); + + if (ret) { + dev_err(&pdev->dev, + "Unable to request interrupt for device (err=%d).\n", + ret); + return ret; + } + + reg = readl(ictlr->hier_ictlr_base + HIER_GROUP_CPU_ENABLE); + writel(reg | (1 << HIER_GROUP1_MSELECT_ERROR), + ictlr->hier_ictlr_base + HIER_GROUP_CPU_ENABLE); + + return 0; +} + +static int tegra_hier_ictlr_mselect_init(struct platform_device *pdev, + struct tegra_hier_ictlr *ictlr) +{ + unsigned long reg; + + writel(0xFFFFFF, ictlr->mselect_base + MSELECT_TIMEOUT_TIMER_0); + + reg = readl(ictlr->mselect_base + MSELECT_CONFIG_0); + writel(reg | + ((1 << MSELECT_CONFIG_0_READ_TIMEOUT_EN_SLAVE0_SHIFT) | + (1 << MSELECT_CONFIG_0_WRITE_TIMEOUT_EN_SLAVE0_SHIFT) | + (1 << MSELECT_CONFIG_0_READ_TIMEOUT_EN_SLAVE1_SHIFT) | + (1 << MSELECT_CONFIG_0_WRITE_TIMEOUT_EN_SLAVE1_SHIFT) | + (1 << MSELECT_CONFIG_0_READ_TIMEOUT_EN_SLAVE2_SHIFT) | + (1 << MSELECT_CONFIG_0_WRITE_TIMEOUT_EN_SLAVE2_SHIFT) | + (1 << MSELECT_CONFIG_0_ERR_RESP_EN_SLAVE1_SHIFT) | + (1 << MSELECT_CONFIG_0_ERR_RESP_EN_SLAVE2_SHIFT)), + ictlr->hier_ictlr_base + MSELECT_CONFIG_0); + + return 0; +} + +static int tegra_hier_ictlr_probe(struct platform_device *pdev) +{ + struct tegra_hier_ictlr *ictlr; + int ret; + + ictlr = devm_kzalloc(&pdev->dev, sizeof(struct tegra_hier_ictlr), + GFP_KERNEL); + if (!ictlr) + return -ENOMEM; + + ret = tegra_hier_ictlr_map_memory(pdev, ictlr); + if (ret) + return ret; + + ret = tegra_hier_ictlr_mselect_init(pdev, ictlr); + if (ret) + return ret; + + ret = tegra_hier_ictlr_irq_init(pdev, ictlr); + if (ret) + return ret; + + dev_notice(&pdev->dev, "probed\n"); + + dev_set_drvdata(&pdev->dev, ictlr); + return 0; +} + +static struct platform_driver tegra_hier_ictlr_driver = { + .driver = { + .name = "tegra-hier-ictlr", + .owner = THIS_MODULE, + }, + .probe = tegra_hier_ictlr_probe, +}; + +static int __init tegra_hier_ictlr_init(void) +{ + return platform_driver_register(&tegra_hier_ictlr_driver); +} + +module_init(tegra_hier_ictlr_init); + +MODULE_DESCRIPTION("Tegra Hierarchical Interrupt Controller Driver"); +MODULE_LICENSE("GPL v2"); |