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]>

Reply via email to