[U-Boot] [PATCH 0/4] add pcie/ahci for mt7623/bpi-r2

with this Patchseries i want to add ahci-support (sata) for bananapi-r2
pci-driver may support other devices too using mt2701 for pcie, but in first step pcie is only activated for mt7623 (dts)
Patches depend on hifsys-patches from ryder.lee:
https://patchwork.ozlabs.org/project/uboot/list/?series=121987
Frank Wunderlich (1): arm: dts: Add PCI-E controller for mt7623
Oleksandr Rybalko (3): ahci-pci: ASM1061 report wrong class, but support AHCI. ata: ahci: Don't forget to clear upper address regs. pci: mediatek: Add pci-driver for mt2701
arch/arm/dts/mt7623.dtsi | 108 +++++++++ drivers/ata/ahci-pci.c | 1 + drivers/ata/ahci.c | 9 +- drivers/pci/Kconfig | 6 + drivers/pci/Makefile | 1 + drivers/pci/pci-mt2701.c | 490 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 613 insertions(+), 2 deletions(-) create mode 100644 drivers/pci/pci-mt2701.c
-- 2.17.1

From: Oleksandr Rybalko ray@ddteam.net
Tested-by: Frank Wunderlich frank-w@public-files.de Signed-off-by: Frank Wunderlich frank-w@public-files.de Signed-off-by: Oleksandr Rybalko ray@ddteam.net --- drivers/ata/ahci-pci.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/ata/ahci-pci.c b/drivers/ata/ahci-pci.c index 1ca439d3fa..11ec98b56f 100644 --- a/drivers/ata/ahci-pci.c +++ b/drivers/ata/ahci-pci.c @@ -35,6 +35,7 @@ U_BOOT_DRIVER(ahci_pci) = {
static struct pci_device_id ahci_pci_supported[] = { { PCI_DEVICE_CLASS(PCI_CLASS_STORAGE_SATA_AHCI, ~0) }, + { PCI_DEVICE(0x1b21, 0x0611) }, {}, };
-- 2.17.1

From: Oleksandr Rybalko ray@ddteam.net
In 32bits mode upper bits need to be set to 0, otherwise controller will try to DMA into not existing memory and stops with error.
Tested-by: Frank Wunderlich frank-w@public-files.de Signed-off-by: Frank Wunderlich frank-w@public-files.de Signed-off-by: Oleksandr Rybalko ray@ddteam.net --- drivers/ata/ahci.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index e3135bb75f..716f9c1c7e 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -593,10 +593,15 @@ static int ahci_port_start(struct ahci_uc_priv *uc_priv, u8 port) pp->cmd_tbl_sg = (struct ahci_sg *)(uintptr_t)virt_to_phys((void *)mem);
- writel_with_flush((unsigned long)pp->cmd_slot, - port_mmio + PORT_LST_ADDR); + writel_with_flush((u32)pp->cmd_slot, port_mmio + PORT_LST_ADDR); +#ifndef CONFIG_PHYS_64BIT + writel_with_flush(0, port_mmio + PORT_LST_ADDR_HI); +#endif
writel_with_flush(pp->rx_fis, port_mmio + PORT_FIS_ADDR); +#ifndef CONFIG_PHYS_64BIT + writel_with_flush(0, port_mmio + PORT_FIS_ADDR_HI); +#endif
#ifdef CONFIG_SUNXI_AHCI sunxi_dma_init(port_mmio); -- 2.17.1

From: Oleksandr Rybalko ray@ddteam.net
this chip is used in MT7623 and some other Mediatek SoCs for pcie
Tested-by: Frank Wunderlich frank-w@public-files.de Signed-off-by: Frank Wunderlich frank-w@public-files.de Signed-off-by: Oleksandr Rybalko ray@ddteam.net --- drivers/pci/Kconfig | 6 + drivers/pci/Makefile | 1 + drivers/pci/pci-mt2701.c | 490 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 497 insertions(+) create mode 100644 drivers/pci/pci-mt2701.c
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 3fe38f7315..cfe8ba5e52 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -145,4 +145,10 @@ config PCI_MVEBU Say Y here if you want to enable PCIe controller support on Armada XP/38x SoCs.
+config PCIE_MT2701 + bool "Mediatek 2701 PCI-E" + help + Say Y here if you want to enable PCIe controller support on + Mediatek MT7623 + endif diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index b5ebd50c85..a4c4002b9c 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -38,3 +38,4 @@ obj-$(CONFIG_PCIE_LAYERSCAPE_GEN4) += pcie_layerscape_gen4.o \ pcie_layerscape_gen4_fixup.o obj-$(CONFIG_PCI_XILINX) += pcie_xilinx.o obj-$(CONFIG_PCIE_INTEL_FPGA) += pcie_intel_fpga.o +obj-$(CONFIG_PCIE_MT2701) += pci-mt2701.o diff --git a/drivers/pci/pci-mt2701.c b/drivers/pci/pci-mt2701.c new file mode 100644 index 0000000000..5904f15330 --- /dev/null +++ b/drivers/pci/pci-mt2701.c @@ -0,0 +1,490 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Mediatek MT7623 SoC PCIE support + * + * Copyright (C) 2015 Mediatek + * Copyright (C) 2015 John Crispin blogic@openwrt.org + * Copyright (C) 2015 Ziv Huang ziv.huang@mediatek.com + * Copyright (C) 2019 Oleksandr Rybalko ray@ddteam.net + */ + +#include <common.h> +#include <malloc.h> + +#include <pci.h> +#include <asm/io.h> + +#include <dm.h> +#include <fdtdec.h> +#include <linux/libfdt.h> +#include <dm/lists.h> + +#define iowrite32(v, a) writel(v, a) +#define iowrite16(v, a) writew(v, a) +#define iowrite8(v, a) writeb(v, a) +#define ioread32(a) readl(a) +#define ioread16(a) readw(a) +#define ioread8(a) readb(a) + +#define RT_HIFSYS_BASE 0x1a000000 +#define RT_PCIE_BASE 0x1a140000 +#define RT_PCIE_IOWIN_BASE 0x1a160000 +#define RT_PCIE_IOWIN_SIZE 0x00010000 +#define RT_PCIE_MEMWIN_BASE 0x60000000 +#define RT_PCIE_MEMWIN_SIZE 0x10000000 + +#define RD(x) readl(RT_PCIE_BASE | (x)) +#define WR(x, v) writel(v, RT_PCIE_BASE | (x)) + +#define SYSCFG1 0x14 +#define RSTCTL 0x34 +#define RSTSTAT 0x38 +#define PCICFG 0x00 +#define PCIINT 0x08 +#define PCIENA 0x0c +#define CFGADDR 0x20 +#define CFGDATA 0x24 +#define MEMBASE 0x28 +#define IOBASE 0x2c + +#define BAR0SETUP 0x10 +#define IMBASEBAR0 0x18 +#define PCIE_CLASS 0x34 +#define PCIE_SISTAT 0x50 + +#define MTK_PCIE_HIGH_PERF BIT(14) +#define PCIEP0_BASE 0x2000 +#define PCIEP1_BASE 0x3000 +#define PCIEP2_BASE 0x4000 + +#define PHY_P0_CTL 0x9000 +#define PHY_P1_CTL 0xa000 +#define PHY_P2_CTL 0x4000 /* in USB space */ + +#define RSTCTL_PCIE0_RST BIT(24) +#define RSTCTL_PCIE1_RST BIT(25) +#define RSTCTL_PCIE2_RST BIT(26) +#define MAX_PORT_NUM 3 + +struct resource { + char *name; + u32 start; + u32 end; +}; + +struct mt_pcie { + char name[16]; +}; + +static struct mtk_pcie_port { + int id; + int enable; + u32 base; + u32 phy_base; + u32 perst_n; + u32 reset; + u32 interrupt_en; + int irq; + u32 link; +} mtk_pcie_port[] = { + { 0, 1, PCIEP0_BASE, PHY_P0_CTL, BIT(1), RSTCTL_PCIE0_RST, BIT(20) }, + { 1, 1, PCIEP1_BASE, PHY_P1_CTL, BIT(2), RSTCTL_PCIE1_RST, BIT(21) }, + { 2, 0, PCIEP2_BASE, PHY_P2_CTL, BIT(3), RSTCTL_PCIE2_RST, BIT(22) }, +}; + +struct mtk_pcie { + struct device *dev; + void __iomem *sys_base; /* HIF SYSCTL registers */ + void __iomem *pcie_base; /* PCIE registers */ + void __iomem *usb_base; /* USB registers */ + + struct resource io; + struct resource pio; + struct resource mem; + struct resource prefetch; + struct resource busn; + + u32 io_bus_addr; + u32 mem_bus_addr; + + struct clk *clk; + int pcie_card_link; +}; + +static const struct mtk_phy_init { + u32 reg; + u32 mask; + u32 val; +} mtk_phy_init[] = { + { 0xc00, 0x33000, 0x22000 }, + { 0xb04, 0xe0000000, 0x40000000 }, + { 0xb00, 0xe, 0x4 }, + { 0xc3C, 0xffff0000, 0x3c0000 }, + { 0xc48, 0xffff, 0x36 }, + { 0xc0c, 0x30000000, 0x10000000 }, + { 0xc08, 0x3800c0, 0xc0 }, + { 0xc10, 0xf0000, 0x20000 }, + { 0xc0c, 0xf000, 0x1000 }, + { 0xc14, 0xf0000, 0xa0000 }, + { 0xa28, 0x3fe00, 0x2000 }, + { 0xa2c, 0x1ff, 0x10 }, +}; + +/* + * Globals. + */ + +struct mtk_pcie pcie; +struct mtk_pcie *pcie0; + +static int mtk_pcie_probe(void); +static int mt_pcie_read_config(struct udevice *, pci_dev_t, uint, ulong *, + enum pci_size_t); +static int mt_pcie_write_config(struct udevice *, pci_dev_t, uint, ulong, + enum pci_size_t); + +#define mtk_foreach_port(p) \ + for ((p) = mtk_pcie_port; \ + (p) != &mtk_pcie_port[ARRAY_SIZE(mtk_pcie_port)]; (p)++) +#define BITS(m, n) (~(BIT(m) - 1) & ((BIT(n) - 1) | BIT(n))) + +static void +mt7623_pcie_pinmux_set(void) +{ + u32 regValue; + + /* Pin208: PCIE0_PERST_N (3) */ + regValue = le32_to_cpu(ioread32(0x100059f0)); + regValue &= ~(BITS(9, 11)); + regValue |= 3 << 9; + iowrite32(regValue, 0x100059f0); + + /* Pin208: PCIE1_PERST_N (3) */ + regValue = le32_to_cpu(ioread32(0x100059f0)); + regValue &= ~(BITS(12, 14)); + regValue |= 3 << 12; + iowrite32(regValue, 0x100059f0); +} + +static void +sys_w32(struct mtk_pcie *pcie, u32 val, unsigned int reg) +{ + iowrite32(val, pcie->sys_base + reg); +} + +static u32 +sys_r32(struct mtk_pcie *pcie, unsigned int reg) +{ + return ioread32(pcie->sys_base + reg); +} + +static void +pcie_w32(struct mtk_pcie *pcie, u32 val, unsigned int reg) +{ + iowrite32(val, pcie->pcie_base + reg); +} + +static void +pcie_w16(struct mtk_pcie *pcie, u16 val, unsigned int reg) +{ + iowrite16(val, pcie->pcie_base + reg); +} + +static void +pcie_w8(struct mtk_pcie *pcie, u8 val, unsigned int reg) +{ + iowrite8(val, pcie->pcie_base + reg); +} + +static u32 +pcie_r32(struct mtk_pcie *pcie, unsigned int reg) +{ + return ioread32(pcie->pcie_base + reg); +} + +static u32 +pcie_r16(struct mtk_pcie *pcie, unsigned int reg) +{ + return ioread16(pcie->pcie_base + reg); +} + +static u32 +pcie_r8(struct mtk_pcie *pcie, unsigned int reg) +{ + return ioread8(pcie->pcie_base + reg); +} + +static void +pcie_m32(struct mtk_pcie *pcie, u32 mask, u32 val, unsigned int reg) +{ + u32 v; + + v = pcie_r32(pcie, reg); + v &= mask; + v |= val; + pcie_w32(pcie, v, reg); +} + +static void +mtk_pcie_configure_phy(struct mtk_pcie_port *port) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mtk_phy_init); i++) { + void __iomem *phy_addr = (void __iomem *)port->phy_base + + mtk_phy_init[i].reg; + u32 val = ioread32(phy_addr); + + val &= ~mtk_phy_init[i].mask; + val |= mtk_phy_init[i].val; + iowrite32(val, phy_addr); + udelay(100); + } + mdelay(16); +} + +static void +mtk_pcie_configure_rc(struct mtk_pcie *pcie, struct mtk_pcie_port *port) +{ + ulong val = 0; + + mt_pcie_write_config(NULL, (port->id) << 3, PCI_BASE_ADDRESS_0, + 0x80000000, PCI_SIZE_32); + mt_pcie_read_config(NULL, (port->id) << 3, PCI_BASE_ADDRESS_0, &val, + PCI_SIZE_32); + + /* Configre RC Credit */ + val = 0; + mt_pcie_read_config(NULL, (port->id) << 3, 0x73c, &val, PCI_SIZE_32); + val &= ~(0x9fffUL) << 16; + val |= 0x806c << 16; + mt_pcie_write_config(NULL, (port->id) << 3, 0x73c, val, PCI_SIZE_32); + mt_pcie_read_config(NULL, (port->id) << 3, 0x73c, &val, PCI_SIZE_32); + + /* Configre RC FTS number */ + mt_pcie_read_config(NULL, (port->id) << 3, 0x70c, &val, PCI_SIZE_32); + val &= ~(0xff3) << 8; + val |= 0x50 << 8; + mt_pcie_write_config(NULL, (port->id) << 3, 0x70c, val, PCI_SIZE_32); + mt_pcie_read_config(NULL, (port->id) << 3, 0x70c, &val, PCI_SIZE_32); +} + +static void +mtk_pcie_preinit(struct mtk_pcie *pcie) +{ + struct mtk_pcie_port *port; + u32 val = 0; + int i; + + mt7623_pcie_pinmux_set(); + + /* PCIe RC Reset */ + val = 0; + mtk_foreach_port(port) + if (port->enable) + val |= port->reset; + sys_w32(pcie, sys_r32(pcie, RSTCTL) | val, RSTCTL); + mdelay(12); + sys_w32(pcie, sys_r32(pcie, RSTCTL) & ~val, RSTCTL); + mdelay(12); + + i = 100000; + while (i--) { + if (sys_r32(pcie, RSTSTAT) == 0) + break; + udelay(10); + } + + /* Configure PCIe PHY */ + + mtk_foreach_port(port) + if (port->enable) + mtk_pcie_configure_phy(port); + + /* PCIe EP reset */ + val = 0; + mtk_foreach_port(port) + if (port->enable) + val |= port->perst_n; + pcie_w32(pcie, pcie_r32(pcie, PCICFG) | val, PCICFG); + mdelay(12); + pcie_w32(pcie, pcie_r32(pcie, PCICFG) & ~val, PCICFG); + mdelay(200); + + /* check the link status */ + val = 0; + mtk_foreach_port(port) { + if (port->enable) { + if ((pcie_r32(pcie, port->base + PCIE_SISTAT) & 0x1)) + port->link = 1; + else + val |= port->reset; + } + } + sys_w32(pcie, sys_r32(pcie, RSTCTL) | val, RSTCTL); + mdelay(200); + + i = 100000; + while (i--) { + if (sys_r32(pcie, RSTSTAT) == 0) + break; + udelay(10); + } + + mtk_foreach_port(port) { + if (port->link) + pcie->pcie_card_link++; + } + printf("%s: PCIe Link count=%d\n", __func__, pcie->pcie_card_link); + if (!pcie->pcie_card_link) + return; + + pcie_w32(pcie, pcie->mem_bus_addr, MEMBASE); + pcie_w32(pcie, pcie->io_bus_addr, IOBASE); + + mtk_foreach_port(port) { + if (port->link) { + pcie_m32(pcie, 0xffffffff, port->interrupt_en, PCIENA); + pcie_w32(pcie, 0x7fff0001, port->base + BAR0SETUP); + pcie_w32(pcie, 0x80000000, port->base + IMBASEBAR0); + pcie_w32(pcie, 0x06040001, port->base + PCIE_CLASS); + } + } + mdelay(100); + + mtk_foreach_port(port) + if (port->link) + mtk_pcie_configure_rc(pcie, port); +} + +static void +mtk_pcie_fill_port(struct mtk_pcie *pcie) +{ + int i; + + for (i = 0; i < 2; i++) + mtk_pcie_port[i].phy_base += (u32)pcie->pcie_base; + + mtk_pcie_port[2].phy_base += (u32)pcie->usb_base; +} + +void +mt_pcie_init(void) +{ + /* Static instance of the controller. */ + static struct pci_controller pcc; + struct pci_controller *hose = &pcc; + + memset(&pcc, 0, sizeof(pcc)); + + /* PCI I/O space */ + pci_set_region(&hose->regions[0], RT_PCIE_IOWIN_BASE, + RT_PCIE_IOWIN_BASE, RT_PCIE_IOWIN_SIZE, PCI_REGION_IO); + + /* PCI memory space */ + pci_set_region(&hose->regions[1], RT_PCIE_MEMWIN_BASE, + RT_PCIE_MEMWIN_BASE, RT_PCIE_MEMWIN_SIZE, + PCI_REGION_MEM); + + hose->region_count = 2; +} + +int +mtk_pcie_probe() +{ + pcie0 = &pcie; + + pcie0->io_bus_addr = RT_PCIE_IOWIN_BASE; + pcie0->mem_bus_addr = RT_PCIE_MEMWIN_BASE; + pcie0->sys_base = (u32 *)RT_HIFSYS_BASE; + pcie0->pcie_base = (u32 *)RT_PCIE_BASE; + + mtk_pcie_fill_port(pcie0); + + mtk_pcie_preinit(pcie0); + + return 0; +} + +/* Probe function. */ +void +pci_init_board(void) +{ + mtk_pcie_probe(); + mt_pcie_init(); +} + +static int +mt_pcie_read_config(struct udevice *bus, pci_dev_t bdf, + uint offset, ulong *valuep, + enum pci_size_t size) +{ + u32 address = bdf | ((offset & 0xf00) << 16) | (offset & 0xfc); + + pcie_m32(pcie0, 0xf0000000, address, CFGADDR); + + switch (size) { + case PCI_SIZE_8: + *valuep = pcie_r8(pcie0, CFGDATA + (offset & 3)); + break; + case PCI_SIZE_16: + *valuep = pcie_r16(pcie0, CFGDATA + (offset & 2)); + break; + case PCI_SIZE_32: + *valuep = pcie_r32(pcie0, CFGDATA); + break; + } + + return 0; +} + +static int +mt_pcie_write_config(struct udevice *bus, pci_dev_t bdf, + uint offset, ulong value, + enum pci_size_t size) +{ + u32 address = bdf | ((offset & 0xf00) << 16) | (offset & 0xfc); + + pcie_m32(pcie0, 0xf0000000, address, CFGADDR); + + switch (size) { + case PCI_SIZE_8: + pcie_w8(pcie0, value, CFGDATA + (offset & 3)); + break; + case PCI_SIZE_16: + pcie_w16(pcie0, value, CFGDATA + (offset & 2)); + break; + case PCI_SIZE_32: + default: + pcie_w32(pcie0, value, CFGDATA); + break; + } + return 0; +} + +static int +mt_pcie_probe(struct udevice *dev) +{ + mtk_pcie_probe(); + mt_pcie_init(); + return 0; +} + +static const struct dm_pci_ops mt_pcie_ops = { + .read_config = mt_pcie_read_config, + .write_config = mt_pcie_write_config, +}; + +static const struct udevice_id mt_pcie_ids[] = { + { .compatible = "mediatek,mt7623-pcie" }, + { } +}; + +U_BOOT_DRIVER(pcie_mt2701) = { + .name = "pci_mt2701", + .id = UCLASS_PCI, + .of_match = mt_pcie_ids, + .ops = &mt_pcie_ops, + .probe = mt_pcie_probe, + .priv_auto_alloc_size = sizeof(struct mt_pcie), +}; -- 2.17.1

+ GSS_MTK_Uboot_upstream GSS_MTK_Uboot_upstream@mediatek.com
On Wed, 2019-07-31 at 13:51 +0200, Frank Wunderlich wrote:
From: Oleksandr Rybalko ray@ddteam.net
this chip is used in MT7623 and some other Mediatek SoCs for pcie
Tested-by: Frank Wunderlich frank-w@public-files.de Signed-off-by: Frank Wunderlich frank-w@public-files.de Signed-off-by: Oleksandr Rybalko ray@ddteam.net
drivers/pci/Kconfig | 6 + drivers/pci/Makefile | 1 + drivers/pci/pci-mt2701.c | 490 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 497 insertions(+) create mode 100644 drivers/pci/pci-mt2701.c
Rename 'pci-mt2701.c' to 'pcie-mediatek.c' and then change the subject.
Obviously, this is an intermediate version of Linux patch, so I suggest to take a look at the latest version of vanilla Kernel: https://github.com/torvalds/linux/blob/master/drivers/pci/controller/pcie-me...
Please see my comments inline:
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 3fe38f7315..cfe8ba5e52 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -145,4 +145,10 @@ config PCI_MVEBU Say Y here if you want to enable PCIe controller support on Armada XP/38x SoCs.
+config PCIE_MT2701
- bool "Mediatek 2701 PCI-E"
- help
Say Y here if you want to enable PCIe controller support on
Mediatek MT7623
endif diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index b5ebd50c85..a4c4002b9c 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -38,3 +38,4 @@ obj-$(CONFIG_PCIE_LAYERSCAPE_GEN4) += pcie_layerscape_gen4.o \ pcie_layerscape_gen4_fixup.o obj-$(CONFIG_PCI_XILINX) += pcie_xilinx.o obj-$(CONFIG_PCIE_INTEL_FPGA) += pcie_intel_fpga.o +obj-$(CONFIG_PCIE_MT2701) += pci-mt2701.o diff --git a/drivers/pci/pci-mt2701.c b/drivers/pci/pci-mt2701.c new file mode 100644 index 0000000000..5904f15330 --- /dev/null +++ b/drivers/pci/pci-mt2701.c @@ -0,0 +1,490 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Mediatek MT7623 SoC PCIE support
- Copyright (C) 2015 Mediatek
- Copyright (C) 2015 John Crispin blogic@openwrt.org
- Copyright (C) 2015 Ziv Huang ziv.huang@mediatek.com
- Copyright (C) 2019 Oleksandr Rybalko ray@ddteam.net
- */
+#include <common.h> +#include <malloc.h>
+#include <pci.h> +#include <asm/io.h>
+#include <dm.h> +#include <fdtdec.h> +#include <linux/libfdt.h> +#include <dm/lists.h>
+#define iowrite32(v, a) writel(v, a) +#define iowrite16(v, a) writew(v, a) +#define iowrite8(v, a) writeb(v, a) +#define ioread32(a) readl(a) +#define ioread16(a) readw(a) +#define ioread8(a) readb(a)
Remove these defines.
+#define RT_HIFSYS_BASE 0x1a000000 +#define RT_PCIE_BASE 0x1a140000 +#define RT_PCIE_IOWIN_BASE 0x1a160000 +#define RT_PCIE_IOWIN_SIZE 0x00010000 +#define RT_PCIE_MEMWIN_BASE 0x60000000 +#define RT_PCIE_MEMWIN_SIZE 0x10000000
Move these base to dts.
+#define RD(x) readl(RT_PCIE_BASE | (x)) +#define WR(x, v) writel(v, RT_PCIE_BASE | (x))
+#define SYSCFG1 0x14 +#define RSTCTL 0x34 +#define RSTSTAT 0x38 +#define PCICFG 0x00 +#define PCIINT 0x08 +#define PCIENA 0x0c +#define CFGADDR 0x20 +#define CFGDATA 0x24 +#define MEMBASE 0x28 +#define IOBASE 0x2c
+#define BAR0SETUP 0x10 +#define IMBASEBAR0 0x18 +#define PCIE_CLASS 0x34 +#define PCIE_SISTAT 0x50
+#define MTK_PCIE_HIGH_PERF BIT(14) +#define PCIEP0_BASE 0x2000 +#define PCIEP1_BASE 0x3000 +#define PCIEP2_BASE 0x4000
+#define PHY_P0_CTL 0x9000 +#define PHY_P1_CTL 0xa000 +#define PHY_P2_CTL 0x4000 /* in USB space */
+#define RSTCTL_PCIE0_RST BIT(24) +#define RSTCTL_PCIE1_RST BIT(25) +#define RSTCTL_PCIE2_RST BIT(26) +#define MAX_PORT_NUM 3
+struct resource {
- char *name;
- u32 start;
- u32 end;
+};
+struct mt_pcie {
- char name[16];
+};
+static struct mtk_pcie_port {
- int id;
- int enable;
- u32 base;
- u32 phy_base;
- u32 perst_n;
- u32 reset;
- u32 interrupt_en;
- int irq;
- u32 link;
+} mtk_pcie_port[] = {
- { 0, 1, PCIEP0_BASE, PHY_P0_CTL, BIT(1), RSTCTL_PCIE0_RST, BIT(20) },
- { 1, 1, PCIEP1_BASE, PHY_P1_CTL, BIT(2), RSTCTL_PCIE1_RST, BIT(21) },
- { 2, 0, PCIEP2_BASE, PHY_P2_CTL, BIT(3), RSTCTL_PCIE2_RST, BIT(22) },
+};
move some of mtk_pcie_port[] to dts.
+struct mtk_pcie {
- struct device *dev;
- void __iomem *sys_base; /* HIF SYSCTL registers */
- void __iomem *pcie_base; /* PCIE registers */
- void __iomem *usb_base; /* USB registers */
- struct resource io;
- struct resource pio;
- struct resource mem;
- struct resource prefetch;
- struct resource busn;
- u32 io_bus_addr;
- u32 mem_bus_addr;
- struct clk *clk;
- int pcie_card_link;
+};
+static const struct mtk_phy_init {
- u32 reg;
- u32 mask;
- u32 val;
+} mtk_phy_init[] = {
- { 0xc00, 0x33000, 0x22000 },
- { 0xb04, 0xe0000000, 0x40000000 },
- { 0xb00, 0xe, 0x4 },
- { 0xc3C, 0xffff0000, 0x3c0000 },
- { 0xc48, 0xffff, 0x36 },
- { 0xc0c, 0x30000000, 0x10000000 },
- { 0xc08, 0x3800c0, 0xc0 },
- { 0xc10, 0xf0000, 0x20000 },
- { 0xc0c, 0xf000, 0x1000 },
- { 0xc14, 0xf0000, 0xa0000 },
- { 0xa28, 0x3fe00, 0x2000 },
- { 0xa2c, 0x1ff, 0x10 },
+};
We should add another PHY driver (drivers/phy/) for these settings. Like what we did for Linux: https://github.com/torvalds/linux/blob/master/drivers/phy/mediatek/phy-mtk-t...
+/*
- Globals.
- */
+struct mtk_pcie pcie; +struct mtk_pcie *pcie0;
+static int mtk_pcie_probe(void); +static int mt_pcie_read_config(struct udevice *, pci_dev_t, uint, ulong *,
enum pci_size_t);
+static int mt_pcie_write_config(struct udevice *, pci_dev_t, uint, ulong,
enum pci_size_t);
+#define mtk_foreach_port(p) \
for ((p) = mtk_pcie_port; \
(p) != &mtk_pcie_port[ARRAY_SIZE(mtk_pcie_port)]; (p)++)
Use dts for each port.
+#define BITS(m, n) (~(BIT(m) - 1) & ((BIT(n) - 1) | BIT(n)))
+static void +mt7623_pcie_pinmux_set(void) +{
- u32 regValue;
- /* Pin208: PCIE0_PERST_N (3) */
- regValue = le32_to_cpu(ioread32(0x100059f0));
- regValue &= ~(BITS(9, 11));
- regValue |= 3 << 9;
- iowrite32(regValue, 0x100059f0);
- /* Pin208: PCIE1_PERST_N (3) */
- regValue = le32_to_cpu(ioread32(0x100059f0));
- regValue &= ~(BITS(12, 14));
- regValue |= 3 << 12;
- iowrite32(regValue, 0x100059f0);
+}
Configure pinmux in dts.
+static void +sys_w32(struct mtk_pcie *pcie, u32 val, unsigned int reg) +{
- iowrite32(val, pcie->sys_base + reg);
+}
+static u32 +sys_r32(struct mtk_pcie *pcie, unsigned int reg) +{
- return ioread32(pcie->sys_base + reg);
+}
+static void +pcie_w32(struct mtk_pcie *pcie, u32 val, unsigned int reg) +{
- iowrite32(val, pcie->pcie_base + reg);
+}
+static void +pcie_w16(struct mtk_pcie *pcie, u16 val, unsigned int reg) +{
- iowrite16(val, pcie->pcie_base + reg);
+}
+static void +pcie_w8(struct mtk_pcie *pcie, u8 val, unsigned int reg) +{
- iowrite8(val, pcie->pcie_base + reg);
+}
+static u32 +pcie_r32(struct mtk_pcie *pcie, unsigned int reg) +{
- return ioread32(pcie->pcie_base + reg);
+}
+static u32 +pcie_r16(struct mtk_pcie *pcie, unsigned int reg) +{
- return ioread16(pcie->pcie_base + reg);
+}
+static u32 +pcie_r8(struct mtk_pcie *pcie, unsigned int reg) +{
- return ioread8(pcie->pcie_base + reg);
+}
+static void +pcie_m32(struct mtk_pcie *pcie, u32 mask, u32 val, unsigned int reg) +{
- u32 v;
- v = pcie_r32(pcie, reg);
- v &= mask;
- v |= val;
- pcie_w32(pcie, v, reg);
+}
+static void +mtk_pcie_configure_phy(struct mtk_pcie_port *port) +{
- int i;
- for (i = 0; i < ARRAY_SIZE(mtk_phy_init); i++) {
void __iomem *phy_addr = (void __iomem *)port->phy_base +
mtk_phy_init[i].reg;
u32 val = ioread32(phy_addr);
val &= ~mtk_phy_init[i].mask;
val |= mtk_phy_init[i].val;
iowrite32(val, phy_addr);
udelay(100);
- }
- mdelay(16);
+}
Use PHY driver.
+static void +mtk_pcie_configure_rc(struct mtk_pcie *pcie, struct mtk_pcie_port *port) +{
- ulong val = 0;
- mt_pcie_write_config(NULL, (port->id) << 3, PCI_BASE_ADDRESS_0,
0x80000000, PCI_SIZE_32);
- mt_pcie_read_config(NULL, (port->id) << 3, PCI_BASE_ADDRESS_0, &val,
PCI_SIZE_32);
- /* Configre RC Credit */
- val = 0;
- mt_pcie_read_config(NULL, (port->id) << 3, 0x73c, &val, PCI_SIZE_32);
- val &= ~(0x9fffUL) << 16;
- val |= 0x806c << 16;
- mt_pcie_write_config(NULL, (port->id) << 3, 0x73c, val, PCI_SIZE_32);
- mt_pcie_read_config(NULL, (port->id) << 3, 0x73c, &val, PCI_SIZE_32);
- /* Configre RC FTS number */
- mt_pcie_read_config(NULL, (port->id) << 3, 0x70c, &val, PCI_SIZE_32);
- val &= ~(0xff3) << 8;
- val |= 0x50 << 8;
- mt_pcie_write_config(NULL, (port->id) << 3, 0x70c, val, PCI_SIZE_32);
- mt_pcie_read_config(NULL, (port->id) << 3, 0x70c, &val, PCI_SIZE_32);
+}
+static void +mtk_pcie_preinit(struct mtk_pcie *pcie) +{
- struct mtk_pcie_port *port;
- u32 val = 0;
- int i;
- mt7623_pcie_pinmux_set();
- /* PCIe RC Reset */
- val = 0;
- mtk_foreach_port(port)
if (port->enable)
val |= port->reset;
- sys_w32(pcie, sys_r32(pcie, RSTCTL) | val, RSTCTL);
- mdelay(12);
- sys_w32(pcie, sys_r32(pcie, RSTCTL) & ~val, RSTCTL);
- mdelay(12);
- i = 100000;
- while (i--) {
if (sys_r32(pcie, RSTSTAT) == 0)
break;
udelay(10);
- }
We should avoid this while loop.
- /* Configure PCIe PHY */
- mtk_foreach_port(port)
if (port->enable)
mtk_pcie_configure_phy(port);
- /* PCIe EP reset */
- val = 0;
- mtk_foreach_port(port)
if (port->enable)
val |= port->perst_n;
- pcie_w32(pcie, pcie_r32(pcie, PCICFG) | val, PCICFG);
- mdelay(12);
- pcie_w32(pcie, pcie_r32(pcie, PCICFG) & ~val, PCICFG);
- mdelay(200);
- /* check the link status */
- val = 0;
- mtk_foreach_port(port) {
if (port->enable) {
if ((pcie_r32(pcie, port->base + PCIE_SISTAT) & 0x1))
port->link = 1;
else
val |= port->reset;
}
- }
- sys_w32(pcie, sys_r32(pcie, RSTCTL) | val, RSTCTL);
- mdelay(200);
- i = 100000;
- while (i--) {
if (sys_r32(pcie, RSTSTAT) == 0)
break;
udelay(10);
- }
- mtk_foreach_port(port) {
if (port->link)
pcie->pcie_card_link++;
- }
- printf("%s: PCIe Link count=%d\n", __func__, pcie->pcie_card_link);
- if (!pcie->pcie_card_link)
return;
- pcie_w32(pcie, pcie->mem_bus_addr, MEMBASE);
- pcie_w32(pcie, pcie->io_bus_addr, IOBASE);
- mtk_foreach_port(port) {
if (port->link) {
pcie_m32(pcie, 0xffffffff, port->interrupt_en, PCIENA);
pcie_w32(pcie, 0x7fff0001, port->base + BAR0SETUP);
pcie_w32(pcie, 0x80000000, port->base + IMBASEBAR0);
pcie_w32(pcie, 0x06040001, port->base + PCIE_CLASS);
magic number.
}
- }
- mdelay(100);
- mtk_foreach_port(port)
if (port->link)
mtk_pcie_configure_rc(pcie, port);
+} +static void +mtk_pcie_fill_port(struct mtk_pcie *pcie) +{
- int i;
- for (i = 0; i < 2; i++)
mtk_pcie_port[i].phy_base += (u32)pcie->pcie_base;
- mtk_pcie_port[2].phy_base += (u32)pcie->usb_base;
+}
Ditto (dts).
+void +mt_pcie_init(void) +{
- /* Static instance of the controller. */
- static struct pci_controller pcc;
- struct pci_controller *hose = &pcc;
- memset(&pcc, 0, sizeof(pcc));
- /* PCI I/O space */
- pci_set_region(&hose->regions[0], RT_PCIE_IOWIN_BASE,
RT_PCIE_IOWIN_BASE, RT_PCIE_IOWIN_SIZE, PCI_REGION_IO);
- /* PCI memory space */
- pci_set_region(&hose->regions[1], RT_PCIE_MEMWIN_BASE,
RT_PCIE_MEMWIN_BASE, RT_PCIE_MEMWIN_SIZE,
PCI_REGION_MEM);
- hose->region_count = 2;
+}
+int +mtk_pcie_probe() +{
- pcie0 = &pcie;
- pcie0->io_bus_addr = RT_PCIE_IOWIN_BASE;
- pcie0->mem_bus_addr = RT_PCIE_MEMWIN_BASE;
- pcie0->sys_base = (u32 *)RT_HIFSYS_BASE;
- pcie0->pcie_base = (u32 *)RT_PCIE_BASE;
- mtk_pcie_fill_port(pcie0);
- mtk_pcie_preinit(pcie0);
- return 0;
+}
+/* Probe function. */ +void +pci_init_board(void) +{
- mtk_pcie_probe();
- mt_pcie_init();
+}
+static int +mt_pcie_read_config(struct udevice *bus, pci_dev_t bdf,
uint offset, ulong *valuep,
enum pci_size_t size)
+{
- u32 address = bdf | ((offset & 0xf00) << 16) | (offset & 0xfc);
- pcie_m32(pcie0, 0xf0000000, address, CFGADDR);
- switch (size) {
- case PCI_SIZE_8:
*valuep = pcie_r8(pcie0, CFGDATA + (offset & 3));
break;
- case PCI_SIZE_16:
*valuep = pcie_r16(pcie0, CFGDATA + (offset & 2));
break;
- case PCI_SIZE_32:
*valuep = pcie_r32(pcie0, CFGDATA);
break;
- }
- return 0;
+}
+static int +mt_pcie_write_config(struct udevice *bus, pci_dev_t bdf,
uint offset, ulong value,
enum pci_size_t size)
+{
- u32 address = bdf | ((offset & 0xf00) << 16) | (offset & 0xfc);
- pcie_m32(pcie0, 0xf0000000, address, CFGADDR);
- switch (size) {
- case PCI_SIZE_8:
pcie_w8(pcie0, value, CFGDATA + (offset & 3));
break;
- case PCI_SIZE_16:
pcie_w16(pcie0, value, CFGDATA + (offset & 2));
break;
- case PCI_SIZE_32:
- default:
pcie_w32(pcie0, value, CFGDATA);
break;
- }
- return 0;
+}
+static int +mt_pcie_probe(struct udevice *dev) +{
- mtk_pcie_probe();
- mt_pcie_init();
- return 0;
+}
+static const struct dm_pci_ops mt_pcie_ops = {
- .read_config = mt_pcie_read_config,
- .write_config = mt_pcie_write_config,
+};
+static const struct udevice_id mt_pcie_ids[] = {
- { .compatible = "mediatek,mt7623-pcie" },
- { }
+};
+U_BOOT_DRIVER(pcie_mt2701) = {
- .name = "pci_mt2701",
- .id = UCLASS_PCI,
- .of_match = mt_pcie_ids,
- .ops = &mt_pcie_ops,
- .probe = mt_pcie_probe,
- .priv_auto_alloc_size = sizeof(struct mt_pcie),
+};
pcie_mediatek.

Hello Ryder.
ср, 31 лип. 2019 о 15:45 Ryder Lee ryder.lee@mediatek.com пише:
- GSS_MTK_Uboot_upstream GSS_MTK_Uboot_upstream@mediatek.com
On Wed, 2019-07-31 at 13:51 +0200, Frank Wunderlich wrote:
From: Oleksandr Rybalko ray@ddteam.net
this chip is used in MT7623 and some other Mediatek SoCs for pcie
Tested-by: Frank Wunderlich frank-w@public-files.de Signed-off-by: Frank Wunderlich frank-w@public-files.de Signed-off-by: Oleksandr Rybalko ray@ddteam.net
drivers/pci/Kconfig | 6 + drivers/pci/Makefile | 1 + drivers/pci/pci-mt2701.c | 490 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 497 insertions(+) create mode 100644 drivers/pci/pci-mt2701.c
Rename 'pci-mt2701.c' to 'pcie-mediatek.c' and then change the subject.
So you promise us, that Mediatek will never produce PCI-E controller which will be totally different from that one? :)
Obviously, this is an intermediate version of Linux patch, so I suggest to take a look at the latest version of vanilla Kernel:
https://github.com/torvalds/linux/blob/master/drivers/pci/controller/pcie-me...
Please see my comments inline:
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 3fe38f7315..cfe8ba5e52 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -145,4 +145,10 @@ config PCI_MVEBU Say Y here if you want to enable PCIe controller support on Armada XP/38x SoCs.
+config PCIE_MT2701
bool "Mediatek 2701 PCI-E"
help
Say Y here if you want to enable PCIe controller support on
Mediatek MT7623
endif diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index b5ebd50c85..a4c4002b9c 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -38,3 +38,4 @@ obj-$(CONFIG_PCIE_LAYERSCAPE_GEN4) +=
pcie_layerscape_gen4.o \
pcie_layerscape_gen4_fixup.o
obj-$(CONFIG_PCI_XILINX) += pcie_xilinx.o obj-$(CONFIG_PCIE_INTEL_FPGA) += pcie_intel_fpga.o +obj-$(CONFIG_PCIE_MT2701) += pci-mt2701.o diff --git a/drivers/pci/pci-mt2701.c b/drivers/pci/pci-mt2701.c new file mode 100644 index 0000000000..5904f15330 --- /dev/null +++ b/drivers/pci/pci-mt2701.c @@ -0,0 +1,490 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Mediatek MT7623 SoC PCIE support
- Copyright (C) 2015 Mediatek
- Copyright (C) 2015 John Crispin blogic@openwrt.org
- Copyright (C) 2015 Ziv Huang ziv.huang@mediatek.com
- Copyright (C) 2019 Oleksandr Rybalko ray@ddteam.net
- */
+#include <common.h> +#include <malloc.h>
+#include <pci.h> +#include <asm/io.h>
+#include <dm.h> +#include <fdtdec.h> +#include <linux/libfdt.h> +#include <dm/lists.h>
+#define iowrite32(v, a) writel(v, a) +#define iowrite16(v, a) writew(v, a) +#define iowrite8(v, a) writeb(v, a) +#define ioread32(a) readl(a) +#define ioread16(a) readw(a) +#define ioread8(a) readb(a)
Remove these defines.
+#define RT_HIFSYS_BASE 0x1a000000 +#define RT_PCIE_BASE 0x1a140000 +#define RT_PCIE_IOWIN_BASE 0x1a160000 +#define RT_PCIE_IOWIN_SIZE 0x00010000 +#define RT_PCIE_MEMWIN_BASE 0x60000000 +#define RT_PCIE_MEMWIN_SIZE 0x10000000
Move these base to dts.
Already there (ranges), just not used yet.
+#define RD(x) readl(RT_PCIE_BASE | (x)) +#define WR(x, v) writel(v, RT_PCIE_BASE | (x))
+#define SYSCFG1 0x14 +#define RSTCTL 0x34 +#define RSTSTAT 0x38 +#define PCICFG 0x00 +#define PCIINT 0x08 +#define PCIENA 0x0c +#define CFGADDR 0x20 +#define CFGDATA 0x24 +#define MEMBASE 0x28 +#define IOBASE 0x2c
+#define BAR0SETUP 0x10 +#define IMBASEBAR0 0x18 +#define PCIE_CLASS 0x34 +#define PCIE_SISTAT 0x50
+#define MTK_PCIE_HIGH_PERF BIT(14) +#define PCIEP0_BASE 0x2000 +#define PCIEP1_BASE 0x3000 +#define PCIEP2_BASE 0x4000
+#define PHY_P0_CTL 0x9000 +#define PHY_P1_CTL 0xa000 +#define PHY_P2_CTL 0x4000 /* in USB space */
+#define RSTCTL_PCIE0_RST BIT(24) +#define RSTCTL_PCIE1_RST BIT(25) +#define RSTCTL_PCIE2_RST BIT(26) +#define MAX_PORT_NUM 3
+struct resource {
char *name;
u32 start;
u32 end;
+};
+struct mt_pcie {
char name[16];
+};
+static struct mtk_pcie_port {
int id;
int enable;
u32 base;
u32 phy_base;
u32 perst_n;
u32 reset;
u32 interrupt_en;
int irq;
u32 link;
+} mtk_pcie_port[] = {
{ 0, 1, PCIEP0_BASE, PHY_P0_CTL, BIT(1), RSTCTL_PCIE0_RST, BIT(20)
},
{ 1, 1, PCIEP1_BASE, PHY_P1_CTL, BIT(2), RSTCTL_PCIE1_RST, BIT(21)
},
{ 2, 0, PCIEP2_BASE, PHY_P2_CTL, BIT(3), RSTCTL_PCIE2_RST, BIT(22)
},
+};
move some of mtk_pcie_port[] to dts.
Main point, at the end use orginal linux kernel DTS files. So it can be passed into kernel, instead of hardcode it inside kernel. Just like we have ACPI blob on PC.
+struct mtk_pcie {
struct device *dev;
void __iomem *sys_base; /* HIF SYSCTL registers */
void __iomem *pcie_base; /* PCIE registers */
void __iomem *usb_base; /* USB registers */
struct resource io;
struct resource pio;
struct resource mem;
struct resource prefetch;
struct resource busn;
u32 io_bus_addr;
u32 mem_bus_addr;
struct clk *clk;
int pcie_card_link;
+};
+static const struct mtk_phy_init {
u32 reg;
u32 mask;
u32 val;
+} mtk_phy_init[] = {
{ 0xc00, 0x33000, 0x22000 },
{ 0xb04, 0xe0000000, 0x40000000 },
{ 0xb00, 0xe, 0x4 },
{ 0xc3C, 0xffff0000, 0x3c0000 },
{ 0xc48, 0xffff, 0x36 },
{ 0xc0c, 0x30000000, 0x10000000 },
{ 0xc08, 0x3800c0, 0xc0 },
{ 0xc10, 0xf0000, 0x20000 },
{ 0xc0c, 0xf000, 0x1000 },
{ 0xc14, 0xf0000, 0xa0000 },
{ 0xa28, 0x3fe00, 0x2000 },
{ 0xa2c, 0x1ff, 0x10 },
+};
We should add another PHY driver (drivers/phy/) for these settings. Like what we did for Linux:
https://github.com/torvalds/linux/blob/master/drivers/phy/mediatek/phy-mtk-t...
Yes, but it more complex way for future releases.
+/*
- Globals.
- */
+struct mtk_pcie pcie; +struct mtk_pcie *pcie0;
+static int mtk_pcie_probe(void); +static int mt_pcie_read_config(struct udevice *, pci_dev_t, uint, ulong
*,
enum pci_size_t);
+static int mt_pcie_write_config(struct udevice *, pci_dev_t, uint,
ulong,
enum pci_size_t);
+#define mtk_foreach_port(p) \
for ((p) = mtk_pcie_port; \
(p) != &mtk_pcie_port[ARRAY_SIZE(mtk_pcie_port)]; (p)++)
Use dts for each port.
+#define BITS(m, n) (~(BIT(m) - 1) & ((BIT(n) - 1) | BIT(n)))
+static void +mt7623_pcie_pinmux_set(void) +{
u32 regValue;
/* Pin208: PCIE0_PERST_N (3) */
regValue = le32_to_cpu(ioread32(0x100059f0));
regValue &= ~(BITS(9, 11));
regValue |= 3 << 9;
iowrite32(regValue, 0x100059f0);
/* Pin208: PCIE1_PERST_N (3) */
regValue = le32_to_cpu(ioread32(0x100059f0));
regValue &= ~(BITS(12, 14));
regValue |= 3 << 12;
iowrite32(regValue, 0x100059f0);
+}
Configure pinmux in dts.
Will be, when we reach point of full tree.
+static void +sys_w32(struct mtk_pcie *pcie, u32 val, unsigned int reg) +{
iowrite32(val, pcie->sys_base + reg);
+}
+static u32 +sys_r32(struct mtk_pcie *pcie, unsigned int reg) +{
return ioread32(pcie->sys_base + reg);
+}
+static void +pcie_w32(struct mtk_pcie *pcie, u32 val, unsigned int reg) +{
iowrite32(val, pcie->pcie_base + reg);
+}
+static void +pcie_w16(struct mtk_pcie *pcie, u16 val, unsigned int reg) +{
iowrite16(val, pcie->pcie_base + reg);
+}
+static void +pcie_w8(struct mtk_pcie *pcie, u8 val, unsigned int reg) +{
iowrite8(val, pcie->pcie_base + reg);
+}
+static u32 +pcie_r32(struct mtk_pcie *pcie, unsigned int reg) +{
return ioread32(pcie->pcie_base + reg);
+}
+static u32 +pcie_r16(struct mtk_pcie *pcie, unsigned int reg) +{
return ioread16(pcie->pcie_base + reg);
+}
+static u32 +pcie_r8(struct mtk_pcie *pcie, unsigned int reg) +{
return ioread8(pcie->pcie_base + reg);
+}
+static void +pcie_m32(struct mtk_pcie *pcie, u32 mask, u32 val, unsigned int reg) +{
u32 v;
v = pcie_r32(pcie, reg);
v &= mask;
v |= val;
pcie_w32(pcie, v, reg);
+}
+static void +mtk_pcie_configure_phy(struct mtk_pcie_port *port) +{
int i;
for (i = 0; i < ARRAY_SIZE(mtk_phy_init); i++) {
void __iomem *phy_addr = (void __iomem *)port->phy_base +
mtk_phy_init[i].reg;
u32 val = ioread32(phy_addr);
val &= ~mtk_phy_init[i].mask;
val |= mtk_phy_init[i].val;
iowrite32(val, phy_addr);
udelay(100);
}
mdelay(16);
+}
Use PHY driver.
+static void +mtk_pcie_configure_rc(struct mtk_pcie *pcie, struct mtk_pcie_port *port) +{
ulong val = 0;
mt_pcie_write_config(NULL, (port->id) << 3, PCI_BASE_ADDRESS_0,
0x80000000, PCI_SIZE_32);
mt_pcie_read_config(NULL, (port->id) << 3, PCI_BASE_ADDRESS_0,
&val,
PCI_SIZE_32);
/* Configre RC Credit */
val = 0;
mt_pcie_read_config(NULL, (port->id) << 3, 0x73c, &val,
PCI_SIZE_32);
val &= ~(0x9fffUL) << 16;
val |= 0x806c << 16;
mt_pcie_write_config(NULL, (port->id) << 3, 0x73c, val,
PCI_SIZE_32);
mt_pcie_read_config(NULL, (port->id) << 3, 0x73c, &val,
PCI_SIZE_32);
/* Configre RC FTS number */
mt_pcie_read_config(NULL, (port->id) << 3, 0x70c, &val,
PCI_SIZE_32);
val &= ~(0xff3) << 8;
val |= 0x50 << 8;
mt_pcie_write_config(NULL, (port->id) << 3, 0x70c, val,
PCI_SIZE_32);
mt_pcie_read_config(NULL, (port->id) << 3, 0x70c, &val,
PCI_SIZE_32);
+}
+static void +mtk_pcie_preinit(struct mtk_pcie *pcie) +{
struct mtk_pcie_port *port;
u32 val = 0;
int i;
mt7623_pcie_pinmux_set();
/* PCIe RC Reset */
val = 0;
mtk_foreach_port(port)
if (port->enable)
val |= port->reset;
sys_w32(pcie, sys_r32(pcie, RSTCTL) | val, RSTCTL);
mdelay(12);
sys_w32(pcie, sys_r32(pcie, RSTCTL) & ~val, RSTCTL);
mdelay(12);
i = 100000;
while (i--) {
if (sys_r32(pcie, RSTSTAT) == 0)
break;
udelay(10);
}
We should avoid this while loop.
/* Configure PCIe PHY */
mtk_foreach_port(port)
if (port->enable)
mtk_pcie_configure_phy(port);
/* PCIe EP reset */
val = 0;
mtk_foreach_port(port)
if (port->enable)
val |= port->perst_n;
pcie_w32(pcie, pcie_r32(pcie, PCICFG) | val, PCICFG);
mdelay(12);
pcie_w32(pcie, pcie_r32(pcie, PCICFG) & ~val, PCICFG);
mdelay(200);
/* check the link status */
val = 0;
mtk_foreach_port(port) {
if (port->enable) {
if ((pcie_r32(pcie, port->base + PCIE_SISTAT) &
0x1))
port->link = 1;
else
val |= port->reset;
}
}
sys_w32(pcie, sys_r32(pcie, RSTCTL) | val, RSTCTL);
mdelay(200);
i = 100000;
while (i--) {
if (sys_r32(pcie, RSTSTAT) == 0)
break;
udelay(10);
}
mtk_foreach_port(port) {
if (port->link)
pcie->pcie_card_link++;
}
printf("%s: PCIe Link count=%d\n", __func__, pcie->pcie_card_link);
if (!pcie->pcie_card_link)
return;
pcie_w32(pcie, pcie->mem_bus_addr, MEMBASE);
pcie_w32(pcie, pcie->io_bus_addr, IOBASE);
mtk_foreach_port(port) {
if (port->link) {
pcie_m32(pcie, 0xffffffff, port->interrupt_en,
PCIENA);
pcie_w32(pcie, 0x7fff0001, port->base + BAR0SETUP);
pcie_w32(pcie, 0x80000000, port->base +
IMBASEBAR0);
pcie_w32(pcie, 0x06040001, port->base +
PCIE_CLASS); magic number.
Descriptive by reg names.
}
}
mdelay(100);
mtk_foreach_port(port)
if (port->link)
mtk_pcie_configure_rc(pcie, port);
+} +static void +mtk_pcie_fill_port(struct mtk_pcie *pcie) +{
int i;
for (i = 0; i < 2; i++)
mtk_pcie_port[i].phy_base += (u32)pcie->pcie_base;
mtk_pcie_port[2].phy_base += (u32)pcie->usb_base;
+}
Ditto (dts).
+void +mt_pcie_init(void) +{
/* Static instance of the controller. */
static struct pci_controller pcc;
struct pci_controller *hose = &pcc;
memset(&pcc, 0, sizeof(pcc));
/* PCI I/O space */
pci_set_region(&hose->regions[0], RT_PCIE_IOWIN_BASE,
RT_PCIE_IOWIN_BASE, RT_PCIE_IOWIN_SIZE,
PCI_REGION_IO);
/* PCI memory space */
pci_set_region(&hose->regions[1], RT_PCIE_MEMWIN_BASE,
RT_PCIE_MEMWIN_BASE, RT_PCIE_MEMWIN_SIZE,
PCI_REGION_MEM);
hose->region_count = 2;
+}
+int +mtk_pcie_probe() +{
pcie0 = &pcie;
pcie0->io_bus_addr = RT_PCIE_IOWIN_BASE;
pcie0->mem_bus_addr = RT_PCIE_MEMWIN_BASE;
pcie0->sys_base = (u32 *)RT_HIFSYS_BASE;
pcie0->pcie_base = (u32 *)RT_PCIE_BASE;
mtk_pcie_fill_port(pcie0);
mtk_pcie_preinit(pcie0);
return 0;
+}
+/* Probe function. */ +void +pci_init_board(void) +{
mtk_pcie_probe();
mt_pcie_init();
+}
+static int +mt_pcie_read_config(struct udevice *bus, pci_dev_t bdf,
uint offset, ulong *valuep,
enum pci_size_t size)
+{
u32 address = bdf | ((offset & 0xf00) << 16) | (offset & 0xfc);
pcie_m32(pcie0, 0xf0000000, address, CFGADDR);
switch (size) {
case PCI_SIZE_8:
*valuep = pcie_r8(pcie0, CFGDATA + (offset & 3));
break;
case PCI_SIZE_16:
*valuep = pcie_r16(pcie0, CFGDATA + (offset & 2));
break;
case PCI_SIZE_32:
*valuep = pcie_r32(pcie0, CFGDATA);
break;
}
return 0;
+}
+static int +mt_pcie_write_config(struct udevice *bus, pci_dev_t bdf,
uint offset, ulong value,
enum pci_size_t size)
+{
u32 address = bdf | ((offset & 0xf00) << 16) | (offset & 0xfc);
pcie_m32(pcie0, 0xf0000000, address, CFGADDR);
switch (size) {
case PCI_SIZE_8:
pcie_w8(pcie0, value, CFGDATA + (offset & 3));
break;
case PCI_SIZE_16:
pcie_w16(pcie0, value, CFGDATA + (offset & 2));
break;
case PCI_SIZE_32:
default:
pcie_w32(pcie0, value, CFGDATA);
break;
}
return 0;
+}
+static int +mt_pcie_probe(struct udevice *dev) +{
mtk_pcie_probe();
mt_pcie_init();
return 0;
+}
+static const struct dm_pci_ops mt_pcie_ops = {
.read_config = mt_pcie_read_config,
.write_config = mt_pcie_write_config,
+};
+static const struct udevice_id mt_pcie_ids[] = {
{ .compatible = "mediatek,mt7623-pcie" },
{ }
+};
+U_BOOT_DRIVER(pcie_mt2701) = {
.name = "pci_mt2701",
.id = UCLASS_PCI,
.of_match = mt_pcie_ids,
.ops = &mt_pcie_ops,
.probe = mt_pcie_probe,
.priv_auto_alloc_size = sizeof(struct mt_pcie),
+};
pcie_mediatek.

On Wed, 2019-07-31 at 17:13 +0300, Aleksandr Rybalko wrote:
Hello Ryder.
ср, 31 лип. 2019 о 15:45 Ryder Lee ryder.lee@mediatek.com пише:
+ GSS_MTK_Uboot_upstream <GSS_MTK_Uboot_upstream@mediatek.com> On Wed, 2019-07-31 at 13:51 +0200, Frank Wunderlich wrote: > From: Oleksandr Rybalko <ray@ddteam.net> > > this chip is used in MT7623 and some other Mediatek SoCs for pcie > > Tested-by: Frank Wunderlich <frank-w@public-files.de> > Signed-off-by: Frank Wunderlich <frank-w@public-files.de> > Signed-off-by: Oleksandr Rybalko <ray@ddteam.net> > --- > drivers/pci/Kconfig | 6 + > drivers/pci/Makefile | 1 + > drivers/pci/pci-mt2701.c | 490 +++++++++++++++++++++++++++++++++++++++ > 3 files changed, 497 insertions(+) > create mode 100644 drivers/pci/pci-mt2701.c Rename 'pci-mt2701.c' to 'pcie-mediatek.c' and then change the subject.
So you promise us, that Mediatek will never produce PCI-E controller which will be totally different from that one? :)
imho we can use single driver for different IP generation and that is what we did in linux now.
MT7623/MT2701 - mtk_pcie_soc_v1 MT7622/MT7629 - v2 gen3 IP - TBD
Obviously, this is an intermediate version of Linux patch, so I suggest to take a look at the latest version of vanilla Kernel: https://github.com/torvalds/linux/blob/master/drivers/pci/controller/pcie-mediatek.c Please see my comments inline: > diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig > index 3fe38f7315..cfe8ba5e52 100644 > --- a/drivers/pci/Kconfig > +++ b/drivers/pci/Kconfig > @@ -145,4 +145,10 @@ config PCI_MVEBU > Say Y here if you want to enable PCIe controller support on > Armada XP/38x SoCs. > > +config PCIE_MT2701 > + bool "Mediatek 2701 PCI-E" > + help > + Say Y here if you want to enable PCIe controller support on > + Mediatek MT7623 > + > endif > diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile > index b5ebd50c85..a4c4002b9c 100644 > --- a/drivers/pci/Makefile > +++ b/drivers/pci/Makefile > @@ -38,3 +38,4 @@ obj-$(CONFIG_PCIE_LAYERSCAPE_GEN4) += pcie_layerscape_gen4.o \ > pcie_layerscape_gen4_fixup.o > obj-$(CONFIG_PCI_XILINX) += pcie_xilinx.o > obj-$(CONFIG_PCIE_INTEL_FPGA) += pcie_intel_fpga.o > +obj-$(CONFIG_PCIE_MT2701) += pci-mt2701.o > diff --git a/drivers/pci/pci-mt2701.c b/drivers/pci/pci-mt2701.c > new file mode 100644 > index 0000000000..5904f15330 > --- /dev/null > +++ b/drivers/pci/pci-mt2701.c > @@ -0,0 +1,490 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * Mediatek MT7623 SoC PCIE support > + * > + * Copyright (C) 2015 Mediatek > + * Copyright (C) 2015 John Crispin <blogic@openwrt.org> > + * Copyright (C) 2015 Ziv Huang <ziv.huang@mediatek.com> > + * Copyright (C) 2019 Oleksandr Rybalko <ray@ddteam.net> > + */ > + > +#include <common.h> > +#include <malloc.h> > + > +#include <pci.h> > +#include <asm/io.h> > + > +#include <dm.h> > +#include <fdtdec.h> > +#include <linux/libfdt.h> > +#include <dm/lists.h> > + > +#define iowrite32(v, a) writel(v, a) > +#define iowrite16(v, a) writew(v, a) > +#define iowrite8(v, a) writeb(v, a) > +#define ioread32(a) readl(a) > +#define ioread16(a) readw(a) > +#define ioread8(a) readb(a) Remove these defines. > +#define RT_HIFSYS_BASE 0x1a000000 > +#define RT_PCIE_BASE 0x1a140000 > +#define RT_PCIE_IOWIN_BASE 0x1a160000 > +#define RT_PCIE_IOWIN_SIZE 0x00010000 > +#define RT_PCIE_MEMWIN_BASE 0x60000000 > +#define RT_PCIE_MEMWIN_SIZE 0x10000000 Move these base to dts.
Already there (ranges), just not used yet.
so it's better remove unused parts, right?
> +#define RD(x) readl(RT_PCIE_BASE | (x)) > +#define WR(x, v) writel(v, RT_PCIE_BASE | (x)) > + > +#define SYSCFG1 0x14 > +#define RSTCTL 0x34 > +#define RSTSTAT 0x38 > +#define PCICFG 0x00 > +#define PCIINT 0x08 > +#define PCIENA 0x0c > +#define CFGADDR 0x20 > +#define CFGDATA 0x24 > +#define MEMBASE 0x28 > +#define IOBASE 0x2c > + > +#define BAR0SETUP 0x10 > +#define IMBASEBAR0 0x18 > +#define PCIE_CLASS 0x34 > +#define PCIE_SISTAT 0x50 > + > +#define MTK_PCIE_HIGH_PERF BIT(14) > +#define PCIEP0_BASE 0x2000 > +#define PCIEP1_BASE 0x3000 > +#define PCIEP2_BASE 0x4000 > + > +#define PHY_P0_CTL 0x9000 > +#define PHY_P1_CTL 0xa000 > +#define PHY_P2_CTL 0x4000 /* in USB space */ > + > +#define RSTCTL_PCIE0_RST BIT(24) > +#define RSTCTL_PCIE1_RST BIT(25) > +#define RSTCTL_PCIE2_RST BIT(26) > +#define MAX_PORT_NUM 3 > + > +struct resource { > + char *name; > + u32 start; > + u32 end; > +}; > + > +struct mt_pcie { > + char name[16]; > +}; > + > +static struct mtk_pcie_port { > + int id; > + int enable; > + u32 base; > + u32 phy_base; > + u32 perst_n; > + u32 reset; > + u32 interrupt_en; > + int irq; > + u32 link; > +} mtk_pcie_port[] = { > + { 0, 1, PCIEP0_BASE, PHY_P0_CTL, BIT(1), RSTCTL_PCIE0_RST, BIT(20) }, > + { 1, 1, PCIEP1_BASE, PHY_P1_CTL, BIT(2), RSTCTL_PCIE1_RST, BIT(21) }, > + { 2, 0, PCIEP2_BASE, PHY_P2_CTL, BIT(3), RSTCTL_PCIE2_RST, BIT(22) }, > +}; move some of mtk_pcie_port[] to dts.
Main point, at the end use orginal linux kernel DTS files. So it can be passed into kernel, instead of hardcode it inside kernel.
Just like we have ACPI blob on PC.
From what I see "[PATCH 4/4] arm: dts: Add PCI-E controller for mt7623"
has enough information about "base/offset/port/phy" (that dts is same as linux one), but this driver does not use them.
> +struct mtk_pcie { > + struct device *dev; > + void __iomem *sys_base; /* HIF SYSCTL registers */ > + void __iomem *pcie_base; /* PCIE registers */ > + void __iomem *usb_base; /* USB registers */ > + > + struct resource io; > + struct resource pio; > + struct resource mem; > + struct resource prefetch; > + struct resource busn; > + > + u32 io_bus_addr; > + u32 mem_bus_addr; > + > + struct clk *clk; > + int pcie_card_link; > +}; > + > +static const struct mtk_phy_init { > + u32 reg; > + u32 mask; > + u32 val; > +} mtk_phy_init[] = { > + { 0xc00, 0x33000, 0x22000 }, > + { 0xb04, 0xe0000000, 0x40000000 }, > + { 0xb00, 0xe, 0x4 }, > + { 0xc3C, 0xffff0000, 0x3c0000 }, > + { 0xc48, 0xffff, 0x36 }, > + { 0xc0c, 0x30000000, 0x10000000 }, > + { 0xc08, 0x3800c0, 0xc0 }, > + { 0xc10, 0xf0000, 0x20000 }, > + { 0xc0c, 0xf000, 0x1000 }, > + { 0xc14, 0xf0000, 0xa0000 }, > + { 0xa28, 0x3fe00, 0x2000 }, > + { 0xa2c, 0x1ff, 0x10 }, > +}; We should add another PHY driver (drivers/phy/) for these settings. Like what we did for Linux: https://github.com/torvalds/linux/blob/master/drivers/phy/mediatek/phy-mtk-tphy.c
Yes, but it more complex way for future releases.
phy driver is used for configuring basic settings, there is no complex logic in it. we can even copy and paste the entire block from that driver.
.version = MTK_PHY_V1 case PHY_TYPE_PCIE: pcie_phy_instance_init(tphy, instance);
> +/* > + * Globals. > + */ > + > +struct mtk_pcie pcie; > +struct mtk_pcie *pcie0; > + > +static int mtk_pcie_probe(void); > +static int mt_pcie_read_config(struct udevice *, pci_dev_t, uint, ulong *, > + enum pci_size_t); > +static int mt_pcie_write_config(struct udevice *, pci_dev_t, uint, ulong, > + enum pci_size_t); > + > +#define mtk_foreach_port(p) \ > + for ((p) = mtk_pcie_port; \ > + (p) != &mtk_pcie_port[ARRAY_SIZE(mtk_pcie_port)]; (p)++) Use dts for each port. > +#define BITS(m, n) (~(BIT(m) - 1) & ((BIT(n) - 1) | BIT(n))) > + > +static void > +mt7623_pcie_pinmux_set(void) > +{ > + u32 regValue; > + > + /* Pin208: PCIE0_PERST_N (3) */ > + regValue = le32_to_cpu(ioread32(0x100059f0)); > + regValue &= ~(BITS(9, 11)); > + regValue |= 3 << 9; > + iowrite32(regValue, 0x100059f0); > + > + /* Pin208: PCIE1_PERST_N (3) */ > + regValue = le32_to_cpu(ioread32(0x100059f0)); > + regValue &= ~(BITS(12, 14)); > + regValue |= 3 << 12; > + iowrite32(regValue, 0x100059f0); > +} Configure pinmux in dts.
Will be, when we reach point of full tree.
now we have mt7623 pinctrl driver that should be enough.
> +static void > +sys_w32(struct mtk_pcie *pcie, u32 val, unsigned int reg) > +{ > + iowrite32(val, pcie->sys_base + reg); > +} > + > +static u32 > +sys_r32(struct mtk_pcie *pcie, unsigned int reg) > +{ > + return ioread32(pcie->sys_base + reg); > +} > + > +static void > +pcie_w32(struct mtk_pcie *pcie, u32 val, unsigned int reg) > +{ > + iowrite32(val, pcie->pcie_base + reg); > +} > + > +static void > +pcie_w16(struct mtk_pcie *pcie, u16 val, unsigned int reg) > +{ > + iowrite16(val, pcie->pcie_base + reg); > +} > + > +static void > +pcie_w8(struct mtk_pcie *pcie, u8 val, unsigned int reg) > +{ > + iowrite8(val, pcie->pcie_base + reg); > +} > + > +static u32 > +pcie_r32(struct mtk_pcie *pcie, unsigned int reg) > +{ > + return ioread32(pcie->pcie_base + reg); > +} > + > +static u32 > +pcie_r16(struct mtk_pcie *pcie, unsigned int reg) > +{ > + return ioread16(pcie->pcie_base + reg); > +} > + > +static u32 > +pcie_r8(struct mtk_pcie *pcie, unsigned int reg) > +{ > + return ioread8(pcie->pcie_base + reg); > +} > + > +static void > +pcie_m32(struct mtk_pcie *pcie, u32 mask, u32 val, unsigned int reg) > +{ > + u32 v; > + > + v = pcie_r32(pcie, reg); > + v &= mask; > + v |= val; > + pcie_w32(pcie, v, reg); > +} > + > +static void > +mtk_pcie_configure_phy(struct mtk_pcie_port *port) > +{ > + int i; > + > + for (i = 0; i < ARRAY_SIZE(mtk_phy_init); i++) { > + void __iomem *phy_addr = (void __iomem *)port->phy_base + > + mtk_phy_init[i].reg; > + u32 val = ioread32(phy_addr); > + > + val &= ~mtk_phy_init[i].mask; > + val |= mtk_phy_init[i].val; > + iowrite32(val, phy_addr); > + udelay(100); > + } > + mdelay(16); > +} Use PHY driver. > +static void > +mtk_pcie_configure_rc(struct mtk_pcie *pcie, struct mtk_pcie_port *port) > +{ > + ulong val = 0; > + > + mt_pcie_write_config(NULL, (port->id) << 3, PCI_BASE_ADDRESS_0, > + 0x80000000, PCI_SIZE_32); > + mt_pcie_read_config(NULL, (port->id) << 3, PCI_BASE_ADDRESS_0, &val, > + PCI_SIZE_32); > + > + /* Configre RC Credit */ > + val = 0; > + mt_pcie_read_config(NULL, (port->id) << 3, 0x73c, &val, PCI_SIZE_32); > + val &= ~(0x9fffUL) << 16; > + val |= 0x806c << 16; > + mt_pcie_write_config(NULL, (port->id) << 3, 0x73c, val, PCI_SIZE_32); > + mt_pcie_read_config(NULL, (port->id) << 3, 0x73c, &val, PCI_SIZE_32); > + > + /* Configre RC FTS number */ > + mt_pcie_read_config(NULL, (port->id) << 3, 0x70c, &val, PCI_SIZE_32); > + val &= ~(0xff3) << 8; > + val |= 0x50 << 8; > + mt_pcie_write_config(NULL, (port->id) << 3, 0x70c, val, PCI_SIZE_32); > + mt_pcie_read_config(NULL, (port->id) << 3, 0x70c, &val, PCI_SIZE_32); > +} > + > +static void > +mtk_pcie_preinit(struct mtk_pcie *pcie) > +{ > + struct mtk_pcie_port *port; > + u32 val = 0; > + int i; > + > + mt7623_pcie_pinmux_set(); > + > + /* PCIe RC Reset */ > + val = 0; > + mtk_foreach_port(port) > + if (port->enable) > + val |= port->reset; > + sys_w32(pcie, sys_r32(pcie, RSTCTL) | val, RSTCTL); > + mdelay(12); > + sys_w32(pcie, sys_r32(pcie, RSTCTL) & ~val, RSTCTL); > + mdelay(12); > + > + i = 100000; > + while (i--) { > + if (sys_r32(pcie, RSTSTAT) == 0) > + break; > + udelay(10); > + } We should avoid this while loop. > + /* Configure PCIe PHY */ > + > + mtk_foreach_port(port) > + if (port->enable) > + mtk_pcie_configure_phy(port); > + > + /* PCIe EP reset */ > + val = 0; > + mtk_foreach_port(port) > + if (port->enable) > + val |= port->perst_n; > + pcie_w32(pcie, pcie_r32(pcie, PCICFG) | val, PCICFG); > + mdelay(12); > + pcie_w32(pcie, pcie_r32(pcie, PCICFG) & ~val, PCICFG); > + mdelay(200); > + > + /* check the link status */ > + val = 0; > + mtk_foreach_port(port) { > + if (port->enable) { > + if ((pcie_r32(pcie, port->base + PCIE_SISTAT) & 0x1)) > + port->link = 1; > + else > + val |= port->reset; > + } > + } > + sys_w32(pcie, sys_r32(pcie, RSTCTL) | val, RSTCTL); > + mdelay(200); > + > + i = 100000; > + while (i--) { > + if (sys_r32(pcie, RSTSTAT) == 0) > + break; > + udelay(10); > + } > + > + mtk_foreach_port(port) { > + if (port->link) > + pcie->pcie_card_link++; > + } > + printf("%s: PCIe Link count=%d\n", __func__, pcie->pcie_card_link); > + if (!pcie->pcie_card_link) > + return; > + > + pcie_w32(pcie, pcie->mem_bus_addr, MEMBASE); > + pcie_w32(pcie, pcie->io_bus_addr, IOBASE); > + > + mtk_foreach_port(port) { > + if (port->link) { > + pcie_m32(pcie, 0xffffffff, port->interrupt_en, PCIENA); > + pcie_w32(pcie, 0x7fff0001, port->base + BAR0SETUP); > + pcie_w32(pcie, 0x80000000, port->base + IMBASEBAR0); > + pcie_w32(pcie, 0x06040001, port->base + PCIE_CLASS); magic number.
Descriptive by reg names.
we can directly replace these chunks with mtk_pcie_startup_port() (pcie-mediatek.c) and there are many defines for the registers/bit field.

On Wed, 2019-07-31 at 22:35 +0800, Ryder Lee wrote:
On Wed, 2019-07-31 at 17:13 +0300, Aleksandr Rybalko wrote:
Hello Ryder.
ср, 31 лип. 2019 о 15:45 Ryder Lee ryder.lee@mediatek.com пише:
+ GSS_MTK_Uboot_upstream <GSS_MTK_Uboot_upstream@mediatek.com> On Wed, 2019-07-31 at 13:51 +0200, Frank Wunderlich wrote: > From: Oleksandr Rybalko <ray@ddteam.net> > > this chip is used in MT7623 and some other Mediatek SoCs for pcie > > Tested-by: Frank Wunderlich <frank-w@public-files.de> > Signed-off-by: Frank Wunderlich <frank-w@public-files.de> > Signed-off-by: Oleksandr Rybalko <ray@ddteam.net> > --- > drivers/pci/Kconfig | 6 + > drivers/pci/Makefile | 1 + > drivers/pci/pci-mt2701.c | 490 +++++++++++++++++++++++++++++++++++++++ > 3 files changed, 497 insertions(+) > create mode 100644 drivers/pci/pci-mt2701.c Rename 'pci-mt2701.c' to 'pcie-mediatek.c' and then change the subject.
So you promise us, that Mediatek will never produce PCI-E controller which will be totally different from that one? :)
imho we can use single driver for different IP generation and that is what we did in linux now.
MT7623/MT2701 - mtk_pcie_soc_v1 MT7622/MT7629 - v2 gen3 IP - TBD
Obviously, this is an intermediate version of Linux patch, so I suggest to take a look at the latest version of vanilla Kernel: https://github.com/torvalds/linux/blob/master/drivers/pci/controller/pcie-mediatek.c Please see my comments inline: > diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig > index 3fe38f7315..cfe8ba5e52 100644 > --- a/drivers/pci/Kconfig > +++ b/drivers/pci/Kconfig > @@ -145,4 +145,10 @@ config PCI_MVEBU > Say Y here if you want to enable PCIe controller support on > Armada XP/38x SoCs. > > +config PCIE_MT2701 > + bool "Mediatek 2701 PCI-E" > + help > + Say Y here if you want to enable PCIe controller support on > + Mediatek MT7623 > + > endif > diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile > index b5ebd50c85..a4c4002b9c 100644 > --- a/drivers/pci/Makefile > +++ b/drivers/pci/Makefile > @@ -38,3 +38,4 @@ obj-$(CONFIG_PCIE_LAYERSCAPE_GEN4) += pcie_layerscape_gen4.o \ > pcie_layerscape_gen4_fixup.o > obj-$(CONFIG_PCI_XILINX) += pcie_xilinx.o > obj-$(CONFIG_PCIE_INTEL_FPGA) += pcie_intel_fpga.o > +obj-$(CONFIG_PCIE_MT2701) += pci-mt2701.o > diff --git a/drivers/pci/pci-mt2701.c b/drivers/pci/pci-mt2701.c > new file mode 100644 > index 0000000000..5904f15330 > --- /dev/null > +++ b/drivers/pci/pci-mt2701.c > @@ -0,0 +1,490 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * Mediatek MT7623 SoC PCIE support > + * > + * Copyright (C) 2015 Mediatek > + * Copyright (C) 2015 John Crispin <blogic@openwrt.org> > + * Copyright (C) 2015 Ziv Huang <ziv.huang@mediatek.com> > + * Copyright (C) 2019 Oleksandr Rybalko <ray@ddteam.net> > + */ > + > +#include <common.h> > +#include <malloc.h> > + > +#include <pci.h> > +#include <asm/io.h> > + > +#include <dm.h> > +#include <fdtdec.h> > +#include <linux/libfdt.h> > +#include <dm/lists.h> > + > +#define iowrite32(v, a) writel(v, a) > +#define iowrite16(v, a) writew(v, a) > +#define iowrite8(v, a) writeb(v, a) > +#define ioread32(a) readl(a) > +#define ioread16(a) readw(a) > +#define ioread8(a) readb(a) Remove these defines. > +#define RT_HIFSYS_BASE 0x1a000000 > +#define RT_PCIE_BASE 0x1a140000 > +#define RT_PCIE_IOWIN_BASE 0x1a160000 > +#define RT_PCIE_IOWIN_SIZE 0x00010000 > +#define RT_PCIE_MEMWIN_BASE 0x60000000 > +#define RT_PCIE_MEMWIN_SIZE 0x10000000 Move these base to dts.
Already there (ranges), just not used yet.
so it's better remove unused parts, right?
> +#define RD(x) readl(RT_PCIE_BASE | (x)) > +#define WR(x, v) writel(v, RT_PCIE_BASE | (x)) > + > +#define SYSCFG1 0x14 > +#define RSTCTL 0x34 > +#define RSTSTAT 0x38 > +#define PCICFG 0x00 > +#define PCIINT 0x08 > +#define PCIENA 0x0c > +#define CFGADDR 0x20 > +#define CFGDATA 0x24 > +#define MEMBASE 0x28 > +#define IOBASE 0x2c > + > +#define BAR0SETUP 0x10 > +#define IMBASEBAR0 0x18 > +#define PCIE_CLASS 0x34 > +#define PCIE_SISTAT 0x50 > + > +#define MTK_PCIE_HIGH_PERF BIT(14) > +#define PCIEP0_BASE 0x2000 > +#define PCIEP1_BASE 0x3000 > +#define PCIEP2_BASE 0x4000 > + > +#define PHY_P0_CTL 0x9000 > +#define PHY_P1_CTL 0xa000 > +#define PHY_P2_CTL 0x4000 /* in USB space */ > + > +#define RSTCTL_PCIE0_RST BIT(24) > +#define RSTCTL_PCIE1_RST BIT(25) > +#define RSTCTL_PCIE2_RST BIT(26) > +#define MAX_PORT_NUM 3 > + > +struct resource { > + char *name; > + u32 start; > + u32 end; > +}; > + > +struct mt_pcie { > + char name[16]; > +}; > + > +static struct mtk_pcie_port { > + int id; > + int enable; > + u32 base; > + u32 phy_base; > + u32 perst_n; > + u32 reset; > + u32 interrupt_en; > + int irq; > + u32 link; > +} mtk_pcie_port[] = { > + { 0, 1, PCIEP0_BASE, PHY_P0_CTL, BIT(1), RSTCTL_PCIE0_RST, BIT(20) }, > + { 1, 1, PCIEP1_BASE, PHY_P1_CTL, BIT(2), RSTCTL_PCIE1_RST, BIT(21) }, > + { 2, 0, PCIEP2_BASE, PHY_P2_CTL, BIT(3), RSTCTL_PCIE2_RST, BIT(22) }, > +}; move some of mtk_pcie_port[] to dts.
Main point, at the end use orginal linux kernel DTS files. So it can be passed into kernel, instead of hardcode it inside kernel.
Just like we have ACPI blob on PC.
From what I see "[PATCH 4/4] arm: dts: Add PCI-E controller for mt7623" has enough information about "base/offset/port/phy" (that dts is same as linux one), but this driver does not use them.
> +struct mtk_pcie { > + struct device *dev; > + void __iomem *sys_base; /* HIF SYSCTL registers */ > + void __iomem *pcie_base; /* PCIE registers */ > + void __iomem *usb_base; /* USB registers */ > + > + struct resource io; > + struct resource pio; > + struct resource mem; > + struct resource prefetch; > + struct resource busn; > + > + u32 io_bus_addr; > + u32 mem_bus_addr; > + > + struct clk *clk; > + int pcie_card_link; > +}; > + > +static const struct mtk_phy_init { > + u32 reg; > + u32 mask; > + u32 val; > +} mtk_phy_init[] = { > + { 0xc00, 0x33000, 0x22000 }, > + { 0xb04, 0xe0000000, 0x40000000 }, > + { 0xb00, 0xe, 0x4 }, > + { 0xc3C, 0xffff0000, 0x3c0000 }, > + { 0xc48, 0xffff, 0x36 }, > + { 0xc0c, 0x30000000, 0x10000000 }, > + { 0xc08, 0x3800c0, 0xc0 }, > + { 0xc10, 0xf0000, 0x20000 }, > + { 0xc0c, 0xf000, 0x1000 }, > + { 0xc14, 0xf0000, 0xa0000 }, > + { 0xa28, 0x3fe00, 0x2000 }, > + { 0xa2c, 0x1ff, 0x10 }, > +}; We should add another PHY driver (drivers/phy/) for these settings. Like what we did for Linux: https://github.com/torvalds/linux/blob/master/drivers/phy/mediatek/phy-mtk-tphy.c
Yes, but it more complex way for future releases.
phy driver is used for configuring basic settings, there is no complex logic in it. we can even copy and paste the entire block from that driver.
.version = MTK_PHY_V1 case PHY_TYPE_PCIE: pcie_phy_instance_init(tphy, instance);
> +/* > + * Globals. > + */ > + > +struct mtk_pcie pcie; > +struct mtk_pcie *pcie0; > + > +static int mtk_pcie_probe(void); > +static int mt_pcie_read_config(struct udevice *, pci_dev_t, uint, ulong *, > + enum pci_size_t); > +static int mt_pcie_write_config(struct udevice *, pci_dev_t, uint, ulong, > + enum pci_size_t); > + > +#define mtk_foreach_port(p) \ > + for ((p) = mtk_pcie_port; \ > + (p) != &mtk_pcie_port[ARRAY_SIZE(mtk_pcie_port)]; (p)++) Use dts for each port. > +#define BITS(m, n) (~(BIT(m) - 1) & ((BIT(n) - 1) | BIT(n))) > + > +static void > +mt7623_pcie_pinmux_set(void) > +{ > + u32 regValue; > + > + /* Pin208: PCIE0_PERST_N (3) */ > + regValue = le32_to_cpu(ioread32(0x100059f0)); > + regValue &= ~(BITS(9, 11)); > + regValue |= 3 << 9; > + iowrite32(regValue, 0x100059f0); > + > + /* Pin208: PCIE1_PERST_N (3) */ > + regValue = le32_to_cpu(ioread32(0x100059f0)); > + regValue &= ~(BITS(12, 14)); > + regValue |= 3 << 12; > + iowrite32(regValue, 0x100059f0); > +} Configure pinmux in dts.
Will be, when we reach point of full tree.
now we have mt7623 pinctrl driver that should be enough.
> +static void > +sys_w32(struct mtk_pcie *pcie, u32 val, unsigned int reg) > +{ > + iowrite32(val, pcie->sys_base + reg); > +} > + > +static u32 > +sys_r32(struct mtk_pcie *pcie, unsigned int reg) > +{ > + return ioread32(pcie->sys_base + reg); > +} > + > +static void > +pcie_w32(struct mtk_pcie *pcie, u32 val, unsigned int reg) > +{ > + iowrite32(val, pcie->pcie_base + reg); > +} > + > +static void > +pcie_w16(struct mtk_pcie *pcie, u16 val, unsigned int reg) > +{ > + iowrite16(val, pcie->pcie_base + reg); > +} > + > +static void > +pcie_w8(struct mtk_pcie *pcie, u8 val, unsigned int reg) > +{ > + iowrite8(val, pcie->pcie_base + reg); > +} > + > +static u32 > +pcie_r32(struct mtk_pcie *pcie, unsigned int reg) > +{ > + return ioread32(pcie->pcie_base + reg); > +} > + > +static u32 > +pcie_r16(struct mtk_pcie *pcie, unsigned int reg) > +{ > + return ioread16(pcie->pcie_base + reg); > +} > + > +static u32 > +pcie_r8(struct mtk_pcie *pcie, unsigned int reg) > +{ > + return ioread8(pcie->pcie_base + reg); > +}
More specifically, we should use pci_generic_mmap_write/read_config() for standard set of confi read/write operations so that we can get rid of the helpers here.
I think the uboot driver end up dealing with nothing but just doing some initial parts (< 300 lines I guess), or you can take pcie_xilinx or pci_tegra as examples.
> +static void > +pcie_m32(struct mtk_pcie *pcie, u32 mask, u32 val, unsigned int reg) > +{ > + u32 v; > + > + v = pcie_r32(pcie, reg); > + v &= mask; > + v |= val; > + pcie_w32(pcie, v, reg); > +} > + > +static void > +mtk_pcie_configure_phy(struct mtk_pcie_port *port) > +{ > + int i; > + > + for (i = 0; i < ARRAY_SIZE(mtk_phy_init); i++) { > + void __iomem *phy_addr = (void __iomem *)port->phy_base + > + mtk_phy_init[i].reg; > + u32 val = ioread32(phy_addr); > + > + val &= ~mtk_phy_init[i].mask; > + val |= mtk_phy_init[i].val; > + iowrite32(val, phy_addr); > + udelay(100); > + } > + mdelay(16); > +} Use PHY driver. > +static void > +mtk_pcie_configure_rc(struct mtk_pcie *pcie, struct mtk_pcie_port *port) > +{ > + ulong val = 0; > + > + mt_pcie_write_config(NULL, (port->id) << 3, PCI_BASE_ADDRESS_0, > + 0x80000000, PCI_SIZE_32); > + mt_pcie_read_config(NULL, (port->id) << 3, PCI_BASE_ADDRESS_0, &val, > + PCI_SIZE_32); > + > + /* Configre RC Credit */ > + val = 0; > + mt_pcie_read_config(NULL, (port->id) << 3, 0x73c, &val, PCI_SIZE_32); > + val &= ~(0x9fffUL) << 16; > + val |= 0x806c << 16; > + mt_pcie_write_config(NULL, (port->id) << 3, 0x73c, val, PCI_SIZE_32); > + mt_pcie_read_config(NULL, (port->id) << 3, 0x73c, &val, PCI_SIZE_32); > + > + /* Configre RC FTS number */ > + mt_pcie_read_config(NULL, (port->id) << 3, 0x70c, &val, PCI_SIZE_32); > + val &= ~(0xff3) << 8; > + val |= 0x50 << 8; > + mt_pcie_write_config(NULL, (port->id) << 3, 0x70c, val, PCI_SIZE_32); > + mt_pcie_read_config(NULL, (port->id) << 3, 0x70c, &val, PCI_SIZE_32); > +} > + > +static void > +mtk_pcie_preinit(struct mtk_pcie *pcie) > +{ > + struct mtk_pcie_port *port; > + u32 val = 0; > + int i; > + > + mt7623_pcie_pinmux_set(); > + > + /* PCIe RC Reset */ > + val = 0; > + mtk_foreach_port(port) > + if (port->enable) > + val |= port->reset; > + sys_w32(pcie, sys_r32(pcie, RSTCTL) | val, RSTCTL); > + mdelay(12); > + sys_w32(pcie, sys_r32(pcie, RSTCTL) & ~val, RSTCTL); > + mdelay(12); > + > + i = 100000; > + while (i--) { > + if (sys_r32(pcie, RSTSTAT) == 0) > + break; > + udelay(10); > + } We should avoid this while loop. > + /* Configure PCIe PHY */ > + > + mtk_foreach_port(port) > + if (port->enable) > + mtk_pcie_configure_phy(port); > + > + /* PCIe EP reset */ > + val = 0; > + mtk_foreach_port(port) > + if (port->enable) > + val |= port->perst_n; > + pcie_w32(pcie, pcie_r32(pcie, PCICFG) | val, PCICFG); > + mdelay(12); > + pcie_w32(pcie, pcie_r32(pcie, PCICFG) & ~val, PCICFG); > + mdelay(200); > + > + /* check the link status */ > + val = 0; > + mtk_foreach_port(port) { > + if (port->enable) { > + if ((pcie_r32(pcie, port->base + PCIE_SISTAT) & 0x1)) > + port->link = 1; > + else > + val |= port->reset; > + } > + } > + sys_w32(pcie, sys_r32(pcie, RSTCTL) | val, RSTCTL); > + mdelay(200); > + > + i = 100000; > + while (i--) { > + if (sys_r32(pcie, RSTSTAT) == 0) > + break; > + udelay(10); > + } > + > + mtk_foreach_port(port) { > + if (port->link) > + pcie->pcie_card_link++; > + } > + printf("%s: PCIe Link count=%d\n", __func__, pcie->pcie_card_link); > + if (!pcie->pcie_card_link) > + return; > + > + pcie_w32(pcie, pcie->mem_bus_addr, MEMBASE); > + pcie_w32(pcie, pcie->io_bus_addr, IOBASE); > + > + mtk_foreach_port(port) { > + if (port->link) { > + pcie_m32(pcie, 0xffffffff, port->interrupt_en, PCIENA); > + pcie_w32(pcie, 0x7fff0001, port->base + BAR0SETUP); > + pcie_w32(pcie, 0x80000000, port->base + IMBASEBAR0); > + pcie_w32(pcie, 0x06040001, port->base + PCIE_CLASS); magic number.
Descriptive by reg names.
we can directly replace these chunks with mtk_pcie_startup_port() (pcie-mediatek.c) and there are many defines for the registers/bit field.

Hi Ryder,
you know that we cannot write a full, multi-device driver here :)
Gesendet: Mittwoch, 31. Juli 2019 um 17:23 Uhr Von: "Ryder Lee" ryder.lee@mediatek.com
imho we can use single driver for different IP generation and that is what we did in linux now.
MT7623/MT2701 - mtk_pcie_soc_v1 MT7622/MT7629 - v2 gen3 IP - TBD
i ack that's the right way, but this cannot be done by people outside (that do not have knowledge about multiple chips the driver should cover) and not only in freetime, so our approach was to create a driver for this chip (that is also used by other soc) as base for future developement (extending for other boards).
on any time it needs to be replaced by a more universal variant to have not the same code multiple times. but thats far away from we can do here
it's not the best code (based on magic values and portability to other devices), but from my point of view we have working sata and do not modify existing code too much (to avoid side-effects), but only figuring out which consts are used in linux take much time for us
phy driver is used for configuring basic settings, there is no complex logic in it. we can even copy and paste the entire block from that driver.
you know the technical details :) what we do is read out registers in linux and try to adapt this in uboot ;) because drivercode itself is too big for us to understand
.version = MTK_PHY_V1 case PHY_TYPE_PCIE: pcie_phy_instance_init(tphy, instance);
More specifically, we should use pci_generic_mmap_write/read_config() for standard set of confi read/write operations so that we can get rid of the helpers here.
a general way is right, but not possible to created by people not working for mtk :) without the right documentation
we do not have the knowledge to port a driver like this from linux to uboot
I think the uboot driver end up dealing with nothing but just doing some initial parts (< 300 lines I guess), or you can take pcie_xilinx or pci_tegra as examples.
we can directly replace these chunks with mtk_pcie_startup_port() (pcie-mediatek.c) and there are many defines for the registers/bit field.
i tried this, but just C&P does not work ( i'm not that naive :) ) because of many depencies (functions used in linux-variant), i have already changed some things, but it ended in needed touching corefiles of uboot (e.g. extending pci.h) which may break other drivers.
but at least i have this version (with some fix-ups you've mentioned here) on my github-repo so that everybody can use it for my board/other boards using mt2701
https://github.com/frank-w/u-boot/commits/2019-07-bpi-r2-sata_new (will merge that in other main branches till official driver is there)
regards Frank

On Wed, 2019-07-31 at 18:09 +0200, Frank Wunderlich wrote:
Hi Ryder,
you know that we cannot write a full, multi-device driver here :)
Just need to write mt7623 part. And what I'm saying is you have a perfect dts with many phandles listed there. (i.e. clk, reset, reg and phy) https://patchwork.ozlabs.org/patch/1139695/ However the patch directly puts everything into PCI driver without using other modules. We should switch to use them.
Gesendet: Mittwoch, 31. Juli 2019 um 17:23 Uhr Von: "Ryder Lee" ryder.lee@mediatek.com
imho we can use single driver for different IP generation and that is what we did in linux now.
MT7623/MT2701 - mtk_pcie_soc_v1 MT7622/MT7629 - v2 gen3 IP - TBD
i ack that's the right way, but this cannot be done by people outside (that do not have knowledge about multiple chips the driver should cover) and not only in freetime, so our approach was to create a driver for this chip (that is also used by other soc) as base for future developement (extending for other boards).
on any time it needs to be replaced by a more universal variant to have not the same code multiple times. but thats far away from we can do here
it's not the best code (based on magic values and portability to other devices), but from my point of view we have working sata and do not modify existing code too much (to avoid side-effects), but only figuring out which consts are used in linux take much time for us
phy driver is used for configuring basic settings, there is no complex logic in it. we can even copy and paste the entire block from that driver.
you know the technical details :) what we do is read out registers in linux and try to adapt this in uboot ;) because drivercode itself is too big for us to understand
.version = MTK_PHY_V1 case PHY_TYPE_PCIE: pcie_phy_instance_init(tphy, instance);
More specifically, we should use pci_generic_mmap_write/read_config() for standard set of confi read/write operations so that we can get rid of the helpers here.
a general way is right, but not possible to created by people not working for mtk :) without the right documentation we do not have the knowledge to port a driver like this from linux to uboot
I think the uboot driver end up dealing with nothing but just doing some initial parts (< 300 lines I guess), or you can take pcie_xilinx or pci_tegra as examples.
we can directly replace these chunks with mtk_pcie_startup_port() (pcie-mediatek.c) and there are many defines for the registers/bit field.
i tried this, but just C&P does not work ( i'm not that naive :) ) because of many depencies (functions used in linux-variant), i have already changed some things, but it ended in needed touching corefiles of uboot (e.g. extending pci.h) which may break other drivers.
but at least i have this version (with some fix-ups you've mentioned here) on my github-repo so that everybody can use it for my board/other boards using mt2701
https://github.com/frank-w/u-boot/commits/2019-07-bpi-r2-sata_new (will merge that in other main branches till official driver is there)
regards Frank
The document has been opened in the air - https://drive.google.com/file/d/0B_YnvHgh2rwjR3pwSzNrS1Nqdjg/view?usp=sharin... or google 'MTK 7623N datasheet for development board programming guide'. or just look at Linux driver to know the defines.
But do you really need these stuff? Since the HW settings are fixed there unless you want to fine-tune something. I think we just need to understand how core layer works and how to add the hook points.
IMHO What we should do for opensource driver is keep code quality and maintainability, modularity thus improves readability through a well-organized design and build state machines in our head of what the code is doing. This meant that when we have a problem, we could easily scrub through all the code that our functionality depended on (modularity), trace the problem, and eventually optimize the code (maintainability) - it all helps everything move forward..
Anyway I wrote a quick patch for PCIe this morning but didn't test it yet (and I'm a careless guy). I think maybe you can try it out and do some proper modifications according your test. https://pastebin.com/kyTqEBJf
Also we need to add a PHY driver support for it :)
Ryder

Part 3 + 4 of this series will be replaced by driver from Ryder Lee (post his series in next hours). i have tested it the last days.
Part 1 + 2 will still be needed to get ahci on bananapi r2 working.
Am 31. Juli 2019 13:51:44 MESZ schrieb Frank Wunderlich frank-w@public-files.de:
From: Oleksandr Rybalko ray@ddteam.net
this chip is used in MT7623 and some other Mediatek SoCs for pcie
Tested-by: Frank Wunderlich frank-w@public-files.de Signed-off-by: Frank Wunderlich frank-w@public-files.de Signed-off-by: Oleksandr Rybalko ray@ddteam.net
drivers/pci/Kconfig | 6 + drivers/pci/Makefile | 1 + drivers/pci/pci-mt2701.c | 490 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 497 insertions(+) create mode 100644 drivers/pci/pci-mt2701.c
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 3fe38f7315..cfe8ba5e52 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -145,4 +145,10 @@ config PCI_MVEBU Say Y here if you want to enable PCIe controller support on Armada XP/38x SoCs.
+config PCIE_MT2701
- bool "Mediatek 2701 PCI-E"
- help
Say Y here if you want to enable PCIe controller support on
Mediatek MT7623
endif diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index b5ebd50c85..a4c4002b9c 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -38,3 +38,4 @@ obj-$(CONFIG_PCIE_LAYERSCAPE_GEN4) += pcie_layerscape_gen4.o \ pcie_layerscape_gen4_fixup.o obj-$(CONFIG_PCI_XILINX) += pcie_xilinx.o obj-$(CONFIG_PCIE_INTEL_FPGA) += pcie_intel_fpga.o +obj-$(CONFIG_PCIE_MT2701) += pci-mt2701.o diff --git a/drivers/pci/pci-mt2701.c b/drivers/pci/pci-mt2701.c new file mode 100644 index 0000000000..5904f15330 --- /dev/null +++ b/drivers/pci/pci-mt2701.c @@ -0,0 +1,490 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Mediatek MT7623 SoC PCIE support
- Copyright (C) 2015 Mediatek
- Copyright (C) 2015 John Crispin blogic@openwrt.org
- Copyright (C) 2015 Ziv Huang ziv.huang@mediatek.com
- Copyright (C) 2019 Oleksandr Rybalko ray@ddteam.net
- */
+#include <common.h> +#include <malloc.h>
+#include <pci.h> +#include <asm/io.h>
+#include <dm.h> +#include <fdtdec.h> +#include <linux/libfdt.h> +#include <dm/lists.h>
+#define iowrite32(v, a) writel(v, a) +#define iowrite16(v, a) writew(v, a) +#define iowrite8(v, a) writeb(v, a) +#define ioread32(a) readl(a) +#define ioread16(a) readw(a) +#define ioread8(a) readb(a)
+#define RT_HIFSYS_BASE 0x1a000000 +#define RT_PCIE_BASE 0x1a140000 +#define RT_PCIE_IOWIN_BASE 0x1a160000 +#define RT_PCIE_IOWIN_SIZE 0x00010000 +#define RT_PCIE_MEMWIN_BASE 0x60000000 +#define RT_PCIE_MEMWIN_SIZE 0x10000000
+#define RD(x) readl(RT_PCIE_BASE | (x)) +#define WR(x, v) writel(v, RT_PCIE_BASE | (x))
+#define SYSCFG1 0x14 +#define RSTCTL 0x34 +#define RSTSTAT 0x38 +#define PCICFG 0x00 +#define PCIINT 0x08 +#define PCIENA 0x0c +#define CFGADDR 0x20 +#define CFGDATA 0x24 +#define MEMBASE 0x28 +#define IOBASE 0x2c
+#define BAR0SETUP 0x10 +#define IMBASEBAR0 0x18 +#define PCIE_CLASS 0x34 +#define PCIE_SISTAT 0x50
+#define MTK_PCIE_HIGH_PERF BIT(14) +#define PCIEP0_BASE 0x2000 +#define PCIEP1_BASE 0x3000 +#define PCIEP2_BASE 0x4000
+#define PHY_P0_CTL 0x9000 +#define PHY_P1_CTL 0xa000 +#define PHY_P2_CTL 0x4000 /* in USB space */
+#define RSTCTL_PCIE0_RST BIT(24) +#define RSTCTL_PCIE1_RST BIT(25) +#define RSTCTL_PCIE2_RST BIT(26) +#define MAX_PORT_NUM 3
+struct resource {
- char *name;
- u32 start;
- u32 end;
+};
+struct mt_pcie {
- char name[16];
+};
+static struct mtk_pcie_port {
- int id;
- int enable;
- u32 base;
- u32 phy_base;
- u32 perst_n;
- u32 reset;
- u32 interrupt_en;
- int irq;
- u32 link;
+} mtk_pcie_port[] = {
- { 0, 1, PCIEP0_BASE, PHY_P0_CTL, BIT(1), RSTCTL_PCIE0_RST, BIT(20) },
- { 1, 1, PCIEP1_BASE, PHY_P1_CTL, BIT(2), RSTCTL_PCIE1_RST, BIT(21) },
- { 2, 0, PCIEP2_BASE, PHY_P2_CTL, BIT(3), RSTCTL_PCIE2_RST, BIT(22) },
+};
+struct mtk_pcie {
- struct device *dev;
- void __iomem *sys_base; /* HIF SYSCTL registers */
- void __iomem *pcie_base; /* PCIE registers */
- void __iomem *usb_base; /* USB registers */
- struct resource io;
- struct resource pio;
- struct resource mem;
- struct resource prefetch;
- struct resource busn;
- u32 io_bus_addr;
- u32 mem_bus_addr;
- struct clk *clk;
- int pcie_card_link;
+};
+static const struct mtk_phy_init {
- u32 reg;
- u32 mask;
- u32 val;
+} mtk_phy_init[] = {
- { 0xc00, 0x33000, 0x22000 },
- { 0xb04, 0xe0000000, 0x40000000 },
- { 0xb00, 0xe, 0x4 },
- { 0xc3C, 0xffff0000, 0x3c0000 },
- { 0xc48, 0xffff, 0x36 },
- { 0xc0c, 0x30000000, 0x10000000 },
- { 0xc08, 0x3800c0, 0xc0 },
- { 0xc10, 0xf0000, 0x20000 },
- { 0xc0c, 0xf000, 0x1000 },
- { 0xc14, 0xf0000, 0xa0000 },
- { 0xa28, 0x3fe00, 0x2000 },
- { 0xa2c, 0x1ff, 0x10 },
+};
+/*
- Globals.
- */
+struct mtk_pcie pcie; +struct mtk_pcie *pcie0;
+static int mtk_pcie_probe(void); +static int mt_pcie_read_config(struct udevice *, pci_dev_t, uint, ulong *,
enum pci_size_t);
+static int mt_pcie_write_config(struct udevice *, pci_dev_t, uint, ulong,
enum pci_size_t);
+#define mtk_foreach_port(p) \
for ((p) = mtk_pcie_port; \
(p) != &mtk_pcie_port[ARRAY_SIZE(mtk_pcie_port)]; (p)++)
+#define BITS(m, n) (~(BIT(m) - 1) & ((BIT(n) - 1) | BIT(n)))
+static void +mt7623_pcie_pinmux_set(void) +{
- u32 regValue;
- /* Pin208: PCIE0_PERST_N (3) */
- regValue = le32_to_cpu(ioread32(0x100059f0));
- regValue &= ~(BITS(9, 11));
- regValue |= 3 << 9;
- iowrite32(regValue, 0x100059f0);
- /* Pin208: PCIE1_PERST_N (3) */
- regValue = le32_to_cpu(ioread32(0x100059f0));
- regValue &= ~(BITS(12, 14));
- regValue |= 3 << 12;
- iowrite32(regValue, 0x100059f0);
+}
+static void +sys_w32(struct mtk_pcie *pcie, u32 val, unsigned int reg) +{
- iowrite32(val, pcie->sys_base + reg);
+}
+static u32 +sys_r32(struct mtk_pcie *pcie, unsigned int reg) +{
- return ioread32(pcie->sys_base + reg);
+}
+static void +pcie_w32(struct mtk_pcie *pcie, u32 val, unsigned int reg) +{
- iowrite32(val, pcie->pcie_base + reg);
+}
+static void +pcie_w16(struct mtk_pcie *pcie, u16 val, unsigned int reg) +{
- iowrite16(val, pcie->pcie_base + reg);
+}
+static void +pcie_w8(struct mtk_pcie *pcie, u8 val, unsigned int reg) +{
- iowrite8(val, pcie->pcie_base + reg);
+}
+static u32 +pcie_r32(struct mtk_pcie *pcie, unsigned int reg) +{
- return ioread32(pcie->pcie_base + reg);
+}
+static u32 +pcie_r16(struct mtk_pcie *pcie, unsigned int reg) +{
- return ioread16(pcie->pcie_base + reg);
+}
+static u32 +pcie_r8(struct mtk_pcie *pcie, unsigned int reg) +{
- return ioread8(pcie->pcie_base + reg);
+}
+static void +pcie_m32(struct mtk_pcie *pcie, u32 mask, u32 val, unsigned int reg) +{
- u32 v;
- v = pcie_r32(pcie, reg);
- v &= mask;
- v |= val;
- pcie_w32(pcie, v, reg);
+}
+static void +mtk_pcie_configure_phy(struct mtk_pcie_port *port) +{
- int i;
- for (i = 0; i < ARRAY_SIZE(mtk_phy_init); i++) {
void __iomem *phy_addr = (void __iomem *)port->phy_base +
mtk_phy_init[i].reg;
u32 val = ioread32(phy_addr);
val &= ~mtk_phy_init[i].mask;
val |= mtk_phy_init[i].val;
iowrite32(val, phy_addr);
udelay(100);
- }
- mdelay(16);
+}
+static void +mtk_pcie_configure_rc(struct mtk_pcie *pcie, struct mtk_pcie_port *port) +{
- ulong val = 0;
- mt_pcie_write_config(NULL, (port->id) << 3, PCI_BASE_ADDRESS_0,
0x80000000, PCI_SIZE_32);
- mt_pcie_read_config(NULL, (port->id) << 3, PCI_BASE_ADDRESS_0, &val,
PCI_SIZE_32);
- /* Configre RC Credit */
- val = 0;
- mt_pcie_read_config(NULL, (port->id) << 3, 0x73c, &val, PCI_SIZE_32);
- val &= ~(0x9fffUL) << 16;
- val |= 0x806c << 16;
- mt_pcie_write_config(NULL, (port->id) << 3, 0x73c, val, PCI_SIZE_32);
- mt_pcie_read_config(NULL, (port->id) << 3, 0x73c, &val, PCI_SIZE_32);
- /* Configre RC FTS number */
- mt_pcie_read_config(NULL, (port->id) << 3, 0x70c, &val, PCI_SIZE_32);
- val &= ~(0xff3) << 8;
- val |= 0x50 << 8;
- mt_pcie_write_config(NULL, (port->id) << 3, 0x70c, val, PCI_SIZE_32);
- mt_pcie_read_config(NULL, (port->id) << 3, 0x70c, &val, PCI_SIZE_32);
+}
+static void +mtk_pcie_preinit(struct mtk_pcie *pcie) +{
- struct mtk_pcie_port *port;
- u32 val = 0;
- int i;
- mt7623_pcie_pinmux_set();
- /* PCIe RC Reset */
- val = 0;
- mtk_foreach_port(port)
if (port->enable)
val |= port->reset;
- sys_w32(pcie, sys_r32(pcie, RSTCTL) | val, RSTCTL);
- mdelay(12);
- sys_w32(pcie, sys_r32(pcie, RSTCTL) & ~val, RSTCTL);
- mdelay(12);
- i = 100000;
- while (i--) {
if (sys_r32(pcie, RSTSTAT) == 0)
break;
udelay(10);
- }
- /* Configure PCIe PHY */
- mtk_foreach_port(port)
if (port->enable)
mtk_pcie_configure_phy(port);
- /* PCIe EP reset */
- val = 0;
- mtk_foreach_port(port)
if (port->enable)
val |= port->perst_n;
- pcie_w32(pcie, pcie_r32(pcie, PCICFG) | val, PCICFG);
- mdelay(12);
- pcie_w32(pcie, pcie_r32(pcie, PCICFG) & ~val, PCICFG);
- mdelay(200);
- /* check the link status */
- val = 0;
- mtk_foreach_port(port) {
if (port->enable) {
if ((pcie_r32(pcie, port->base + PCIE_SISTAT) & 0x1))
port->link = 1;
else
val |= port->reset;
}
- }
- sys_w32(pcie, sys_r32(pcie, RSTCTL) | val, RSTCTL);
- mdelay(200);
- i = 100000;
- while (i--) {
if (sys_r32(pcie, RSTSTAT) == 0)
break;
udelay(10);
- }
- mtk_foreach_port(port) {
if (port->link)
pcie->pcie_card_link++;
- }
- printf("%s: PCIe Link count=%d\n", __func__, pcie->pcie_card_link);
- if (!pcie->pcie_card_link)
return;
- pcie_w32(pcie, pcie->mem_bus_addr, MEMBASE);
- pcie_w32(pcie, pcie->io_bus_addr, IOBASE);
- mtk_foreach_port(port) {
if (port->link) {
pcie_m32(pcie, 0xffffffff, port->interrupt_en, PCIENA);
pcie_w32(pcie, 0x7fff0001, port->base + BAR0SETUP);
pcie_w32(pcie, 0x80000000, port->base + IMBASEBAR0);
pcie_w32(pcie, 0x06040001, port->base + PCIE_CLASS);
}
- }
- mdelay(100);
- mtk_foreach_port(port)
if (port->link)
mtk_pcie_configure_rc(pcie, port);
+}
+static void +mtk_pcie_fill_port(struct mtk_pcie *pcie) +{
- int i;
- for (i = 0; i < 2; i++)
mtk_pcie_port[i].phy_base += (u32)pcie->pcie_base;
- mtk_pcie_port[2].phy_base += (u32)pcie->usb_base;
+}
+void +mt_pcie_init(void) +{
- /* Static instance of the controller. */
- static struct pci_controller pcc;
- struct pci_controller *hose = &pcc;
- memset(&pcc, 0, sizeof(pcc));
- /* PCI I/O space */
- pci_set_region(&hose->regions[0], RT_PCIE_IOWIN_BASE,
RT_PCIE_IOWIN_BASE, RT_PCIE_IOWIN_SIZE, PCI_REGION_IO);
- /* PCI memory space */
- pci_set_region(&hose->regions[1], RT_PCIE_MEMWIN_BASE,
RT_PCIE_MEMWIN_BASE, RT_PCIE_MEMWIN_SIZE,
PCI_REGION_MEM);
- hose->region_count = 2;
+}
+int +mtk_pcie_probe() +{
- pcie0 = &pcie;
- pcie0->io_bus_addr = RT_PCIE_IOWIN_BASE;
- pcie0->mem_bus_addr = RT_PCIE_MEMWIN_BASE;
- pcie0->sys_base = (u32 *)RT_HIFSYS_BASE;
- pcie0->pcie_base = (u32 *)RT_PCIE_BASE;
- mtk_pcie_fill_port(pcie0);
- mtk_pcie_preinit(pcie0);
- return 0;
+}
+/* Probe function. */ +void +pci_init_board(void) +{
- mtk_pcie_probe();
- mt_pcie_init();
+}
+static int +mt_pcie_read_config(struct udevice *bus, pci_dev_t bdf,
uint offset, ulong *valuep,
enum pci_size_t size)
+{
- u32 address = bdf | ((offset & 0xf00) << 16) | (offset & 0xfc);
- pcie_m32(pcie0, 0xf0000000, address, CFGADDR);
- switch (size) {
- case PCI_SIZE_8:
*valuep = pcie_r8(pcie0, CFGDATA + (offset & 3));
break;
- case PCI_SIZE_16:
*valuep = pcie_r16(pcie0, CFGDATA + (offset & 2));
break;
- case PCI_SIZE_32:
*valuep = pcie_r32(pcie0, CFGDATA);
break;
- }
- return 0;
+}
+static int +mt_pcie_write_config(struct udevice *bus, pci_dev_t bdf,
uint offset, ulong value,
enum pci_size_t size)
+{
- u32 address = bdf | ((offset & 0xf00) << 16) | (offset & 0xfc);
- pcie_m32(pcie0, 0xf0000000, address, CFGADDR);
- switch (size) {
- case PCI_SIZE_8:
pcie_w8(pcie0, value, CFGDATA + (offset & 3));
break;
- case PCI_SIZE_16:
pcie_w16(pcie0, value, CFGDATA + (offset & 2));
break;
- case PCI_SIZE_32:
- default:
pcie_w32(pcie0, value, CFGDATA);
break;
- }
- return 0;
+}
+static int +mt_pcie_probe(struct udevice *dev) +{
- mtk_pcie_probe();
- mt_pcie_init();
- return 0;
+}
+static const struct dm_pci_ops mt_pcie_ops = {
- .read_config = mt_pcie_read_config,
- .write_config = mt_pcie_write_config,
+};
+static const struct udevice_id mt_pcie_ids[] = {
- { .compatible = "mediatek,mt7623-pcie" },
- { }
+};
+U_BOOT_DRIVER(pcie_mt2701) = {
- .name = "pci_mt2701",
- .id = UCLASS_PCI,
- .of_match = mt_pcie_ids,
- .ops = &mt_pcie_ops,
- .probe = mt_pcie_probe,
- .priv_auto_alloc_size = sizeof(struct mt_pcie),
+};
2.17.1

this Patch adds pcie-controller node for mt7623
Signed-off-by: Frank Wunderlich frank-w@public-files.de --- arch/arm/dts/mt7623.dtsi | 108 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+)
diff --git a/arch/arm/dts/mt7623.dtsi b/arch/arm/dts/mt7623.dtsi index 64079c61bf..5d7c62bb8d 100644 --- a/arch/arm/dts/mt7623.dtsi +++ b/arch/arm/dts/mt7623.dtsi @@ -255,6 +255,114 @@ #reset-cells = <1>; };
+ pcie: pcie-controller@1a140000 { + compatible = "mediatek,mt7623-pcie"; + device_type = "pci"; + reg = <0x1a140000 0x1000>, /* PCIe shared registers */ + <0x1a142000 0x1000>, /* Port0 registers */ + <0x1a143000 0x1000>, /* Port1 registers */ + <0x1a144000 0x1000>; /* Port2 registers */ + reg-names = "subsys", "port0", "port1", "port2"; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xf800 0 0 0>; + interrupt-map = <0x0000 0 0 0 &sysirq GIC_SPI 193 + IRQ_TYPE_LEVEL_LOW>, + <0x0800 0 0 0 &sysirq GIC_SPI 194 + IRQ_TYPE_LEVEL_LOW>, + <0x1000 0 0 0 &sysirq GIC_SPI 195 + IRQ_TYPE_LEVEL_LOW>; + clocks = <&topckgen CLK_TOP_ETHIF_SEL>, + <&hifsys CLK_HIFSYS_PCIE0>, + <&hifsys CLK_HIFSYS_PCIE1>, + <&hifsys CLK_HIFSYS_PCIE2>; + clock-names = "free_ck", "sys_ck0", "sys_ck1", "sys_ck2"; + reset-names = "pcie-rst0", "pcie-rst1", "pcie-rst2"; + phy-names = "pcie-phy0", "pcie-phy1", "pcie-phy2"; + power-domains = <&scpsys MT7623_POWER_DOMAIN_HIF>; + bus-range = <0x00 0xff>; + status = "okay"; + ranges = <0x81000000 0 0x1a160000 0x1a160000 0 0x00010000 + 0x83000000 0 0x60000000 0x60000000 0 0x10000000>; + + pcie@0,0 { + device_type = "pci"; + reg = <0x0000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &sysirq GIC_SPI 193 + IRQ_TYPE_LEVEL_LOW>; + ranges; + num-lanes = <1>; + status = "disabled"; + }; + + pcie@1,0 { + device_type = "pci"; + reg = <0x0800 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &sysirq GIC_SPI 194 + IRQ_TYPE_LEVEL_LOW>; + ranges; + num-lanes = <1>; + status = "disabled"; + }; + + pcie@2,0 { + device_type = "pci"; + reg = <0x1000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &sysirq GIC_SPI 195 + IRQ_TYPE_LEVEL_LOW>; + ranges; + num-lanes = <1>; + status = "disabled"; + }; + }; + + pcie0_phy: pcie-phy@1a149000 { + compatible = "mediatek,generic-tphy-v1"; + reg = <0x1a149000 0x0700>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + status = "disabled"; + + pcie0_port: pcie-phy@1a149900 { + reg = <0x1a149900 0x0700>; + clocks = <&clk26m>; + clock-names = "ref"; + #phy-cells = <1>; + status = "okay"; + }; + }; + + pcie1_phy: pcie-phy@1a14a000 { + compatible = "mediatek,generic-tphy-v1"; + reg = <0x1a14a000 0x0700>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + status = "disabled"; + + pcie1_port: pcie-phy@1a14a900 { + reg = <0x1a14a900 0x0700>; + clocks = <&clk26m>; + clock-names = "ref"; + #phy-cells = <1>; + status = "okay"; + }; + }; + ethsys: syscon@1b000000 { compatible = "mediatek,mt7623-ethsys", "syscon"; reg = <0x1b000000 0x1000>; -- 2.17.1

Part 3 + 4 of this series will be replaced by driver from Ryder Lee (post his series in next hours). i have tested it the last days. Part 1 + 2 will still be needed to get ahci on bananapi r2 working.
participants (3)
-
Aleksandr Rybalko
-
Frank Wunderlich
-
Ryder Lee