Merge "ipq806x: Add PCIE entries for AP148 board"
diff --git a/arch/arm/dts/ipq806x-ap148.dts b/arch/arm/dts/ipq806x-ap148.dts
index 71e950e..1f282e0 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 = <GPIO_PULL_UP>;
+ drvstr = <GPIO_12MA>;
+ oe = <GPIO_OE_ENABLE>;
+ };
+ };
+ };
+
+ pci@1b700000 {
+ pci_gpio {
+ gpio48 {
+ gpio = <48>;
+ func = <1>;
+ pull = <GPIO_PULL_UP>;
+ drvstr = <GPIO_12MA>;
+ oe = <GPIO_OE_ENABLE>;
+ };
+ };
+ };
+
};
diff --git a/arch/arm/dts/ipq806x-soc.dtsi b/arch/arm/dts/ipq806x-soc.dtsi
index e40ab1b..cb5ac7b 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 3881fef..35e5ca4 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 659a634..c7249d2 100644
--- a/board/qca/arm/ipq40xx/ipq40xx.h
+++ b/board/qca/arm/ipq40xx/ipq40xx.h
@@ -73,6 +73,7 @@
#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 4535ee5..94b94e8 100644
--- a/board/qca/arm/ipq806x/ipq806x.c
+++ b/board/qca/arm/ipq806x/ipq806x.c
@@ -72,6 +72,48 @@
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 @@
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 4b01a3f..c9a26fe 100644
--- a/board/qca/arm/ipq806x/ipq806x.h
+++ b/board/qca/arm/ipq806x/ipq806x.h
@@ -117,4 +117,6 @@
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 e592bd8..ce9ca24 100644
--- a/drivers/clk/ipq806x_clk.c
+++ b/drivers/clk/ipq806x_clk.c
@@ -435,8 +435,7 @@
}
#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 @@
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 @@
/* 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 3a56dbb..464d4b7 100644
--- a/drivers/pci/pci_ipq.c
+++ b/drivers/pci/pci_ipq.c
@@ -159,6 +159,29 @@
#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 @@
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 @@
}
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 @@
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 cd7bc54..ba3fac7 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
*/