1 /* 2 * Intel CE4100 platform specific setup code 3 * 4 * (C) Copyright 2010 Intel Corporation 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; version 2 9 * of the License. 10 */ 11 #include <linux/init.h> 12 #include <linux/kernel.h> 13 #include <linux/irq.h> 14 #include <linux/module.h> 15 #include <linux/serial_reg.h> 16 #include <linux/serial_8250.h> 17 18 #include <asm/setup.h> 19 #include <asm/io.h> 20 21 static int ce4100_i8042_detect(void) 22 { 23 return 0; 24 } 25 26 static void __init sdv_find_smp_config(void) 27 { 28 } 29 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) 117 { 118 sdv_serial_fixup(); 119 } 120 121 /* 122 * CE4100 specific x86_init function overrides and early setup 123 * calls. 124 */ 125 void __init x86_ce4100_early_setup(void) 126 { 127 x86_init.oem.arch_setup = sdv_arch_setup; 128 x86_platform.i8042_detect = ce4100_i8042_detect; 129 x86_init.resources.probe_roms = x86_init_noop; 130 x86_init.mpparse.get_smp_config = x86_init_uint_noop; 131 x86_init.mpparse.find_smp_config = sdv_find_smp_config; 132 } 133