xref: /openbmc/linux/drivers/bus/uniphier-system-bus.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
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