252 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>4 */5 6#include <linux/io.h>7#include <linux/log2.h>8#include <linux/module.h>9#include <linux/of.h>10#include <linux/of_address.h>11#include <linux/of_platform.h>12#include <linux/platform_device.h>13 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 */22 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 */26 27struct uniphier_system_bus_bank {28 u32 base;29 u32 end;30};31 32struct uniphier_system_bus_priv {33 struct device *dev;34 void __iomem *membase;35 struct uniphier_system_bus_bank bank[UNIPHIER_SBC_NR_BANKS];36};37 38static int uniphier_system_bus_add_bank(struct uniphier_system_bus_priv *priv,39 int bank, u32 addr, u64 paddr, u32 size)40{41 u64 end, mask;42 43 dev_dbg(priv->dev,44 "range found: bank = %d, addr = %08x, paddr = %08llx, size = %08x\n",45 bank, addr, paddr, size);46 47 if (bank >= ARRAY_SIZE(priv->bank)) {48 dev_err(priv->dev, "unsupported bank number %d\n", bank);49 return -EINVAL;50 }51 52 if (priv->bank[bank].base || priv->bank[bank].end) {53 dev_err(priv->dev,54 "range for bank %d has already been specified\n", bank);55 return -EINVAL;56 }57 58 if (paddr > U32_MAX) {59 dev_err(priv->dev, "base address %llx is too high\n", paddr);60 return -EINVAL;61 }62 63 end = paddr + size;64 65 if (addr > paddr) {66 dev_err(priv->dev,67 "base %08x cannot be mapped to %08llx of parent\n",68 addr, paddr);69 return -EINVAL;70 }71 paddr -= addr;72 73 paddr = round_down(paddr, 0x00020000);74 end = round_up(end, 0x00020000);75 76 if (end > U32_MAX) {77 dev_err(priv->dev, "end address %08llx is too high\n", end);78 return -EINVAL;79 }80 mask = paddr ^ (end - 1);81 mask = roundup_pow_of_two(mask);82 83 paddr = round_down(paddr, mask);84 end = round_up(end, mask);85 86 priv->bank[bank].base = paddr;87 priv->bank[bank].end = end;88 89 dev_dbg(priv->dev, "range added: bank = %d, addr = %08x, end = %08x\n",90 bank, priv->bank[bank].base, priv->bank[bank].end);91 92 return 0;93}94 95static int uniphier_system_bus_check_overlap(96 const struct uniphier_system_bus_priv *priv)97{98 int i, j;99 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) {104 dev_err(priv->dev,105 "region overlap between bank%d and bank%d\n",106 i, j);107 return -EINVAL;108 }109 }110 }111 112 return 0;113}114 115static void uniphier_system_bus_check_boot_swap(116 struct uniphier_system_bus_priv *priv)117{118 void __iomem *base_reg = priv->membase + UNIPHIER_SBC_BASE;119 int is_swapped;120 121 is_swapped = !(readl(base_reg) & UNIPHIER_SBC_BASE_BE);122 123 dev_dbg(priv->dev, "Boot Swap: %s\n", is_swapped ? "on" : "off");124 125 /*126 * If BOOT_SWAP was asserted on power-on-reset, the CS0 and CS1 are127 * swapped. In this case, bank0 and bank1 should be swapped as well.128 */129 if (is_swapped)130 swap(priv->bank[0], priv->bank[1]);131}132 133static void uniphier_system_bus_set_reg(134 const struct uniphier_system_bus_priv *priv)135{136 void __iomem *base_reg = priv->membase + UNIPHIER_SBC_BASE;137 u32 base, end, mask, val;138 int i;139 140 for (i = 0; i < ARRAY_SIZE(priv->bank); i++) {141 base = priv->bank[i].base;142 end = priv->bank[i].end;143 144 if (base == end) {145 /*146 * If SBC_BASE0 or SBC_BASE1 is set to zero, the access147 * to anywhere in the system bus space is routed to148 * bank 0 (if boot swap if off) or bank 1 (if boot swap149 * if on). It means that CPUs cannot get access to150 * bank 2 or later. In other words, bank 0/1 cannot151 * 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 be154 * set when the bank 0/1 is unused. As for bank 2 and155 * later, they can be simply disable by clearing the156 * bank_enable bit.157 */158 if (i < 2)159 val = UNIPHIER_SBC_BASE_DUMMY;160 else161 val = 0;162 } else {163 mask = base ^ (end - 1);164 165 val = base & 0xfffe0000;166 val |= (~mask >> 16) & 0xfffe;167 val |= UNIPHIER_SBC_BASE_BE;168 }169 dev_dbg(priv->dev, "SBC_BASE[%d] = 0x%08x\n", i, val);170 171 writel(val, base_reg + UNIPHIER_SBC_STRIDE * i);172 }173}174 175static int uniphier_system_bus_probe(struct platform_device *pdev)176{177 struct device *dev = &pdev->dev;178 struct uniphier_system_bus_priv *priv;179 struct of_range_parser parser;180 struct of_range range;181 int ret;182 183 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);184 if (!priv)185 return -ENOMEM;186 187 priv->membase = devm_platform_ioremap_resource(pdev, 0);188 if (IS_ERR(priv->membase))189 return PTR_ERR(priv->membase);190 191 priv->dev = dev;192 193 ret = of_range_parser_init(&parser, dev->of_node);194 if (ret)195 return ret;196 197 for_each_of_range(&parser, &range) {198 if (range.cpu_addr == OF_BAD_ADDR)199 return -EINVAL;200 ret = uniphier_system_bus_add_bank(priv,201 upper_32_bits(range.bus_addr),202 lower_32_bits(range.bus_addr),203 range.cpu_addr, range.size);204 if (ret)205 return ret;206 }207 208 ret = uniphier_system_bus_check_overlap(priv);209 if (ret)210 return ret;211 212 uniphier_system_bus_check_boot_swap(priv);213 214 uniphier_system_bus_set_reg(priv);215 216 platform_set_drvdata(pdev, priv);217 218 /* Now, the bus is configured. Populate platform_devices below it */219 return of_platform_default_populate(dev->of_node, NULL, dev);220}221 222static int __maybe_unused uniphier_system_bus_resume(struct device *dev)223{224 uniphier_system_bus_set_reg(dev_get_drvdata(dev));225 226 return 0;227}228 229static const struct dev_pm_ops uniphier_system_bus_pm_ops = {230 SET_SYSTEM_SLEEP_PM_OPS(NULL, uniphier_system_bus_resume)231};232 233static const struct of_device_id uniphier_system_bus_match[] = {234 { .compatible = "socionext,uniphier-system-bus" },235 { /* sentinel */ }236};237MODULE_DEVICE_TABLE(of, uniphier_system_bus_match);238 239static struct platform_driver uniphier_system_bus_driver = {240 .probe = uniphier_system_bus_probe,241 .driver = {242 .name = "uniphier-system-bus",243 .of_match_table = uniphier_system_bus_match,244 .pm = &uniphier_system_bus_pm_ops,245 },246};247module_platform_driver(uniphier_system_bus_driver);248 249MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");250MODULE_DESCRIPTION("UniPhier System Bus driver");251MODULE_LICENSE("GPL");252