[PATCH 5/5] powerpc: kernel: 16650 UART reg-shift support

From: Tanmay Inamdar
Date: Mon Apr 02 2012 - 02:50:38 EST


In APM8018X SOC, UART register address space has been relocated to 32-bit
data boundaries for APB bus implementation.
Current legacy_serial driver ignores the reg-shift property. This patch
modifies legacy_serial.c and udbg_16550.c to work with above mentioned UARTs.

Signed-off-by: Tanmay Inamdar <tinamdar@xxxxxxx>
---
:100644 100644 8338aef... f5fc106... M arch/powerpc/include/asm/udbg.h
:100644 100644 bedd12e... d523b7d... M arch/powerpc/kernel/legacy_serial.c
:100644 100644 6837f83... e0cb7dc... M arch/powerpc/kernel/udbg_16550.c
arch/powerpc/include/asm/udbg.h | 2 +-
arch/powerpc/kernel/legacy_serial.c | 16 +++++---
arch/powerpc/kernel/udbg_16550.c | 64 ++++++++++++++++++++++------------
3 files changed, 52 insertions(+), 30 deletions(-)

diff --git a/arch/powerpc/include/asm/udbg.h b/arch/powerpc/include/asm/udbg.h
index 8338aef..f5fc106 100644
--- a/arch/powerpc/include/asm/udbg.h
+++ b/arch/powerpc/include/asm/udbg.h
@@ -29,7 +29,7 @@ extern void udbg_printf(const char *fmt, ...)
extern void udbg_progress(char *s, unsigned short hex);

extern void udbg_init_uart(void __iomem *comport, unsigned int speed,
- unsigned int clock);
+ unsigned int clock, unsigned int regshift);
extern unsigned int udbg_probe_uart_speed(void __iomem *comport,
unsigned int clock);

diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c
index bedd12e..d523b7d 100644
--- a/arch/powerpc/kernel/legacy_serial.c
+++ b/arch/powerpc/kernel/legacy_serial.c
@@ -33,6 +33,7 @@ static struct legacy_serial_info {
unsigned int clock;
int irq_check_parent;
phys_addr_t taddr;
+ unsigned int regshift;
} legacy_serial_infos[MAX_LEGACY_SERIAL_PORTS];

static struct __initdata of_device_id legacy_serial_parents[] = {
@@ -42,6 +43,7 @@ static struct __initdata of_device_id legacy_serial_parents[] = {
{.compatible = "ibm,opb",},
{.compatible = "simple-bus",},
{.compatible = "wrs,epld-localbus",},
+ {.compatible = "apm,apb",},
{},
};

@@ -163,11 +165,6 @@ static int __init add_legacy_soc_port(struct device_node *np,
if (of_get_property(np, "clock-frequency", NULL) == NULL)
return -1;

- /* if reg-shift or offset, don't try to use it */
- if ((of_get_property(np, "reg-shift", NULL) != NULL) ||
- (of_get_property(np, "reg-offset", NULL) != NULL))
- return -1;
-
/* if rtas uses this device, don't try to use it as well */
if (of_get_property(np, "used-by-rtas", NULL) != NULL)
return -1;
@@ -319,7 +316,7 @@ static void __init setup_legacy_serial_console(int console)
if (info->speed == 0)
info->speed = udbg_probe_uart_speed(addr, info->clock);
DBG("default console speed = %d\n", info->speed);
- udbg_init_uart(addr, info->speed, info->clock);
+ udbg_init_uart(addr, info->speed, info->clock, info->regshift);
}

/*
@@ -336,6 +333,7 @@ void __init find_legacy_serial_ports(void)
struct device_node *np, *stdout = NULL;
const char *path;
int index;
+ unsigned int regshift;

DBG(" -> find_legacy_serial_port()\n");

@@ -359,6 +357,12 @@ void __init find_legacy_serial_ports(void)
index = add_legacy_soc_port(np, np);
if (index >= 0 && np == stdout)
legacy_serial_console = index;
+ if (of_property_read_u32(np, "reg-shift",
+ &regshift) == 0) {
+ legacy_serial_infos
+ [legacy_serial_console].regshift =
+ regshift;
+ }
}
}
of_node_put(parent);
diff --git a/arch/powerpc/kernel/udbg_16550.c b/arch/powerpc/kernel/udbg_16550.c
index 6837f83..e0cb7dc 100644
--- a/arch/powerpc/kernel/udbg_16550.c
+++ b/arch/powerpc/kernel/udbg_16550.c
@@ -47,12 +47,29 @@ struct NS16550 {

#define LCR_DLAB 0x80

+static unsigned int reg_shift;
+#define ns16550_offset(addr) (addr - (unsigned char *)udbg_comport)
+
static struct NS16550 __iomem *udbg_comport;

+static inline u8 serial_read(unsigned char *addr)
+{
+ u32 offset = ns16550_offset(addr) << reg_shift;
+ return readb(udbg_comport + offset);
+}
+
+static inline void serial_write(unsigned char *addr, char val)
+{
+ u32 offset = ns16550_offset(addr) << reg_shift;
+ writeb(val, udbg_comport + offset);
+}
+
static void udbg_550_flush(void)
{
+ u32 timeout = 1000;
if (udbg_comport) {
- while ((in_8(&udbg_comport->lsr) & LSR_THRE) == 0)
+ while (((serial_read(&udbg_comport->lsr) & LSR_THRE) == 0)
+ && --timeout)
/* wait for idle */;
}
}
@@ -63,15 +80,15 @@ static void udbg_550_putc(char c)
if (c == '\n')
udbg_550_putc('\r');
udbg_550_flush();
- out_8(&udbg_comport->thr, c);
+ serial_write(&udbg_comport->thr, c);
}
}

static int udbg_550_getc_poll(void)
{
if (udbg_comport) {
- if ((in_8(&udbg_comport->lsr) & LSR_DR) != 0)
- return in_8(&udbg_comport->rbr);
+ if ((serial_read(&udbg_comport->lsr) & LSR_DR) != 0)
+ return serial_read(&udbg_comport->rbr);
else
return -1;
}
@@ -81,15 +98,15 @@ static int udbg_550_getc_poll(void)
static int udbg_550_getc(void)
{
if (udbg_comport) {
- while ((in_8(&udbg_comport->lsr) & LSR_DR) == 0)
+ while ((serial_read(&udbg_comport->lsr) & LSR_DR) == 0)
/* wait for char */;
- return in_8(&udbg_comport->rbr);
+ return serial_read(&udbg_comport->rbr);
}
return -1;
}

void udbg_init_uart(void __iomem *comport, unsigned int speed,
- unsigned int clock)
+ unsigned int clock, unsigned int regshift)
{
unsigned int dll, base_bauds;

@@ -103,22 +120,23 @@ void udbg_init_uart(void __iomem *comport, unsigned int speed,

if (comport) {
udbg_comport = (struct NS16550 __iomem *)comport;
- out_8(&udbg_comport->lcr, 0x00);
- out_8(&udbg_comport->ier, 0xff);
- out_8(&udbg_comport->ier, 0x00);
- out_8(&udbg_comport->lcr, LCR_DLAB);
- out_8(&udbg_comport->dll, dll & 0xff);
- out_8(&udbg_comport->dlm, dll >> 8);
+ serial_write(&udbg_comport->lcr, 0x00);
+ serial_write(&udbg_comport->ier, 0xff);
+ serial_write(&udbg_comport->ier, 0x00);
+ serial_write(&udbg_comport->lcr, LCR_DLAB);
+ serial_write(&udbg_comport->dll, dll & 0xff);
+ serial_write(&udbg_comport->dlm, dll >> 8);
/* 8 data, 1 stop, no parity */
- out_8(&udbg_comport->lcr, 0x03);
+ serial_write(&udbg_comport->lcr, 0x03);
/* RTS/DTR */
- out_8(&udbg_comport->mcr, 0x03);
+ serial_write(&udbg_comport->mcr, 0x03);
/* Clear & enable FIFOs */
- out_8(&udbg_comport->fcr ,0x07);
+ serial_write(&udbg_comport->fcr, 0x07);
udbg_putc = udbg_550_putc;
udbg_flush = udbg_550_flush;
udbg_getc = udbg_550_getc;
udbg_getc_poll = udbg_550_getc_poll;
+ reg_shift = regshift;
}
}

@@ -128,24 +146,24 @@ unsigned int udbg_probe_uart_speed(void __iomem *comport, unsigned int clock)
u8 old_lcr;
struct NS16550 __iomem *port = comport;

- old_lcr = in_8(&port->lcr);
+ old_lcr = serial_read(&port->lcr);

/* select divisor latch registers. */
- out_8(&port->lcr, LCR_DLAB);
+ serial_write(&port->lcr, LCR_DLAB);

/* now, read the divisor */
- dll = in_8(&port->dll);
- dlm = in_8(&port->dlm);
+ dll = serial_read(&port->dll);
+ dlm = serial_read(&port->dlm);
divisor = dlm << 8 | dll;

/* check prescaling */
- if (in_8(&port->mcr) & 0x80)
+ if (serial_read(&port->mcr) & 0x80)
prescaler = 4;
else
prescaler = 1;

/* restore the LCR */
- out_8(&port->lcr, old_lcr);
+ serial_write(&port->lcr, old_lcr);

/* calculate speed */
speed = (clock / prescaler) / (divisor * 16);
@@ -341,7 +359,7 @@ void __init udbg_init_wsp(void)
{
udbg_comport = (struct NS16550 __iomem *)WSP_UART_VIRT;

- udbg_init_uart(udbg_comport, 57600, 50000000);
+ udbg_init_uart(udbg_comport, 57600, 50000000, 0);

udbg_putc = udbg_wsp_putc;
udbg_flush = udbg_wsp_flush;
--
1.6.1.rc3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/