1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Intel CE4100 platform specific setup code 4 * 5 * (C) Copyright 2010 Intel Corporation 6 */ 7 8 #include <linux/init.h> 9 #include <linux/io.h> 10 #include <linux/types.h> 11 12 #include <asm/ce4100.h> 13 #include <asm/fixmap.h> 14 #include <asm/page.h> 15 16 #include <linux/serial_reg.h> 17 #include <linux/serial_8250.h> 18 19 static unsigned int mem_serial_in(struct uart_port *p, int offset) 20 { 21 offset = offset << p->regshift; 22 return readl(p->membase + offset); 23 } 24 25 /* 26 * The UART Tx interrupts are not set under some conditions and therefore serial 27 * transmission hangs. This is a silicon issue and has not been root caused. The 28 * workaround for this silicon issue checks UART_LSR_THRE bit and UART_LSR_TEMT 29 * bit of LSR register in interrupt handler to see whether at least one of these 30 * two bits is set, if so then process the transmit request. If this workaround 31 * is not applied, then the serial transmission may hang. This workaround is for 32 * errata number 9 in Errata - B step. 33 */ 34 static u32 ce4100_mem_serial_in(struct uart_port *p, unsigned int offset) 35 { 36 u32 ret, ier, lsr; 37 38 ret = mem_serial_in(p, offset); 39 if (offset != UART_IIR || !(ret & UART_IIR_NO_INT)) 40 return ret; 41 42 /* see if the TX interrupt should have really set */ 43 ier = mem_serial_in(p, UART_IER); 44 /* see if the UART's XMIT interrupt is enabled */ 45 if (!(ier & UART_IER_THRI)) 46 return ret; 47 48 lsr = mem_serial_in(p, UART_LSR); 49 /* now check to see if the UART should be generating an interrupt (but isn't) */ 50 if (lsr & (UART_LSR_THRE | UART_LSR_TEMT)) 51 ret &= ~UART_IIR_NO_INT; 52 53 return ret; 54 } 55 56 static void ce4100_mem_serial_out(struct uart_port *p, unsigned int offset, u32 value) 57 { 58 offset <<= p->regshift; 59 writel(value, p->membase + offset); 60 } 61 62 static void ce4100_serial_fixup(int port, struct uart_port *up, u32 *capabilities) 63 { 64 #ifdef CONFIG_EARLY_PRINTK 65 /* 66 * Override the legacy port configuration that comes from 67 * asm/serial.h. Using the ioport driver then switching to the 68 * PCI memmaped driver hangs the IOAPIC. 69 */ 70 if (up->iotype != UPIO_MEM32) { 71 up->uartclk = 14745600; 72 up->mapbase = 0xdffe0200; 73 set_fixmap_nocache(FIX_EARLYCON_MEM_BASE, up->mapbase & PAGE_MASK); 74 up->membase = (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE); 75 up->membase += up->mapbase & ~PAGE_MASK; 76 up->mapbase += port * 0x100; 77 up->membase += port * 0x100; 78 up->iotype = UPIO_MEM32; 79 up->regshift = 2; 80 up->irq = 4; 81 } 82 #endif 83 up->iobase = 0; 84 up->serial_in = ce4100_mem_serial_in; 85 up->serial_out = ce4100_mem_serial_out; 86 87 *capabilities |= (1 << 12); 88 } 89 90 void __init sdv_serial_fixup(void) 91 { 92 serial8250_set_isa_configurator(ce4100_serial_fixup); 93 } 94