summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-tegra/board-ardbeg.c1
-rw-r--r--arch/arm/mach-tegra/devices.c27
-rw-r--r--arch/arm/mach-tegra/devices.h7
-rw-r--r--arch/arm/mach-tegra/iomap.h9
-rw-r--r--drivers/platform/tegra/Makefile2
-rw-r--r--drivers/platform/tegra/hier_ictlr/Makefile8
-rw-r--r--drivers/platform/tegra/hier_ictlr/hier_ictlr.c192
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");