Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Intel CE4100  platform specific setup code
0004  *
0005  * (C) Copyright 2010 Intel Corporation
0006  */
0007 #include <linux/init.h>
0008 #include <linux/kernel.h>
0009 #include <linux/irq.h>
0010 #include <linux/reboot.h>
0011 #include <linux/serial_reg.h>
0012 #include <linux/serial_8250.h>
0013 
0014 #include <asm/ce4100.h>
0015 #include <asm/prom.h>
0016 #include <asm/setup.h>
0017 #include <asm/i8259.h>
0018 #include <asm/io.h>
0019 #include <asm/io_apic.h>
0020 #include <asm/emergency-restart.h>
0021 
0022 /*
0023  * The CE4100 platform has an internal 8051 Microcontroller which is
0024  * responsible for signaling to the external Power Management Unit the
0025  * intention to reset, reboot or power off the system. This 8051 device has
0026  * its command register mapped at I/O port 0xcf9 and the value 0x4 is used
0027  * to power off the system.
0028  */
0029 static void ce4100_power_off(void)
0030 {
0031     outb(0x4, 0xcf9);
0032 }
0033 
0034 #ifdef CONFIG_SERIAL_8250
0035 
0036 static unsigned int mem_serial_in(struct uart_port *p, int offset)
0037 {
0038     offset = offset << p->regshift;
0039     return readl(p->membase + offset);
0040 }
0041 
0042 /*
0043  * The UART Tx interrupts are not set under some conditions and therefore serial
0044  * transmission hangs. This is a silicon issue and has not been root caused. The
0045  * workaround for this silicon issue checks UART_LSR_THRE bit and UART_LSR_TEMT
0046  * bit of LSR register in interrupt handler to see whether at least one of these
0047  * two bits is set, if so then process the transmit request. If this workaround
0048  * is not applied, then the serial transmission may hang. This workaround is for
0049  * errata number 9 in Errata - B step.
0050 */
0051 
0052 static unsigned int ce4100_mem_serial_in(struct uart_port *p, int offset)
0053 {
0054     unsigned int ret, ier, lsr;
0055 
0056     if (offset == UART_IIR) {
0057         offset = offset << p->regshift;
0058         ret = readl(p->membase + offset);
0059         if (ret & UART_IIR_NO_INT) {
0060             /* see if the TX interrupt should have really set */
0061             ier = mem_serial_in(p, UART_IER);
0062             /* see if the UART's XMIT interrupt is enabled */
0063             if (ier & UART_IER_THRI) {
0064                 lsr = mem_serial_in(p, UART_LSR);
0065                 /* now check to see if the UART should be
0066                    generating an interrupt (but isn't) */
0067                 if (lsr & (UART_LSR_THRE | UART_LSR_TEMT))
0068                     ret &= ~UART_IIR_NO_INT;
0069             }
0070         }
0071     } else
0072         ret =  mem_serial_in(p, offset);
0073     return ret;
0074 }
0075 
0076 static void ce4100_mem_serial_out(struct uart_port *p, int offset, int value)
0077 {
0078     offset = offset << p->regshift;
0079     writel(value, p->membase + offset);
0080 }
0081 
0082 static void ce4100_serial_fixup(int port, struct uart_port *up,
0083     u32 *capabilities)
0084 {
0085 #ifdef CONFIG_EARLY_PRINTK
0086     /*
0087      * Over ride the legacy port configuration that comes from
0088      * asm/serial.h. Using the ioport driver then switching to the
0089      * PCI memmaped driver hangs the IOAPIC
0090      */
0091     if (up->iotype !=  UPIO_MEM32) {
0092         up->uartclk  = 14745600;
0093         up->mapbase = 0xdffe0200;
0094         set_fixmap_nocache(FIX_EARLYCON_MEM_BASE,
0095                 up->mapbase & PAGE_MASK);
0096         up->membase =
0097             (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE);
0098         up->membase += up->mapbase & ~PAGE_MASK;
0099         up->mapbase += port * 0x100;
0100         up->membase += port * 0x100;
0101         up->iotype   = UPIO_MEM32;
0102         up->regshift = 2;
0103         up->irq = 4;
0104     }
0105 #endif
0106     up->iobase = 0;
0107     up->serial_in = ce4100_mem_serial_in;
0108     up->serial_out = ce4100_mem_serial_out;
0109 
0110     *capabilities |= (1 << 12);
0111 }
0112 
0113 static __init void sdv_serial_fixup(void)
0114 {
0115     serial8250_set_isa_configurator(ce4100_serial_fixup);
0116 }
0117 
0118 #else
0119 static inline void sdv_serial_fixup(void) {};
0120 #endif
0121 
0122 static void __init sdv_arch_setup(void)
0123 {
0124     sdv_serial_fixup();
0125 }
0126 
0127 static void sdv_pci_init(void)
0128 {
0129     x86_of_pci_init();
0130 }
0131 
0132 /*
0133  * CE4100 specific x86_init function overrides and early setup
0134  * calls.
0135  */
0136 void __init x86_ce4100_early_setup(void)
0137 {
0138     x86_init.oem.arch_setup = sdv_arch_setup;
0139     x86_init.resources.probe_roms = x86_init_noop;
0140     x86_init.mpparse.get_smp_config = x86_init_uint_noop;
0141     x86_init.mpparse.find_smp_config = x86_init_noop;
0142     x86_init.mpparse.setup_ioapic_ids = setup_ioapic_ids_from_mpc_nocheck;
0143     x86_init.pci.init = ce4100_pci_init;
0144     x86_init.pci.init_irq = sdv_pci_init;
0145 
0146     /*
0147      * By default, the reboot method is ACPI which is supported by the
0148      * CE4100 bootloader CEFDK using FADT.ResetReg Address and ResetValue
0149      * the bootloader will however issue a system power off instead of
0150      * reboot. By using BOOT_KBD we ensure proper system reboot as
0151      * expected.
0152      */
0153     reboot_type = BOOT_KBD;
0154 
0155     pm_power_off = ce4100_power_off;
0156 }