On Sat, Oct 3, 2026 at 5:30 AM Dave Klotz <[email protected]> wrote:
>
> The probe brings the controller up from whatever state it was left in.
> After a warm reboot, or when an earlier boot stage has used the port,
> the link can still be trained; the driver then prints "PCI Link already
> up before configuration!" and skips the link configuration altogether.
>
> Linux's pcie-spacemit-k1 driver and FreeBSD's spacemit_pcie driver both
> pulse PCIE_SOFT_RESET in the APMU control logic register for 2 ms
> before enabling the application clocks and resets. Do the same, and
> drop the "already up" shortcut, which can no longer be taken.
>
> Signed-off-by: Dave Klotz <[email protected]>
> ---
> drivers/pci/pcie_dw_spacemit.c | 23 ++++++++++++++++++-----
> 1 file changed, 18 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/pci/pcie_dw_spacemit.c b/drivers/pci/pcie_dw_spacemit.c
> index 04b3161e94..b85de73ad3 100644
> --- a/drivers/pci/pcie_dw_spacemit.c
> +++ b/drivers/pci/pcie_dw_spacemit.c
> @@ -106,11 +106,6 @@ static int pcie_dw_spacemit_pcie_link_up(struct
> pcie_dw_spacemit *pci, u32 cap_s
> {
> u32 reg;
>
> - if (is_link_up(pci)) {
> - printf("PCI Link already up before configuration!\n");
> - return 1;
> - }
> -
> /* DW pre link configurations */
> pcie_dw_configure(pci, cap_speed);
>
> @@ -133,6 +128,22 @@ static int pcie_dw_spacemit_pcie_link_up(struct
> pcie_dw_spacemit *pci, u32 cap_s
> return 1;
> }
>
> +/*
> + * Reset the controller, so that nothing left over from an earlier boot
> + * stage or a warm reboot (a trained link, a stale LTSSM state) survives.
> + */
> +static void spacemit_pcie_toggle_soft_reset(struct pcie_dw_spacemit *pci)
> +{
> + u32 reg;
> +
> + reg = spacemit_pcie_readl(pci, PCIE_CTRL_LOGIC);
> + spacemit_pcie_writel(pci, PCIE_CTRL_LOGIC, reg | PCIE_SOFT_RESET);
> + /* Read back so that the write has landed before the delay */
> + spacemit_pcie_readl(pci, PCIE_CTRL_LOGIC);
> + mdelay(2);
> + spacemit_pcie_writel(pci, PCIE_CTRL_LOGIC, reg & ~PCIE_SOFT_RESET);
> +}
> +
> static int pcie_set_mode(struct pcie_dw_spacemit *pci,
> enum dw_pcie_device_mode mode)
> {
> @@ -216,6 +227,8 @@ static int pcie_dw_spacemit_probe(struct udevice *dev)
> int ret;
> u32 reg;
>
> + spacemit_pcie_toggle_soft_reset(pci);
> +
> /* enable pcie clk and deassert resets */
> clk_enable_bulk(&pci->clks);
> reset_deassert_bulk(&pci->rsts);
> --
> 2.55.0
>
>
Reviewed-by: Eric Chung <[email protected]>