[U-Boot] [PATCH v2 3/5] dm: ns16550: Don't map_physmem for I/O ports

Simon Glass sjg at chromium.org
Tue May 17 17:54:21 CEST 2016


Hi Daniel,

On 17 May 2016 at 09:51, Daniel Schwierzeck
<daniel.schwierzeck at gmail.com> wrote:
>
> 2016-05-17 14:48 GMT+02:00 Paul Burton <paul.burton at imgtec.com>:
> > On Tue, May 17, 2016 at 06:11:22AM -0600, Simon Glass wrote:
> >> Hi Paul,
> >>
> >> On 16 May 2016 at 11:44, Paul Burton <paul.burton at imgtec.com> wrote:
> >> > If the UART is to be accessed using I/O port accessors (inb & outb) then
> >> > using map_physmem doesn't make sense, since it operates in a different
> >> > memory space. Remove the call to map_physmem when
> >> > CONFIG_SYS_NS16550_PORT_MAPPED is defined, allowing I/O port addresses
> >> > to not be mangled by the incorrect mapping.
> >> >
> >> > Signed-off-by: Paul Burton <paul.burton at imgtec.com>
> >> > ---
> >> >
> >> > Changes in v2:
> >> > - New patch, part of a simplified approach tackling only a single Malta UART.
> >> >
> >> >  drivers/serial/ns16550.c | 8 ++++++++
> >> >  1 file changed, 8 insertions(+)
> >> >
> >> > diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c
> >> > index 28da9dd..e58e6aa 100644
> >> > --- a/drivers/serial/ns16550.c
> >> > +++ b/drivers/serial/ns16550.c
> >> > @@ -100,7 +100,11 @@ static void ns16550_writeb(NS16550_t port, int offset, int value)
> >> >         unsigned char *addr;
> >> >
> >> >         offset *= 1 << plat->reg_shift;
> >> > +#ifdef CONFIG_SYS_NS16550_PORT_MAPPED
> >> > +       addr = (unsigned char *)plat->base + offset;
> >> > +#else
> >> >         addr = map_physmem(plat->base, 0, MAP_NOCACHE) + offset;
> >> > +#endif
> >>
> >> Please don't add CONFIG #ifdefs in these functions. Perhaps it needs
> >> to be another parameter? Possibly a flag. But with driver-model we
> >> need to be able to support both options in the core code.
> >
> > Hi Simon,
> >
> > Are you sure systems rely on using I/O ports with map_physmem? The only
> > other systems that define CONFIG_SYS_NS16550_PORT_MAPPED are x86 ones,
> > in include/configs/x86-common.h, and so far as I can tell they don't use
> > device model which suggests this code has simply been untested before. I
> > don't see why you would use map_physmem on an I/O port address that is
> > then going to be passed to inb/outb & I think the code here is simply
> > wrong to do so.
>
> the current code looks wrong. serial_in_shift() is expanded to inb()
> in case of CONFIG_SYS_NS16550_PORT_MAPPED and to
> in_le32()/in_be32()/readl()/readb() otherwise. Only in the latter case
> a map_physmem() is required and should be done in serial_in_shift()
> itself or preferrably only once in
> ns16550_serial_ofdata_to_platdata().
>
> I think the correct approach would be the following:

This is better I think. But how about adding a device tree binding to
select I/O access? In principle each device might have its own
settings.

>
> --- a/drivers/serial/ns16550.c
> +++ b/drivers/serial/ns16550.c
> @@ -100,7 +100,8 @@ static void ns16550_writeb(NS16550_t port, int
> offset, int value)
>         unsigned char *addr;
>
>         offset *= 1 << plat->reg_shift;
> -       addr = map_physmem(plat->base, 0, MAP_NOCACHE) + offset;
> +       addr = plat->base + offset;
> +
>         /*
>          * As far as we know it doesn't make sense to support selection of
>          * these options at run-time, so use the existing CONFIG options.
> @@ -114,7 +115,7 @@ static int ns16550_readb(NS16550_t port, int offset)
>         unsigned char *addr;
>
>         offset *= 1 << plat->reg_shift;
> -       addr = map_physmem(plat->base, 0, MAP_NOCACHE) + offset;
> +       addr = plat->base + offset;
>
>         return serial_in_shift(addr + plat->reg_offset, plat->reg_shift);
>  }
> @@ -400,7 +401,12 @@ int ns16550_serial_ofdata_to_platdata(struct udevice *dev)
>         if (addr == FDT_ADDR_T_NONE)
>                 return -EINVAL;
>
> +#ifdef CONFIG_SYS_NS16550_PORT_MAPPED
>         plat->base = addr;
> +#else
> +       plat->base = map_physmem(addr, 0, MAP_NOCACHE);
> +#endif
> +
>         plat->reg_offset = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
>                                      "reg-offset", 0);
>         plat->reg_shift = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
>
> --
> - Daniel

Regards,
Simon


More information about the U-Boot mailing list