2 * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 #include <linux/module.h>
20 #include <linux/interrupt.h>
21 #include <linux/platform_device.h>
22 #include <linux/err.h>
24 #include "hier_ictlr.h"
26 #define HIER_GROUP_CPU_ENABLE 0x00000000
27 #define HIER_GROUP_CPU_STATUS 0x00000004
28 #define HIER_GROUP1_MSELECT_ERROR 15
30 #define MSELECT_CONFIG_0 0x0
31 #define MSELECT_CONFIG_0_READ_TIMEOUT_EN_SLAVE0_SHIFT 16
32 #define MSELECT_CONFIG_0_WRITE_TIMEOUT_EN_SLAVE0_SHIFT 17
33 #define MSELECT_CONFIG_0_READ_TIMEOUT_EN_SLAVE1_SHIFT 18
34 #define MSELECT_CONFIG_0_WRITE_TIMEOUT_EN_SLAVE1_SHIFT 19
35 #define MSELECT_CONFIG_0_READ_TIMEOUT_EN_SLAVE2_SHIFT 20
36 #define MSELECT_CONFIG_0_WRITE_TIMEOUT_EN_SLAVE2_SHIFT 21
37 #define MSELECT_CONFIG_0_ERR_RESP_EN_SLAVE1_SHIFT 24
38 #define MSELECT_CONFIG_0_ERR_RESP_EN_SLAVE2_SHIFT 25
40 #define MSELECT_TIMEOUT_TIMER_0 0x5c
41 #define MSELECT_ERROR_STATUS_0 0x60
42 #define MSELECT_DEFAULT_TIMEOUT 0xFFFFFF
44 static irqreturn_t tegra_hier_ictlr_irq_handler(int irq, void *data)
46 struct device *dev = data;
47 struct tegra_hier_ictlr *ictlr = dev_get_drvdata(dev);
50 status = readl(ictlr->mselect_base + MSELECT_ERROR_STATUS_0);
52 pr_err("MSELECT error detected! status=0x%x\n",
53 (unsigned int)status);
60 static int tegra_hier_ictlr_map_memory(struct platform_device *pdev,
61 struct tegra_hier_ictlr *ictlr)
65 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
68 "Unable to allocate resources (hier-ictlr).\n");
72 ictlr->hier_ictlr_base = devm_request_and_ioremap(&pdev->dev, res);
73 if (!ictlr->hier_ictlr_base) {
74 dev_err(&pdev->dev, "Unable to map memory (hier-ictlr).\n");
78 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
81 "Unable to allocate resources (mselect).\n");
85 ictlr->mselect_base = devm_request_and_ioremap(&pdev->dev, res);
86 if (!ictlr->mselect_base) {
87 dev_err(&pdev->dev, "Unable to map memory (mselect).\n");
94 static int tegra_hier_ictlr_irq_init(struct platform_device *pdev,
95 struct tegra_hier_ictlr *ictlr)
100 ictlr->irq = platform_get_irq(pdev, 0);
104 ret = devm_request_irq(&pdev->dev, ictlr->irq,
105 tegra_hier_ictlr_irq_handler, IRQF_TRIGGER_HIGH,
106 "hier_ictlr_irq", &pdev->dev);
110 "Unable to request interrupt for device (err=%d).\n",
115 reg = readl(ictlr->hier_ictlr_base + HIER_GROUP_CPU_ENABLE);
116 writel(reg | (1 << HIER_GROUP1_MSELECT_ERROR),
117 ictlr->hier_ictlr_base + HIER_GROUP_CPU_ENABLE);
122 static int tegra_hier_ictlr_mselect_init(struct platform_device *pdev,
123 struct tegra_hier_ictlr *ictlr)
127 tegra_hier_ictlr_set_mselect_timeout(ictlr, MSELECT_DEFAULT_TIMEOUT);
129 reg = readl(ictlr->mselect_base + MSELECT_CONFIG_0);
131 ((1 << MSELECT_CONFIG_0_READ_TIMEOUT_EN_SLAVE0_SHIFT) |
132 (1 << MSELECT_CONFIG_0_WRITE_TIMEOUT_EN_SLAVE0_SHIFT) |
133 (1 << MSELECT_CONFIG_0_READ_TIMEOUT_EN_SLAVE1_SHIFT) |
134 (1 << MSELECT_CONFIG_0_WRITE_TIMEOUT_EN_SLAVE1_SHIFT) |
135 (1 << MSELECT_CONFIG_0_READ_TIMEOUT_EN_SLAVE2_SHIFT) |
136 (1 << MSELECT_CONFIG_0_WRITE_TIMEOUT_EN_SLAVE2_SHIFT) |
137 (1 << MSELECT_CONFIG_0_ERR_RESP_EN_SLAVE1_SHIFT) |
138 (1 << MSELECT_CONFIG_0_ERR_RESP_EN_SLAVE2_SHIFT)),
139 ictlr->mselect_base + MSELECT_CONFIG_0);
144 void tegra_hier_ictlr_set_mselect_timeout(struct tegra_hier_ictlr *ictlr,
147 ictlr->mselect_timeout_cycles = timeout_cycles;
149 writel(ictlr->mselect_timeout_cycles, ictlr->mselect_base +
150 MSELECT_TIMEOUT_TIMER_0);
153 static int tegra_hier_ictlr_probe(struct platform_device *pdev)
155 struct tegra_hier_ictlr *ictlr;
158 ictlr = devm_kzalloc(&pdev->dev, sizeof(struct tegra_hier_ictlr),
163 ret = tegra_hier_ictlr_map_memory(pdev, ictlr);
167 ret = tegra_hier_ictlr_mselect_init(pdev, ictlr);
171 ret = tegra_hier_ictlr_irq_init(pdev, ictlr);
175 tegra_hier_ictlr_create_sysfs(pdev);
177 dev_notice(&pdev->dev, "probed\n");
179 dev_set_drvdata(&pdev->dev, ictlr);
183 static int __exit tegra_hier_ictlr_remove(struct platform_device *pdev)
185 tegra_hier_ictlr_remove_sysfs(pdev);
189 static struct platform_driver tegra_hier_ictlr_driver = {
191 .name = "tegra-hier-ictlr",
192 .owner = THIS_MODULE,
194 .probe = tegra_hier_ictlr_probe,
195 .remove = __exit_p(tegra_hier_ictrl_remove),
198 static int __init tegra_hier_ictlr_init(void)
200 return platform_driver_register(&tegra_hier_ictlr_driver);
203 static void __exit tegra_hier_ictlr_exit(void)
205 platform_driver_unregister(&tegra_hier_ictlr_driver);
208 module_init(tegra_hier_ictlr_init);
209 module_exit(tegra_hier_ictlr_exit);
211 MODULE_DESCRIPTION("Tegra Hierarchical Interrupt Controller Driver");
212 MODULE_LICENSE("GPL v2");