blob: 7f73ee772b7e3d9c86b64e1520ddf75268f5c91b [file] [log] [blame]
Per Åstrand87ca5da2021-04-15 09:47:03 +02001/*
2 * Copyright (c) 2021 Arm Limited. All rights reserved.
3 *
4 * This program is free software and is provided to you under the terms of the
5 * GNU General Public License version 2 as published by the Free Software
6 * Foundation, and any use by you of this program is subject to the terms
7 * of such GNU licence.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, you can access it online at
16 * http://www.gnu.org/licenses/gpl-2.0.html.
17 *
18 * SPDX-License-Identifier: GPL-2.0-only
19 */
20
21#include <linux/io.h>
22#include <linux/kernel.h>
23#include <linux/module.h>
24#include <linux/of.h>
25#include <linux/of_device.h>
26#include <linux/platform_device.h>
27#include <linux/reset-controller.h>
28
29#define ETHOSU_BRIDGE_RESET_DRIVER_VERSION "0.0.1"
30
31struct ethosu_reset {
32 struct reset_controller_dev rst;
33 struct device *dev;
34 void __iomem *base;
35};
36
37#define ETHOSU_BRIDGE_ID(base) (base)
38#define ETHOSU_BRIDGE_CTRL(base) ((base) + 0x100)
39
40#define ETHOSU_BRIDGE_WAIT_ENABLE (0x2)
41#define ETHOSU_BRIDGE_RESET (0x1)
42
43static void __iomem *bridge_verify_and_remap(struct device *dev,
44 struct resource *res)
45{
46 void __iomem *base = devm_ioremap_resource(dev, res);
47 u32 id;
48 u16 magic;
49 u8 minor;
50 u8 major;
51
52 if (IS_ERR(base))
53 return base;
54
55 id = readl(ETHOSU_BRIDGE_ID(base));
56 magic = id & 0x0000ffff;
57 minor = (id & 0x00ff0000) >> 16;
58 major = (id & 0xff000000) >> 24;
59
60 dev_dbg(dev, "verifying bridge %d.%d", major, minor);
61
62 if (magic != 0xBD9E)
63 return IOMEM_ERR_PTR(-EINVAL);
64
65 return base;
66}
67
68int ethosu_bridge_assert(struct reset_controller_dev *rcdev,
69 unsigned long id)
70{
71 struct ethosu_reset *ethosu = container_of(rcdev, struct ethosu_reset,
72 rst);
73
74 /* pull reset */
75 dev_dbg(ethosu->dev, "Asserting reset");
76
77 /* set wait and reset */
78 writel(ETHOSU_BRIDGE_WAIT_ENABLE | ETHOSU_BRIDGE_RESET,
79 ETHOSU_BRIDGE_CTRL(ethosu->base));
80
81 return 0;
82}
83
84int ethosu_bridge_deassert(struct reset_controller_dev *rcdev,
85 unsigned long id)
86{
87 struct ethosu_reset *ethosu = container_of(rcdev, struct ethosu_reset,
88 rst);
89
90 /* release reset */
91 dev_dbg(ethosu->dev, "Deasserting reset");
92 writel(~ETHOSU_BRIDGE_WAIT_ENABLE & ETHOSU_BRIDGE_RESET,
93 ETHOSU_BRIDGE_CTRL(ethosu->base));
94
95 return 0;
96}
97
98static struct reset_control_ops ethosu_reset_bridge_ops = {
99 .assert = ethosu_bridge_assert,
100 .deassert = ethosu_bridge_deassert,
101};
102
103static const struct of_device_id ethosu_reset_match[] = {
104 { .compatible = "arm,ethosu-bridge-reset", .data = 0 },
105 { /* sentinel */ },
106};
107
108static int ethosu_bridge_reset_probe(struct platform_device *pdev)
109{
110 struct device *dev = &pdev->dev;
111 struct ethosu_reset *ethosu;
112 struct resource *res;
113
114 ethosu = devm_kzalloc(&pdev->dev, sizeof(*ethosu), GFP_KERNEL);
115 if (!ethosu)
116 return -ENOMEM;
117
118 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
119
120 ethosu->base = bridge_verify_and_remap(dev, res);
121 ethosu->dev = dev;
122
123 if (IS_ERR(ethosu->base))
124 return PTR_ERR(ethosu->base);
125
126 platform_set_drvdata(pdev, ethosu);
127
128 ethosu->rst.owner = THIS_MODULE;
129 ethosu->rst.nr_resets = 1;
130 ethosu->rst.ops = &ethosu_reset_bridge_ops;
131 ethosu->rst.of_node = pdev->dev.of_node;
132
133 dev_dbg(dev, "registering to reset controller core");
134
135 return devm_reset_controller_register(dev, &ethosu->rst);
136}
137
138static int ethosu_bridge_reset_remove(struct platform_device *pdev)
139{
140 return 0;
141}
142
143static struct platform_driver ethosu_reset_driver = {
144 .probe = ethosu_bridge_reset_probe,
145 .remove = ethosu_bridge_reset_remove,
146 .driver = {
147 .name = "ethosu-bridge-reset",
148 .of_match_table = of_match_ptr(ethosu_reset_match),
149 },
150};
151
152module_platform_driver(ethosu_reset_driver);
153
154MODULE_LICENSE("GPL v2");
155MODULE_AUTHOR("Arm Ltd");
156MODULE_DESCRIPTION("Arm Ethos-U NPU Bridge Reset Driver");
157MODULE_VERSION(ETHOSU_BRIDGE_RESET_DRIVER_VERSION);