cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ce4100.c (4334B)


      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#include <linux/init.h>
      8#include <linux/kernel.h>
      9#include <linux/irq.h>
     10#include <linux/reboot.h>
     11#include <linux/serial_reg.h>
     12#include <linux/serial_8250.h>
     13
     14#include <asm/ce4100.h>
     15#include <asm/prom.h>
     16#include <asm/setup.h>
     17#include <asm/i8259.h>
     18#include <asm/io.h>
     19#include <asm/io_apic.h>
     20#include <asm/emergency-restart.h>
     21
     22/*
     23 * The CE4100 platform has an internal 8051 Microcontroller which is
     24 * responsible for signaling to the external Power Management Unit the
     25 * intention to reset, reboot or power off the system. This 8051 device has
     26 * its command register mapped at I/O port 0xcf9 and the value 0x4 is used
     27 * to power off the system.
     28 */
     29static void ce4100_power_off(void)
     30{
     31	outb(0x4, 0xcf9);
     32}
     33
     34#ifdef CONFIG_SERIAL_8250
     35
     36static unsigned int mem_serial_in(struct uart_port *p, int offset)
     37{
     38	offset = offset << p->regshift;
     39	return readl(p->membase + offset);
     40}
     41
     42/*
     43 * The UART Tx interrupts are not set under some conditions and therefore serial
     44 * transmission hangs. This is a silicon issue and has not been root caused. The
     45 * workaround for this silicon issue checks UART_LSR_THRE bit and UART_LSR_TEMT
     46 * bit of LSR register in interrupt handler to see whether at least one of these
     47 * two bits is set, if so then process the transmit request. If this workaround
     48 * is not applied, then the serial transmission may hang. This workaround is for
     49 * errata number 9 in Errata - B step.
     50*/
     51
     52static unsigned int ce4100_mem_serial_in(struct uart_port *p, int offset)
     53{
     54	unsigned int ret, ier, lsr;
     55
     56	if (offset == UART_IIR) {
     57		offset = offset << p->regshift;
     58		ret = readl(p->membase + offset);
     59		if (ret & UART_IIR_NO_INT) {
     60			/* see if the TX interrupt should have really set */
     61			ier = mem_serial_in(p, UART_IER);
     62			/* see if the UART's XMIT interrupt is enabled */
     63			if (ier & UART_IER_THRI) {
     64				lsr = mem_serial_in(p, UART_LSR);
     65				/* now check to see if the UART should be
     66				   generating an interrupt (but isn't) */
     67				if (lsr & (UART_LSR_THRE | UART_LSR_TEMT))
     68					ret &= ~UART_IIR_NO_INT;
     69			}
     70		}
     71	} else
     72		ret =  mem_serial_in(p, offset);
     73	return ret;
     74}
     75
     76static void ce4100_mem_serial_out(struct uart_port *p, int offset, int value)
     77{
     78	offset = offset << p->regshift;
     79	writel(value, p->membase + offset);
     80}
     81
     82static void ce4100_serial_fixup(int port, struct uart_port *up,
     83	u32 *capabilities)
     84{
     85#ifdef CONFIG_EARLY_PRINTK
     86	/*
     87	 * Over ride the legacy port configuration that comes from
     88	 * asm/serial.h. Using the ioport driver then switching to the
     89	 * PCI memmaped driver hangs the IOAPIC
     90	 */
     91	if (up->iotype !=  UPIO_MEM32) {
     92		up->uartclk  = 14745600;
     93		up->mapbase = 0xdffe0200;
     94		set_fixmap_nocache(FIX_EARLYCON_MEM_BASE,
     95				up->mapbase & PAGE_MASK);
     96		up->membase =
     97			(void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE);
     98		up->membase += up->mapbase & ~PAGE_MASK;
     99		up->mapbase += port * 0x100;
    100		up->membase += port * 0x100;
    101		up->iotype   = UPIO_MEM32;
    102		up->regshift = 2;
    103		up->irq = 4;
    104	}
    105#endif
    106	up->iobase = 0;
    107	up->serial_in = ce4100_mem_serial_in;
    108	up->serial_out = ce4100_mem_serial_out;
    109
    110	*capabilities |= (1 << 12);
    111}
    112
    113static __init void sdv_serial_fixup(void)
    114{
    115	serial8250_set_isa_configurator(ce4100_serial_fixup);
    116}
    117
    118#else
    119static inline void sdv_serial_fixup(void) {};
    120#endif
    121
    122static void __init sdv_arch_setup(void)
    123{
    124	sdv_serial_fixup();
    125}
    126
    127static void sdv_pci_init(void)
    128{
    129	x86_of_pci_init();
    130}
    131
    132/*
    133 * CE4100 specific x86_init function overrides and early setup
    134 * calls.
    135 */
    136void __init x86_ce4100_early_setup(void)
    137{
    138	x86_init.oem.arch_setup = sdv_arch_setup;
    139	x86_init.resources.probe_roms = x86_init_noop;
    140	x86_init.mpparse.get_smp_config = x86_init_uint_noop;
    141	x86_init.mpparse.find_smp_config = x86_init_noop;
    142	x86_init.mpparse.setup_ioapic_ids = setup_ioapic_ids_from_mpc_nocheck;
    143	x86_init.pci.init = ce4100_pci_init;
    144	x86_init.pci.init_irq = sdv_pci_init;
    145
    146	/*
    147	 * By default, the reboot method is ACPI which is supported by the
    148	 * CE4100 bootloader CEFDK using FADT.ResetReg Address and ResetValue
    149	 * the bootloader will however issue a system power off instead of
    150	 * reboot. By using BOOT_KBD we ensure proper system reboot as
    151	 * expected.
    152	 */
    153	reboot_type = BOOT_KBD;
    154
    155	pm_power_off = ce4100_power_off;
    156}