Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/bus/intel-ixp4xx-eb.c
26278 views
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 <[email protected]>
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(eb->rmap, IXP4XX_EXP_TIMING_CS0 +
192
IXP4XX_EXP_TIMING_STRIDE * cs_index, &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, ip->prop, &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, "intel,ixp4xx-eb-cycle-type", &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(eb->rmap,
266
IXP4XX_EXP_TIMING_CS0 + IXP4XX_EXP_TIMING_STRIDE * cs_index,
267
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 + 1,
279
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, "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, "reg",
305
i * IXP4XX_OF_REG_SIZE, &csindex);
306
if (ret)
307
break;
308
ret = of_property_read_u32_index(np, "reg",
309
i * IXP4XX_OF_REG_SIZE + 1, &rbase);
310
if (ret)
311
break;
312
ret = of_property_read_u32_index(np, "reg",
313
i * IXP4XX_OF_REG_SIZE + 2, &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, csindex, 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, sizeof(*eb), GFP_KERNEL);
355
if (!eb)
356
return -ENOMEM;
357
358
eb->dev = dev;
359
eb->is_42x = of_device_is_compatible(np, "intel,ixp42x-expansion-bus-controller");
360
eb->is_43x = of_device_is_compatible(np, "intel,ixp43x-expansion-bus-controller");
361
362
eb->rmap = syscon_node_to_regmap(np);
363
if (IS_ERR(eb->rmap))
364
return dev_err_probe(dev, PTR_ERR(eb->rmap), "no regmap\n");
365
366
/* We check that the regmap work only on first read */
367
ret = regmap_read(eb->rmap, IXP4XX_EXP_CNFG0, &val);
368
if (ret)
369
return dev_err_probe(dev, ret, "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(eb->rmap, IXP43X_EXP_UNIT_FUSE_RESET, &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, child);
398
/* We have at least one child */
399
have_children = true;
400
}
401
402
if (have_children)
403
return of_platform_default_populate(np, NULL, 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 <[email protected]>");
425
MODULE_DESCRIPTION("Intel IXP4xx external bus driver");
426
427