1 /*
2 * vendor/amlogic/iomap/iomap.c
3 *
4 * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 */
17
18 #include <asm/compiler.h>
19 #include <linux/module.h>
20 #include <linux/kernel.h>
21 #include <linux/init.h>
22 #include <linux/printk.h>
23 #include <linux/string.h>
24 #include <linux/of_address.h>
25 #include <linux/io.h>
26 #include <linux/regmap.h>
27 #include <linux/device.h>
28 #include <linux/of_platform.h>
29 #include <linux/platform_device.h>
30 #include <linux/amlogic/iomap.h>
31 #undef pr_fmt
32 #define pr_fmt(fmt) "aml_iomap: " fmt
33
34 static const struct of_device_id iomap_dt_match[] = {
35 {.compatible = "amlogic, iomap"},
36 {},
37 };
38
39 static void __iomem *meson_reg_map[IO_BUS_MAX] = {NULL};
40 static uint meson_reg_max[IO_BUS_MAX] = {0};
41 void __iomem *vpp_base;
42 EXPORT_SYMBOL(vpp_base);
43 unsigned int vpp_max;
44
aml_reg_read(u32 bus_type,unsigned int reg,unsigned int * val)45 inline int aml_reg_read(u32 bus_type, unsigned int reg, unsigned int *val)
46 {
47 if (bus_type < IO_BUS_MAX && (meson_reg_map[bus_type]) && (meson_reg_max[bus_type] >= reg)) {
48 *val = readl((meson_reg_map[bus_type] + reg));
49 return 0;
50 } else {
51 return -1;
52 }
53 }
54 EXPORT_SYMBOL(aml_reg_read);
55
aml_reg_write(u32 bus_type,unsigned int reg,unsigned int val)56 inline int aml_reg_write(u32 bus_type, unsigned int reg, unsigned int val)
57 {
58 if (bus_type < IO_BUS_MAX && (meson_reg_map[bus_type]) && (meson_reg_max[bus_type] >= reg)) {
59 writel(val, (meson_reg_map[bus_type] + reg));
60 return 0;
61 } else {
62 return -1;
63 }
64 }
65 EXPORT_SYMBOL(aml_reg_write);
66
aml_regmap_update_bits(u32 bus_type,unsigned int reg,unsigned int mask,unsigned int val)67 int aml_regmap_update_bits(u32 bus_type, unsigned int reg, unsigned int mask, unsigned int val)
68 {
69 int ret = 0;
70 unsigned int tmp, orig;
71
72 ret = aml_reg_read(bus_type, reg, &orig);
73 if (ret) {
74 pr_err("read bus reg %x error %d\n", reg, ret);
75 return ret;
76 }
77 tmp = orig & ~mask;
78 tmp |= val & mask;
79 ret = aml_reg_write(bus_type, reg, tmp);
80 if (ret) {
81 pr_err("write bus reg %x error %d\n", reg, ret);
82 }
83 return ret;
84 }
85 EXPORT_SYMBOL(aml_regmap_update_bits);
86
87 /*
88 * CBUS REG Read Write and Update some bits
89 */
aml_read_cbus(unsigned int reg)90 int aml_read_cbus(unsigned int reg)
91 {
92 int ret, val;
93
94 ret = aml_reg_read(IO_CBUS_BASE, reg << 2L, &val);
95 if (ret) {
96 pr_err("read cbus reg %x error %d\n", reg, ret);
97 return -1;
98 } else {
99 return val;
100 }
101 }
102 EXPORT_SYMBOL(aml_read_cbus);
103
aml_write_cbus(unsigned int reg,unsigned int val)104 void aml_write_cbus(unsigned int reg, unsigned int val)
105 {
106 int ret;
107
108 ret = aml_reg_write(IO_CBUS_BASE, reg << 2L, val);
109 if (ret) {
110 pr_err("write cbus reg %x error %d\n", reg, ret);
111 }
112 }
113 EXPORT_SYMBOL(aml_write_cbus);
114
aml_cbus_update_bits(unsigned int reg,unsigned int mask,unsigned int val)115 void aml_cbus_update_bits(unsigned int reg, unsigned int mask, unsigned int val)
116 {
117 int ret;
118
119 ret = aml_regmap_update_bits(IO_CBUS_BASE, reg << 2L, mask, val);
120 if (ret) {
121 pr_err("write cbus reg %x error %d\n", reg, ret);
122 }
123 }
124 EXPORT_SYMBOL(aml_cbus_update_bits);
125
126 /*
127 * AO REG Read Write and Update some bits
128 */
aml_read_aobus(unsigned int reg)129 int aml_read_aobus(unsigned int reg)
130 {
131 int ret, val;
132
133 ret = aml_reg_read(IO_AOBUS_BASE, reg, &val);
134 if (ret) {
135 pr_err("read ao bus reg %x error %d\n", reg, ret);
136 return -1;
137 } else {
138 return val;
139 }
140 }
141 EXPORT_SYMBOL(aml_read_aobus);
142
aml_write_aobus(unsigned int reg,unsigned int val)143 void aml_write_aobus(unsigned int reg, unsigned int val)
144 {
145 int ret;
146
147 ret = aml_reg_write(IO_AOBUS_BASE, reg, val);
148 if (ret) {
149 pr_err("write ao bus reg %x error %d\n", reg, ret);
150 }
151 }
152 EXPORT_SYMBOL(aml_write_aobus);
153
aml_aobus_update_bits(unsigned int reg,unsigned int mask,unsigned int val)154 void aml_aobus_update_bits(unsigned int reg, unsigned int mask, unsigned int val)
155 {
156 int ret;
157
158 ret = aml_regmap_update_bits(IO_AOBUS_BASE, reg, mask, val);
159 if (ret) {
160 pr_err("write aobus reg %x error %d\n", reg, ret);
161 }
162 }
163 EXPORT_SYMBOL(aml_aobus_update_bits);
164
165 /*
166 ** VCBUS Bus REG Read Write and Update some bits
167 */
aml_read_vcbus(unsigned int reg)168 int aml_read_vcbus(unsigned int reg)
169 {
170 int ret, val;
171 ret = aml_reg_read(IO_VAPB_BUS_BASE, reg << 2L, &val);
172 if (ret) {
173 pr_err("read vcbus reg %x error %d\n", reg, ret);
174 return -1;
175 } else {
176 return val;
177 }
178 }
179 EXPORT_SYMBOL(aml_read_vcbus);
180
aml_write_vcbus(unsigned int reg,unsigned int val)181 void aml_write_vcbus(unsigned int reg, unsigned int val)
182 {
183 int ret;
184
185 ret = aml_reg_write(IO_VAPB_BUS_BASE, reg << 2L, val);
186 if (ret) {
187 pr_err("write vcbus reg %x error %d\n", reg, ret);
188 }
189 }
190 EXPORT_SYMBOL(aml_write_vcbus);
191
aml_vcbus_update_bits(unsigned int reg,unsigned int mask,unsigned int val)192 void aml_vcbus_update_bits(unsigned int reg, unsigned int mask, unsigned int val)
193 {
194 int ret;
195
196 ret = aml_regmap_update_bits(IO_VAPB_BUS_BASE, reg << 2L, mask, val);
197 if (ret) {
198 pr_err("write vcbus reg %x error %d\n", reg, ret);
199 }
200 }
201 EXPORT_SYMBOL(aml_vcbus_update_bits);
202
203 /*
204 ** DOS BUS Bus REG Read Write and Update some bits
205 */
aml_read_dosbus(unsigned int reg)206 int aml_read_dosbus(unsigned int reg)
207 {
208 int ret, val;
209
210 ret = aml_reg_read(IO_APB_BUS_BASE, reg << 2L, &val);
211 if (ret) {
212 pr_err("read vcbus reg %x error %d\n", reg, ret);
213 return -1;
214 } else {
215 return val;
216 }
217 }
218 EXPORT_SYMBOL(aml_read_dosbus);
219
aml_write_dosbus(unsigned int reg,unsigned int val)220 void aml_write_dosbus(unsigned int reg, unsigned int val)
221 {
222 int ret;
223
224 ret = aml_reg_write(IO_APB_BUS_BASE, reg << 2L, val);
225 if (ret) {
226 pr_err("write vcbus reg %x error %d\n", reg, ret);
227 }
228 }
229 EXPORT_SYMBOL(aml_write_dosbus);
230
aml_dosbus_update_bits(unsigned int reg,unsigned int mask,unsigned int val)231 void aml_dosbus_update_bits(unsigned int reg, unsigned int mask, unsigned int val)
232 {
233 int ret;
234
235 ret = aml_regmap_update_bits(IO_APB_BUS_BASE, reg << 2L, mask, val);
236 if (ret) {
237 pr_err("write vcbus reg %x error %d\n", reg, ret);
238 }
239 }
240 EXPORT_SYMBOL(aml_dosbus_update_bits);
241
242 /*
243 * HIUBUS REG Read Write and Update some bits
244 */
aml_read_hiubus(unsigned int reg)245 int aml_read_hiubus(unsigned int reg)
246 {
247 int ret, val;
248
249 ret = aml_reg_read(IO_HIUBUS_BASE, reg << 2L, &val);
250 if (ret) {
251 pr_err("read cbus reg %x error %d\n", reg, ret);
252 return -1;
253 } else {
254 return val;
255 }
256 }
257 EXPORT_SYMBOL(aml_read_hiubus);
258
aml_write_hiubus(unsigned int reg,unsigned int val)259 void aml_write_hiubus(unsigned int reg, unsigned int val)
260 {
261 int ret;
262
263 ret = aml_reg_write(IO_HIUBUS_BASE, reg << 2L, val);
264 if (ret) {
265 pr_err("write cbus reg %x error %d\n", reg, ret);
266 }
267 }
268 EXPORT_SYMBOL(aml_write_hiubus);
269
aml_hiubus_update_bits(unsigned int reg,unsigned int mask,unsigned int val)270 void aml_hiubus_update_bits(unsigned int reg, unsigned int mask, unsigned int val)
271 {
272 int ret;
273
274 ret = aml_regmap_update_bits(IO_HIUBUS_BASE, reg << 2L, mask, val);
275 if (ret) {
276 pr_err("write cbus reg %x error %d\n", reg, ret);
277 }
278 }
279 EXPORT_SYMBOL(aml_hiubus_update_bits);
280
iomap_probe(struct platform_device * pdev)281 static int iomap_probe(struct platform_device *pdev)
282 {
283 int i = 0;
284 struct resource res;
285 struct device_node *np, *child;
286
287 np = pdev->dev.of_node;
288
289 for_each_child_of_node(np, child)
290 {
291 if (of_address_to_resource(child, 0, &res)) {
292 return -1;
293 }
294 meson_reg_map[i] = ioremap(res.start, resource_size(&res));
295 meson_reg_max[i] = res.end - res.start;
296 i++;
297 }
298 if (i > IO_VAPB_BUS_BASE) {
299 vpp_base = meson_reg_map[IO_VAPB_BUS_BASE];
300 vpp_max = meson_reg_max[IO_VAPB_BUS_BASE];
301 }
302 pr_info("amlogic iomap probe done\n");
303 return 0;
304 }
305
306 static struct platform_driver iomap_platform_driver = {
307 .probe = iomap_probe,
308 .driver =
309 {
310 .owner = THIS_MODULE,
311 .name = "iomap_version",
312 .of_match_table = iomap_dt_match,
313 },
314 };
315
meson_iomap_version_init(void)316 int __init meson_iomap_version_init(void)
317 {
318 int ret;
319
320 ret = platform_driver_register(&iomap_platform_driver);
321
322 return ret;
323 }
324 core_initcall(meson_iomap_version_init);
325