1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Intel IXP4xx Expansion Bus Controller |
4 | * Copyright (C) 2021 Linaro Ltd. |
5 | * |
6 | * Author: Linus Walleij <linus.walleij@linaro.org> |
7 | */ |
8 | |
9 | #include <linux/bitfield.h> |
10 | #include <linux/bits.h> |
11 | #include <linux/err.h> |
12 | #include <linux/init.h> |
13 | #include <linux/log2.h> |
14 | #include <linux/mfd/syscon.h> |
15 | #include <linux/module.h> |
16 | #include <linux/of.h> |
17 | #include <linux/of_platform.h> |
18 | #include <linux/platform_device.h> |
19 | #include <linux/regmap.h> |
20 | |
21 | #define IXP4XX_EXP_NUM_CS 8 |
22 | |
23 | #define IXP4XX_EXP_TIMING_CS0 0x00 |
24 | #define IXP4XX_EXP_TIMING_CS1 0x04 |
25 | #define IXP4XX_EXP_TIMING_CS2 0x08 |
26 | #define IXP4XX_EXP_TIMING_CS3 0x0c |
27 | #define IXP4XX_EXP_TIMING_CS4 0x10 |
28 | #define IXP4XX_EXP_TIMING_CS5 0x14 |
29 | #define IXP4XX_EXP_TIMING_CS6 0x18 |
30 | #define IXP4XX_EXP_TIMING_CS7 0x1c |
31 | |
32 | /* Bits inside each CS timing register */ |
33 | #define IXP4XX_EXP_TIMING_STRIDE 0x04 |
34 | #define IXP4XX_EXP_CS_EN BIT(31) |
35 | #define IXP456_EXP_PAR_EN BIT(30) /* Only on IXP45x and IXP46x */ |
36 | #define IXP4XX_EXP_T1_MASK GENMASK(29, 28) |
37 | #define IXP4XX_EXP_T1_SHIFT 28 |
38 | #define IXP4XX_EXP_T2_MASK GENMASK(27, 26) |
39 | #define IXP4XX_EXP_T2_SHIFT 26 |
40 | #define IXP4XX_EXP_T3_MASK GENMASK(25, 22) |
41 | #define IXP4XX_EXP_T3_SHIFT 22 |
42 | #define IXP4XX_EXP_T4_MASK GENMASK(21, 20) |
43 | #define IXP4XX_EXP_T4_SHIFT 20 |
44 | #define IXP4XX_EXP_T5_MASK GENMASK(19, 16) |
45 | #define IXP4XX_EXP_T5_SHIFT 16 |
46 | #define IXP4XX_EXP_CYC_TYPE_MASK GENMASK(15, 14) |
47 | #define IXP4XX_EXP_CYC_TYPE_SHIFT 14 |
48 | #define IXP4XX_EXP_SIZE_MASK GENMASK(13, 10) |
49 | #define IXP4XX_EXP_SIZE_SHIFT 10 |
50 | #define IXP4XX_EXP_CNFG_0 BIT(9) /* Always zero */ |
51 | #define IXP43X_EXP_SYNC_INTEL BIT(8) /* Only on IXP43x */ |
52 | #define IXP43X_EXP_EXP_CHIP BIT(7) /* Only on IXP43x, dangerous to touch on IXP42x */ |
53 | #define IXP4XX_EXP_BYTE_RD16 BIT(6) |
54 | #define IXP4XX_EXP_HRDY_POL BIT(5) /* Only on IXP42x */ |
55 | #define IXP4XX_EXP_MUX_EN BIT(4) |
56 | #define IXP4XX_EXP_SPLT_EN BIT(3) |
57 | #define IXP4XX_EXP_WORD BIT(2) /* Always zero */ |
58 | #define IXP4XX_EXP_WR_EN BIT(1) |
59 | #define IXP4XX_EXP_BYTE_EN BIT(0) |
60 | |
61 | #define IXP4XX_EXP_CNFG0 0x20 |
62 | #define IXP4XX_EXP_CNFG0_MEM_MAP BIT(31) |
63 | #define IXP4XX_EXP_CNFG1 0x24 |
64 | |
65 | #define IXP4XX_EXP_BOOT_BASE 0x00000000 |
66 | #define IXP4XX_EXP_NORMAL_BASE 0x50000000 |
67 | #define IXP4XX_EXP_STRIDE 0x01000000 |
68 | |
69 | /* Fuses on the IXP43x */ |
70 | #define IXP43X_EXP_UNIT_FUSE_RESET 0x28 |
71 | #define IXP43x_EXP_FUSE_SPEED_MASK GENMASK(23, 22) |
72 | |
73 | /* Number of device tree values in "reg" */ |
74 | #define IXP4XX_OF_REG_SIZE 3 |
75 | |
76 | struct ixp4xx_eb { |
77 | struct device *dev; |
78 | struct regmap *rmap; |
79 | u32 bus_base; |
80 | bool is_42x; |
81 | bool is_43x; |
82 | }; |
83 | |
84 | struct ixp4xx_exp_tim_prop { |
85 | const char *prop; |
86 | u32 max; |
87 | u32 mask; |
88 | u16 shift; |
89 | }; |
90 | |
91 | static const struct ixp4xx_exp_tim_prop ixp4xx_exp_tim_props[] = { |
92 | { |
93 | .prop = "intel,ixp4xx-eb-t1" , |
94 | .max = 3, |
95 | .mask = IXP4XX_EXP_T1_MASK, |
96 | .shift = IXP4XX_EXP_T1_SHIFT, |
97 | }, |
98 | { |
99 | .prop = "intel,ixp4xx-eb-t2" , |
100 | .max = 3, |
101 | .mask = IXP4XX_EXP_T2_MASK, |
102 | .shift = IXP4XX_EXP_T2_SHIFT, |
103 | }, |
104 | { |
105 | .prop = "intel,ixp4xx-eb-t3" , |
106 | .max = 15, |
107 | .mask = IXP4XX_EXP_T3_MASK, |
108 | .shift = IXP4XX_EXP_T3_SHIFT, |
109 | }, |
110 | { |
111 | .prop = "intel,ixp4xx-eb-t4" , |
112 | .max = 3, |
113 | .mask = IXP4XX_EXP_T4_MASK, |
114 | .shift = IXP4XX_EXP_T4_SHIFT, |
115 | }, |
116 | { |
117 | .prop = "intel,ixp4xx-eb-t5" , |
118 | .max = 15, |
119 | .mask = IXP4XX_EXP_T5_MASK, |
120 | .shift = IXP4XX_EXP_T5_SHIFT, |
121 | }, |
122 | { |
123 | .prop = "intel,ixp4xx-eb-byte-access-on-halfword" , |
124 | .max = 1, |
125 | .mask = IXP4XX_EXP_BYTE_RD16, |
126 | }, |
127 | { |
128 | .prop = "intel,ixp4xx-eb-hpi-hrdy-pol-high" , |
129 | .max = 1, |
130 | .mask = IXP4XX_EXP_HRDY_POL, |
131 | }, |
132 | { |
133 | .prop = "intel,ixp4xx-eb-mux-address-and-data" , |
134 | .max = 1, |
135 | .mask = IXP4XX_EXP_MUX_EN, |
136 | }, |
137 | { |
138 | .prop = "intel,ixp4xx-eb-ahb-split-transfers" , |
139 | .max = 1, |
140 | .mask = IXP4XX_EXP_SPLT_EN, |
141 | }, |
142 | { |
143 | .prop = "intel,ixp4xx-eb-write-enable" , |
144 | .max = 1, |
145 | .mask = IXP4XX_EXP_WR_EN, |
146 | }, |
147 | { |
148 | .prop = "intel,ixp4xx-eb-byte-access" , |
149 | .max = 1, |
150 | .mask = IXP4XX_EXP_BYTE_EN, |
151 | }, |
152 | }; |
153 | |
154 | static void ixp4xx_exp_setup_chipselect(struct ixp4xx_eb *eb, |
155 | struct device_node *np, |
156 | u32 cs_index, |
157 | u32 cs_size) |
158 | { |
159 | u32 cs_cfg; |
160 | u32 val; |
161 | u32 cur_cssize; |
162 | u32 cs_order; |
163 | int ret; |
164 | int i; |
165 | |
166 | if (eb->is_42x && (cs_index > 7)) { |
167 | dev_err(eb->dev, |
168 | "invalid chipselect %u, we only support 0-7\n" , |
169 | cs_index); |
170 | return; |
171 | } |
172 | if (eb->is_43x && (cs_index > 3)) { |
173 | dev_err(eb->dev, |
174 | "invalid chipselect %u, we only support 0-3\n" , |
175 | cs_index); |
176 | return; |
177 | } |
178 | |
179 | /* Several chip selects can be joined into one device */ |
180 | if (cs_size > IXP4XX_EXP_STRIDE) |
181 | cur_cssize = IXP4XX_EXP_STRIDE; |
182 | else |
183 | cur_cssize = cs_size; |
184 | |
185 | |
186 | /* |
187 | * The following will read/modify/write the configuration for one |
188 | * chipselect, attempting to leave the boot defaults in place unless |
189 | * something is explicitly defined. |
190 | */ |
191 | regmap_read(map: eb->rmap, IXP4XX_EXP_TIMING_CS0 + |
192 | IXP4XX_EXP_TIMING_STRIDE * cs_index, val: &cs_cfg); |
193 | dev_info(eb->dev, "CS%d at %#08x, size %#08x, config before: %#08x\n" , |
194 | cs_index, eb->bus_base + IXP4XX_EXP_STRIDE * cs_index, |
195 | cur_cssize, cs_cfg); |
196 | |
197 | /* Size set-up first align to 2^9 .. 2^24 */ |
198 | cur_cssize = roundup_pow_of_two(cur_cssize); |
199 | if (cur_cssize < 512) |
200 | cur_cssize = 512; |
201 | cs_order = ilog2(cur_cssize); |
202 | if (cs_order < 9 || cs_order > 24) { |
203 | dev_err(eb->dev, "illegal size order %d\n" , cs_order); |
204 | return; |
205 | } |
206 | dev_dbg(eb->dev, "CS%d size order: %d\n" , cs_index, cs_order); |
207 | cs_cfg &= ~(IXP4XX_EXP_SIZE_MASK); |
208 | cs_cfg |= ((cs_order - 9) << IXP4XX_EXP_SIZE_SHIFT); |
209 | |
210 | for (i = 0; i < ARRAY_SIZE(ixp4xx_exp_tim_props); i++) { |
211 | const struct ixp4xx_exp_tim_prop *ip = &ixp4xx_exp_tim_props[i]; |
212 | |
213 | /* All are regular u32 values */ |
214 | ret = of_property_read_u32(np, propname: ip->prop, out_value: &val); |
215 | if (ret) |
216 | continue; |
217 | |
218 | /* Handle bools (single bits) first */ |
219 | if (ip->max == 1) { |
220 | if (val) |
221 | cs_cfg |= ip->mask; |
222 | else |
223 | cs_cfg &= ~ip->mask; |
224 | dev_info(eb->dev, "CS%d %s %s\n" , cs_index, |
225 | val ? "enabled" : "disabled" , |
226 | ip->prop); |
227 | continue; |
228 | } |
229 | |
230 | if (val > ip->max) { |
231 | dev_err(eb->dev, |
232 | "CS%d too high value for %s: %u, capped at %u\n" , |
233 | cs_index, ip->prop, val, ip->max); |
234 | val = ip->max; |
235 | } |
236 | /* This assumes max value fills all the assigned bits (and it does) */ |
237 | cs_cfg &= ~ip->mask; |
238 | cs_cfg |= (val << ip->shift); |
239 | dev_info(eb->dev, "CS%d set %s to %u\n" , cs_index, ip->prop, val); |
240 | } |
241 | |
242 | ret = of_property_read_u32(np, propname: "intel,ixp4xx-eb-cycle-type" , out_value: &val); |
243 | if (!ret) { |
244 | if (val > 3) { |
245 | dev_err(eb->dev, "illegal cycle type %d\n" , val); |
246 | return; |
247 | } |
248 | dev_info(eb->dev, "CS%d set cycle type %d\n" , cs_index, val); |
249 | cs_cfg &= ~IXP4XX_EXP_CYC_TYPE_MASK; |
250 | cs_cfg |= val << IXP4XX_EXP_CYC_TYPE_SHIFT; |
251 | } |
252 | |
253 | if (eb->is_43x) { |
254 | /* Should always be zero */ |
255 | cs_cfg &= ~IXP4XX_EXP_WORD; |
256 | /* |
257 | * This bit for Intel strata flash is currently unused, but let's |
258 | * report it if we find one. |
259 | */ |
260 | if (cs_cfg & IXP43X_EXP_SYNC_INTEL) |
261 | dev_info(eb->dev, "claims to be Intel strata flash\n" ); |
262 | } |
263 | cs_cfg |= IXP4XX_EXP_CS_EN; |
264 | |
265 | regmap_write(map: eb->rmap, |
266 | IXP4XX_EXP_TIMING_CS0 + IXP4XX_EXP_TIMING_STRIDE * cs_index, |
267 | val: cs_cfg); |
268 | dev_info(eb->dev, "CS%d wrote %#08x into CS config\n" , cs_index, cs_cfg); |
269 | |
270 | /* |
271 | * If several chip selects are joined together into one big |
272 | * device area, we call ourselves recursively for each successive |
273 | * chip select. For a 32MB flash chip this results in two calls |
274 | * for example. |
275 | */ |
276 | if (cs_size > IXP4XX_EXP_STRIDE) |
277 | ixp4xx_exp_setup_chipselect(eb, np, |
278 | cs_index: cs_index + 1, |
279 | cs_size: cs_size - IXP4XX_EXP_STRIDE); |
280 | } |
281 | |
282 | static void ixp4xx_exp_setup_child(struct ixp4xx_eb *eb, |
283 | struct device_node *np) |
284 | { |
285 | u32 cs_sizes[IXP4XX_EXP_NUM_CS]; |
286 | int num_regs; |
287 | u32 csindex; |
288 | u32 cssize; |
289 | int ret; |
290 | int i; |
291 | |
292 | num_regs = of_property_count_elems_of_size(np, propname: "reg" , IXP4XX_OF_REG_SIZE); |
293 | if (num_regs <= 0) |
294 | return; |
295 | dev_dbg(eb->dev, "child %s has %d register sets\n" , |
296 | of_node_full_name(np), num_regs); |
297 | |
298 | for (csindex = 0; csindex < IXP4XX_EXP_NUM_CS; csindex++) |
299 | cs_sizes[csindex] = 0; |
300 | |
301 | for (i = 0; i < num_regs; i++) { |
302 | u32 rbase, rsize; |
303 | |
304 | ret = of_property_read_u32_index(np, propname: "reg" , |
305 | index: i * IXP4XX_OF_REG_SIZE, out_value: &csindex); |
306 | if (ret) |
307 | break; |
308 | ret = of_property_read_u32_index(np, propname: "reg" , |
309 | index: i * IXP4XX_OF_REG_SIZE + 1, out_value: &rbase); |
310 | if (ret) |
311 | break; |
312 | ret = of_property_read_u32_index(np, propname: "reg" , |
313 | index: i * IXP4XX_OF_REG_SIZE + 2, out_value: &rsize); |
314 | if (ret) |
315 | break; |
316 | |
317 | if (csindex >= IXP4XX_EXP_NUM_CS) { |
318 | dev_err(eb->dev, "illegal CS %d\n" , csindex); |
319 | continue; |
320 | } |
321 | /* |
322 | * The memory window always starts from CS base so we need to add |
323 | * the start and size to get to the size from the start of the CS |
324 | * base. For example if CS0 is at 0x50000000 and the reg is |
325 | * <0 0xe40000 0x40000> the size is e80000. |
326 | * |
327 | * Roof this if we have several regs setting the same CS. |
328 | */ |
329 | cssize = rbase + rsize; |
330 | dev_dbg(eb->dev, "CS%d size %#08x\n" , csindex, cssize); |
331 | if (cs_sizes[csindex] < cssize) |
332 | cs_sizes[csindex] = cssize; |
333 | } |
334 | |
335 | for (csindex = 0; csindex < IXP4XX_EXP_NUM_CS; csindex++) { |
336 | cssize = cs_sizes[csindex]; |
337 | if (!cssize) |
338 | continue; |
339 | /* Just this one, so set it up and return */ |
340 | ixp4xx_exp_setup_chipselect(eb, np, cs_index: csindex, cs_size: cssize); |
341 | } |
342 | } |
343 | |
344 | static int ixp4xx_exp_probe(struct platform_device *pdev) |
345 | { |
346 | struct device *dev = &pdev->dev; |
347 | struct device_node *np = dev->of_node; |
348 | struct ixp4xx_eb *eb; |
349 | struct device_node *child; |
350 | bool have_children = false; |
351 | u32 val; |
352 | int ret; |
353 | |
354 | eb = devm_kzalloc(dev, size: sizeof(*eb), GFP_KERNEL); |
355 | if (!eb) |
356 | return -ENOMEM; |
357 | |
358 | eb->dev = dev; |
359 | eb->is_42x = of_device_is_compatible(device: np, "intel,ixp42x-expansion-bus-controller" ); |
360 | eb->is_43x = of_device_is_compatible(device: np, "intel,ixp43x-expansion-bus-controller" ); |
361 | |
362 | eb->rmap = syscon_node_to_regmap(np); |
363 | if (IS_ERR(ptr: eb->rmap)) |
364 | return dev_err_probe(dev, err: PTR_ERR(ptr: eb->rmap), fmt: "no regmap\n" ); |
365 | |
366 | /* We check that the regmap work only on first read */ |
367 | ret = regmap_read(map: eb->rmap, IXP4XX_EXP_CNFG0, val: &val); |
368 | if (ret) |
369 | return dev_err_probe(dev, err: ret, fmt: "cannot read regmap\n" ); |
370 | if (val & IXP4XX_EXP_CNFG0_MEM_MAP) |
371 | eb->bus_base = IXP4XX_EXP_BOOT_BASE; |
372 | else |
373 | eb->bus_base = IXP4XX_EXP_NORMAL_BASE; |
374 | dev_info(dev, "expansion bus at %08x\n" , eb->bus_base); |
375 | |
376 | if (eb->is_43x) { |
377 | /* Check some fuses */ |
378 | regmap_read(map: eb->rmap, IXP43X_EXP_UNIT_FUSE_RESET, val: &val); |
379 | switch (FIELD_GET(IXP43x_EXP_FUSE_SPEED_MASK, val)) { |
380 | case 0: |
381 | dev_info(dev, "IXP43x at 533 MHz\n" ); |
382 | break; |
383 | case 1: |
384 | dev_info(dev, "IXP43x at 400 MHz\n" ); |
385 | break; |
386 | case 2: |
387 | dev_info(dev, "IXP43x at 667 MHz\n" ); |
388 | break; |
389 | default: |
390 | dev_info(dev, "IXP43x unknown speed\n" ); |
391 | break; |
392 | } |
393 | } |
394 | |
395 | /* Walk over the child nodes and see what chipselects we use */ |
396 | for_each_available_child_of_node(np, child) { |
397 | ixp4xx_exp_setup_child(eb, np: child); |
398 | /* We have at least one child */ |
399 | have_children = true; |
400 | } |
401 | |
402 | if (have_children) |
403 | return of_platform_default_populate(root: np, NULL, parent: dev); |
404 | |
405 | return 0; |
406 | } |
407 | |
408 | static const struct of_device_id ixp4xx_exp_of_match[] = { |
409 | { .compatible = "intel,ixp42x-expansion-bus-controller" , }, |
410 | { .compatible = "intel,ixp43x-expansion-bus-controller" , }, |
411 | { .compatible = "intel,ixp45x-expansion-bus-controller" , }, |
412 | { .compatible = "intel,ixp46x-expansion-bus-controller" , }, |
413 | { } |
414 | }; |
415 | |
416 | static struct platform_driver ixp4xx_exp_driver = { |
417 | .probe = ixp4xx_exp_probe, |
418 | .driver = { |
419 | .name = "intel-extbus" , |
420 | .of_match_table = ixp4xx_exp_of_match, |
421 | }, |
422 | }; |
423 | module_platform_driver(ixp4xx_exp_driver); |
424 | MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>" ); |
425 | MODULE_DESCRIPTION("Intel IXP4xx external bus driver" ); |
426 | |