183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0
25f14f7d7SMarek Vasut /*
35f14f7d7SMarek Vasut * Renesas RCar Gen2 PCIEC driver
45f14f7d7SMarek Vasut *
55f14f7d7SMarek Vasut * Copyright (C) 2018 Marek Vasut <marek.vasut@gmail.com>
65f14f7d7SMarek Vasut */
75f14f7d7SMarek Vasut
85f14f7d7SMarek Vasut #include <common.h>
95f14f7d7SMarek Vasut #include <asm/io.h>
105f14f7d7SMarek Vasut #include <clk.h>
115f14f7d7SMarek Vasut #include <dm.h>
125f14f7d7SMarek Vasut #include <errno.h>
135f14f7d7SMarek Vasut #include <pci.h>
145f14f7d7SMarek Vasut
155f14f7d7SMarek Vasut /* AHB-PCI Bridge PCI communication registers */
165f14f7d7SMarek Vasut #define RCAR_AHBPCI_PCICOM_OFFSET 0x800
175f14f7d7SMarek Vasut
185f14f7d7SMarek Vasut #define RCAR_PCIAHB_WIN1_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x00)
195f14f7d7SMarek Vasut #define RCAR_PCIAHB_WIN2_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x04)
205f14f7d7SMarek Vasut #define RCAR_PCIAHB_PREFETCH0 0x0
215f14f7d7SMarek Vasut #define RCAR_PCIAHB_PREFETCH4 0x1
225f14f7d7SMarek Vasut #define RCAR_PCIAHB_PREFETCH8 0x2
235f14f7d7SMarek Vasut #define RCAR_PCIAHB_PREFETCH16 0x3
245f14f7d7SMarek Vasut
255f14f7d7SMarek Vasut #define RCAR_AHBPCI_WIN1_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x10)
265f14f7d7SMarek Vasut #define RCAR_AHBPCI_WIN2_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x14)
275f14f7d7SMarek Vasut #define RCAR_AHBPCI_WIN_CTR_MEM (3 << 1)
285f14f7d7SMarek Vasut #define RCAR_AHBPCI_WIN_CTR_CFG (5 << 1)
295f14f7d7SMarek Vasut #define RCAR_AHBPCI_WIN1_HOST BIT(30)
305f14f7d7SMarek Vasut #define RCAR_AHBPCI_WIN1_DEVICE BIT(31)
315f14f7d7SMarek Vasut
325f14f7d7SMarek Vasut #define RCAR_PCI_INT_ENABLE_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x20)
335f14f7d7SMarek Vasut #define RCAR_PCI_INT_STATUS_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x24)
345f14f7d7SMarek Vasut #define RCAR_PCI_INT_SIGTABORT BIT(0)
355f14f7d7SMarek Vasut #define RCAR_PCI_INT_SIGRETABORT BIT(1)
365f14f7d7SMarek Vasut #define RCAR_PCI_INT_REMABORT BIT(2)
375f14f7d7SMarek Vasut #define RCAR_PCI_INT_PERR BIT(3)
385f14f7d7SMarek Vasut #define RCAR_PCI_INT_SIGSERR BIT(4)
395f14f7d7SMarek Vasut #define RCAR_PCI_INT_RESERR BIT(5)
405f14f7d7SMarek Vasut #define RCAR_PCI_INT_WIN1ERR BIT(12)
415f14f7d7SMarek Vasut #define RCAR_PCI_INT_WIN2ERR BIT(13)
425f14f7d7SMarek Vasut #define RCAR_PCI_INT_A BIT(16)
435f14f7d7SMarek Vasut #define RCAR_PCI_INT_B BIT(17)
445f14f7d7SMarek Vasut #define RCAR_PCI_INT_PME BIT(19)
455f14f7d7SMarek Vasut #define RCAR_PCI_INT_ALLERRORS (RCAR_PCI_INT_SIGTABORT | \
465f14f7d7SMarek Vasut RCAR_PCI_INT_SIGRETABORT | \
475f14f7d7SMarek Vasut RCAR_PCI_INT_SIGRETABORT | \
485f14f7d7SMarek Vasut RCAR_PCI_INT_REMABORT | \
495f14f7d7SMarek Vasut RCAR_PCI_INT_PERR | \
505f14f7d7SMarek Vasut RCAR_PCI_INT_SIGSERR | \
515f14f7d7SMarek Vasut RCAR_PCI_INT_RESERR | \
525f14f7d7SMarek Vasut RCAR_PCI_INT_WIN1ERR | \
535f14f7d7SMarek Vasut RCAR_PCI_INT_WIN2ERR)
545f14f7d7SMarek Vasut
555f14f7d7SMarek Vasut #define RCAR_AHB_BUS_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x30)
565f14f7d7SMarek Vasut #define RCAR_AHB_BUS_MMODE_HTRANS BIT(0)
575f14f7d7SMarek Vasut #define RCAR_AHB_BUS_MMODE_BYTE_BURST BIT(1)
585f14f7d7SMarek Vasut #define RCAR_AHB_BUS_MMODE_WR_INCR BIT(2)
595f14f7d7SMarek Vasut #define RCAR_AHB_BUS_MMODE_HBUS_REQ BIT(7)
605f14f7d7SMarek Vasut #define RCAR_AHB_BUS_SMODE_READYCTR BIT(17)
615f14f7d7SMarek Vasut #define RCAR_AHB_BUS_MODE (RCAR_AHB_BUS_MMODE_HTRANS | \
625f14f7d7SMarek Vasut RCAR_AHB_BUS_MMODE_BYTE_BURST | \
635f14f7d7SMarek Vasut RCAR_AHB_BUS_MMODE_WR_INCR | \
645f14f7d7SMarek Vasut RCAR_AHB_BUS_MMODE_HBUS_REQ | \
655f14f7d7SMarek Vasut RCAR_AHB_BUS_SMODE_READYCTR)
665f14f7d7SMarek Vasut
675f14f7d7SMarek Vasut #define RCAR_USBCTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x34)
685f14f7d7SMarek Vasut #define RCAR_USBCTR_USBH_RST BIT(0)
695f14f7d7SMarek Vasut #define RCAR_USBCTR_PCICLK_MASK BIT(1)
705f14f7d7SMarek Vasut #define RCAR_USBCTR_PLL_RST BIT(2)
715f14f7d7SMarek Vasut #define RCAR_USBCTR_DIRPD BIT(8)
725f14f7d7SMarek Vasut #define RCAR_USBCTR_PCIAHB_WIN2_EN BIT(9)
735f14f7d7SMarek Vasut #define RCAR_USBCTR_PCIAHB_WIN1_256M (0 << 10)
745f14f7d7SMarek Vasut #define RCAR_USBCTR_PCIAHB_WIN1_512M (1 << 10)
755f14f7d7SMarek Vasut #define RCAR_USBCTR_PCIAHB_WIN1_1G (2 << 10)
765f14f7d7SMarek Vasut #define RCAR_USBCTR_PCIAHB_WIN1_2G (3 << 10)
775f14f7d7SMarek Vasut #define RCAR_USBCTR_PCIAHB_WIN1_MASK (3 << 10)
785f14f7d7SMarek Vasut
795f14f7d7SMarek Vasut #define RCAR_PCI_ARBITER_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x40)
805f14f7d7SMarek Vasut #define RCAR_PCI_ARBITER_PCIREQ0 BIT(0)
815f14f7d7SMarek Vasut #define RCAR_PCI_ARBITER_PCIREQ1 BIT(1)
825f14f7d7SMarek Vasut #define RCAR_PCI_ARBITER_PCIBP_MODE BIT(12)
835f14f7d7SMarek Vasut
845f14f7d7SMarek Vasut #define RCAR_PCI_UNIT_REV_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x48)
855f14f7d7SMarek Vasut
865f14f7d7SMarek Vasut struct rcar_gen2_pci_priv {
875f14f7d7SMarek Vasut fdt_addr_t cfg_base;
885f14f7d7SMarek Vasut fdt_addr_t mem_base;
895f14f7d7SMarek Vasut };
905f14f7d7SMarek Vasut
rcar_gen2_pci_addr_valid(pci_dev_t d,uint offset)915f14f7d7SMarek Vasut static int rcar_gen2_pci_addr_valid(pci_dev_t d, uint offset)
925f14f7d7SMarek Vasut {
935f14f7d7SMarek Vasut u32 slot;
945f14f7d7SMarek Vasut
955f14f7d7SMarek Vasut if (PCI_FUNC(d))
965f14f7d7SMarek Vasut return -EINVAL;
975f14f7d7SMarek Vasut
985f14f7d7SMarek Vasut /* Only one EHCI/OHCI device built-in */
995f14f7d7SMarek Vasut slot = PCI_DEV(d);
100*313360b1SMarek Vasut if (slot != 1 && slot != 2)
1015f14f7d7SMarek Vasut return -EINVAL;
1025f14f7d7SMarek Vasut
1035f14f7d7SMarek Vasut /* bridge logic only has registers to 0x40 */
1045f14f7d7SMarek Vasut if (slot == 0x0 && offset >= 0x40)
1055f14f7d7SMarek Vasut return -EINVAL;
1065f14f7d7SMarek Vasut
1075f14f7d7SMarek Vasut return 0;
1085f14f7d7SMarek Vasut }
1095f14f7d7SMarek Vasut
get_bus_address(struct udevice * dev,pci_dev_t bdf,u32 offset)1105f14f7d7SMarek Vasut static u32 get_bus_address(struct udevice *dev, pci_dev_t bdf, u32 offset)
1115f14f7d7SMarek Vasut {
1125f14f7d7SMarek Vasut struct rcar_gen2_pci_priv *priv = dev_get_priv(dev);
1135f14f7d7SMarek Vasut
1145f14f7d7SMarek Vasut return priv->cfg_base + (PCI_DEV(bdf) >> 1) * 0x100 + (offset & ~3);
1155f14f7d7SMarek Vasut }
1165f14f7d7SMarek Vasut
setup_bus_address(struct udevice * dev,pci_dev_t bdf,u32 offset)1175f14f7d7SMarek Vasut static u32 setup_bus_address(struct udevice *dev, pci_dev_t bdf, u32 offset)
1185f14f7d7SMarek Vasut {
1195f14f7d7SMarek Vasut struct rcar_gen2_pci_priv *priv = dev_get_priv(dev);
1205f14f7d7SMarek Vasut u32 reg;
1215f14f7d7SMarek Vasut
1225f14f7d7SMarek Vasut reg = PCI_DEV(bdf) ? RCAR_AHBPCI_WIN1_DEVICE : RCAR_AHBPCI_WIN1_HOST;
1235f14f7d7SMarek Vasut reg |= RCAR_AHBPCI_WIN_CTR_CFG;
1245f14f7d7SMarek Vasut writel(reg, priv->cfg_base + RCAR_AHBPCI_WIN1_CTR_REG);
1255f14f7d7SMarek Vasut
1265f14f7d7SMarek Vasut return get_bus_address(dev, bdf, offset);
1275f14f7d7SMarek Vasut }
1285f14f7d7SMarek Vasut
rcar_gen2_pci_read_config(struct udevice * dev,pci_dev_t bdf,uint offset,ulong * value,enum pci_size_t size)1295f14f7d7SMarek Vasut static int rcar_gen2_pci_read_config(struct udevice *dev, pci_dev_t bdf,
1305f14f7d7SMarek Vasut uint offset, ulong *value,
1315f14f7d7SMarek Vasut enum pci_size_t size)
1325f14f7d7SMarek Vasut {
1335f14f7d7SMarek Vasut u32 addr, reg;
1345f14f7d7SMarek Vasut int ret;
1355f14f7d7SMarek Vasut
1365f14f7d7SMarek Vasut ret = rcar_gen2_pci_addr_valid(bdf, offset);
1375f14f7d7SMarek Vasut if (ret) {
1385f14f7d7SMarek Vasut *value = pci_get_ff(size);
1395f14f7d7SMarek Vasut return 0;
1405f14f7d7SMarek Vasut }
1415f14f7d7SMarek Vasut
1425f14f7d7SMarek Vasut addr = get_bus_address(dev, bdf, offset);
1435f14f7d7SMarek Vasut reg = readl(addr);
1445f14f7d7SMarek Vasut *value = pci_conv_32_to_size(reg, offset, size);
1455f14f7d7SMarek Vasut
1465f14f7d7SMarek Vasut return 0;
1475f14f7d7SMarek Vasut }
1485f14f7d7SMarek Vasut
rcar_gen2_pci_write_config(struct udevice * dev,pci_dev_t bdf,uint offset,ulong value,enum pci_size_t size)1495f14f7d7SMarek Vasut static int rcar_gen2_pci_write_config(struct udevice *dev, pci_dev_t bdf,
1505f14f7d7SMarek Vasut uint offset, ulong value,
1515f14f7d7SMarek Vasut enum pci_size_t size)
1525f14f7d7SMarek Vasut {
1535f14f7d7SMarek Vasut u32 addr, reg, old;
1545f14f7d7SMarek Vasut int ret;
1555f14f7d7SMarek Vasut
1565f14f7d7SMarek Vasut ret = rcar_gen2_pci_addr_valid(bdf, offset);
1575f14f7d7SMarek Vasut if (ret)
1585f14f7d7SMarek Vasut return ret;
1595f14f7d7SMarek Vasut
1605f14f7d7SMarek Vasut addr = get_bus_address(dev, bdf, offset);
1615f14f7d7SMarek Vasut
1625f14f7d7SMarek Vasut old = readl(addr);
1635f14f7d7SMarek Vasut reg = pci_conv_size_to_32(old, value, offset, size);
1645f14f7d7SMarek Vasut writel(reg, addr);
1655f14f7d7SMarek Vasut
1665f14f7d7SMarek Vasut return 0;
1675f14f7d7SMarek Vasut }
1685f14f7d7SMarek Vasut
rcar_gen2_pci_probe(struct udevice * dev)1695f14f7d7SMarek Vasut static int rcar_gen2_pci_probe(struct udevice *dev)
1705f14f7d7SMarek Vasut {
1715f14f7d7SMarek Vasut struct rcar_gen2_pci_priv *priv = dev_get_priv(dev);
1725f14f7d7SMarek Vasut struct clk pci_clk;
1735f14f7d7SMarek Vasut u32 devad;
1745f14f7d7SMarek Vasut int ret;
1755f14f7d7SMarek Vasut
1765f14f7d7SMarek Vasut ret = clk_get_by_index(dev, 0, &pci_clk);
1775f14f7d7SMarek Vasut if (ret)
1785f14f7d7SMarek Vasut return ret;
1795f14f7d7SMarek Vasut
1805f14f7d7SMarek Vasut ret = clk_enable(&pci_clk);
1815f14f7d7SMarek Vasut if (ret)
1825f14f7d7SMarek Vasut return ret;
1835f14f7d7SMarek Vasut
1845f14f7d7SMarek Vasut /* Clock & Reset & Direct Power Down */
1855f14f7d7SMarek Vasut clrsetbits_le32(priv->cfg_base + RCAR_USBCTR_REG,
1865f14f7d7SMarek Vasut RCAR_USBCTR_DIRPD | RCAR_USBCTR_PCICLK_MASK |
1875f14f7d7SMarek Vasut RCAR_USBCTR_USBH_RST,
1885f14f7d7SMarek Vasut RCAR_USBCTR_PCIAHB_WIN1_1G);
1895f14f7d7SMarek Vasut clrbits_le32(priv->cfg_base + RCAR_USBCTR_REG, RCAR_USBCTR_PLL_RST);
1905f14f7d7SMarek Vasut
1915f14f7d7SMarek Vasut /* AHB-PCI Bridge Communication Registers */
1925f14f7d7SMarek Vasut writel(RCAR_AHB_BUS_MODE, priv->cfg_base + RCAR_AHB_BUS_CTR_REG);
1935f14f7d7SMarek Vasut writel((CONFIG_SYS_SDRAM_BASE & 0xf0000000) | RCAR_PCIAHB_PREFETCH16,
1945f14f7d7SMarek Vasut priv->cfg_base + RCAR_PCIAHB_WIN1_CTR_REG);
1955f14f7d7SMarek Vasut writel(0xf0000000 | RCAR_PCIAHB_PREFETCH16,
1965f14f7d7SMarek Vasut priv->cfg_base + RCAR_PCIAHB_WIN2_CTR_REG);
1975f14f7d7SMarek Vasut writel(priv->mem_base | RCAR_AHBPCI_WIN_CTR_MEM,
1985f14f7d7SMarek Vasut priv->cfg_base + RCAR_AHBPCI_WIN2_CTR_REG);
1995f14f7d7SMarek Vasut setbits_le32(priv->cfg_base + RCAR_PCI_ARBITER_CTR_REG,
2005f14f7d7SMarek Vasut RCAR_PCI_ARBITER_PCIREQ0 | RCAR_PCI_ARBITER_PCIREQ1 |
2015f14f7d7SMarek Vasut RCAR_PCI_ARBITER_PCIBP_MODE);
2025f14f7d7SMarek Vasut
2035f14f7d7SMarek Vasut /* PCI Configuration Registers for AHBPCI */
2045f14f7d7SMarek Vasut devad = setup_bus_address(dev, PCI_BDF(0, 0, 0), 0);
2055f14f7d7SMarek Vasut writel(priv->cfg_base + 0x800, devad + PCI_BASE_ADDRESS_0);
2065f14f7d7SMarek Vasut writel(CONFIG_SYS_SDRAM_BASE & 0xf0000000, devad + PCI_BASE_ADDRESS_1);
2075f14f7d7SMarek Vasut writel(0xf0000000, devad + PCI_BASE_ADDRESS_2);
2085f14f7d7SMarek Vasut writel(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
2095f14f7d7SMarek Vasut PCI_COMMAND_PARITY | PCI_COMMAND_SERR,
2105f14f7d7SMarek Vasut devad + PCI_COMMAND);
2115f14f7d7SMarek Vasut
2125f14f7d7SMarek Vasut /* PCI Configuration Registers for OHCI */
2135f14f7d7SMarek Vasut devad = setup_bus_address(dev, PCI_BDF(0, 1, 0), 0);
2145f14f7d7SMarek Vasut writel(priv->mem_base + 0x0, devad + PCI_BASE_ADDRESS_0);
2155f14f7d7SMarek Vasut writel(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
2165f14f7d7SMarek Vasut PCI_COMMAND_PARITY | PCI_COMMAND_SERR,
2175f14f7d7SMarek Vasut devad + PCI_COMMAND);
2185f14f7d7SMarek Vasut
2195f14f7d7SMarek Vasut /* PCI Configuration Registers for EHCI */
2205f14f7d7SMarek Vasut devad = setup_bus_address(dev, PCI_BDF(0, 2, 0), 0);
2215f14f7d7SMarek Vasut writel(priv->mem_base + 0x1000, devad + PCI_BASE_ADDRESS_0);
2225f14f7d7SMarek Vasut writel(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
2235f14f7d7SMarek Vasut PCI_COMMAND_PARITY | PCI_COMMAND_SERR,
2245f14f7d7SMarek Vasut devad + PCI_COMMAND);
2255f14f7d7SMarek Vasut
2265f14f7d7SMarek Vasut /* Enable PCI interrupt */
2275f14f7d7SMarek Vasut setbits_le32(priv->cfg_base + RCAR_PCI_INT_ENABLE_REG,
2285f14f7d7SMarek Vasut RCAR_PCI_INT_A | RCAR_PCI_INT_B | RCAR_PCI_INT_PME);
2295f14f7d7SMarek Vasut
2305f14f7d7SMarek Vasut return 0;
2315f14f7d7SMarek Vasut }
2325f14f7d7SMarek Vasut
rcar_gen2_pci_ofdata_to_platdata(struct udevice * dev)2335f14f7d7SMarek Vasut static int rcar_gen2_pci_ofdata_to_platdata(struct udevice *dev)
2345f14f7d7SMarek Vasut {
2355f14f7d7SMarek Vasut struct rcar_gen2_pci_priv *priv = dev_get_priv(dev);
2365f14f7d7SMarek Vasut
2375f14f7d7SMarek Vasut priv->cfg_base = devfdt_get_addr_index(dev, 0);
2385f14f7d7SMarek Vasut priv->mem_base = devfdt_get_addr_index(dev, 1);
2395f14f7d7SMarek Vasut if (!priv->cfg_base || !priv->mem_base)
2405f14f7d7SMarek Vasut return -EINVAL;
2415f14f7d7SMarek Vasut
2425f14f7d7SMarek Vasut return 0;
2435f14f7d7SMarek Vasut }
2445f14f7d7SMarek Vasut
2455f14f7d7SMarek Vasut static const struct dm_pci_ops rcar_gen2_pci_ops = {
2465f14f7d7SMarek Vasut .read_config = rcar_gen2_pci_read_config,
2475f14f7d7SMarek Vasut .write_config = rcar_gen2_pci_write_config,
2485f14f7d7SMarek Vasut };
2495f14f7d7SMarek Vasut
2505f14f7d7SMarek Vasut static const struct udevice_id rcar_gen2_pci_ids[] = {
2515f14f7d7SMarek Vasut { .compatible = "renesas,pci-rcar-gen2" },
2525f14f7d7SMarek Vasut { }
2535f14f7d7SMarek Vasut };
2545f14f7d7SMarek Vasut
2555f14f7d7SMarek Vasut U_BOOT_DRIVER(rcar_gen2_pci) = {
2565f14f7d7SMarek Vasut .name = "rcar_gen2_pci",
2575f14f7d7SMarek Vasut .id = UCLASS_PCI,
2585f14f7d7SMarek Vasut .of_match = rcar_gen2_pci_ids,
2595f14f7d7SMarek Vasut .ops = &rcar_gen2_pci_ops,
2605f14f7d7SMarek Vasut .probe = rcar_gen2_pci_probe,
2615f14f7d7SMarek Vasut .ofdata_to_platdata = rcar_gen2_pci_ofdata_to_platdata,
2625f14f7d7SMarek Vasut .priv_auto_alloc_size = sizeof(struct rcar_gen2_pci_priv),
2635f14f7d7SMarek Vasut };
264