From: Rodolfo Giometti <giometti@linux.it>
To: Sergei Shtylyov <sshtylyov@ru.mvista.com>
Cc: linux-mips@linux-mips.org
Subject: [PATCH] 8250_early console support for au1x00 (again)
Date: Mon, 22 May 2006 22:50:36 +0200 [thread overview]
Message-ID: <20060522205036.GB16223@enneenne.com> (raw)
In-Reply-To: <20060504163301.GH19913@gundam.enneenne.com>
[-- Attachment #1.1: Type: text/plain, Size: 2156 bytes --]
Hello.
Here, attached and published on my site, my two new proposal for
serial line and early console for au1x00.
The first patch:
http://ftp.enneenne.com/pub/misc/au1100-patches/linux/patch-au1x00-early-console
adds early console support for au1x00. In this version I decided to
add the "AU" serial type in all kernel messages.
The second patch:
http://ftp.enneenne.com/pub/misc/au1100-patches/linux/patch-au1x00-serial-phys-addr
fixes serial address space by using only physical addresses. Please,
note that this change allow to simply file "drivers/serial/8250.c"
since functions __raw_readl()/__raw_writel() can be replaced by
functions readl()/writel().
At boot time I get:
Starting kernel .Linux version 2.6.17-rc4-gde4a1dae-dirty (giometti@zaigor) (gcc version 3.4.3) #83 Mon May 22 22:34:47 CEST 2006
CPU revision is: 02030204
Board WWPC1000 version 1.0
WWPC-setup: uC=off
(PRId 02030204) @ 396MHZ
BCLK switching enabled!
Early serial console at AU 0x11100000 (options '115200')
...
Serial: 8250/16550 driver $Revision: 1.90 $ 3 ports, IRQ sharing disabled
serial8250.8: ttyS0 at MMIO 0x11100000 (irq = 0) is a 16550A
serial8250.8: ttyS1 at MMIO 0x11200000 (irq = 1) is a 16550A
serial8250.8: ttyS2 at MMIO 0x11400000 (irq = 3) is a 16550A
...
Adding console on ttyS0 at AU 0x11100000 (options '115200')
...
and at system running time I get:
hostname:~# cat /proc/iomem
10100000-101fffff : au1xxx-ohci.0
10100000-101fffff : ohci_hcd
10500000-1050ffff : eth-base
10520000-10520003 : eth-mac
11100000-111fffff : serial
11200000-112fffff : serial
11400000-114fffff : serial
which is coherent with other system devices. :)
Ciao,
Rodolfo
--
GNU/Linux Solutions e-mail: giometti@enneenne.com
Linux Device Driver giometti@gnudd.com
Embedded Systems giometti@linux.it
UNIX programming phone: +39 349 2432127
[-- Attachment #1.2: patch-au1x00-early-console --]
[-- Type: text/plain, Size: 10521 bytes --]
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index bcf1b10..78dcded 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -32,6 +32,7 @@
#include <linux/kdev_t.h>
#include <linux/root_dev.h>
#include <linux/highmem.h>
+#include <linux/serial.h>
#include <linux/console.h>
#include <linux/mmzone.h>
#include <linux/pfn.h>
@@ -517,6 +518,10 @@ void __init setup_arch(char **cmdline_p)
*cmdline_p = command_line;
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+ early_serial_console_init(*cmdline_p);
+#endif
+
parse_cmdline_early();
bootmem_init();
sparse_init();
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index bbf78aa..784d9d3 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -2336,8 +2336,11 @@ int __init serial8250_start_console(stru
add_preferred_console("ttyS", line, options);
printk("Adding console on ttyS%d at %s 0x%lx (options '%s')\n",
- line, port->iotype == UPIO_MEM ? "MMIO" : "I/O port",
- port->iotype == UPIO_MEM ? (unsigned long) port->mapbase :
+ line,
+ (port->iotype == UPIO_MEM) ? "MMIO" : \
+ (port->iotype == UPIO_AU) ? "AU" : "I/O port",
+ (port->iotype == UPIO_MEM) || \
+ (port->iotype == UPIO_AU) ? (unsigned long) port->mapbase :
(unsigned long) port->iobase, options);
if (!(serial8250_console.flags & CON_ENABLED)) {
serial8250_console.flags &= ~CON_PRINTBUFFER;
diff --git a/drivers/serial/8250_early.c b/drivers/serial/8250_early.c
index 7e51119..319baa9 100644
--- a/drivers/serial/8250_early.c
+++ b/drivers/serial/8250_early.c
@@ -4,6 +4,13 @@
* (c) Copyright 2004 Hewlett-Packard Development Company, L.P.
* Bjorn Helgaas <bjorn.helgaas@hp.com>
*
+ * 2006 - Support for AU1x00 CPUs
+ * Rodolfo Giometti <giometti@linux.it>
+ *
+ * Know bugs:
+ * * for au1x00 probe_baud() is not correct so you _must_ specify
+ * baudrate at command line!
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
@@ -19,6 +26,7 @@
* The user can specify the device directly, e.g.,
* console=uart,io,0x3f8,9600n8
* console=uart,mmio,0xff5e0000,115200n8
+ * console=uart,au,0x11100000,115200
* or platform code can call early_uart_console_init() to set
* the early UART device.
*
@@ -44,22 +52,133 @@ struct early_uart_device {
static struct early_uart_device early_device __initdata;
static int early_uart_registered __initdata;
-static unsigned int __init serial_in(struct uart_port *port, int offset)
+#define CPU_SPEED 396000000 /* Default Au1x00 CPU speed */
+#define SYS_POWERCTRL ((u32 *) 0xB190003C)
+
+#ifdef CONFIG_SERIAL_8250_AU1X00
+
+/* Au1x00 UART hardware has a weird register layout */
+static const u8 au_io_in_map[] = {
+ [UART_RX] = 0,
+ [UART_IER] = 2,
+ [UART_IIR] = 3,
+ [UART_LCR] = 5,
+ [UART_MCR] = 6,
+ [UART_LSR] = 7,
+};
+
+static const u8 au_io_out_map[] = {
+ [UART_TX] = 1,
+ [UART_IER] = 2,
+ [UART_FCR] = 4,
+ [UART_LCR] = 5,
+ [UART_MCR] = 6,
+};
+
+/* sane hardware needs no mapping */
+static inline int map_in_reg(struct uart_port *port, int offset)
+{
+ if (port->iotype != UPIO_AU)
+ return offset;
+ return au_io_in_map[offset];
+}
+
+static inline int map_out_reg(struct uart_port *port, int offset)
+{
+ if (port->iotype != UPIO_AU)
+ return offset;
+ return au_io_out_map[offset];
+}
+
+#else
+
+/* sane hardware needs no mapping */
+#define map_in_reg(port, offset) (offset)
+#define map_out_reg(port, offset) (offset)
+
+#endif
+
+static unsigned int serial_in(struct uart_port *port, int offset)
{
- if (port->iotype == UPIO_MEM)
+ offset = map_in_reg(port, offset) << port->regshift;
+
+ switch (port->iotype) {
+ case UPIO_HUB6:
+ outb(port->hub6 - 1 + offset, port->iobase);
+ return inb(port->iobase + 1);
+
+ case UPIO_MEM:
return readb(port->membase + offset);
- else
+
+ case UPIO_MEM32:
+ case UPIO_AU:
+ return readl(port->membase + offset);
+
+ default:
return inb(port->iobase + offset);
+ }
}
-static void __init serial_out(struct uart_port *port, int offset, int value)
+static void
+serial_out(struct uart_port *port, int offset, int value)
{
- if (port->iotype == UPIO_MEM)
+ offset = map_out_reg(port, offset) << port->regshift;
+
+ switch (port->iotype) {
+ case UPIO_HUB6:
+ outb(port->hub6 - 1 + offset, port->iobase);
+ outb(value, port->iobase + 1);
+ break;
+
+ case UPIO_MEM:
writeb(value, port->membase + offset);
- else
+ break;
+
+ case UPIO_MEM32:
+ case UPIO_AU:
+ writel(value, port->membase + offset);
+ break;
+
+ default:
outb(value, port->iobase + offset);
+ }
+}
+
+/* Uart divisor latch read */
+static inline int _serial_dl_read(struct uart_port *port)
+{
+ return serial_in(port, UART_DLL) | serial_in(port, UART_DLM) << 8;
+}
+
+/* Uart divisor latch write */
+static inline void _serial_dl_write(struct uart_port *port, int value)
+{
+ serial_out(port, UART_DLL, value & 0xff);
+ serial_out(port, UART_DLM, value >> 8 & 0xff);
+}
+
+#ifdef CONFIG_SERIAL_8250_AU1X00
+/* Au1x00 haven't got a standard divisor latch */
+static int serial_dl_read(struct uart_port *port)
+{
+ if (port->iotype == UPIO_AU)
+ return readl(port->membase + 0x28);
+ else
+ return _serial_dl_read(port);
}
+static void serial_dl_write(struct uart_port *port, int value)
+{
+ if (port->iotype == UPIO_AU)
+ writel(value, port->membase + 0x28);
+ else
+ _serial_dl_write(port, value);
+}
+#else
+#define serial_dl_read(port) _serial_dl_read(port)
+#define serial_dl_write(port, value) _serial_dl_write(port, value)
+#endif
+
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
static void __init wait_for_xmitr(struct uart_port *port)
@@ -98,16 +217,17 @@ static void __init early_uart_write(stru
static unsigned int __init probe_baud(struct uart_port *port)
{
- unsigned char lcr, dll, dlm;
+ unsigned char lcr;
unsigned int quot;
+ int sd = ((int)(__raw_readl(SYS_POWERCTRL)&0x03)) + 2; /* Au1x00 SD */
lcr = serial_in(port, UART_LCR);
serial_out(port, UART_LCR, lcr | UART_LCR_DLAB);
- dll = serial_in(port, UART_DLL);
- dlm = serial_in(port, UART_DLM);
+ quot = serial_dl_read(port);
serial_out(port, UART_LCR, lcr);
- quot = (dlm << 8) | dll;
+ if (port->iotype == UPIO_AU)
+ return CPU_SPEED / (sd * quot * 32);
return (port->uartclk / 16) / quot;
}
@@ -116,17 +236,20 @@ static void __init init_port(struct earl
struct uart_port *port = &device->port;
unsigned int divisor;
unsigned char c;
+ int sd = ((int)(__raw_readl(SYS_POWERCTRL)&0x03)) + 2; /* Au1x00 SD */
serial_out(port, UART_LCR, 0x3); /* 8n1 */
serial_out(port, UART_IER, 0); /* no interrupt */
serial_out(port, UART_FCR, 0); /* no fifo */
serial_out(port, UART_MCR, 0x3); /* DTR + RTS */
- divisor = port->uartclk / (16 * device->baud);
+ if (port->iotype == UPIO_AU)
+ divisor = CPU_SPEED / ( sd * device->baud * 32);
+ else
+ divisor = port->uartclk / (16 * device->baud);
c = serial_in(port, UART_LCR);
serial_out(port, UART_LCR, c | UART_LCR_DLAB);
- serial_out(port, UART_DLL, divisor & 0xff);
- serial_out(port, UART_DLM, (divisor >> 8) & 0xff);
+ serial_dl_write(port, divisor);
serial_out(port, UART_LCR, c & ~UART_LCR_DLAB);
}
@@ -135,6 +258,7 @@ static int __init parse_options(struct e
struct uart_port *port = &device->port;
int mapsize = 64;
int mmio, length;
+ char buf[16];
if (!options)
return -ENODEV;
@@ -142,6 +266,7 @@ static int __init parse_options(struct e
port->uartclk = BASE_BAUD * 16;
if (!strncmp(options, "mmio,", 5)) {
port->iotype = UPIO_MEM;
+ port->regshift = 0;
port->mapbase = simple_strtoul(options + 5, &options, 0);
port->membase = ioremap(port->mapbase, mapsize);
if (!port->membase) {
@@ -150,10 +275,25 @@ static int __init parse_options(struct e
return -ENOMEM;
}
mmio = 1;
+ strcpy(buf, "MMIO");
+ } else if (!strncmp(options, "au,", 3)) {
+ port->iotype = UPIO_AU;
+ port->regshift = 2;
+ port->mapbase = simple_strtoul(options + 3, &options, 0);
+ port->membase = ioremap(port->mapbase, mapsize);
+ if (!port->membase) {
+ printk(KERN_ERR "%s: Couldn't ioremap 0x%lx\n",
+ __FUNCTION__, port->mapbase);
+ return -ENOMEM;
+ }
+ mmio = 1;
+ strcpy(buf, "AU");
} else if (!strncmp(options, "io,", 3)) {
port->iotype = UPIO_PORT;
+ port->regshift = 0;
port->iobase = simple_strtoul(options + 3, &options, 0);
mmio = 0;
+ strcpy(buf, "IO");
} else
return -EINVAL;
@@ -169,8 +309,7 @@ static int __init parse_options(struct e
}
printk(KERN_INFO "Early serial console at %s 0x%lx (options '%s')\n",
- mmio ? "MMIO" : "I/O port",
- mmio ? port->mapbase : (unsigned long) port->iobase,
+ buf, mmio ? port->mapbase : (unsigned long) port->iobase,
device->options);
return 0;
}
@@ -227,22 +366,23 @@ static int __init early_uart_console_swi
{
struct early_uart_device *device = &early_device;
struct uart_port *port = &device->port;
- int mmio, line;
+ int line;
if (!(early_uart_console.flags & CON_ENABLED))
return 0;
/* Try to start the normal driver on a matching line. */
- mmio = (port->iotype == UPIO_MEM);
line = serial8250_start_console(port, device->options);
if (line < 0)
printk("No ttyS device at %s 0x%lx for console\n",
- mmio ? "MMIO" : "I/O port",
- mmio ? port->mapbase :
+ (port->iotype == UPIO_MEM) ? "MMIO" : \
+ (port->iotype == UPIO_AU) ? "AU" : "I/O port",
+ (port->iotype == UPIO_MEM) || \
+ (port->iotype == UPIO_AU) ? port->mapbase :
(unsigned long) port->iobase);
unregister_console(&early_uart_console);
- if (mmio)
+ if ((port->iotype == UPIO_MEM) || (port->iotype == UPIO_AU))
iounmap(port->membase);
return 0;
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index 17839e7..9e27aee 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -2367,6 +2367,7 @@ int uart_match_port(struct uart_port *po
return (port1->iobase == port2->iobase) &&
(port1->hub6 == port2->hub6);
case UPIO_MEM:
+ case UPIO_AU:
return (port1->mapbase == port2->mapbase);
}
return 0;
[-- Attachment #1.3: patch-au1x00-serial-phys-addr --]
[-- Type: text/plain, Size: 3574 bytes --]
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 784d9d3..40c9097 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -311,12 +311,8 @@ static unsigned int serial_in(struct uar
return readb(up->port.membase + offset);
case UPIO_MEM32:
- return readl(up->port.membase + offset);
-
-#ifdef CONFIG_SERIAL_8250_AU1X00
case UPIO_AU:
- return __raw_readl(up->port.membase + offset);
-#endif
+ return readl(up->port.membase + offset);
default:
return inb(up->port.iobase + offset);
@@ -339,14 +335,9 @@ serial_out(struct uart_8250_port *up, in
break;
case UPIO_MEM32:
- writel(value, up->port.membase + offset);
- break;
-
-#ifdef CONFIG_SERIAL_8250_AU1X00
case UPIO_AU:
- __raw_writel(value, up->port.membase + offset);
+ writel(value, up->port.membase + offset);
break;
-#endif
default:
outb(value, up->port.iobase + offset);
@@ -380,7 +371,7 @@ static inline void _serial_dl_write(stru
static int serial_dl_read(struct uart_8250_port *up)
{
if (up->port.iotype == UPIO_AU)
- return __raw_readl(up->port.membase + 0x28);
+ return readl(up->port.membase + 0x28);
else
return _serial_dl_read(up);
}
@@ -388,7 +379,7 @@ static int serial_dl_read(struct uart_82
static void serial_dl_write(struct uart_8250_port *up, int value)
{
if (up->port.iotype == UPIO_AU)
- __raw_writel(value, up->port.membase + 0x28);
+ writel(value, up->port.membase + 0x28);
else
_serial_dl_write(up, value);
}
diff --git a/drivers/serial/8250_au1x00.c b/drivers/serial/8250_au1x00.c
index 58015fd..9d0f1be 100644
--- a/drivers/serial/8250_au1x00.c
+++ b/drivers/serial/8250_au1x00.c
@@ -29,36 +29,36 @@
#define PORT(_base, _irq) \
{ \
.iobase = _base, \
- .membase = (void __iomem *)_base,\
- .mapbase = CPHYSADDR(_base), \
+ .mapbase = _base, \
.irq = _irq, \
.uartclk = 0, /* filled */ \
.regshift = 2, \
.iotype = UPIO_AU, \
- .flags = UPF_SKIP_TEST \
+ .flags = UPF_SKIP_TEST | \
+ UPF_IOREMAP \
}
static struct plat_serial8250_port au1x00_data[] = {
#if defined(CONFIG_SOC_AU1000)
- PORT(UART0_ADDR, AU1000_UART0_INT),
- PORT(UART1_ADDR, AU1000_UART1_INT),
- PORT(UART2_ADDR, AU1000_UART2_INT),
- PORT(UART3_ADDR, AU1000_UART3_INT),
+ PORT(UART0_PHYS_ADDR, AU1000_UART0_INT),
+ PORT(UART1_PHYS_ADDR, AU1000_UART1_INT),
+ PORT(UART2_PHYS_ADDR, AU1000_UART2_INT),
+ PORT(UART3_PHYS_ADDR, AU1000_UART3_INT),
#elif defined(CONFIG_SOC_AU1500)
- PORT(UART0_ADDR, AU1500_UART0_INT),
- PORT(UART3_ADDR, AU1500_UART3_INT),
+ PORT(UART0_PHYS_ADDR, AU1500_UART0_INT),
+ PORT(UART3_PHYS_ADDR, AU1500_UART3_INT),
#elif defined(CONFIG_SOC_AU1100)
- PORT(UART0_ADDR, AU1100_UART0_INT),
- PORT(UART1_ADDR, AU1100_UART1_INT),
+ PORT(UART0_PHYS_ADDR, AU1100_UART0_INT),
+ PORT(UART1_PHYS_ADDR, AU1100_UART1_INT),
/* The internal UART2 does not exist on the AU1100 processor. */
- PORT(UART3_ADDR, AU1100_UART3_INT),
+ PORT(UART3_PHYS_ADDR, AU1100_UART3_INT),
#elif defined(CONFIG_SOC_AU1550)
- PORT(UART0_ADDR, AU1550_UART0_INT),
- PORT(UART1_ADDR, AU1550_UART1_INT),
- PORT(UART3_ADDR, AU1550_UART3_INT),
+ PORT(UART0_PHYS_ADDR, AU1550_UART0_INT),
+ PORT(UART1_PHYS_ADDR, AU1550_UART1_INT),
+ PORT(UART3_PHYS_ADDR, AU1550_UART3_INT),
#elif defined(CONFIG_SOC_AU1200)
- PORT(UART0_ADDR, AU1200_UART0_INT),
- PORT(UART1_ADDR, AU1200_UART1_INT),
+ PORT(UART0_PHYS_ADDR, AU1200_UART0_INT),
+ PORT(UART1_PHYS_ADDR, AU1200_UART1_INT),
#endif
{ },
};
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
next prev parent reply other threads:[~2006-05-22 20:50 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-05-04 13:45 [PATCH] 8250_early console support for au1x00 Rodolfo Giometti
2006-05-04 14:35 ` Sergei Shtylyov
2006-05-04 15:20 ` Rodolfo Giometti
2006-05-04 15:48 ` Sergei Shtylyov
2006-05-04 16:33 ` Rodolfo Giometti
2006-05-22 20:50 ` Rodolfo Giometti [this message]
2006-08-28 14:51 ` [PATCH] 8250_early console support for au1x00 (again) Sergei Shtylyov
2006-08-30 10:53 ` Rodolfo Giometti
2006-08-30 12:41 ` Sergei Shtylyov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20060522205036.GB16223@enneenne.com \
--to=giometti@linux.it \
--cc=linux-mips@linux-mips.org \
--cc=sshtylyov@ru.mvista.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.