1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
7 #include <linux/log2.h>
8 #include <linux/module.h>
10 #include <linux/of_address.h>
11 #include <linux/of_platform.h>
12 #include <linux/platform_device.h>
14 /* System Bus Controller registers */
15 #define UNIPHIER_SBC_BASE 0x100 /* base address of bank0 space */
16 #define UNIPHIER_SBC_BASE_BE BIT(0) /* bank_enable */
17 #define UNIPHIER_SBC_CTRL0 0x200 /* timing parameter 0 of bank0 */
18 #define UNIPHIER_SBC_CTRL1 0x204 /* timing parameter 1 of bank0 */
19 #define UNIPHIER_SBC_CTRL2 0x208 /* timing parameter 2 of bank0 */
20 #define UNIPHIER_SBC_CTRL3 0x20c /* timing parameter 3 of bank0 */
21 #define UNIPHIER_SBC_CTRL4 0x300 /* timing parameter 4 of bank0 */
23 #define UNIPHIER_SBC_STRIDE 0x10 /* register stride to next bank */
24 #define UNIPHIER_SBC_NR_BANKS 8 /* number of banks (chip select) */
25 #define UNIPHIER_SBC_BASE_DUMMY 0xffffffff /* data to squash bank 0, 1 */
27 struct uniphier_system_bus_bank
{
32 struct uniphier_system_bus_priv
{
34 void __iomem
*membase
;
35 struct uniphier_system_bus_bank bank
[UNIPHIER_SBC_NR_BANKS
];
38 static int uniphier_system_bus_add_bank(struct uniphier_system_bus_priv
*priv
,
39 int bank
, u32 addr
, u64 paddr
, u32 size
)
44 "range found: bank = %d, addr = %08x, paddr = %08llx, size = %08x\n",
45 bank
, addr
, paddr
, size
);
47 if (bank
>= ARRAY_SIZE(priv
->bank
)) {
48 dev_err(priv
->dev
, "unsupported bank number %d\n", bank
);
52 if (priv
->bank
[bank
].base
|| priv
->bank
[bank
].end
) {
54 "range for bank %d has already been specified\n", bank
);
58 if (paddr
> U32_MAX
) {
59 dev_err(priv
->dev
, "base address %llx is too high\n", paddr
);
67 "base %08x cannot be mapped to %08llx of parent\n",
73 paddr
= round_down(paddr
, 0x00020000);
74 end
= round_up(end
, 0x00020000);
77 dev_err(priv
->dev
, "end address %08llx is too high\n", end
);
80 mask
= paddr
^ (end
- 1);
81 mask
= roundup_pow_of_two(mask
);
83 paddr
= round_down(paddr
, mask
);
84 end
= round_up(end
, mask
);
86 priv
->bank
[bank
].base
= paddr
;
87 priv
->bank
[bank
].end
= end
;
89 dev_dbg(priv
->dev
, "range added: bank = %d, addr = %08x, end = %08x\n",
90 bank
, priv
->bank
[bank
].base
, priv
->bank
[bank
].end
);
95 static int uniphier_system_bus_check_overlap(
96 const struct uniphier_system_bus_priv
*priv
)
100 for (i
= 0; i
< ARRAY_SIZE(priv
->bank
); i
++) {
101 for (j
= i
+ 1; j
< ARRAY_SIZE(priv
->bank
); j
++) {
102 if (priv
->bank
[i
].end
> priv
->bank
[j
].base
&&
103 priv
->bank
[i
].base
< priv
->bank
[j
].end
) {
105 "region overlap between bank%d and bank%d\n",
115 static void uniphier_system_bus_check_boot_swap(
116 struct uniphier_system_bus_priv
*priv
)
118 void __iomem
*base_reg
= priv
->membase
+ UNIPHIER_SBC_BASE
;
121 is_swapped
= !(readl(base_reg
) & UNIPHIER_SBC_BASE_BE
);
123 dev_dbg(priv
->dev
, "Boot Swap: %s\n", is_swapped
? "on" : "off");
126 * If BOOT_SWAP was asserted on power-on-reset, the CS0 and CS1 are
127 * swapped. In this case, bank0 and bank1 should be swapped as well.
130 swap(priv
->bank
[0], priv
->bank
[1]);
133 static void uniphier_system_bus_set_reg(
134 const struct uniphier_system_bus_priv
*priv
)
136 void __iomem
*base_reg
= priv
->membase
+ UNIPHIER_SBC_BASE
;
137 u32 base
, end
, mask
, val
;
140 for (i
= 0; i
< ARRAY_SIZE(priv
->bank
); i
++) {
141 base
= priv
->bank
[i
].base
;
142 end
= priv
->bank
[i
].end
;
146 * If SBC_BASE0 or SBC_BASE1 is set to zero, the access
147 * to anywhere in the system bus space is routed to
148 * bank 0 (if boot swap if off) or bank 1 (if boot swap
149 * if on). It means that CPUs cannot get access to
150 * bank 2 or later. In other words, bank 0/1 cannot
151 * be disabled even if its bank_enable bits is cleared.
152 * This seems odd, but it is how this hardware goes.
153 * As a workaround, dummy data (0xffffffff) should be
154 * set when the bank 0/1 is unused. As for bank 2 and
155 * later, they can be simply disable by clearing the
159 val
= UNIPHIER_SBC_BASE_DUMMY
;
163 mask
= base
^ (end
- 1);
165 val
= base
& 0xfffe0000;
166 val
|= (~mask
>> 16) & 0xfffe;
167 val
|= UNIPHIER_SBC_BASE_BE
;
169 dev_dbg(priv
->dev
, "SBC_BASE[%d] = 0x%08x\n", i
, val
);
171 writel(val
, base_reg
+ UNIPHIER_SBC_STRIDE
* i
);
175 static int uniphier_system_bus_probe(struct platform_device
*pdev
)
177 struct device
*dev
= &pdev
->dev
;
178 struct uniphier_system_bus_priv
*priv
;
179 struct resource
*regs
;
180 const __be32
*ranges
;
181 u32 cells
, addr
, size
;
183 int pna
, bank
, rlen
, rone
, ret
;
185 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
189 regs
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
190 priv
->membase
= devm_ioremap_resource(dev
, regs
);
191 if (IS_ERR(priv
->membase
))
192 return PTR_ERR(priv
->membase
);
196 pna
= of_n_addr_cells(dev
->of_node
);
198 ret
= of_property_read_u32(dev
->of_node
, "#address-cells", &cells
);
200 dev_err(dev
, "failed to get #address-cells\n");
204 dev_err(dev
, "#address-cells must be 2\n");
208 ret
= of_property_read_u32(dev
->of_node
, "#size-cells", &cells
);
210 dev_err(dev
, "failed to get #size-cells\n");
214 dev_err(dev
, "#size-cells must be 1\n");
218 ranges
= of_get_property(dev
->of_node
, "ranges", &rlen
);
220 dev_err(dev
, "failed to get ranges property\n");
224 rlen
/= sizeof(*ranges
);
227 for (; rlen
>= rone
; rlen
-= rone
) {
228 bank
= be32_to_cpup(ranges
++);
229 addr
= be32_to_cpup(ranges
++);
230 paddr
= of_translate_address(dev
->of_node
, ranges
);
231 if (paddr
== OF_BAD_ADDR
)
234 size
= be32_to_cpup(ranges
++);
236 ret
= uniphier_system_bus_add_bank(priv
, bank
, addr
,
242 ret
= uniphier_system_bus_check_overlap(priv
);
246 uniphier_system_bus_check_boot_swap(priv
);
248 uniphier_system_bus_set_reg(priv
);
250 platform_set_drvdata(pdev
, priv
);
252 /* Now, the bus is configured. Populate platform_devices below it */
253 return of_platform_default_populate(dev
->of_node
, NULL
, dev
);
256 static int __maybe_unused
uniphier_system_bus_resume(struct device
*dev
)
258 uniphier_system_bus_set_reg(dev_get_drvdata(dev
));
263 static const struct dev_pm_ops uniphier_system_bus_pm_ops
= {
264 SET_SYSTEM_SLEEP_PM_OPS(NULL
, uniphier_system_bus_resume
)
267 static const struct of_device_id uniphier_system_bus_match
[] = {
268 { .compatible
= "socionext,uniphier-system-bus" },
271 MODULE_DEVICE_TABLE(of
, uniphier_system_bus_match
);
273 static struct platform_driver uniphier_system_bus_driver
= {
274 .probe
= uniphier_system_bus_probe
,
276 .name
= "uniphier-system-bus",
277 .of_match_table
= uniphier_system_bus_match
,
278 .pm
= &uniphier_system_bus_pm_ops
,
281 module_platform_driver(uniphier_system_bus_driver
);
283 MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
284 MODULE_DESCRIPTION("UniPhier System Bus driver");
285 MODULE_LICENSE("GPL");