static int exynos_pcie_establish_link(struct pcie_port *pp) { struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); void __iomem *elbi_base = exynos_pcie->elbi_base; void __iomem *pmu_base = exynos_pcie->pmu_base; if (dw_pcie_link_up(pp)) { dev_err(pp->dev, "Link already up\n"); return 0; } writel(1, pmu_base + PCIE_PHY_CONTROL); exynos_pcie_assert_phy_reset(pp); exynos_pcie_sideband_dbi_r_mode(pp, true); exynos_pcie_sideband_dbi_w_mode(pp, true); /* setup root complex */ dw_pcie_setup_rc(pp); exynos_pcie_sideband_dbi_r_mode(pp, false); exynos_pcie_sideband_dbi_w_mode(pp, false); /* assert LTSSM enable */ writel(PCIE_ELBI_LTSSM_ENABLE, elbi_base + PCIE_APP_LTSSM_ENABLE); dev_info(pp->dev, "Link up\n"); return 0; }
static void exynos_pcie_power_off_phy(struct pcie_port *pp) { u32 val; struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); val = exynos_phy_readl(exynos_pcie, PCIE_PHY_COMMON_POWER); val |= PCIE_PHY_COMMON_PD_CMN; exynos_phy_writel(exynos_pcie, val, PCIE_PHY_COMMON_POWER); val = exynos_phy_readl(exynos_pcie, PCIE_PHY_TRSV0_POWER); val |= PCIE_PHY_TRSV0_PD_TSV; exynos_phy_writel(exynos_pcie, val, PCIE_PHY_TRSV0_POWER); val = exynos_phy_readl(exynos_pcie, PCIE_PHY_TRSV1_POWER); val |= PCIE_PHY_TRSV1_PD_TSV; exynos_phy_writel(exynos_pcie, val, PCIE_PHY_TRSV1_POWER); val = exynos_phy_readl(exynos_pcie, PCIE_PHY_TRSV2_POWER); val |= PCIE_PHY_TRSV2_PD_TSV; exynos_phy_writel(exynos_pcie, val, PCIE_PHY_TRSV2_POWER); val = exynos_phy_readl(exynos_pcie, PCIE_PHY_TRSV3_POWER); val |= PCIE_PHY_TRSV3_PD_TSV; exynos_phy_writel(exynos_pcie, val, PCIE_PHY_TRSV3_POWER); }
static void exynos_pcie_assert_phy_reset(struct pcie_port *pp) { struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); exynos_blk_writel(exynos_pcie, 0, PCIE_PHY_MAC_RESET); exynos_blk_writel(exynos_pcie, 1, PCIE_PHY_GLOBAL_RESET); }
static void exynos_pcie_host_init(struct pcie_port *pp) { struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); exynos_pcie_establish_link(exynos_pcie); exynos_pcie_enable_interrupts(exynos_pcie); }
static int exynos_pcie_establish_link(struct pcie_port *pp) { u32 val; int count = 0; struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); if (dw_pcie_link_up(pp)) { dev_err(pp->dev, "Link already up\n"); return 0; } /* assert reset signals */ exynos_pcie_assert_core_reset(pp); exynos_pcie_assert_phy_reset(pp); /* de-assert phy reset */ exynos_pcie_deassert_phy_reset(pp); /* initialize phy */ exynos_pcie_init_phy(pp); /* pulse for common reset */ exynos_blk_writel(exynos_pcie, 1, PCIE_PHY_COMMON_RESET); udelay(500); exynos_blk_writel(exynos_pcie, 0, PCIE_PHY_COMMON_RESET); /* de-assert core reset */ exynos_pcie_deassert_core_reset(pp); /* setup root complex */ dw_pcie_setup_rc(pp); /* assert reset signal */ exynos_pcie_assert_reset(pp); /* assert LTSSM enable */ exynos_elb_writel(exynos_pcie, PCIE_ELBI_LTSSM_ENABLE, PCIE_APP_LTSSM_ENABLE); /* check if the link is up or not */ while (!dw_pcie_link_up(pp)) { mdelay(100); count++; if (count == 10) { while (exynos_phy_readl(exynos_pcie, PCIE_PHY_PLL_LOCKED) == 0) { val = exynos_blk_readl(exynos_pcie, PCIE_PHY_PLL_LOCKED); dev_info(pp->dev, "PLL Locked: 0x%x\n", val); } dev_err(pp->dev, "PCIe Link Fail\n"); return -EINVAL; } } dev_info(pp->dev, "Link up\n"); return 0; }
static void exynos_pcie_writel_rc(struct pcie_port *pp, u32 reg, u32 val) { struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); exynos_pcie_sideband_dbi_w_mode(exynos_pcie, true); writel(val, pp->dbi_base + reg); exynos_pcie_sideband_dbi_w_mode(exynos_pcie, false); }
static void exynos_pcie_clear_irq_pulse(struct pcie_port *pp) { u32 val; struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); val = exynos_elb_readl(exynos_pcie, PCIE_IRQ_PULSE); exynos_elb_writel(exynos_pcie, val, PCIE_IRQ_PULSE); }
static void exynos_pcie_assert_reset(struct pcie_port *pp) { struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); if (exynos_pcie->reset_gpio >= 0) devm_gpio_request_one(pp->dev, exynos_pcie->reset_gpio, GPIOF_OUT_INIT_HIGH, "RESET"); }
static void exynos_pcie_write_dbi(struct dw_pcie *pci, void __iomem *base, u32 reg, size_t size, u32 val) { struct exynos_pcie *ep = to_exynos_pcie(pci); exynos_pcie_sideband_dbi_w_mode(ep, true); dw_pcie_write(base + reg, size, val); exynos_pcie_sideband_dbi_w_mode(ep, false); }
static int exynos_pcie_link_up(struct pcie_port *pp) { struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); u32 val = readl(exynos_pcie->elbi_base + PCIE_ELBI_RDLH_LINKUP); if (val == PCIE_ELBI_LTSSM_ENABLE) return 1; return 0; }
static void exynos_pcie_clear_irq_level(struct pcie_port *pp) { u32 val; struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); void __iomem *elbi_base = exynos_pcie->elbi_base; val = readl(elbi_base + PCIE_IRQ_LEVEL); writel(val, elbi_base + PCIE_IRQ_LEVEL); return; }
static u32 exynos_pcie_readl_rc(struct pcie_port *pp, u32 reg) { struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); u32 val; exynos_pcie_sideband_dbi_r_mode(exynos_pcie, true); val = readl(pp->dbi_base + reg); exynos_pcie_sideband_dbi_r_mode(exynos_pcie, false); return val; }
static void exynos_pcie_enable_irq_pulse(struct pcie_port *pp) { u32 val; struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); /* enable INTX interrupt */ val = IRQ_INTA_ASSERT | IRQ_INTB_ASSERT | IRQ_INTC_ASSERT | IRQ_INTD_ASSERT; exynos_elb_writel(exynos_pcie, val, PCIE_IRQ_EN_PULSE); }
static int exynos_pcie_host_init(struct pcie_port *pp) { struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct exynos_pcie *ep = to_exynos_pcie(pci); exynos_pcie_establish_link(ep); exynos_pcie_enable_interrupts(ep); return 0; }
static int exynos_pcie_wr_own_conf(struct pcie_port *pp, int where, int size, u32 val) { struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); int ret; exynos_pcie_sideband_dbi_w_mode(exynos_pcie, true); ret = dw_pcie_cfg_write(pp->dbi_base + where, size, val); exynos_pcie_sideband_dbi_w_mode(exynos_pcie, false); return ret; }
static int exynos_pcie_link_up(struct dw_pcie *pci) { struct exynos_pcie *ep = to_exynos_pcie(pci); u32 val; val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_ELBI_RDLH_LINKUP); if (val == PCIE_ELBI_LTSSM_ENABLE) return 1; return 0; }
static u32 exynos_pcie_read_dbi(struct dw_pcie *pci, void __iomem *base, u32 reg, size_t size) { struct exynos_pcie *ep = to_exynos_pcie(pci); u32 val; exynos_pcie_sideband_dbi_r_mode(ep, true); dw_pcie_read(base + reg, size, &val); exynos_pcie_sideband_dbi_r_mode(ep, false); return val; }
static void exynos_pcie_deassert_phy_reset(struct pcie_port *pp) { struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); exynos_blk_writel(exynos_pcie, 0, PCIE_PHY_GLOBAL_RESET); exynos_elb_writel(exynos_pcie, 1, PCIE_PWR_RESET); exynos_blk_writel(exynos_pcie, 0, PCIE_PHY_COMMON_RESET); exynos_blk_writel(exynos_pcie, 0, PCIE_PHY_CMN_REG); exynos_blk_writel(exynos_pcie, 0, PCIE_PHY_TRSVREG_RESET); exynos_blk_writel(exynos_pcie, 0, PCIE_PHY_TRSV_RESET); }
static void exynos_pcie_enable_irq_pulse(struct pcie_port *pp) { u32 val; struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); void __iomem *elbi_base = exynos_pcie->elbi_base; /* enable INTX interrupt */ val = IRQ_INTA_ASSERT | IRQ_INTB_ASSERT | IRQ_INTC_ASSERT | IRQ_INTD_ASSERT, writel(val, elbi_base + PCIE_IRQ_EN_PULSE); return; }
static int exynos_pcie_wr_own_conf(struct pcie_port *pp, int where, int size, u32 val) { struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct exynos_pcie *ep = to_exynos_pcie(pci); int ret; exynos_pcie_sideband_dbi_w_mode(ep, true); ret = dw_pcie_write(pci->dbi_base + where, size, val); exynos_pcie_sideband_dbi_w_mode(ep, false); return ret; }
static void exynos_pcie_msi_init(struct pcie_port *pp) { u32 val; struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); dw_pcie_msi_init(pp); /* enable MSI interrupt */ val = exynos_elb_readl(exynos_pcie, PCIE_IRQ_EN_LEVEL); val |= IRQ_MSI_ENABLE; exynos_elb_writel(exynos_pcie, val, PCIE_IRQ_EN_LEVEL); }
static void exynos_pcie_assert_core_reset(struct pcie_port *pp) { u32 val; struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); val = exynos_elb_readl(exynos_pcie, PCIE_CORE_RESET); val &= ~PCIE_CORE_RESET_ENABLE; exynos_elb_writel(exynos_pcie, val, PCIE_CORE_RESET); exynos_elb_writel(exynos_pcie, 0, PCIE_PWR_RESET); exynos_elb_writel(exynos_pcie, 0, PCIE_STICKY_RESET); exynos_elb_writel(exynos_pcie, 0, PCIE_NONSTICKY_RESET); }
static void exynos_pcie_msi_init(struct pcie_port *pp) { u32 val; struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); void __iomem *elbi_base = exynos_pcie->elbi_base; dw_pcie_msi_init(pp); /* enable MSI interrupt */ val = readl(elbi_base + PCIE_IRQ_EN_LEVEL); val |= IRQ_MSI_ENABLE; writel(val, elbi_base + PCIE_IRQ_EN_LEVEL); return; }
static int exynos_pcie_phy_clock_enable(struct pcie_port *pp, int enable) { struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); struct exynos_pcie_clks *clks = &exynos_pcie->clks; int i; if (enable) { for (i = 0; i < exynos_pcie->phy_clk_num; i++) clk_prepare_enable(clks->phy_clks[i]); } else { for (i = 0; i < exynos_pcie->phy_clk_num; i++) clk_disable_unprepare(clks->phy_clks[i]); } return 0; }
static void exynos_pcie_deassert_core_reset(struct pcie_port *pp) { u32 val; struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); val = exynos_elb_readl(exynos_pcie, PCIE_CORE_RESET); val |= PCIE_CORE_RESET_ENABLE; exynos_elb_writel(exynos_pcie, val, PCIE_CORE_RESET); exynos_elb_writel(exynos_pcie, 1, PCIE_STICKY_RESET); exynos_elb_writel(exynos_pcie, 1, PCIE_NONSTICKY_RESET); exynos_elb_writel(exynos_pcie, 1, PCIE_APP_INIT_RESET); exynos_elb_writel(exynos_pcie, 0, PCIE_APP_INIT_RESET); exynos_blk_writel(exynos_pcie, 1, PCIE_PHY_MAC_RESET); }
static void exynos_pcie_sideband_dbi_r_mode(struct pcie_port *pp, bool on) { u32 val; struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); if (on) { val = exynos_elb_readl(exynos_pcie, PCIE_ELBI_SLV_ARMISC); val |= PCIE_ELBI_SLV_DBI_ENABLE; exynos_elb_writel(exynos_pcie, val, PCIE_ELBI_SLV_ARMISC); } else { val = exynos_elb_readl(exynos_pcie, PCIE_ELBI_SLV_ARMISC); val &= ~PCIE_ELBI_SLV_DBI_ENABLE; exynos_elb_writel(exynos_pcie, val, PCIE_ELBI_SLV_ARMISC); } }
static void exynos_pcie_sideband_dbi_w_mode(struct pcie_port *pp, bool on) { u32 val; struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); if (on) { val = readl(exynos_pcie->elbi_base + PCIE_ELBI_SLV_AWMISC); val |= PCIE_ELBI_SLV_DBI_ENABLE; writel(val, exynos_pcie->elbi_base + PCIE_ELBI_SLV_AWMISC); } else { val = readl(exynos_pcie->elbi_base + PCIE_ELBI_SLV_AWMISC); val &= ~PCIE_ELBI_SLV_DBI_ENABLE; writel(val, exynos_pcie->elbi_base + PCIE_ELBI_SLV_AWMISC); } }
static int exynos_pcie_clock_get(struct pcie_port *pp) { struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); struct exynos_pcie_clks *clks = &exynos_pcie->clks; int i; if (exynos_pcie->ch_num == 0) { clks->pcie_clks[0] = devm_clk_get(pp->dev, "aclk_xiu_modemx"); clks->pcie_clks[1] = devm_clk_get(pp->dev, "aclk_combo_phy_modem_pcs_pclk"); clks->pcie_clks[2] = devm_clk_get(pp->dev, "sclk_combo_phy_modem_26m"); clks->pcie_clks[3] = devm_clk_get(pp->dev, "pclk_async_combo_phy_modem"); clks->pcie_clks[4] = devm_clk_get(pp->dev, "aclk_pcie_modem_mstr_aclk"); clks->pcie_clks[5] = devm_clk_get(pp->dev, "aclk_pcie_modem_slv_aclk"); clks->pcie_clks[6] = devm_clk_get(pp->dev, "aclk_pcie_modem_dbi_aclk"); clks->pcie_clks[7] = devm_clk_get(pp->dev, "sclk_pcie_modem_gated"); clks->pcie_clks[8] = devm_clk_get(pp->dev, "sclk_phy_fsys0"); clks->phy_clks[0] = devm_clk_get(pp->dev, "phyclk_pcie_tx0_gated"); clks->phy_clks[1] = devm_clk_get(pp->dev, "phyclk_pcie_rx0_gated"); } else if (exynos_pcie->ch_num == 1) { clks->pcie_clks[0] = devm_clk_get(pp->dev, "aclk_xiu_wifi1x"); clks->pcie_clks[1] = devm_clk_get(pp->dev, "aclk_ahb2axi_pcie_wifi1"); clks->pcie_clks[2] = devm_clk_get(pp->dev, "aclk_pcie_wifi1_mstr_aclk"); clks->pcie_clks[3] = devm_clk_get(pp->dev, "aclk_pcie_wifi1_slv_aclk"); clks->pcie_clks[4] = devm_clk_get(pp->dev, "aclk_pcie_wifi1_dbi_aclk"); clks->pcie_clks[5] = devm_clk_get(pp->dev, "aclk_combo_phy_pcs_pclk_wifi1"); clks->pcie_clks[6] = devm_clk_get(pp->dev, "pclk_async_combo_phy_wifi1"); clks->pcie_clks[7] = devm_clk_get(pp->dev, "sclk_pcie_link_wifi1_gated"); clks->pcie_clks[8] = devm_clk_get(pp->dev, "sclk_combo_phy_wifi1_26m_gated"); clks->pcie_clks[9] = devm_clk_get(pp->dev, "sclk_phy_fsys1_gated"); clks->phy_clks[0] = devm_clk_get(pp->dev, "phyclk_pcie_wifi1_tx0_gated"); clks->phy_clks[1] = devm_clk_get(pp->dev, "phyclk_pcie_wifi1_rx0_gated"); } for (i = 0; i < exynos_pcie->pcie_clk_num; i++) { if (IS_ERR(clks->pcie_clks[i])) { dev_err(pp->dev, "Failed to get pcie clock\n"); return -ENODEV; } } for (i = 0; i < exynos_pcie->phy_clk_num; i++) { if (IS_ERR(clks->phy_clks[i])) { dev_err(pp->dev, "Failed to get pcie clock\n"); return -ENODEV; } } return 0; }
static int exynos_pcie_ref_clock_enable(struct pcie_port *pp, int enable) { struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); struct exynos_pcie_clks *clks = &exynos_pcie->clks; int i = exynos_pcie->pcie_clk_num - 1; void __iomem *block_base = exynos_pcie->block_base; if (enable) { clk_prepare_enable(clks->pcie_clks[i]); if (exynos_pcie->ch_num == 0) writel(readl(block_base) & ~(0x1 << 1), block_base); } else { if (exynos_pcie->ch_num == 0) writel(readl(block_base) | (0x1 << 1), block_base); clk_disable_unprepare(clks->pcie_clks[i]); } return 0; }
static void exynos_pcie_assert_phy_reset(struct pcie_port *pp) { struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); void __iomem *block_base = exynos_pcie->block_base; u32 val; /* PHY Global Reset */ val = readl(block_base + PCIE_PHY_GLOBAL_RESET); val &= ~(0x1); writel(val, block_base + PCIE_PHY_GLOBAL_RESET); /* PHY Common Reset */ val = readl(block_base + PCIE_PHY_COMMON_RESET); val &= ~(0x1); writel(val, block_base + PCIE_PHY_COMMON_RESET); /* PHY Mac Reset */ val = readl(block_base + PCIE_PHY_MAC_RESET); val |= 0x1 << 4; writel(val, block_base + PCIE_PHY_MAC_RESET); }