diff options
| -rw-r--r-- | arch/x86/platform/ce4100/ce4100.c | 94 |
1 files changed, 92 insertions, 2 deletions
diff --git a/arch/x86/platform/ce4100/ce4100.c b/arch/x86/platform/ce4100/ce4100.c index 0ede12bde456..d2c0d51a7178 100644 --- a/arch/x86/platform/ce4100/ce4100.c +++ b/arch/x86/platform/ce4100/ce4100.c | |||
| @@ -12,20 +12,110 @@ | |||
| 12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
| 13 | #include <linux/irq.h> | 13 | #include <linux/irq.h> |
| 14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
| 15 | #include <linux/serial_reg.h> | ||
| 16 | #include <linux/serial_8250.h> | ||
| 15 | 17 | ||
| 16 | #include <asm/setup.h> | 18 | #include <asm/setup.h> |
| 19 | #include <asm/io.h> | ||
| 17 | 20 | ||
| 18 | static int ce4100_i8042_detect(void) | 21 | static int ce4100_i8042_detect(void) |
| 19 | { | 22 | { |
| 20 | return 0; | 23 | return 0; |
| 21 | } | 24 | } |
| 22 | 25 | ||
| 23 | static void __init sdv_arch_setup(void) | 26 | static void __init sdv_find_smp_config(void) |
| 24 | { | 27 | { |
| 25 | } | 28 | } |
| 26 | 29 | ||
| 27 | static void __init sdv_find_smp_config(void) | 30 | #ifdef CONFIG_SERIAL_8250 |
| 31 | |||
| 32 | |||
| 33 | static unsigned int mem_serial_in(struct uart_port *p, int offset) | ||
| 34 | { | ||
| 35 | offset = offset << p->regshift; | ||
| 36 | return readl(p->membase + offset); | ||
| 37 | } | ||
| 38 | |||
| 39 | /* | ||
| 40 | * The UART Tx interrupts are not set under some conditions and therefore serial | ||
| 41 | * transmission hangs. This is a silicon issue and has not been root caused. The | ||
| 42 | * workaround for this silicon issue checks UART_LSR_THRE bit and UART_LSR_TEMT | ||
| 43 | * bit of LSR register in interrupt handler to see whether at least one of these | ||
| 44 | * two bits is set, if so then process the transmit request. If this workaround | ||
| 45 | * is not applied, then the serial transmission may hang. This workaround is for | ||
| 46 | * errata number 9 in Errata - B step. | ||
| 47 | */ | ||
| 48 | |||
| 49 | static unsigned int ce4100_mem_serial_in(struct uart_port *p, int offset) | ||
| 50 | { | ||
| 51 | unsigned int ret, ier, lsr; | ||
| 52 | |||
| 53 | if (offset == UART_IIR) { | ||
| 54 | offset = offset << p->regshift; | ||
| 55 | ret = readl(p->membase + offset); | ||
| 56 | if (ret & UART_IIR_NO_INT) { | ||
| 57 | /* see if the TX interrupt should have really set */ | ||
| 58 | ier = mem_serial_in(p, UART_IER); | ||
| 59 | /* see if the UART's XMIT interrupt is enabled */ | ||
| 60 | if (ier & UART_IER_THRI) { | ||
| 61 | lsr = mem_serial_in(p, UART_LSR); | ||
| 62 | /* now check to see if the UART should be | ||
| 63 | generating an interrupt (but isn't) */ | ||
| 64 | if (lsr & (UART_LSR_THRE | UART_LSR_TEMT)) | ||
| 65 | ret &= ~UART_IIR_NO_INT; | ||
| 66 | } | ||
| 67 | } | ||
| 68 | } else | ||
| 69 | ret = mem_serial_in(p, offset); | ||
| 70 | return ret; | ||
| 71 | } | ||
| 72 | |||
| 73 | static void ce4100_mem_serial_out(struct uart_port *p, int offset, int value) | ||
| 74 | { | ||
| 75 | offset = offset << p->regshift; | ||
| 76 | writel(value, p->membase + offset); | ||
| 77 | } | ||
| 78 | |||
| 79 | static void ce4100_serial_fixup(int port, struct uart_port *up, | ||
| 80 | unsigned short *capabilites) | ||
| 81 | { | ||
| 82 | #ifdef CONFIG_EARLY_PRINTK | ||
| 83 | /* | ||
| 84 | * Over ride the legacy port configuration that comes from | ||
| 85 | * asm/serial.h. Using the ioport driver then switching to the | ||
| 86 | * PCI memmaped driver hangs the IOAPIC | ||
| 87 | */ | ||
| 88 | if (up->iotype != UPIO_MEM32) { | ||
| 89 | up->uartclk = 14745600; | ||
| 90 | up->mapbase = 0xdffe0200; | ||
| 91 | set_fixmap_nocache(FIX_EARLYCON_MEM_BASE, | ||
| 92 | up->mapbase & PAGE_MASK); | ||
| 93 | up->membase = | ||
| 94 | (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE); | ||
| 95 | up->membase += up->mapbase & ~PAGE_MASK; | ||
| 96 | up->iotype = UPIO_MEM32; | ||
| 97 | up->regshift = 2; | ||
| 98 | } | ||
| 99 | #endif | ||
| 100 | up->iobase = 0; | ||
| 101 | up->serial_in = ce4100_mem_serial_in; | ||
| 102 | up->serial_out = ce4100_mem_serial_out; | ||
| 103 | |||
| 104 | *capabilites |= (1 << 12); | ||
| 105 | } | ||
| 106 | |||
| 107 | static __init void sdv_serial_fixup(void) | ||
| 108 | { | ||
| 109 | serial8250_set_isa_configurator(ce4100_serial_fixup); | ||
| 110 | } | ||
| 111 | |||
| 112 | #else | ||
| 113 | static inline void sdv_serial_fixup(void); | ||
| 114 | #endif | ||
| 115 | |||
| 116 | static void __init sdv_arch_setup(void) | ||
| 28 | { | 117 | { |
| 118 | sdv_serial_fixup(); | ||
| 29 | } | 119 | } |
| 30 | 120 | ||
| 31 | /* | 121 | /* |
