Browse Source

davinci: serial: generalize for more SoCs

Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
Kevin Hilman 16 years ago
parent
commit
617b925f94
2 changed files with 96 additions and 20 deletions
  1. 18 3
      arch/arm/mach-davinci/include/mach/serial.h
  2. 78 17
      arch/arm/mach-davinci/serial.c

+ 18 - 3
arch/arm/mach-davinci/include/mach/serial.h

@@ -13,8 +13,23 @@
 
 #include <mach/io.h>
 
-#define DAVINCI_UART0_BASE   (IO_PHYS + 0x20000)
-#define DAVINCI_UART1_BASE   (IO_PHYS + 0x20400)
-#define DAVINCI_UART2_BASE   (IO_PHYS + 0x20800)
+#define DAVINCI_MAX_NR_UARTS	3
+#define DAVINCI_UART0_BASE	(IO_PHYS + 0x20000)
+#define DAVINCI_UART1_BASE	(IO_PHYS + 0x20400)
+#define DAVINCI_UART2_BASE	(IO_PHYS + 0x20800)
+
+#define DM355_UART2_BASE	(IO_PHYS + 0x206000)
+
+/* DaVinci UART register offsets */
+#define UART_DAVINCI_PWREMU		0x0c
+#define UART_DM646X_SCR			0x10
+#define UART_DM646X_SCR_TX_WATERMARK	0x08
+
+struct davinci_uart_config {
+	/* Bit field of UARTs present; bit 0 --> UART1 */
+	unsigned int enabled_uarts;
+};
+
+extern void davinci_serial_init(struct davinci_uart_config *);
 
 #endif /* __ASM_ARCH_SERIAL_H */

+ 78 - 17
arch/arm/mach-davinci/serial.c

@@ -32,32 +32,47 @@
 #include <mach/hardware.h>
 #include <mach/serial.h>
 #include <mach/irqs.h>
+#include <mach/cputype.h>
+#include "clock.h"
 
-#define UART_DAVINCI_PWREMU 0x0c
-
-static inline unsigned int davinci_serial_in(struct plat_serial8250_port *up,
-					  int offset)
+static inline unsigned int serial_read_reg(struct plat_serial8250_port *up,
+					   int offset)
 {
 	offset <<= up->regshift;
-	return (unsigned int)__raw_readb(up->membase + offset);
+	return (unsigned int)__raw_readl(IO_ADDRESS(up->mapbase) + offset);
 }
 
-static inline void davinci_serial_outp(struct plat_serial8250_port *p,
-				       int offset, int value)
+static inline void serial_write_reg(struct plat_serial8250_port *p, int offset,
+				    int value)
 {
 	offset <<= p->regshift;
-	__raw_writeb(value, p->membase + offset);
+	__raw_writel(value, IO_ADDRESS(p->mapbase) + offset);
 }
 
 static struct plat_serial8250_port serial_platform_data[] = {
 	{
-		.membase	= (char *)IO_ADDRESS(DAVINCI_UART0_BASE),
-		.mapbase	= (unsigned long)DAVINCI_UART0_BASE,
+		.mapbase	= DAVINCI_UART0_BASE,
 		.irq		= IRQ_UARTINT0,
-		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+				  UPF_IOREMAP,
+		.iotype		= UPIO_MEM,
+		.regshift	= 2,
+	},
+	{
+		.mapbase	= DAVINCI_UART1_BASE,
+		.irq		= IRQ_UARTINT1,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+				  UPF_IOREMAP,
+		.iotype		= UPIO_MEM,
+		.regshift	= 2,
+	},
+	{
+		.mapbase	= DAVINCI_UART2_BASE,
+		.irq		= IRQ_UARTINT2,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+				  UPF_IOREMAP,
 		.iotype		= UPIO_MEM,
 		.regshift	= 2,
-		.uartclk	= 27000000,
 	},
 	{
 		.flags		= 0
@@ -74,22 +89,68 @@ static struct platform_device serial_device = {
 
 static void __init davinci_serial_reset(struct plat_serial8250_port *p)
 {
-	/* reset both transmitter and receiver: bits 14,13 = UTRST, URRST */
 	unsigned int pwremu = 0;
 
-	davinci_serial_outp(p, UART_IER, 0);  /* disable all interrupts */
+	serial_write_reg(p, UART_IER, 0);  /* disable all interrupts */
 
-	davinci_serial_outp(p, UART_DAVINCI_PWREMU, pwremu);
+	/* reset both transmitter and receiver: bits 14,13 = UTRST, URRST */
+	serial_write_reg(p, UART_DAVINCI_PWREMU, pwremu);
 	mdelay(10);
 
 	pwremu |= (0x3 << 13);
 	pwremu |= 0x1;
-	davinci_serial_outp(p, UART_DAVINCI_PWREMU, pwremu);
+	serial_write_reg(p, UART_DAVINCI_PWREMU, pwremu);
+
+	if (cpu_is_davinci_dm646x())
+		serial_write_reg(p, UART_DM646X_SCR,
+				 UART_DM646X_SCR_TX_WATERMARK);
+}
+
+void __init davinci_serial_init(struct davinci_uart_config *info)
+{
+	int i;
+	char name[16];
+	struct clk *uart_clk;
+	struct device *dev = &serial_device.dev;
+
+	/*
+	 * Make sure the serial ports are muxed on at this point.
+	 * You have to mux them off in device drivers later on
+	 * if not needed.
+	 */
+	for (i = 0; i < DAVINCI_MAX_NR_UARTS; i++) {
+		struct plat_serial8250_port *p = serial_platform_data + i;
+
+		if (!(info->enabled_uarts & (1 << i))) {
+			p->flags = 0;
+			continue;
+		}
+
+		if (cpu_is_davinci_dm646x())
+			p->iotype = UPIO_MEM32;
+
+		if (cpu_is_davinci_dm355()) {
+			if (i == 2) {
+				p->mapbase = (unsigned long)DM355_UART2_BASE;
+				p->irq = IRQ_DM355_UARTINT2;
+			}
+		}
+
+		sprintf(name, "uart%d", i);
+		uart_clk = clk_get(dev, name);
+		if (IS_ERR(uart_clk))
+			printk(KERN_ERR "%s:%d: failed to get UART%d clock\n",
+					__func__, __LINE__, i);
+		else {
+			clk_enable(uart_clk);
+			p->uartclk = clk_get_rate(uart_clk);
+			davinci_serial_reset(p);
+		}
+	}
 }
 
 static int __init davinci_init(void)
 {
-	davinci_serial_reset(&serial_platform_data[0]);
 	return platform_device_register(&serial_device);
 }