From 9f556d4b6fc71d548e5c984c416f4f1b7d599d2f Mon Sep 17 00:00:00 2001 From: Michel Stam Date: Mon, 7 Apr 2014 12:01:22 +0200 Subject: x86: ns16550: Rework driver to allow for x86 I/O space The current implementation fakes a memory-mapped I/O device at 0x3f8 and 0x2f8, then uses platform read/write functions to do the actual reading and writing. These platform functions only exist for the x86 platform; better to move the I/O routines into the driver and have the driver request I/O ports using request_ioport_region. Signed-off-by: Michel Stam Signed-off-by: Sascha Hauer --- drivers/serial/serial_ns16550.c | 123 ++++++++++++++++++++++++++++++++++------ 1 file changed, 107 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/serial_ns16550.c b/drivers/serial/serial_ns16550.c index 0c00eb182c..7d22873835 100644 --- a/drivers/serial/serial_ns16550.c +++ b/drivers/serial/serial_ns16550.c @@ -47,6 +47,7 @@ struct ns16550_priv { struct console_device cdev; struct NS16550_plat plat; int access_width; + int mmio; struct clk *clk; uint32_t fcrval; }; @@ -61,6 +62,90 @@ struct ns16550_drvdata { const char *linux_console_name; }; +/** + * @brief read system i/o (byte) + * @param[in] addr address to read + * @param[in] mmio memory i/o space or i/o port space + */ +static inline uint8_t ns16550_sys_readb(void __iomem *addr, int mmio) +{ + if (mmio) + return readb(addr); + else + return (uint8_t) inb((int) addr); +} + +/** + * @brief read system i/o (word) + * @param[in] addr address to read + * @param[in] mmio memory i/o space or i/o port space + */ +static inline uint16_t ns16550_sys_readw(void __iomem *addr, int mmio) +{ + if (mmio) + return readw(addr); + else + return (uint16_t) inw((int) addr); +} + +/** + * @brief read system i/o (dword) + * @param[in] addr address to read + * @param[in] mmio memory i/o space or i/o port space + */ +static inline uint32_t ns16550_sys_readl(void __iomem *addr, int mmio) +{ + if (mmio) + return readl(addr); + else + return (uint32_t) inl((int) addr); +} + +/** + * @brief write system i/o (byte) + * @param[in] val data to write + * @param[in] addr address to write to + * @param[in] mmio memory i/o space or i/o port space + */ +static inline void ns16550_sys_writeb(uint8_t val, void __iomem *addr, + int mmio) +{ + if (mmio) + writeb(val, addr); + else + outb(val, (int) addr); +} + +/** + * @brief read system i/o (word) + * @param[in] val data to write + * @param[in] addr address to write to + * @param[in] mmio memory i/o space or i/o port space + */ +static inline void ns16550_sys_writew(uint16_t val, void __iomem *addr, + int mmio) +{ + if (mmio) + writew(val, addr); + else + outw(val, (int) addr); +} + +/** + * @brief read system i/o (dword) + * @param[in] val data to write + * @param[in] addr address to write to + * @param[in] mmio memory i/o space or i/o port space + */ +static inline void ns16550_sys_writel(uint32_t val, void __iomem *addr, + int mmio) +{ + if (mmio) + writel(val, addr); + else + outl(val, (int) addr); +} + /** * @brief read register * @@ -78,16 +163,13 @@ static uint32_t ns16550_read(struct console_device *cdev, uint32_t off) off <<= plat->shift; - if (plat->reg_read) - return plat->reg_read((unsigned long)dev->priv, off); - switch (width) { case IORESOURCE_MEM_8BIT: - return readb(dev->priv + off); + return ns16550_sys_readb(dev->priv + off, priv->mmio); case IORESOURCE_MEM_16BIT: - return readw(dev->priv + off); + return ns16550_sys_readw(dev->priv + off, priv->mmio); case IORESOURCE_MEM_32BIT: - return readl(dev->priv + off); + return ns16550_sys_readl(dev->priv + off, priv->mmio); } return -1; } @@ -109,20 +191,15 @@ static void ns16550_write(struct console_device *cdev, uint32_t val, off <<= plat->shift; - if (plat->reg_write) { - plat->reg_write(val, (unsigned long)dev->priv, off); - return; - } - switch (width) { case IORESOURCE_MEM_8BIT: - writeb(val & 0xff, dev->priv + off); + ns16550_sys_writeb(val & 0xff, dev->priv + off, priv->mmio); break; case IORESOURCE_MEM_16BIT: - writew(val & 0xffff, dev->priv + off); + ns16550_sys_writew(val & 0xffff, dev->priv + off, priv->mmio); break; case IORESOURCE_MEM_32BIT: - writel(val, dev->priv + off); + ns16550_sys_writel(val, dev->priv + off, priv->mmio); break; } } @@ -293,16 +370,30 @@ static int ns16550_probe(struct device_d *dev) struct console_device *cdev; struct NS16550_plat *plat = (struct NS16550_plat *)dev->platform_data; struct ns16550_drvdata *devtype; + struct resource *res; int ret; ret = dev_get_drvdata(dev, (unsigned long *)&devtype); if (ret) devtype = &ns16550_drvdata; - dev->priv = dev_request_mem_region(dev, 0); - priv = xzalloc(sizeof(*priv)); + res = dev_get_resource(dev, IORESOURCE_MEM, 0); + priv->mmio = (res != NULL); + if (res) { + res = request_iomem_region(dev_name(dev), res->start, res->end); + } else { + res = dev_get_resource(dev, IORESOURCE_IO, 0); + if (res) + res = request_ioport_region(dev_name(dev), res->start, + res->end); + } + if (!res) + goto err; + dev->priv = (void __force __iomem *) res->start; + + if (plat) priv->plat = *plat; else -- cgit v1.2.3