/* Parameters for the waiting for link up routine */ #define LINK_WAIT_MAX_RETRIES 10 #define LINK_WAIT_USLEEP_MIN 90000 #define LINK_WAIT_USLEEP_MAX 100000
/* * JH7110 PCIe port BAR0/1 can be configured as 64-bit prefetchable memory * space. PCIe read and write requests targeting BAR0/1 are routed to so called * 'Bridge Configuration space' in PLDA IP datasheet, which contains the bridge * internal registers, such as interrupt, DMA and ATU registers... * JH7110 can access the Bridge Configuration space by local bus, and don`t * want the bridge internal registers accessed by the DMA from EP devices. * Thus, they are unimplemented and should be hidden here.
*/ staticbool starfive_pcie_hide_rc_bar(struct pci_bus *bus, unsignedint devfn, int offset)
{ if (pci_is_root_bus(bus) && !devfn &&
(offset == PCI_BASE_ADDRESS_0 || offset == PCI_BASE_ADDRESS_1)) returntrue;
returnfalse;
}
staticint starfive_pcie_config_write(struct pci_bus *bus, unsignedint devfn, int where, int size, u32 value)
{ if (starfive_pcie_hide_rc_bar(bus, devfn, where)) return PCIBIOS_SUCCESSFUL;
staticint starfive_pcie_parse_dt(struct starfive_jh7110_pcie *pcie, struct device *dev)
{ int domain_nr;
pcie->num_clks = devm_clk_bulk_get_all(dev, &pcie->clks); if (pcie->num_clks < 0) return dev_err_probe(dev, pcie->num_clks, "failed to get pcie clocks\n");
pcie->resets = devm_reset_control_array_get_exclusive(dev); if (IS_ERR(pcie->resets)) return dev_err_probe(dev, PTR_ERR(pcie->resets), "failed to get pcie resets");
if (IS_ERR(pcie->reg_syscon)) return dev_err_probe(dev, PTR_ERR(pcie->reg_syscon), "failed to parse starfive,stg-syscon\n");
pcie->phy = devm_phy_optional_get(dev, NULL); if (IS_ERR(pcie->phy)) return dev_err_probe(dev, PTR_ERR(pcie->phy), "failed to get pcie phy\n");
/* * The PCIe domain numbers are set to be static in JH7110 DTS. * As the STG system controller defines different bases in PCIe RP0 & * RP1, we use them to identify which controller is doing the hardware * initialization.
*/
domain_nr = of_get_pci_domain_nr(dev->of_node);
if (domain_nr < 0 || domain_nr > 1) return dev_err_probe(dev, -ENODEV, "failed to get valid pcie domain\n");
pcie->reset_gpio = devm_gpiod_get_optional(dev, "perst",
GPIOD_OUT_HIGH); if (IS_ERR(pcie->reset_gpio)) return dev_err_probe(dev, PTR_ERR(pcie->reset_gpio), "failed to get perst-gpio\n");
pcie->power_gpio = devm_gpiod_get_optional(dev, "enable",
GPIOD_OUT_LOW); if (IS_ERR(pcie->power_gpio)) return dev_err_probe(dev, PTR_ERR(pcie->power_gpio), "failed to get power-gpio\n");
ret = clk_bulk_prepare_enable(pcie->num_clks, pcie->clks); if (ret) return dev_err_probe(dev, ret, "failed to enable clocks\n");
ret = reset_control_deassert(pcie->resets); if (ret) {
clk_bulk_disable_unprepare(pcie->num_clks, pcie->clks);
dev_err_probe(dev, ret, "failed to deassert resets\n");
}
ret = regmap_read(pcie->reg_syscon,
pcie->stg_pcie_base + STG_SYSCON_LNKSTA_OFFSET,
&stg_reg_val); if (ret) {
dev_err(pcie->plda.dev, "failed to read link status\n"); returnfalse;
}
return !!(stg_reg_val & DATA_LINK_ACTIVE);
}
staticint starfive_pcie_host_wait_for_link(struct starfive_jh7110_pcie *pcie)
{ int retries;
/* Check if the link is up or not */ for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) { if (starfive_pcie_link_up(&pcie->plda)) {
dev_info(pcie->plda.dev, "port link up\n"); return 0;
}
usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
}
return -ETIMEDOUT;
}
staticint starfive_pcie_enable_phy(struct device *dev, struct starfive_jh7110_pcie *pcie)
{ int ret;
if (!pcie->phy) return 0;
ret = phy_init(pcie->phy); if (ret) return dev_err_probe(dev, ret, "failed to initialize pcie phy\n");
ret = phy_set_mode(pcie->phy, PHY_MODE_PCIE); if (ret) {
dev_err_probe(dev, ret, "failed to set pcie mode\n"); goto err_phy_on;
}
ret = phy_power_on(pcie->phy); if (ret) {
dev_err_probe(dev, ret, "failed to power on pcie phy\n"); goto err_phy_on;
}
/* PCIe PCI Standard Configuration Identification Settings. */
plda_pcie_set_standard_class(plda);
/* * The LTR message receiving is enabled by the register "PCIe Message * Reception" as default, but the forward id & addr are uninitialized. * If we do not disable LTR message forwarding here, or set a legal * forwarding address, the kernel will get stuck. * To workaround, disable the LTR message forwarding here before using * this feature.
*/
plda_pcie_disable_ltr(plda);
/* * Enable the prefetchable memory window 64-bit addressing in JH7110. * The 64-bits prefetchable address translation configurations in ATU * can be work after enable the register setting below.
*/
plda_pcie_set_pref_win_64bit(plda);
/* * Ensure that PERST has been asserted for at least 100 ms, * the sleep value is T_PVPERL from PCIe CEM spec r2.0 (Table 2-4)
*/
msleep(100); if (pcie->reset_gpio)
gpiod_set_value_cansleep(pcie->reset_gpio, 0);
/* * With a Downstream Port (<=5GT/s), software must wait a minimum * of 100ms following exit from a conventional reset before * sending a configuration request to the device.
*/
msleep(PCIE_RESET_CONFIG_WAIT_MS);
if (starfive_pcie_host_wait_for_link(pcie))
dev_info(dev, "port link down\n");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.