diff --git a/arch/arm/dts/ipq806x-ap148.dts b/arch/arm/dts/ipq806x-ap148.dts index 71e950e20e..1f282e0608 100644 --- a/arch/arm/dts/ipq806x-ap148.dts +++ b/arch/arm/dts/ipq806x-ap148.dts @@ -25,6 +25,8 @@ nand = "/nand@1A600000"; gmac_gpio = "/gmac1_gpio"; i2c0 = "/i2c@16380000"; + pci0 = "/pci@1b500000"; + pci1 = "/pci@1b700000"; }; serial@16340000 { @@ -65,4 +67,29 @@ phy_name = "IPQ MDIO2"; }; }; + + pci@1b500000 { + pci_gpio { + gpio3 { + gpio = <3>; + func = <1>; + pull = ; + drvstr = ; + oe = ; + }; + }; + }; + + pci@1b700000 { + pci_gpio { + gpio48 { + gpio = <48>; + func = <1>; + pull = ; + drvstr = ; + oe = ; + }; + }; + }; + }; diff --git a/arch/arm/dts/ipq806x-soc.dtsi b/arch/arm/dts/ipq806x-soc.dtsi index e40ab1b445..cb5ac7bf98 100644 --- a/arch/arm/dts/ipq806x-soc.dtsi +++ b/arch/arm/dts/ipq806x-soc.dtsi @@ -408,6 +408,36 @@ clock-frequency = <24000>; }; + pci@1b500000 { + compatible = "qcom,ipq806x-pcie"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x1b500000 0xf1d + 0x1b600000 0x2000 + 0x1b502000 0xa8 + 0x08000000 0x08000000 + 0x0ff00000 0x100000 + 0x009022DC 0x40>; + reg-names = "pci_dbi", "parf", "elbi", "axi_bars", + "axi_conf", "pci_rst"; + perst_gpio = <3>; + }; + + pci@1b700000 { + compatible = "qcom,ipq806x-pcie"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x1b700000 0xf1d + 0x1b800000 0x2000 + 0x1b702000 0xa8 + 0x2E000000 0x04000000 + 0x31f00000 0x100000 + 0x00903A9C 0x40>; + reg-names = "pci_dbi", "parf", "elbi", "axi_bars", + "axi_conf", "pci_rst"; + perst_gpio = <48>; + }; + spi { spi0 { mosi_miso_clk { diff --git a/arch/arm/include/asm/arch-ipq806x/clk.h b/arch/arm/include/asm/arch-ipq806x/clk.h index 3881fef8b6..35e5ca4f09 100644 --- a/arch/arm/include/asm/arch-ipq806x/clk.h +++ b/arch/arm/include/asm/arch-ipq806x/clk.h @@ -73,11 +73,49 @@ #define emmc_clk_ns_mask (BM(BIT_POS_23, BIT_POS_16) | BM(BIT_POS_6, BIT_POS_0)) #define emmc_en_mask BIT(11) +#define PCIE_0_ACLK_CTL 0x9022C0 +#define PCIE_1_ACLK_CTL 0x903a80 +#define PCIE_2_ACLK_CTL 0x903ac0 +#define PCIE_0_PCLK_CTL 0x9022D0 +#define PCIE_1_PCLK_CTL 0x903A90 +#define PCIE_2_PCLK_CTL 0x903AD0 +#define PCIE_0_HCLK_CTL 0x9022CC +#define PCIE_1_HCLK_CTL 0x903A8C +#define PCIE_2_HCLK_CTL 0x903ACC +#define PCIE_0_AUX_CLK_CTL 0x9022C8 +#define PCIE_1_AUX_CLK_CTL 0x903A88 +#define PCIE_2_AUX_CLK_CTL 0x903AC8 +#define PCIE_0_ALT_REF_CLK_NS 0x903860 +#define PCIE_1_ALT_REF_CLK_NS 0x903AA0 +#define PCIE_2_ALT_REF_CLK_NS 0x903AE0 +#define PCIE_0_ALT_REF_CLK_ACR 0x901344 +#define PCIE_1_ALT_REF_CLK_ACR 0x901354 +#define PCIE_2_ALT_REF_CLK_ACR 0x90135C +#define PCIE_0_ACLK_FS 0x9022C4 +#define PCIE_0_PCLK_FS 0x9022D4 +#define PCIE_1_ACLK_FS 0x903A84 +#define PCIE_1_PCLK_FS 0x903A94 +#define PCIE_2_ACLK_FS 0x903AC4 +#define PCIE_2_PCLK_FS 0x903AD4 +#define PCIE20_0_PARF_PHY_REFCLK 0x1B60004C +#define PCIE20_1_PARF_PHY_REFCLK 0x1B80004C +#define PCIE20_2_PARF_PHY_REFCLK 0x1BA0004C + +typedef struct { + unsigned int aclk_ctl; + unsigned int pclk_ctl; + unsigned int hclk_ctl; + unsigned int aux_clk_ctl; + unsigned int alt_ref_clk_ns; + unsigned int alt_ref_clk_acr; + unsigned int aclk_fs; + unsigned int pclk_fs; + unsigned int parf_phy_refclk; +} pci_clk_offset_t; void i2c_clock_config(void); /* Uart specific clock settings */ - void uart_pll_vote_clk_enable(void); void uart_clock_config(unsigned int gsbi_port, unsigned int m, unsigned int n, unsigned int d); diff --git a/board/qca/arm/ipq40xx/ipq40xx.h b/board/qca/arm/ipq40xx/ipq40xx.h index 659a63430d..c7249d20b0 100644 --- a/board/qca/arm/ipq40xx/ipq40xx.h +++ b/board/qca/arm/ipq40xx/ipq40xx.h @@ -73,6 +73,7 @@ typedef struct { #endif void board_pci_init(int id); +__weak void board_pcie_clock_init(int id) {} __weak void aquantia_phy_reset(void) {} /* Board specific parameters */ diff --git a/board/qca/arm/ipq806x/ipq806x.c b/board/qca/arm/ipq806x/ipq806x.c index 4535ee5a73..94b94e893a 100644 --- a/board/qca/arm/ipq806x/ipq806x.c +++ b/board/qca/arm/ipq806x/ipq806x.c @@ -72,6 +72,48 @@ int dump_entries_s = dump_entries_n; extern int ipq_spi_init(u16); +pci_clk_offset_t pcie_0_clk = { + .aclk_ctl = PCIE_0_ACLK_CTL, + .pclk_ctl = PCIE_0_PCLK_CTL, + .hclk_ctl = PCIE_0_HCLK_CTL, + .aux_clk_ctl = PCIE_0_AUX_CLK_CTL, + .alt_ref_clk_ns = PCIE_0_ALT_REF_CLK_NS, + .alt_ref_clk_acr = PCIE_0_ALT_REF_CLK_ACR, + .aclk_fs = PCIE_0_ACLK_FS, + .pclk_fs = PCIE_0_PCLK_FS, + .parf_phy_refclk = PCIE20_0_PARF_PHY_REFCLK +}; + +pci_clk_offset_t pcie_1_clk = { + .aclk_ctl = PCIE_1_ACLK_CTL, + .pclk_ctl = PCIE_1_PCLK_CTL, + .hclk_ctl = PCIE_1_HCLK_CTL, + .aux_clk_ctl = PCIE_1_AUX_CLK_CTL, + .alt_ref_clk_ns = PCIE_1_ALT_REF_CLK_NS, + .alt_ref_clk_acr = PCIE_1_ALT_REF_CLK_ACR, + .aclk_fs = PCIE_1_ACLK_FS, + .pclk_fs = PCIE_1_PCLK_FS, + .parf_phy_refclk = PCIE20_1_PARF_PHY_REFCLK +}; + +pci_clk_offset_t pcie_2_clk = { + .aclk_ctl = PCIE_2_ACLK_CTL, + .pclk_ctl = PCIE_2_PCLK_CTL, + .hclk_ctl = PCIE_2_HCLK_CTL, + .aux_clk_ctl = PCIE_2_AUX_CLK_CTL, + .alt_ref_clk_ns = PCIE_2_ALT_REF_CLK_NS, + .alt_ref_clk_acr = PCIE_2_ALT_REF_CLK_ACR, + .aclk_fs = PCIE_2_ACLK_FS, + .pclk_fs = PCIE_2_PCLK_FS, + .parf_phy_refclk = PCIE20_2_PARF_PHY_REFCLK +}; + +enum pcie_id { + PCIE_0, + PCIE_1, + PCIE_2, +}; + unsigned long timer_read_counter(void) { return 0; @@ -315,6 +357,38 @@ void qca_serial_init(struct ipq_serial_platdata *plat) GSBI_CTRL_REG(gsbi_base)); } +void board_pcie_clock_init(int id) +{ + switch(id) { + case PCIE_0: + pcie_clock_config(&pcie_0_clk); + break; + case PCIE_1: + pcie_clock_config(&pcie_1_clk); + break; + case PCIE_2: + pcie_clock_config(&pcie_2_clk); + break; + } +} + +void board_pci_init(int id) +{ + int node, gpio_node; + char name[16]; + + sprintf(name, "pci%d", id); + node = fdt_path_offset(gd->fdt_blob, name); + if (node < 0) { + printf("Could not find PCI in device tree\n"); + return; + } + gpio_node = fdt_subnode_offset(gd->fdt_blob, node, "pci_gpio"); + if (gpio_node >= 0) + qca_gpio_init(gpio_node); + + return; +} void ipq_fdt_fixup_socinfo(void *blob) { diff --git a/board/qca/arm/ipq806x/ipq806x.h b/board/qca/arm/ipq806x/ipq806x.h index 4b01a3fe2e..c9a26febce 100644 --- a/board/qca/arm/ipq806x/ipq806x.h +++ b/board/qca/arm/ipq806x/ipq806x.h @@ -117,4 +117,6 @@ extern const char *del_node[]; extern const add_node_t add_node[]; void reset_crashdump(void); void ipq_fdt_fixup_socinfo(void *blob); +void board_pci_init(int id); +void board_pcie_clock_init(int id); #endif /* _IPQ806X_H_ */ diff --git a/drivers/clk/ipq806x_clk.c b/drivers/clk/ipq806x_clk.c index e592bd8d22..ce9ca240ef 100644 --- a/drivers/clk/ipq806x_clk.c +++ b/drivers/clk/ipq806x_clk.c @@ -435,8 +435,7 @@ void nand_clock_config(void) } #endif -#ifdef CONFIG_IPQ806X_PCI -void pcie_clock_shutdown(clk_offset_t *pci_clk) +void pcie_clock_shutdown(pci_clk_offset_t *pci_clk) { /* PCIE_ALT_REF_CLK_NS */ writel(0x0, pci_clk->alt_ref_clk_ns); @@ -457,7 +456,7 @@ void pcie_clock_shutdown(clk_offset_t *pci_clk) writel(0x0, pci_clk->aux_clk_ctl); } -void pcie_clock_config(clk_offset_t *pci_clk) +void pcie_clock_config(pci_clk_offset_t *pci_clk) { /* PCIE_ALT_REF_CLK_NS */ writel(0x0A59, pci_clk->alt_ref_clk_ns); @@ -481,7 +480,6 @@ void pcie_clock_config(clk_offset_t *pci_clk) /* PCIE_AUX_CLK_CTL */ writel(0x10, pci_clk->aux_clk_ctl); } -#endif /* CONFIG_IPQ806X_PCI */ #ifdef CONFIG_QCA_MMC void emmc_pll_vote_clk_enable(void) diff --git a/drivers/pci/pci_ipq.c b/drivers/pci/pci_ipq.c index 3a56dbbdb6..464d4b746d 100644 --- a/drivers/pci/pci_ipq.c +++ b/drivers/pci/pci_ipq.c @@ -159,6 +159,29 @@ DECLARE_GLOBAL_DATA_PTR; #define PCIE_USB3_PCS_SW_RESET 0x800 #define PCIE_USB3_PCS_START_CONTROL 0x808 +#define PCIE20_PARF_PHY_CTRL 0x40 +#define PHY_CTRL_PHY_TX0_TERM_OFFSET_MASK (0x1f << 16) +#define PHY_CTRL_PHY_TX0_TERM_OFFSET(x) (x << 16) + +#define PCIE20_PARF_PHY_REFCLK 0x4C +#define REF_SSP_EN BIT(16) +#define REF_USE_PAD BIT(12) + +#define PCIE20_PARF_PCS_DEEMPH 0x34 +#define PCIE20_PARF_PCS_DEEMPH_TX_DEEMPH_GEN1(x) (x << 16) +#define PCIE20_PARF_PCS_DEEMPH_TX_DEEMPH_GEN2_3_5DB(x) (x << 8) +#define PCIE20_PARF_PCS_DEEMPH_TX_DEEMPH_GEN2_6DB(x) (x << 0) + +#define PCIE20_PARF_PCS_SWING 0x38 +#define PCIE20_PARF_PCS_SWING_TX_SWING_FULL(x) (x << 8) +#define PCIE20_PARF_PCS_SWING_TX_SWING_LOW(x) (x << 0) + +#define PCIE20_PARF_CONFIG_BITS 0x50 + +#define PCIE_SFAB_AXI_S5_FCLK_CTL 0x00902154 + +#define PCIE20_ELBI_SYS_CTRL 0x04 + static unsigned int local_buses[] = { 0, 0 }; struct pci_controller pci_hose[PCI_MAX_DEVICES]; static int phy_initialised; @@ -196,6 +219,24 @@ struct ipq_pcie { int version; }; +static void ipq_pcie_write_mask(uint32_t addr, + uint32_t clear_mask, uint32_t set_mask) +{ + uint32_t val; + + val = (readl(addr) & ~clear_mask) | set_mask; + writel(val, addr); +} + +static void ipq_pcie_parf_reset(uint32_t addr, int domain, int assert) + +{ + if (assert) + ipq_pcie_write_mask(addr, 0, domain); + else + ipq_pcie_write_mask(addr, domain, 0); +} + void ipq_pcie_config_cfgtype(uint32_t phyaddr) { uint32_t bdf, cfgtype; @@ -455,18 +496,88 @@ void pcie_linkup(struct ipq_pcie *pcie) } ipq_pcie_config_controller(pcie); } + +void pcie_v0_linkup(struct ipq_pcie *pcie, int id) +{ + int j; + uint32_t val; + /* assert PCIe PARF reset while powering the core */ + ipq_pcie_parf_reset(pcie->pci_rst.start, BIT(6), 0); + + ipq_pcie_parf_reset(pcie->pci_rst.start, BIT(2), 1); + board_pcie_clock_init(id); + /* + * de-assert PCIe PARF reset; + * wait 1us before accessing PARF registers + */ + ipq_pcie_parf_reset(pcie->pci_rst.start, BIT(2), 0); + udelay(1); + + /* enable PCIe clocks and resets */ + val = (readl(pcie->parf.start + PCIE20_PARF_PHY_CTRL) & ~BIT(0)); + writel(val, pcie->parf.start + PCIE20_PARF_PHY_CTRL); + + ipq_pcie_write_mask(pcie->parf.start + PCIE20_PARF_PHY_CTRL, + PHY_CTRL_PHY_TX0_TERM_OFFSET_MASK, + PHY_CTRL_PHY_TX0_TERM_OFFSET(0)); + + /* PARF programming */ + writel(PCIE20_PARF_PCS_DEEMPH_TX_DEEMPH_GEN1(0x18) | + PCIE20_PARF_PCS_DEEMPH_TX_DEEMPH_GEN2_3_5DB(0x18) | + PCIE20_PARF_PCS_DEEMPH_TX_DEEMPH_GEN2_6DB(0x22), + pcie->parf.start + PCIE20_PARF_PCS_DEEMPH); + + writel(PCIE20_PARF_PCS_SWING_TX_SWING_FULL(0x78) | + PCIE20_PARF_PCS_SWING_TX_SWING_LOW(0x78), + pcie->parf.start + PCIE20_PARF_PCS_SWING); + + writel((4<<24), pcie->parf.start + PCIE20_PARF_CONFIG_BITS); + + ipq_pcie_write_mask(pcie->parf.start + PCIE20_PARF_PHY_REFCLK, + REF_USE_PAD, REF_SSP_EN); + + /* enable access to PCIe slave port on system fabric */ + if (id == 0) { + writel(BIT(4), PCIE_SFAB_AXI_S5_FCLK_CTL); + } + + udelay(1); + /* de-assert PICe PHY, Core, POR and AXI clk domain resets */ + ipq_pcie_parf_reset(pcie->pci_rst.start, BIT(5), 0); + ipq_pcie_parf_reset(pcie->pci_rst.start, BIT(4), 0); + ipq_pcie_parf_reset(pcie->pci_rst.start, BIT(3), 0); + ipq_pcie_parf_reset(pcie->pci_rst.start, BIT(0), 0); + + /* enable link training */ + ipq_pcie_write_mask( pcie->elbi.start + PCIE20_ELBI_SYS_CTRL, 0, + BIT(0)); + udelay(500); + + for (j = 0; j < 10; j++) { + val = readl(pcie->pci_dbi.start + + PCIE_0_TYPE0_LINK_CONTROL_LINK_STATUS_REG_1); + if (val & BIT(29)) { + printf("PCI%d Link Intialized\n", id); + pcie->linkup = 1; + break; + } + udelay(10000); + } + ipq_pcie_config_controller(pcie); + +} + static int ipq_pcie_parse_dt(const void *fdt, int id, struct ipq_pcie *pcie) { int err, rst_gpio, node; + char name[16]; - if (id == 0) { - node = fdt_path_offset(fdt, "pci0"); - } else if (id == 1) { - node = fdt_path_offset(fdt, "pci1"); - } else { - printf("PCI is not defined in the device tree\n"); - return -1; + sprintf(name, "pci%d", id); + node = fdt_path_offset(fdt, name); + if (node < 0) { + printf("PCI%d is not defined in the device tree\n", id); + return node; } err = fdt_get_named_resource(fdt, node, "reg", "reg-names", "pci_dbi", @@ -703,6 +814,9 @@ static int pci_ipq_ofdata_to_platdata(int id, struct ipq_pcie *pcie) board_pci_init(id); switch(pcie->version) { + case PCIE_V0: + pcie_v0_linkup(pcie, id); + break; case PCIE_V1: pci_controller_init_v1(pcie); pcie_linkup(pcie); diff --git a/include/configs/ipq806x.h b/include/configs/ipq806x.h index cd7bc54a9d..ba3fac7e50 100644 --- a/include/configs/ipq806x.h +++ b/include/configs/ipq806x.h @@ -142,14 +142,15 @@ /* * PCI Configs */ -#undef CONFIG_IPQ806X_PCI - -#ifdef CONFIG_IPQ806X_PCI +#define CONFIG_PCI_IPQ +#define PCI_MAX_DEVICES 3 +#ifdef CONFIG_PCI_IPQ #define CONFIG_PCI #define CONFIG_CMD_PCI #define CONFIG_PCI_SCAN_SHOW #endif + /* * MMC Configs */