diff mbox series

[U-Boot,033/126] dm: pci: Add a function to read a PCI BAR

Message ID 20190925145750.200592-34-sjg@chromium.org
State Accepted
Delegated to: Bin Meng
Headers show
Series x86: Add initial support for apollolake | expand

Commit Message

Simon Glass Sept. 25, 2019, 2:56 p.m. UTC
At present PCI address transaction is not supported so drivers must
manually read the correct BAR after reading the device tree info. The
ns16550 has a suitable implementation, so move this code into the core
DM support.

Note that there is no live-tree equivalent at present.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 arch/sandbox/dts/test.dts |  7 ++++--
 drivers/core/fdtaddr.c    | 33 ++++++++++++++++++++++++++++
 drivers/core/read.c       | 11 ++++++++++
 drivers/serial/ns16550.c  | 31 +--------------------------
 include/dm/fdtaddr.h      |  8 +++++++
 include/dm/read.h         | 25 ++++++++++++++++++++++
 test/dm/pci.c             | 45 +++++++++++++++++++++++++++++++++++++++
 7 files changed, 128 insertions(+), 32 deletions(-)

Comments

Bin Meng Oct. 5, 2019, 1:12 p.m. UTC | #1
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass <sjg@chromium.org> wrote:
>
> At present PCI address transaction is not supported so drivers must
> manually read the correct BAR after reading the device tree info. The
> ns16550 has a suitable implementation, so move this code into the core
> DM support.
>
> Note that there is no live-tree equivalent at present.
>
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
>
>  arch/sandbox/dts/test.dts |  7 ++++--
>  drivers/core/fdtaddr.c    | 33 ++++++++++++++++++++++++++++
>  drivers/core/read.c       | 11 ++++++++++
>  drivers/serial/ns16550.c  | 31 +--------------------------
>  include/dm/fdtaddr.h      |  8 +++++++
>  include/dm/read.h         | 25 ++++++++++++++++++++++
>  test/dm/pci.c             | 45 +++++++++++++++++++++++++++++++++++++++
>  7 files changed, 128 insertions(+), 32 deletions(-)
>
> diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
> index a2e75981f0b..8733e0d7e19 100644
> --- a/arch/sandbox/dts/test.dts
> +++ b/arch/sandbox/dts/test.dts
> @@ -456,12 +456,15 @@
>                 };
>                 pci@1,0 {
>                         compatible = "pci-generic";
> -                       reg = <0x0800 0 0 0 0>;
> +                       /* BAR0 is at 0x14, using FDT_PCI_SPACE_MEM32 */

reg 0

> +                       reg = <0x02000814 0 0 0 0
> +                               0x0100f810 0 0 0 0>;

it should be 0x01000810, and should have a similar comment like reg 0

>                         sandbox,emul = <&swap_case_emul1>;
>                 };
>                 pci@1f,0 {
>                         compatible = "pci-generic";
> -                       reg = <0xf800 0 0 0 0>;
> +                       /* BAR1 is at 0x10, using FDT_PCI_SPACE_IO */

reg 0

> +                       reg = <0x0100f810 0 0 0 0>;
>                         sandbox,emul = <&swap_case_emul1f>;
>                 };
>         };
> diff --git a/drivers/core/fdtaddr.c b/drivers/core/fdtaddr.c
> index 6850003a287..c9a941116a3 100644
> --- a/drivers/core/fdtaddr.c
> +++ b/drivers/core/fdtaddr.c
> @@ -190,3 +190,36 @@ void *devfdt_map_physmem(struct udevice *dev, unsigned long size)
>
>         return map_physmem(addr, size, MAP_NOCACHE);
>  }
> +
> +fdt_addr_t devfdt_get_addr_pci(struct udevice *dev)
> +{
> +       ulong addr;
> +
> +       addr = devfdt_get_addr(dev);
> +       if (CONFIG_IS_ENABLED(PCI) && IS_ENABLED(CONFIG_DM_PCI) &&
> +           addr == FDT_ADDR_T_NONE) {
> +               struct fdt_pci_addr pci_addr;
> +               u32 bar;
> +               int ret;
> +
> +               ret = fdtdec_get_pci_addr(gd->fdt_blob,
> +                                         dev_of_offset(dev),
> +                                         FDT_PCI_SPACE_MEM32, "reg",
> +                                         &pci_addr);
> +               if (ret) {
> +                       /* try if there is any i/o-mapped register */
> +                       ret = fdtdec_get_pci_addr(gd->fdt_blob,
> +                                                 dev_of_offset(dev),
> +                                                 FDT_PCI_SPACE_IO, "reg",
> +                                                 &pci_addr);
> +                       if (ret)
> +                               return FDT_ADDR_T_NONE;
> +               }
> +               ret = fdtdec_get_pci_bar32(dev, &pci_addr, &bar);
> +               if (ret)
> +                       return FDT_ADDR_T_NONE;
> +               addr = bar;
> +       }
> +
> +       return addr;
> +}
> diff --git a/drivers/core/read.c b/drivers/core/read.c
> index fb3dcd9a790..9602e52d1b1 100644
> --- a/drivers/core/read.c
> +++ b/drivers/core/read.c
> @@ -307,3 +307,14 @@ int dev_read_alias_highest_id(const char *stem)
>
>         return fdtdec_get_alias_highest_id(gd->fdt_blob, stem);
>  }
> +
> +fdt_addr_t dev_read_addr_pci(struct udevice *dev)
> +{
> +       ulong addr;
> +
> +       addr = dev_read_addr(dev);
> +       if (addr == FDT_ADDR_T_NONE && !of_live_active())
> +               addr = devfdt_get_addr_pci(dev);
> +
> +       return addr;
> +}
> diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c
> index 01f334938ea..754b6e99215 100644
> --- a/drivers/serial/ns16550.c
> +++ b/drivers/serial/ns16550.c
> @@ -440,36 +440,7 @@ int ns16550_serial_ofdata_to_platdata(struct udevice *dev)
>         int err;
>
>         /* try Processor Local Bus device first */
> -       addr = dev_read_addr(dev);
> -#if CONFIG_IS_ENABLED(PCI) && defined(CONFIG_DM_PCI)
> -       if (addr == FDT_ADDR_T_NONE) {
> -               /* then try pci device */
> -               struct fdt_pci_addr pci_addr;
> -               u32 bar;
> -               int ret;
> -
> -               /* we prefer to use a memory-mapped register */
> -               ret = fdtdec_get_pci_addr(gd->fdt_blob, dev_of_offset(dev),
> -                                         FDT_PCI_SPACE_MEM32, "reg",
> -                                         &pci_addr);
> -               if (ret) {
> -                       /* try if there is any i/o-mapped register */
> -                       ret = fdtdec_get_pci_addr(gd->fdt_blob,
> -                                                 dev_of_offset(dev),
> -                                                 FDT_PCI_SPACE_IO,
> -                                                 "reg", &pci_addr);
> -                       if (ret)
> -                               return ret;
> -               }
> -
> -               ret = fdtdec_get_pci_bar32(dev, &pci_addr, &bar);
> -               if (ret)
> -                       return ret;
> -
> -               addr = bar;
> -       }
> -#endif
> -
> +       addr = dev_read_addr_pci(dev);
>         if (addr == FDT_ADDR_T_NONE)
>                 return -EINVAL;
>
> diff --git a/include/dm/fdtaddr.h b/include/dm/fdtaddr.h
> index 57b326cb336..959d3bc2d69 100644
> --- a/include/dm/fdtaddr.h
> +++ b/include/dm/fdtaddr.h
> @@ -138,4 +138,12 @@ fdt_addr_t devfdt_get_addr_name(struct udevice *dev, const char *name);
>  fdt_addr_t devfdt_get_addr_size_name(struct udevice *dev, const char *name,
>                                      fdt_size_t *size);
>
> +/**
> + * devfdt_get_addr_pci() - Read an address and handle PCI address translation
> + *
> + * @dev: Device to read from
> + * @return address or FDT_ADDR_T_NONE if not found
> + */
> +fdt_addr_t devfdt_get_addr_pci(struct udevice *dev);
> +
>  #endif
> diff --git a/include/dm/read.h b/include/dm/read.h
> index 03189838ff7..4f02d07d001 100644
> --- a/include/dm/read.h
> +++ b/include/dm/read.h
> @@ -247,6 +247,26 @@ fdt_addr_t dev_read_addr(struct udevice *dev);
>   */
>  void *dev_read_addr_ptr(struct udevice *dev);
>
> +/**
> + * dev_read_addr_pci() - Read an address and handle PCI address translation
> + *
> + * At present U-Boot does not have address translation logic for PCI in the
> + * livetree implementation (of_addr.c). This special function supports this for
> + * the flat tree implementation.
> + *
> + * This function should be removed (and code should use dev_read() instead)
> + * once:
> + *
> + * 1. PCI address translation is added; and either
> + * 2. everything uses livetree where PCI translation is used (which is feasible
> + *    in SPL and U-Boot proper) or PCI address translation is added to
> + *    fdtdec_get_addr() and friends.
> + *
> + * @dev: Device to read from
> + * @return address or FDT_ADDR_T_NONE if not found
> + */
> +fdt_addr_t dev_read_addr_pci(struct udevice *dev);
> +
>  /**
>   * dev_remap_addr() - Get the reg property of a device as a
>   *                         memory-mapped I/O pointer
> @@ -690,6 +710,11 @@ static inline void *dev_read_addr_ptr(struct udevice *dev)
>         return devfdt_get_addr_ptr(dev);
>  }
>
> +static inline fdt_addr_t dev_read_addr_pci(struct udevice *dev)
> +{
> +       return devfdt_get_addr_pci(dev);
> +}
> +
>  static inline void *dev_remap_addr(struct udevice *dev)
>  {
>         return devfdt_remap_addr(dev);
> diff --git a/test/dm/pci.c b/test/dm/pci.c
> index e70b65aea4a..fb93e4c78ae 100644
> --- a/test/dm/pci.c
> +++ b/test/dm/pci.c
> @@ -294,3 +294,48 @@ static int dm_test_pci_ea(struct unit_test_state *uts)
>         return 0;
>  }
>  DM_TEST(dm_test_pci_ea, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
> +
> +/* Test the dev_read_addr_pci() function */
> +static int dm_test_pci_addr_flat(struct unit_test_state *uts)
> +{
> +       struct udevice *swap1f, *swap1;
> +       ulong io_addr, mem_addr;
> +
> +       ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1f, 0), &swap1f));
> +       io_addr = dm_pci_read_bar32(swap1f, 0);
> +       ut_asserteq(io_addr, dev_read_addr_pci(swap1f));
> +
> +       /*
> +        * This device has both I/O and MEM spaces but the MEM space appears
> +        * first
> +        */
> +       ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1, 0), &swap1));
> +       mem_addr = dm_pci_read_bar32(swap1, 1);
> +       ut_asserteq(mem_addr, dev_read_addr_pci(swap1));
> +
> +       return 0;
> +}
> +DM_TEST(dm_test_pci_addr_flat, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT |
> +               DM_TESTF_FLAT_TREE);
> +
> +/*
> + * Test the dev_read_addr_pci() function with livetree. That function is
> + * not currently fully implemented, in that it fails to return the BAR address.
> + * Once that is implemented this test can be removed and dm_test_pci_addr_flat()
> + * can be used for both flattree and livetree by removing the DM_TESTF_FLAT_TREE
> + * flag above.
> + */
> +static int dm_test_pci_addr_live(struct unit_test_state *uts)
> +{
> +       struct udevice *swap1f, *swap1;
> +
> +       ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1f, 0), &swap1f));
> +       ut_asserteq(FDT_ADDR_T_NONE, dev_read_addr_pci(swap1f));
> +
> +       ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1, 0), &swap1));
> +       ut_asserteq(FDT_ADDR_T_NONE, dev_read_addr_pci(swap1));
> +
> +       return 0;
> +}
> +DM_TEST(dm_test_pci_addr_live, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT |
> +               DM_TESTF_LIVE_TREE);
> --

Other than above,
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Tested-by: Bin Meng <bmeng.cn@gmail.com>
Bin Meng Oct. 6, 2019, 11:19 a.m. UTC | #2
On Sat, Oct 5, 2019 at 9:12 PM Bin Meng <bmeng.cn@gmail.com> wrote:
>
> On Wed, Sep 25, 2019 at 10:58 PM Simon Glass <sjg@chromium.org> wrote:
> >
> > At present PCI address transaction is not supported so drivers must
> > manually read the correct BAR after reading the device tree info. The
> > ns16550 has a suitable implementation, so move this code into the core
> > DM support.
> >
> > Note that there is no live-tree equivalent at present.
> >
> > Signed-off-by: Simon Glass <sjg@chromium.org>
> > ---
> >
> >  arch/sandbox/dts/test.dts |  7 ++++--
> >  drivers/core/fdtaddr.c    | 33 ++++++++++++++++++++++++++++
> >  drivers/core/read.c       | 11 ++++++++++
> >  drivers/serial/ns16550.c  | 31 +--------------------------
> >  include/dm/fdtaddr.h      |  8 +++++++
> >  include/dm/read.h         | 25 ++++++++++++++++++++++
> >  test/dm/pci.c             | 45 +++++++++++++++++++++++++++++++++++++++
> >  7 files changed, 128 insertions(+), 32 deletions(-)
> >
> > diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
> > index a2e75981f0b..8733e0d7e19 100644
> > --- a/arch/sandbox/dts/test.dts
> > +++ b/arch/sandbox/dts/test.dts
> > @@ -456,12 +456,15 @@
> >                 };
> >                 pci@1,0 {
> >                         compatible = "pci-generic";
> > -                       reg = <0x0800 0 0 0 0>;
> > +                       /* BAR0 is at 0x14, using FDT_PCI_SPACE_MEM32 */
>
> reg 0
>
> > +                       reg = <0x02000814 0 0 0 0
> > +                               0x0100f810 0 0 0 0>;
>
> it should be 0x01000810, and should have a similar comment like reg 0
>
> >                         sandbox,emul = <&swap_case_emul1>;
> >                 };
> >                 pci@1f,0 {
> >                         compatible = "pci-generic";
> > -                       reg = <0xf800 0 0 0 0>;
> > +                       /* BAR1 is at 0x10, using FDT_PCI_SPACE_IO */
>
> reg 0

Corrected the above comments, and

>
> > +                       reg = <0x0100f810 0 0 0 0>;
> >                         sandbox,emul = <&swap_case_emul1f>;
> >                 };
> >         };
> > diff --git a/drivers/core/fdtaddr.c b/drivers/core/fdtaddr.c
> > index 6850003a287..c9a941116a3 100644
> > --- a/drivers/core/fdtaddr.c
> > +++ b/drivers/core/fdtaddr.c
> > @@ -190,3 +190,36 @@ void *devfdt_map_physmem(struct udevice *dev, unsigned long size)
> >
> >         return map_physmem(addr, size, MAP_NOCACHE);
> >  }
> > +
> > +fdt_addr_t devfdt_get_addr_pci(struct udevice *dev)
> > +{
> > +       ulong addr;
> > +
> > +       addr = devfdt_get_addr(dev);
> > +       if (CONFIG_IS_ENABLED(PCI) && IS_ENABLED(CONFIG_DM_PCI) &&
> > +           addr == FDT_ADDR_T_NONE) {
> > +               struct fdt_pci_addr pci_addr;
> > +               u32 bar;
> > +               int ret;
> > +
> > +               ret = fdtdec_get_pci_addr(gd->fdt_blob,
> > +                                         dev_of_offset(dev),
> > +                                         FDT_PCI_SPACE_MEM32, "reg",
> > +                                         &pci_addr);
> > +               if (ret) {
> > +                       /* try if there is any i/o-mapped register */
> > +                       ret = fdtdec_get_pci_addr(gd->fdt_blob,
> > +                                                 dev_of_offset(dev),
> > +                                                 FDT_PCI_SPACE_IO, "reg",
> > +                                                 &pci_addr);
> > +                       if (ret)
> > +                               return FDT_ADDR_T_NONE;
> > +               }
> > +               ret = fdtdec_get_pci_bar32(dev, &pci_addr, &bar);
> > +               if (ret)
> > +                       return FDT_ADDR_T_NONE;
> > +               addr = bar;
> > +       }
> > +
> > +       return addr;
> > +}
> > diff --git a/drivers/core/read.c b/drivers/core/read.c
> > index fb3dcd9a790..9602e52d1b1 100644
> > --- a/drivers/core/read.c
> > +++ b/drivers/core/read.c
> > @@ -307,3 +307,14 @@ int dev_read_alias_highest_id(const char *stem)
> >
> >         return fdtdec_get_alias_highest_id(gd->fdt_blob, stem);
> >  }
> > +
> > +fdt_addr_t dev_read_addr_pci(struct udevice *dev)
> > +{
> > +       ulong addr;
> > +
> > +       addr = dev_read_addr(dev);
> > +       if (addr == FDT_ADDR_T_NONE && !of_live_active())
> > +               addr = devfdt_get_addr_pci(dev);
> > +
> > +       return addr;
> > +}
> > diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c
> > index 01f334938ea..754b6e99215 100644
> > --- a/drivers/serial/ns16550.c
> > +++ b/drivers/serial/ns16550.c
> > @@ -440,36 +440,7 @@ int ns16550_serial_ofdata_to_platdata(struct udevice *dev)
> >         int err;
> >
> >         /* try Processor Local Bus device first */
> > -       addr = dev_read_addr(dev);
> > -#if CONFIG_IS_ENABLED(PCI) && defined(CONFIG_DM_PCI)
> > -       if (addr == FDT_ADDR_T_NONE) {
> > -               /* then try pci device */
> > -               struct fdt_pci_addr pci_addr;
> > -               u32 bar;
> > -               int ret;
> > -
> > -               /* we prefer to use a memory-mapped register */
> > -               ret = fdtdec_get_pci_addr(gd->fdt_blob, dev_of_offset(dev),
> > -                                         FDT_PCI_SPACE_MEM32, "reg",
> > -                                         &pci_addr);
> > -               if (ret) {
> > -                       /* try if there is any i/o-mapped register */
> > -                       ret = fdtdec_get_pci_addr(gd->fdt_blob,
> > -                                                 dev_of_offset(dev),
> > -                                                 FDT_PCI_SPACE_IO,
> > -                                                 "reg", &pci_addr);
> > -                       if (ret)
> > -                               return ret;
> > -               }
> > -
> > -               ret = fdtdec_get_pci_bar32(dev, &pci_addr, &bar);
> > -               if (ret)
> > -                       return ret;
> > -
> > -               addr = bar;
> > -       }
> > -#endif
> > -
> > +       addr = dev_read_addr_pci(dev);
> >         if (addr == FDT_ADDR_T_NONE)
> >                 return -EINVAL;
> >
> > diff --git a/include/dm/fdtaddr.h b/include/dm/fdtaddr.h
> > index 57b326cb336..959d3bc2d69 100644
> > --- a/include/dm/fdtaddr.h
> > +++ b/include/dm/fdtaddr.h
> > @@ -138,4 +138,12 @@ fdt_addr_t devfdt_get_addr_name(struct udevice *dev, const char *name);
> >  fdt_addr_t devfdt_get_addr_size_name(struct udevice *dev, const char *name,
> >                                      fdt_size_t *size);
> >
> > +/**
> > + * devfdt_get_addr_pci() - Read an address and handle PCI address translation
> > + *
> > + * @dev: Device to read from
> > + * @return address or FDT_ADDR_T_NONE if not found
> > + */
> > +fdt_addr_t devfdt_get_addr_pci(struct udevice *dev);
> > +
> >  #endif
> > diff --git a/include/dm/read.h b/include/dm/read.h
> > index 03189838ff7..4f02d07d001 100644
> > --- a/include/dm/read.h
> > +++ b/include/dm/read.h
> > @@ -247,6 +247,26 @@ fdt_addr_t dev_read_addr(struct udevice *dev);
> >   */
> >  void *dev_read_addr_ptr(struct udevice *dev);
> >
> > +/**
> > + * dev_read_addr_pci() - Read an address and handle PCI address translation
> > + *
> > + * At present U-Boot does not have address translation logic for PCI in the
> > + * livetree implementation (of_addr.c). This special function supports this for
> > + * the flat tree implementation.
> > + *
> > + * This function should be removed (and code should use dev_read() instead)
> > + * once:
> > + *
> > + * 1. PCI address translation is added; and either
> > + * 2. everything uses livetree where PCI translation is used (which is feasible
> > + *    in SPL and U-Boot proper) or PCI address translation is added to
> > + *    fdtdec_get_addr() and friends.
> > + *
> > + * @dev: Device to read from
> > + * @return address or FDT_ADDR_T_NONE if not found
> > + */
> > +fdt_addr_t dev_read_addr_pci(struct udevice *dev);
> > +
> >  /**
> >   * dev_remap_addr() - Get the reg property of a device as a
> >   *                         memory-mapped I/O pointer
> > @@ -690,6 +710,11 @@ static inline void *dev_read_addr_ptr(struct udevice *dev)
> >         return devfdt_get_addr_ptr(dev);
> >  }
> >
> > +static inline fdt_addr_t dev_read_addr_pci(struct udevice *dev)
> > +{
> > +       return devfdt_get_addr_pci(dev);
> > +}
> > +
> >  static inline void *dev_remap_addr(struct udevice *dev)
> >  {
> >         return devfdt_remap_addr(dev);
> > diff --git a/test/dm/pci.c b/test/dm/pci.c
> > index e70b65aea4a..fb93e4c78ae 100644
> > --- a/test/dm/pci.c
> > +++ b/test/dm/pci.c
> > @@ -294,3 +294,48 @@ static int dm_test_pci_ea(struct unit_test_state *uts)
> >         return 0;
> >  }
> >  DM_TEST(dm_test_pci_ea, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
> > +
> > +/* Test the dev_read_addr_pci() function */
> > +static int dm_test_pci_addr_flat(struct unit_test_state *uts)
> > +{
> > +       struct udevice *swap1f, *swap1;
> > +       ulong io_addr, mem_addr;
> > +
> > +       ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1f, 0), &swap1f));
> > +       io_addr = dm_pci_read_bar32(swap1f, 0);
> > +       ut_asserteq(io_addr, dev_read_addr_pci(swap1f));
> > +
> > +       /*
> > +        * This device has both I/O and MEM spaces but the MEM space appears
> > +        * first
> > +        */
> > +       ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1, 0), &swap1));
> > +       mem_addr = dm_pci_read_bar32(swap1, 1);
> > +       ut_asserteq(mem_addr, dev_read_addr_pci(swap1));
> > +
> > +       return 0;
> > +}
> > +DM_TEST(dm_test_pci_addr_flat, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT |
> > +               DM_TESTF_FLAT_TREE);
> > +
> > +/*
> > + * Test the dev_read_addr_pci() function with livetree. That function is
> > + * not currently fully implemented, in that it fails to return the BAR address.
> > + * Once that is implemented this test can be removed and dm_test_pci_addr_flat()
> > + * can be used for both flattree and livetree by removing the DM_TESTF_FLAT_TREE
> > + * flag above.
> > + */
> > +static int dm_test_pci_addr_live(struct unit_test_state *uts)
> > +{
> > +       struct udevice *swap1f, *swap1;
> > +
> > +       ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1f, 0), &swap1f));
> > +       ut_asserteq(FDT_ADDR_T_NONE, dev_read_addr_pci(swap1f));
> > +
> > +       ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1, 0), &swap1));
> > +       ut_asserteq(FDT_ADDR_T_NONE, dev_read_addr_pci(swap1));
> > +
> > +       return 0;
> > +}
> > +DM_TEST(dm_test_pci_addr_live, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT |
> > +               DM_TESTF_LIVE_TREE);
> > --
>
> Other than above,
> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
> Tested-by: Bin Meng <bmeng.cn@gmail.com>

applied to u-boot-x86/next, thanks!
diff mbox series

Patch

diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index a2e75981f0b..8733e0d7e19 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -456,12 +456,15 @@ 
 		};
 		pci@1,0 {
 			compatible = "pci-generic";
-			reg = <0x0800 0 0 0 0>;
+			/* BAR0 is at 0x14, using FDT_PCI_SPACE_MEM32 */
+			reg = <0x02000814 0 0 0 0
+				0x0100f810 0 0 0 0>;
 			sandbox,emul = <&swap_case_emul1>;
 		};
 		pci@1f,0 {
 			compatible = "pci-generic";
-			reg = <0xf800 0 0 0 0>;
+			/* BAR1 is at 0x10, using FDT_PCI_SPACE_IO */
+			reg = <0x0100f810 0 0 0 0>;
 			sandbox,emul = <&swap_case_emul1f>;
 		};
 	};
diff --git a/drivers/core/fdtaddr.c b/drivers/core/fdtaddr.c
index 6850003a287..c9a941116a3 100644
--- a/drivers/core/fdtaddr.c
+++ b/drivers/core/fdtaddr.c
@@ -190,3 +190,36 @@  void *devfdt_map_physmem(struct udevice *dev, unsigned long size)
 
 	return map_physmem(addr, size, MAP_NOCACHE);
 }
+
+fdt_addr_t devfdt_get_addr_pci(struct udevice *dev)
+{
+	ulong addr;
+
+	addr = devfdt_get_addr(dev);
+	if (CONFIG_IS_ENABLED(PCI) && IS_ENABLED(CONFIG_DM_PCI) &&
+	    addr == FDT_ADDR_T_NONE) {
+		struct fdt_pci_addr pci_addr;
+		u32 bar;
+		int ret;
+
+		ret = fdtdec_get_pci_addr(gd->fdt_blob,
+					  dev_of_offset(dev),
+					  FDT_PCI_SPACE_MEM32, "reg",
+					  &pci_addr);
+		if (ret) {
+			/* try if there is any i/o-mapped register */
+			ret = fdtdec_get_pci_addr(gd->fdt_blob,
+						  dev_of_offset(dev),
+						  FDT_PCI_SPACE_IO, "reg",
+						  &pci_addr);
+			if (ret)
+				return FDT_ADDR_T_NONE;
+		}
+		ret = fdtdec_get_pci_bar32(dev, &pci_addr, &bar);
+		if (ret)
+			return FDT_ADDR_T_NONE;
+		addr = bar;
+	}
+
+	return addr;
+}
diff --git a/drivers/core/read.c b/drivers/core/read.c
index fb3dcd9a790..9602e52d1b1 100644
--- a/drivers/core/read.c
+++ b/drivers/core/read.c
@@ -307,3 +307,14 @@  int dev_read_alias_highest_id(const char *stem)
 
 	return fdtdec_get_alias_highest_id(gd->fdt_blob, stem);
 }
+
+fdt_addr_t dev_read_addr_pci(struct udevice *dev)
+{
+	ulong addr;
+
+	addr = dev_read_addr(dev);
+	if (addr == FDT_ADDR_T_NONE && !of_live_active())
+		addr = devfdt_get_addr_pci(dev);
+
+	return addr;
+}
diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c
index 01f334938ea..754b6e99215 100644
--- a/drivers/serial/ns16550.c
+++ b/drivers/serial/ns16550.c
@@ -440,36 +440,7 @@  int ns16550_serial_ofdata_to_platdata(struct udevice *dev)
 	int err;
 
 	/* try Processor Local Bus device first */
-	addr = dev_read_addr(dev);
-#if CONFIG_IS_ENABLED(PCI) && defined(CONFIG_DM_PCI)
-	if (addr == FDT_ADDR_T_NONE) {
-		/* then try pci device */
-		struct fdt_pci_addr pci_addr;
-		u32 bar;
-		int ret;
-
-		/* we prefer to use a memory-mapped register */
-		ret = fdtdec_get_pci_addr(gd->fdt_blob, dev_of_offset(dev),
-					  FDT_PCI_SPACE_MEM32, "reg",
-					  &pci_addr);
-		if (ret) {
-			/* try if there is any i/o-mapped register */
-			ret = fdtdec_get_pci_addr(gd->fdt_blob,
-						  dev_of_offset(dev),
-						  FDT_PCI_SPACE_IO,
-						  "reg", &pci_addr);
-			if (ret)
-				return ret;
-		}
-
-		ret = fdtdec_get_pci_bar32(dev, &pci_addr, &bar);
-		if (ret)
-			return ret;
-
-		addr = bar;
-	}
-#endif
-
+	addr = dev_read_addr_pci(dev);
 	if (addr == FDT_ADDR_T_NONE)
 		return -EINVAL;
 
diff --git a/include/dm/fdtaddr.h b/include/dm/fdtaddr.h
index 57b326cb336..959d3bc2d69 100644
--- a/include/dm/fdtaddr.h
+++ b/include/dm/fdtaddr.h
@@ -138,4 +138,12 @@  fdt_addr_t devfdt_get_addr_name(struct udevice *dev, const char *name);
 fdt_addr_t devfdt_get_addr_size_name(struct udevice *dev, const char *name,
 				     fdt_size_t *size);
 
+/**
+ * devfdt_get_addr_pci() - Read an address and handle PCI address translation
+ *
+ * @dev: Device to read from
+ * @return address or FDT_ADDR_T_NONE if not found
+ */
+fdt_addr_t devfdt_get_addr_pci(struct udevice *dev);
+
 #endif
diff --git a/include/dm/read.h b/include/dm/read.h
index 03189838ff7..4f02d07d001 100644
--- a/include/dm/read.h
+++ b/include/dm/read.h
@@ -247,6 +247,26 @@  fdt_addr_t dev_read_addr(struct udevice *dev);
  */
 void *dev_read_addr_ptr(struct udevice *dev);
 
+/**
+ * dev_read_addr_pci() - Read an address and handle PCI address translation
+ *
+ * At present U-Boot does not have address translation logic for PCI in the
+ * livetree implementation (of_addr.c). This special function supports this for
+ * the flat tree implementation.
+ *
+ * This function should be removed (and code should use dev_read() instead)
+ * once:
+ *
+ * 1. PCI address translation is added; and either
+ * 2. everything uses livetree where PCI translation is used (which is feasible
+ *    in SPL and U-Boot proper) or PCI address translation is added to
+ *    fdtdec_get_addr() and friends.
+ *
+ * @dev: Device to read from
+ * @return address or FDT_ADDR_T_NONE if not found
+ */
+fdt_addr_t dev_read_addr_pci(struct udevice *dev);
+
 /**
  * dev_remap_addr() - Get the reg property of a device as a
  *                         memory-mapped I/O pointer
@@ -690,6 +710,11 @@  static inline void *dev_read_addr_ptr(struct udevice *dev)
 	return devfdt_get_addr_ptr(dev);
 }
 
+static inline fdt_addr_t dev_read_addr_pci(struct udevice *dev)
+{
+	return devfdt_get_addr_pci(dev);
+}
+
 static inline void *dev_remap_addr(struct udevice *dev)
 {
 	return devfdt_remap_addr(dev);
diff --git a/test/dm/pci.c b/test/dm/pci.c
index e70b65aea4a..fb93e4c78ae 100644
--- a/test/dm/pci.c
+++ b/test/dm/pci.c
@@ -294,3 +294,48 @@  static int dm_test_pci_ea(struct unit_test_state *uts)
 	return 0;
 }
 DM_TEST(dm_test_pci_ea, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test the dev_read_addr_pci() function */
+static int dm_test_pci_addr_flat(struct unit_test_state *uts)
+{
+	struct udevice *swap1f, *swap1;
+	ulong io_addr, mem_addr;
+
+	ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1f, 0), &swap1f));
+	io_addr = dm_pci_read_bar32(swap1f, 0);
+	ut_asserteq(io_addr, dev_read_addr_pci(swap1f));
+
+	/*
+	 * This device has both I/O and MEM spaces but the MEM space appears
+	 * first
+	 */
+	ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1, 0), &swap1));
+	mem_addr = dm_pci_read_bar32(swap1, 1);
+	ut_asserteq(mem_addr, dev_read_addr_pci(swap1));
+
+	return 0;
+}
+DM_TEST(dm_test_pci_addr_flat, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT |
+		DM_TESTF_FLAT_TREE);
+
+/*
+ * Test the dev_read_addr_pci() function with livetree. That function is
+ * not currently fully implemented, in that it fails to return the BAR address.
+ * Once that is implemented this test can be removed and dm_test_pci_addr_flat()
+ * can be used for both flattree and livetree by removing the DM_TESTF_FLAT_TREE
+ * flag above.
+ */
+static int dm_test_pci_addr_live(struct unit_test_state *uts)
+{
+	struct udevice *swap1f, *swap1;
+
+	ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1f, 0), &swap1f));
+	ut_asserteq(FDT_ADDR_T_NONE, dev_read_addr_pci(swap1f));
+
+	ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1, 0), &swap1));
+	ut_asserteq(FDT_ADDR_T_NONE, dev_read_addr_pci(swap1));
+
+	return 0;
+}
+DM_TEST(dm_test_pci_addr_live, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT |
+		DM_TESTF_LIVE_TREE);