The driver takes the slot power switch from a "k1x,pwr_on" GPIO and a "power-on-status" polarity flag. Those are vendor properties: neither the spacemit,k1-pcie binding nor any upstream device tree has them. The binding describes the 3.3 V slot supply as a regulator, vpcie3v3-supply, on the root port node, and that is ignored. On boards whose M.2 slot sits behind a GPIO-switched regulator, such as the OrangePi RV2 (GPIO 116), the slot is never powered and the link cannot train.
Look up vpcie3v3-supply on the root port, falling back to the host bridge node where some board device trees also put it and where Linux's pcie-spacemit-k1 driver reads it, and enable it in place of the GPIO. PERST# is still held for 100 ms after the supply is turned on. Drop the vendor GPIO properties. Unlike Linux, only warn when the supply is described but cannot be found: the Banana Pi F3 and MUSE Pi Pro describe always-on fixed supplies, and spacemit_k1_defconfig does not build the fixed regulator driver, so failing the probe would break ports that work today. Signed-off-by: Dave Klotz <[email protected]> --- drivers/pci/pcie_dw_spacemit.c | 72 +++++++++++++++++----------------- 1 file changed, 35 insertions(+), 37 deletions(-) diff --git a/drivers/pci/pcie_dw_spacemit.c b/drivers/pci/pcie_dw_spacemit.c index 09c56d8a4c..7ca5a5ad1a 100644 --- a/drivers/pci/pcie_dw_spacemit.c +++ b/drivers/pci/pcie_dw_spacemit.c @@ -8,7 +8,6 @@ */ #include <asm/global_data.h> #include <asm/io.h> -#include <asm-generic/gpio.h> #include <clk.h> #include <dm.h> #include <dm/device_compat.h> @@ -21,6 +20,7 @@ #include <log.h> #include <pci.h> #include <power-domain.h> +#include <power/regulator.h> #include <reset.h> #include "pcie_dw_common.h" @@ -39,8 +39,7 @@ struct pcie_dw_spacemit { /* reset, clock resources */ struct clk_bulk clks; struct reset_ctl_bulk rsts; - struct gpio_desc pwr_on_gpio; - int power_on_status; + struct udevice *vpcie3v3; /* slot supply, if described */ }; static inline u32 spacemit_pcie_readl(struct pcie_dw_spacemit *pcie, u32 offset) @@ -185,30 +184,26 @@ static int pcie_dw_init_id(struct pcie_dw_spacemit *pci) return 0; } -static int k1x_power_on(struct pcie_dw_spacemit *pci, int on) +/* + * The binding describes the 3.3 V slot supply on the root port node. Some + * board device trees also, or only, put it on the host bridge node, which + * is where Linux's driver looks for it. + */ +static int spacemit_pcie_get_vpcie3v3(struct udevice *dev, ofnode port, + struct udevice **supplyp) { - struct pcie_dw *dwp = &pci->dw; - int gpio_val = 0; - - if (on) { - if (pci->power_on_status) - gpio_val = 1; - else - gpio_val = 0; - } else { - if (pci->power_on_status) - gpio_val = 0; - else - gpio_val = 1; - } - - if (dm_gpio_is_valid(&pci->pwr_on_gpio)) { - dev_info(dwp->dev, "PCIe interface power %s, set gpio %d to %d\n", - on ? "on" : "off", pci->pwr_on_gpio.offset, gpio_val); - dm_gpio_set_value(&pci->pwr_on_gpio, gpio_val); + ofnode supply; + + supply = ofnode_parse_phandle(port, "vpcie3v3-supply", 0); + if (!ofnode_valid(supply)) + supply = ofnode_parse_phandle(dev_ofnode(dev), + "vpcie3v3-supply", 0); + if (!ofnode_valid(supply)) { + *supplyp = NULL; + return 0; } - return 0; + return uclass_get_device_by_ofnode(UCLASS_REGULATOR, supply, supplyp); } static int pcie_dw_spacemit_probe(struct udevice *dev) @@ -241,6 +236,13 @@ static int pcie_dw_spacemit_probe(struct udevice *dev) return -ENODEV; } + ret = spacemit_pcie_get_vpcie3v3(dev, port, &pci->vpcie3v3); + if (ret) { + /* e.g. an always-on fixed supply with no driver built in */ + dev_warn(dev, "vpcie3v3 supply not available: %d\n", ret); + pci->vpcie3v3 = NULL; + } + ret = generic_phy_get_by_index_nodev(port, 0, &phy0); if (!ret) { reg = spacemit_pcie_readl(pci, PCIECTRL_K1X_CONF_DEVICE_CMD); @@ -271,8 +273,15 @@ static int pcie_dw_spacemit_probe(struct udevice *dev) pcie_set_mode(pci, DW_PCIE_RC_TYPE); - /* power on the interface */ - k1x_power_on(pci, 1); + /* Power the slot; PERST# stays asserted for 100 ms after this */ + if (pci->vpcie3v3) { + ret = regulator_set_enable_if_allowed(pci->vpcie3v3, true); + if (ret) { + dev_err(dev, "failed to enable vpcie3v3 supply: %d\n", + ret); + return ret; + } + } spacemit_pcie_host_init(pci); pcie_dw_setup_host(&pci->dw); @@ -356,17 +365,6 @@ static int pcie_dw_spacemit_of_to_plat(struct udevice *dev) return ret; } - gpio_request_by_name(dev, "k1x,pwr_on", 0, &pcie->pwr_on_gpio, - GPIOD_IS_OUT); - if (!dm_gpio_is_valid(&pcie->pwr_on_gpio)) - dev_info(dev, "has no power on gpio.\n"); - - ret = dev_read_u32(dev, "power-on-status", &pcie->power_on_status); - if (ret) { - dev_info(dev, "has no power-on-status flag, use default.\n"); - pcie->power_on_status = 1; - } - return 0; } -- 2.55.0
