1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
24b7f48d3SMasahiro Yamada /*
34b7f48d3SMasahiro Yamada * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
44b7f48d3SMasahiro Yamada */
54b7f48d3SMasahiro Yamada
64b7f48d3SMasahiro Yamada #include <linux/io.h>
74b7f48d3SMasahiro Yamada #include <linux/log2.h>
84b7f48d3SMasahiro Yamada #include <linux/module.h>
94b7f48d3SMasahiro Yamada #include <linux/of.h>
104b7f48d3SMasahiro Yamada #include <linux/of_address.h>
114b7f48d3SMasahiro Yamada #include <linux/of_platform.h>
124b7f48d3SMasahiro Yamada #include <linux/platform_device.h>
134b7f48d3SMasahiro Yamada
144b7f48d3SMasahiro Yamada /* System Bus Controller registers */
154b7f48d3SMasahiro Yamada #define UNIPHIER_SBC_BASE 0x100 /* base address of bank0 space */
164b7f48d3SMasahiro Yamada #define UNIPHIER_SBC_BASE_BE BIT(0) /* bank_enable */
174b7f48d3SMasahiro Yamada #define UNIPHIER_SBC_CTRL0 0x200 /* timing parameter 0 of bank0 */
184b7f48d3SMasahiro Yamada #define UNIPHIER_SBC_CTRL1 0x204 /* timing parameter 1 of bank0 */
194b7f48d3SMasahiro Yamada #define UNIPHIER_SBC_CTRL2 0x208 /* timing parameter 2 of bank0 */
204b7f48d3SMasahiro Yamada #define UNIPHIER_SBC_CTRL3 0x20c /* timing parameter 3 of bank0 */
214b7f48d3SMasahiro Yamada #define UNIPHIER_SBC_CTRL4 0x300 /* timing parameter 4 of bank0 */
224b7f48d3SMasahiro Yamada
234b7f48d3SMasahiro Yamada #define UNIPHIER_SBC_STRIDE 0x10 /* register stride to next bank */
244b7f48d3SMasahiro Yamada #define UNIPHIER_SBC_NR_BANKS 8 /* number of banks (chip select) */
254b7f48d3SMasahiro Yamada #define UNIPHIER_SBC_BASE_DUMMY 0xffffffff /* data to squash bank 0, 1 */
264b7f48d3SMasahiro Yamada
274b7f48d3SMasahiro Yamada struct uniphier_system_bus_bank {
284b7f48d3SMasahiro Yamada u32 base;
294b7f48d3SMasahiro Yamada u32 end;
304b7f48d3SMasahiro Yamada };
314b7f48d3SMasahiro Yamada
324b7f48d3SMasahiro Yamada struct uniphier_system_bus_priv {
334b7f48d3SMasahiro Yamada struct device *dev;
344b7f48d3SMasahiro Yamada void __iomem *membase;
354b7f48d3SMasahiro Yamada struct uniphier_system_bus_bank bank[UNIPHIER_SBC_NR_BANKS];
364b7f48d3SMasahiro Yamada };
374b7f48d3SMasahiro Yamada
uniphier_system_bus_add_bank(struct uniphier_system_bus_priv * priv,int bank,u32 addr,u64 paddr,u32 size)384b7f48d3SMasahiro Yamada static int uniphier_system_bus_add_bank(struct uniphier_system_bus_priv *priv,
394b7f48d3SMasahiro Yamada int bank, u32 addr, u64 paddr, u32 size)
404b7f48d3SMasahiro Yamada {
414b7f48d3SMasahiro Yamada u64 end, mask;
424b7f48d3SMasahiro Yamada
434b7f48d3SMasahiro Yamada dev_dbg(priv->dev,
444b7f48d3SMasahiro Yamada "range found: bank = %d, addr = %08x, paddr = %08llx, size = %08x\n",
454b7f48d3SMasahiro Yamada bank, addr, paddr, size);
464b7f48d3SMasahiro Yamada
474b7f48d3SMasahiro Yamada if (bank >= ARRAY_SIZE(priv->bank)) {
484b7f48d3SMasahiro Yamada dev_err(priv->dev, "unsupported bank number %d\n", bank);
494b7f48d3SMasahiro Yamada return -EINVAL;
504b7f48d3SMasahiro Yamada }
514b7f48d3SMasahiro Yamada
524b7f48d3SMasahiro Yamada if (priv->bank[bank].base || priv->bank[bank].end) {
534b7f48d3SMasahiro Yamada dev_err(priv->dev,
544b7f48d3SMasahiro Yamada "range for bank %d has already been specified\n", bank);
554b7f48d3SMasahiro Yamada return -EINVAL;
564b7f48d3SMasahiro Yamada }
574b7f48d3SMasahiro Yamada
584b7f48d3SMasahiro Yamada if (paddr > U32_MAX) {
594b7f48d3SMasahiro Yamada dev_err(priv->dev, "base address %llx is too high\n", paddr);
604b7f48d3SMasahiro Yamada return -EINVAL;
614b7f48d3SMasahiro Yamada }
624b7f48d3SMasahiro Yamada
634b7f48d3SMasahiro Yamada end = paddr + size;
644b7f48d3SMasahiro Yamada
654b7f48d3SMasahiro Yamada if (addr > paddr) {
664b7f48d3SMasahiro Yamada dev_err(priv->dev,
674b7f48d3SMasahiro Yamada "base %08x cannot be mapped to %08llx of parent\n",
684b7f48d3SMasahiro Yamada addr, paddr);
694b7f48d3SMasahiro Yamada return -EINVAL;
704b7f48d3SMasahiro Yamada }
714b7f48d3SMasahiro Yamada paddr -= addr;
724b7f48d3SMasahiro Yamada
734b7f48d3SMasahiro Yamada paddr = round_down(paddr, 0x00020000);
744b7f48d3SMasahiro Yamada end = round_up(end, 0x00020000);
754b7f48d3SMasahiro Yamada
764b7f48d3SMasahiro Yamada if (end > U32_MAX) {
774b7f48d3SMasahiro Yamada dev_err(priv->dev, "end address %08llx is too high\n", end);
784b7f48d3SMasahiro Yamada return -EINVAL;
794b7f48d3SMasahiro Yamada }
804b7f48d3SMasahiro Yamada mask = paddr ^ (end - 1);
814b7f48d3SMasahiro Yamada mask = roundup_pow_of_two(mask);
824b7f48d3SMasahiro Yamada
834b7f48d3SMasahiro Yamada paddr = round_down(paddr, mask);
844b7f48d3SMasahiro Yamada end = round_up(end, mask);
854b7f48d3SMasahiro Yamada
864b7f48d3SMasahiro Yamada priv->bank[bank].base = paddr;
874b7f48d3SMasahiro Yamada priv->bank[bank].end = end;
884b7f48d3SMasahiro Yamada
894b7f48d3SMasahiro Yamada dev_dbg(priv->dev, "range added: bank = %d, addr = %08x, end = %08x\n",
904b7f48d3SMasahiro Yamada bank, priv->bank[bank].base, priv->bank[bank].end);
914b7f48d3SMasahiro Yamada
924b7f48d3SMasahiro Yamada return 0;
934b7f48d3SMasahiro Yamada }
944b7f48d3SMasahiro Yamada
uniphier_system_bus_check_overlap(const struct uniphier_system_bus_priv * priv)954b7f48d3SMasahiro Yamada static int uniphier_system_bus_check_overlap(
964b7f48d3SMasahiro Yamada const struct uniphier_system_bus_priv *priv)
974b7f48d3SMasahiro Yamada {
984b7f48d3SMasahiro Yamada int i, j;
994b7f48d3SMasahiro Yamada
1004b7f48d3SMasahiro Yamada for (i = 0; i < ARRAY_SIZE(priv->bank); i++) {
1014b7f48d3SMasahiro Yamada for (j = i + 1; j < ARRAY_SIZE(priv->bank); j++) {
1023de7beebSKunihiko Hayashi if (priv->bank[i].end > priv->bank[j].base &&
1034b7f48d3SMasahiro Yamada priv->bank[i].base < priv->bank[j].end) {
1044b7f48d3SMasahiro Yamada dev_err(priv->dev,
1054b7f48d3SMasahiro Yamada "region overlap between bank%d and bank%d\n",
1064b7f48d3SMasahiro Yamada i, j);
1074b7f48d3SMasahiro Yamada return -EINVAL;
1084b7f48d3SMasahiro Yamada }
1094b7f48d3SMasahiro Yamada }
1104b7f48d3SMasahiro Yamada }
1114b7f48d3SMasahiro Yamada
1124b7f48d3SMasahiro Yamada return 0;
1134b7f48d3SMasahiro Yamada }
1144b7f48d3SMasahiro Yamada
uniphier_system_bus_check_boot_swap(struct uniphier_system_bus_priv * priv)1154b7f48d3SMasahiro Yamada static void uniphier_system_bus_check_boot_swap(
1164b7f48d3SMasahiro Yamada struct uniphier_system_bus_priv *priv)
1174b7f48d3SMasahiro Yamada {
1184b7f48d3SMasahiro Yamada void __iomem *base_reg = priv->membase + UNIPHIER_SBC_BASE;
1194b7f48d3SMasahiro Yamada int is_swapped;
1204b7f48d3SMasahiro Yamada
1214b7f48d3SMasahiro Yamada is_swapped = !(readl(base_reg) & UNIPHIER_SBC_BASE_BE);
1224b7f48d3SMasahiro Yamada
1234b7f48d3SMasahiro Yamada dev_dbg(priv->dev, "Boot Swap: %s\n", is_swapped ? "on" : "off");
1244b7f48d3SMasahiro Yamada
1254b7f48d3SMasahiro Yamada /*
1264b7f48d3SMasahiro Yamada * If BOOT_SWAP was asserted on power-on-reset, the CS0 and CS1 are
1274b7f48d3SMasahiro Yamada * swapped. In this case, bank0 and bank1 should be swapped as well.
1284b7f48d3SMasahiro Yamada */
1294b7f48d3SMasahiro Yamada if (is_swapped)
1304b7f48d3SMasahiro Yamada swap(priv->bank[0], priv->bank[1]);
1314b7f48d3SMasahiro Yamada }
1324b7f48d3SMasahiro Yamada
uniphier_system_bus_set_reg(const struct uniphier_system_bus_priv * priv)1334b7f48d3SMasahiro Yamada static void uniphier_system_bus_set_reg(
1344b7f48d3SMasahiro Yamada const struct uniphier_system_bus_priv *priv)
1354b7f48d3SMasahiro Yamada {
1364b7f48d3SMasahiro Yamada void __iomem *base_reg = priv->membase + UNIPHIER_SBC_BASE;
1374b7f48d3SMasahiro Yamada u32 base, end, mask, val;
1384b7f48d3SMasahiro Yamada int i;
1394b7f48d3SMasahiro Yamada
1404b7f48d3SMasahiro Yamada for (i = 0; i < ARRAY_SIZE(priv->bank); i++) {
1414b7f48d3SMasahiro Yamada base = priv->bank[i].base;
1424b7f48d3SMasahiro Yamada end = priv->bank[i].end;
1434b7f48d3SMasahiro Yamada
1444b7f48d3SMasahiro Yamada if (base == end) {
1454b7f48d3SMasahiro Yamada /*
1464b7f48d3SMasahiro Yamada * If SBC_BASE0 or SBC_BASE1 is set to zero, the access
1474b7f48d3SMasahiro Yamada * to anywhere in the system bus space is routed to
1484b7f48d3SMasahiro Yamada * bank 0 (if boot swap if off) or bank 1 (if boot swap
1494b7f48d3SMasahiro Yamada * if on). It means that CPUs cannot get access to
1504b7f48d3SMasahiro Yamada * bank 2 or later. In other words, bank 0/1 cannot
1514b7f48d3SMasahiro Yamada * be disabled even if its bank_enable bits is cleared.
1524b7f48d3SMasahiro Yamada * This seems odd, but it is how this hardware goes.
1534b7f48d3SMasahiro Yamada * As a workaround, dummy data (0xffffffff) should be
1544b7f48d3SMasahiro Yamada * set when the bank 0/1 is unused. As for bank 2 and
1554b7f48d3SMasahiro Yamada * later, they can be simply disable by clearing the
1564b7f48d3SMasahiro Yamada * bank_enable bit.
1574b7f48d3SMasahiro Yamada */
1584b7f48d3SMasahiro Yamada if (i < 2)
1594b7f48d3SMasahiro Yamada val = UNIPHIER_SBC_BASE_DUMMY;
1604b7f48d3SMasahiro Yamada else
1614b7f48d3SMasahiro Yamada val = 0;
1624b7f48d3SMasahiro Yamada } else {
1634b7f48d3SMasahiro Yamada mask = base ^ (end - 1);
1644b7f48d3SMasahiro Yamada
1654b7f48d3SMasahiro Yamada val = base & 0xfffe0000;
1664b7f48d3SMasahiro Yamada val |= (~mask >> 16) & 0xfffe;
1674b7f48d3SMasahiro Yamada val |= UNIPHIER_SBC_BASE_BE;
1684b7f48d3SMasahiro Yamada }
1694b7f48d3SMasahiro Yamada dev_dbg(priv->dev, "SBC_BASE[%d] = 0x%08x\n", i, val);
1704b7f48d3SMasahiro Yamada
1714b7f48d3SMasahiro Yamada writel(val, base_reg + UNIPHIER_SBC_STRIDE * i);
1724b7f48d3SMasahiro Yamada }
1734b7f48d3SMasahiro Yamada }
1744b7f48d3SMasahiro Yamada
uniphier_system_bus_probe(struct platform_device * pdev)1754b7f48d3SMasahiro Yamada static int uniphier_system_bus_probe(struct platform_device *pdev)
1764b7f48d3SMasahiro Yamada {
1774b7f48d3SMasahiro Yamada struct device *dev = &pdev->dev;
1784b7f48d3SMasahiro Yamada struct uniphier_system_bus_priv *priv;
179*c12cc1bcSRob Herring struct of_range_parser parser;
180*c12cc1bcSRob Herring struct of_range range;
181*c12cc1bcSRob Herring int ret;
1824b7f48d3SMasahiro Yamada
1834b7f48d3SMasahiro Yamada priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
1844b7f48d3SMasahiro Yamada if (!priv)
1854b7f48d3SMasahiro Yamada return -ENOMEM;
1864b7f48d3SMasahiro Yamada
187ef92bfdaSMasahiro Yamada priv->membase = devm_platform_ioremap_resource(pdev, 0);
1884b7f48d3SMasahiro Yamada if (IS_ERR(priv->membase))
1894b7f48d3SMasahiro Yamada return PTR_ERR(priv->membase);
1904b7f48d3SMasahiro Yamada
1914b7f48d3SMasahiro Yamada priv->dev = dev;
1924b7f48d3SMasahiro Yamada
193*c12cc1bcSRob Herring ret = of_range_parser_init(&parser, dev->of_node);
194*c12cc1bcSRob Herring if (ret)
1954b7f48d3SMasahiro Yamada return ret;
196*c12cc1bcSRob Herring
197*c12cc1bcSRob Herring for_each_of_range(&parser, &range) {
198*c12cc1bcSRob Herring if (range.cpu_addr == OF_BAD_ADDR)
1994b7f48d3SMasahiro Yamada return -EINVAL;
200*c12cc1bcSRob Herring ret = uniphier_system_bus_add_bank(priv,
201*c12cc1bcSRob Herring upper_32_bits(range.bus_addr),
202*c12cc1bcSRob Herring lower_32_bits(range.bus_addr),
203*c12cc1bcSRob Herring range.cpu_addr, range.size);
2044b7f48d3SMasahiro Yamada if (ret)
2054b7f48d3SMasahiro Yamada return ret;
2064b7f48d3SMasahiro Yamada }
2074b7f48d3SMasahiro Yamada
2084b7f48d3SMasahiro Yamada ret = uniphier_system_bus_check_overlap(priv);
2094b7f48d3SMasahiro Yamada if (ret)
2104b7f48d3SMasahiro Yamada return ret;
2114b7f48d3SMasahiro Yamada
2124b7f48d3SMasahiro Yamada uniphier_system_bus_check_boot_swap(priv);
2134b7f48d3SMasahiro Yamada
2144b7f48d3SMasahiro Yamada uniphier_system_bus_set_reg(priv);
2154b7f48d3SMasahiro Yamada
2162f4233eeSMasahiro Yamada platform_set_drvdata(pdev, priv);
2172f4233eeSMasahiro Yamada
2184b7f48d3SMasahiro Yamada /* Now, the bus is configured. Populate platform_devices below it */
2192cf66924SKefeng Wang return of_platform_default_populate(dev->of_node, NULL, dev);
2204b7f48d3SMasahiro Yamada }
2214b7f48d3SMasahiro Yamada
uniphier_system_bus_resume(struct device * dev)2222f4233eeSMasahiro Yamada static int __maybe_unused uniphier_system_bus_resume(struct device *dev)
2232f4233eeSMasahiro Yamada {
2242f4233eeSMasahiro Yamada uniphier_system_bus_set_reg(dev_get_drvdata(dev));
2252f4233eeSMasahiro Yamada
2262f4233eeSMasahiro Yamada return 0;
2272f4233eeSMasahiro Yamada }
2282f4233eeSMasahiro Yamada
2292f4233eeSMasahiro Yamada static const struct dev_pm_ops uniphier_system_bus_pm_ops = {
2302f4233eeSMasahiro Yamada SET_SYSTEM_SLEEP_PM_OPS(NULL, uniphier_system_bus_resume)
2312f4233eeSMasahiro Yamada };
2322f4233eeSMasahiro Yamada
2334b7f48d3SMasahiro Yamada static const struct of_device_id uniphier_system_bus_match[] = {
2344b7f48d3SMasahiro Yamada { .compatible = "socionext,uniphier-system-bus" },
2354b7f48d3SMasahiro Yamada { /* sentinel */ }
2364b7f48d3SMasahiro Yamada };
2374b7f48d3SMasahiro Yamada MODULE_DEVICE_TABLE(of, uniphier_system_bus_match);
2384b7f48d3SMasahiro Yamada
2394b7f48d3SMasahiro Yamada static struct platform_driver uniphier_system_bus_driver = {
2404b7f48d3SMasahiro Yamada .probe = uniphier_system_bus_probe,
2414b7f48d3SMasahiro Yamada .driver = {
2424b7f48d3SMasahiro Yamada .name = "uniphier-system-bus",
2434b7f48d3SMasahiro Yamada .of_match_table = uniphier_system_bus_match,
2442f4233eeSMasahiro Yamada .pm = &uniphier_system_bus_pm_ops,
2454b7f48d3SMasahiro Yamada },
2464b7f48d3SMasahiro Yamada };
2474b7f48d3SMasahiro Yamada module_platform_driver(uniphier_system_bus_driver);
2484b7f48d3SMasahiro Yamada
2494b7f48d3SMasahiro Yamada MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
2504b7f48d3SMasahiro Yamada MODULE_DESCRIPTION("UniPhier System Bus driver");
2514b7f48d3SMasahiro Yamada MODULE_LICENSE("GPL");
252