xref: /linux/drivers/bus/uniphier-system-bus.c (revision b6ebbac51bedf9e98e837688bc838f400196da5e)
1 /*
2  * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
3  *
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.
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 
15 #include <linux/io.h>
16 #include <linux/log2.h>
17 #include <linux/module.h>
18 #include <linux/of.h>
19 #include <linux/of_address.h>
20 #include <linux/of_platform.h>
21 #include <linux/platform_device.h>
22 
23 /* System Bus Controller registers */
24 #define UNIPHIER_SBC_BASE	0x100	/* base address of bank0 space */
25 #define    UNIPHIER_SBC_BASE_BE		BIT(0)	/* bank_enable */
26 #define UNIPHIER_SBC_CTRL0	0x200	/* timing parameter 0 of bank0 */
27 #define UNIPHIER_SBC_CTRL1	0x204	/* timing parameter 1 of bank0 */
28 #define UNIPHIER_SBC_CTRL2	0x208	/* timing parameter 2 of bank0 */
29 #define UNIPHIER_SBC_CTRL3	0x20c	/* timing parameter 3 of bank0 */
30 #define UNIPHIER_SBC_CTRL4	0x300	/* timing parameter 4 of bank0 */
31 
32 #define UNIPHIER_SBC_STRIDE	0x10	/* register stride to next bank */
33 #define UNIPHIER_SBC_NR_BANKS	8	/* number of banks (chip select) */
34 #define UNIPHIER_SBC_BASE_DUMMY	0xffffffff	/* data to squash bank 0, 1 */
35 
36 struct uniphier_system_bus_bank {
37 	u32 base;
38 	u32 end;
39 };
40 
41 struct uniphier_system_bus_priv {
42 	struct device *dev;
43 	void __iomem *membase;
44 	struct uniphier_system_bus_bank bank[UNIPHIER_SBC_NR_BANKS];
45 };
46 
47 static int uniphier_system_bus_add_bank(struct uniphier_system_bus_priv *priv,
48 					int bank, u32 addr, u64 paddr, u32 size)
49 {
50 	u64 end, mask;
51 
52 	dev_dbg(priv->dev,
53 		"range found: bank = %d, addr = %08x, paddr = %08llx, size = %08x\n",
54 		bank, addr, paddr, size);
55 
56 	if (bank >= ARRAY_SIZE(priv->bank)) {
57 		dev_err(priv->dev, "unsupported bank number %d\n", bank);
58 		return -EINVAL;
59 	}
60 
61 	if (priv->bank[bank].base || priv->bank[bank].end) {
62 		dev_err(priv->dev,
63 			"range for bank %d has already been specified\n", bank);
64 		return -EINVAL;
65 	}
66 
67 	if (paddr > U32_MAX) {
68 		dev_err(priv->dev, "base address %llx is too high\n", paddr);
69 		return -EINVAL;
70 	}
71 
72 	end = paddr + size;
73 
74 	if (addr > paddr) {
75 		dev_err(priv->dev,
76 			"base %08x cannot be mapped to %08llx of parent\n",
77 			addr, paddr);
78 		return -EINVAL;
79 	}
80 	paddr -= addr;
81 
82 	paddr = round_down(paddr, 0x00020000);
83 	end = round_up(end, 0x00020000);
84 
85 	if (end > U32_MAX) {
86 		dev_err(priv->dev, "end address %08llx is too high\n", end);
87 		return -EINVAL;
88 	}
89 	mask = paddr ^ (end - 1);
90 	mask = roundup_pow_of_two(mask);
91 
92 	paddr = round_down(paddr, mask);
93 	end = round_up(end, mask);
94 
95 	priv->bank[bank].base = paddr;
96 	priv->bank[bank].end = end;
97 
98 	dev_dbg(priv->dev, "range added: bank = %d, addr = %08x, end = %08x\n",
99 		bank, priv->bank[bank].base, priv->bank[bank].end);
100 
101 	return 0;
102 }
103 
104 static int uniphier_system_bus_check_overlap(
105 				const struct uniphier_system_bus_priv *priv)
106 {
107 	int i, j;
108 
109 	for (i = 0; i < ARRAY_SIZE(priv->bank); i++) {
110 		for (j = i + 1; j < ARRAY_SIZE(priv->bank); j++) {
111 			if (priv->bank[i].end > priv->bank[j].base &&
112 			    priv->bank[i].base < priv->bank[j].end) {
113 				dev_err(priv->dev,
114 					"region overlap between bank%d and bank%d\n",
115 					i, j);
116 				return -EINVAL;
117 			}
118 		}
119 	}
120 
121 	return 0;
122 }
123 
124 static void uniphier_system_bus_check_boot_swap(
125 					struct uniphier_system_bus_priv *priv)
126 {
127 	void __iomem *base_reg = priv->membase + UNIPHIER_SBC_BASE;
128 	int is_swapped;
129 
130 	is_swapped = !(readl(base_reg) & UNIPHIER_SBC_BASE_BE);
131 
132 	dev_dbg(priv->dev, "Boot Swap: %s\n", is_swapped ? "on" : "off");
133 
134 	/*
135 	 * If BOOT_SWAP was asserted on power-on-reset, the CS0 and CS1 are
136 	 * swapped.  In this case, bank0 and bank1 should be swapped as well.
137 	 */
138 	if (is_swapped)
139 		swap(priv->bank[0], priv->bank[1]);
140 }
141 
142 static void uniphier_system_bus_set_reg(
143 				const struct uniphier_system_bus_priv *priv)
144 {
145 	void __iomem *base_reg = priv->membase + UNIPHIER_SBC_BASE;
146 	u32 base, end, mask, val;
147 	int i;
148 
149 	for (i = 0; i < ARRAY_SIZE(priv->bank); i++) {
150 		base = priv->bank[i].base;
151 		end = priv->bank[i].end;
152 
153 		if (base == end) {
154 			/*
155 			 * If SBC_BASE0 or SBC_BASE1 is set to zero, the access
156 			 * to anywhere in the system bus space is routed to
157 			 * bank 0 (if boot swap if off) or bank 1 (if boot swap
158 			 * if on).  It means that CPUs cannot get access to
159 			 * bank 2 or later.  In other words, bank 0/1 cannot
160 			 * be disabled even if its bank_enable bits is cleared.
161 			 * This seems odd, but it is how this hardware goes.
162 			 * As a workaround, dummy data (0xffffffff) should be
163 			 * set when the bank 0/1 is unused.  As for bank 2 and
164 			 * later, they can be simply disable by clearing the
165 			 * bank_enable bit.
166 			 */
167 			if (i < 2)
168 				val = UNIPHIER_SBC_BASE_DUMMY;
169 			else
170 				val = 0;
171 		} else {
172 			mask = base ^ (end - 1);
173 
174 			val = base & 0xfffe0000;
175 			val |= (~mask >> 16) & 0xfffe;
176 			val |= UNIPHIER_SBC_BASE_BE;
177 		}
178 		dev_dbg(priv->dev, "SBC_BASE[%d] = 0x%08x\n", i, val);
179 
180 		writel(val, base_reg + UNIPHIER_SBC_STRIDE * i);
181 	}
182 }
183 
184 static int uniphier_system_bus_probe(struct platform_device *pdev)
185 {
186 	struct device *dev = &pdev->dev;
187 	struct uniphier_system_bus_priv *priv;
188 	struct resource *regs;
189 	const __be32 *ranges;
190 	u32 cells, addr, size;
191 	u64 paddr;
192 	int pna, bank, rlen, rone, ret;
193 
194 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
195 	if (!priv)
196 		return -ENOMEM;
197 
198 	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
199 	priv->membase = devm_ioremap_resource(dev, regs);
200 	if (IS_ERR(priv->membase))
201 		return PTR_ERR(priv->membase);
202 
203 	priv->dev = dev;
204 
205 	pna = of_n_addr_cells(dev->of_node);
206 
207 	ret = of_property_read_u32(dev->of_node, "#address-cells", &cells);
208 	if (ret) {
209 		dev_err(dev, "failed to get #address-cells\n");
210 		return ret;
211 	}
212 	if (cells != 2) {
213 		dev_err(dev, "#address-cells must be 2\n");
214 		return -EINVAL;
215 	}
216 
217 	ret = of_property_read_u32(dev->of_node, "#size-cells", &cells);
218 	if (ret) {
219 		dev_err(dev, "failed to get #size-cells\n");
220 		return ret;
221 	}
222 	if (cells != 1) {
223 		dev_err(dev, "#size-cells must be 1\n");
224 		return -EINVAL;
225 	}
226 
227 	ranges = of_get_property(dev->of_node, "ranges", &rlen);
228 	if (!ranges) {
229 		dev_err(dev, "failed to get ranges property\n");
230 		return -ENOENT;
231 	}
232 
233 	rlen /= sizeof(*ranges);
234 	rone = pna + 2;
235 
236 	for (; rlen >= rone; rlen -= rone) {
237 		bank = be32_to_cpup(ranges++);
238 		addr = be32_to_cpup(ranges++);
239 		paddr = of_translate_address(dev->of_node, ranges);
240 		if (paddr == OF_BAD_ADDR)
241 			return -EINVAL;
242 		ranges += pna;
243 		size = be32_to_cpup(ranges++);
244 
245 		ret = uniphier_system_bus_add_bank(priv, bank, addr,
246 						   paddr, size);
247 		if (ret)
248 			return ret;
249 	}
250 
251 	ret = uniphier_system_bus_check_overlap(priv);
252 	if (ret)
253 		return ret;
254 
255 	uniphier_system_bus_check_boot_swap(priv);
256 
257 	uniphier_system_bus_set_reg(priv);
258 
259 	/* Now, the bus is configured.  Populate platform_devices below it */
260 	return of_platform_default_populate(dev->of_node, NULL, dev);
261 }
262 
263 static const struct of_device_id uniphier_system_bus_match[] = {
264 	{ .compatible = "socionext,uniphier-system-bus" },
265 	{ /* sentinel */ }
266 };
267 MODULE_DEVICE_TABLE(of, uniphier_system_bus_match);
268 
269 static struct platform_driver uniphier_system_bus_driver = {
270 	.probe		= uniphier_system_bus_probe,
271 	.driver = {
272 		.name	= "uniphier-system-bus",
273 		.of_match_table = uniphier_system_bus_match,
274 	},
275 };
276 module_platform_driver(uniphier_system_bus_driver);
277 
278 MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
279 MODULE_DESCRIPTION("UniPhier System Bus driver");
280 MODULE_LICENSE("GPL");
281