From 86ddd732bd82b84724883b1f1579e18790611fe5 Mon Sep 17 00:00:00 2001 From: Stefan Reinauer Date: Fri, 11 Mar 2016 20:22:28 -0800 Subject: kbuild: Allow drivers to fit src/drivers/[X]/[Y]/ scheme Reorder drivers to fit src/drivers/[X]/[Y]/ scheme to make them pluggable. Also, fix up the following driver subdirectories by switching to the src/drivers/[X]/[Y]/ scheme as these are hard requirements for the main change: * drivers/intel * drivers/pc80 * drivers/dec Change-Id: I455d3089a317181d5b99bf658df759ec728a5f6b Signed-off-by: Stefan Reinauer Reviewed-on: https://review.coreboot.org/14047 Tested-by: build bot (Jenkins) Reviewed-by: Martin Roth --- src/Kconfig | 2 + src/drivers/dec/21143/Makefile.inc | 4 + src/drivers/dec/Kconfig | 1 - src/drivers/dec/Makefile.inc | 1 - src/drivers/intel/Kconfig | 19 - src/drivers/intel/Makefile.inc | 6 - src/drivers/intel/fsp1_0/Makefile.inc | 3 + src/drivers/intel/fsp1_1/Makefile.inc | 4 + src/drivers/intel/fsp2_0/Makefile.inc | 17 + src/drivers/intel/i210/Makefile.inc | 6 +- src/drivers/intel/wifi/Makefile.inc | 18 + src/drivers/pc80/Kconfig | 27 -- src/drivers/pc80/Makefile.inc | 25 -- src/drivers/pc80/i8254.c | 51 --- src/drivers/pc80/i8259.c | 138 ------- src/drivers/pc80/isa-dma.c | 44 --- src/drivers/pc80/keyboard.c | 381 -------------------- src/drivers/pc80/mc146818rtc.c | 397 -------------------- src/drivers/pc80/mc146818rtc_early.c | 103 ------ src/drivers/pc80/pc/Kconfig | 18 + src/drivers/pc80/pc/Makefile.inc | 12 + src/drivers/pc80/pc/i8254.c | 51 +++ src/drivers/pc80/pc/i8259.c | 139 +++++++ src/drivers/pc80/pc/isa-dma.c | 44 +++ src/drivers/pc80/pc/keyboard.c | 387 ++++++++++++++++++++ src/drivers/pc80/pc/ps2_controller.asl | 46 +++ src/drivers/pc80/pc/spkmodem.c | 126 +++++++ src/drivers/pc80/pc/udelay_io.c | 14 + src/drivers/pc80/ps2_controller.asl | 46 --- src/drivers/pc80/rtc/Kconfig | 4 + src/drivers/pc80/rtc/Makefile.inc | 15 + src/drivers/pc80/rtc/mc146818rtc.c | 400 +++++++++++++++++++++ src/drivers/pc80/rtc/mc146818rtc_early.c | 104 ++++++ src/drivers/pc80/spkmodem.c | 124 ------- src/drivers/pc80/tpm/Makefile.inc | 4 + src/drivers/pc80/udelay_io.c | 13 - src/drivers/pc80/vga/Makefile.inc | 4 + src/ec/compal/ene932/acpi/superio.asl | 2 +- src/include/pc80/mc146818rtc.h | 2 +- src/mainboard/dmp/vortex86ex/romstage.c | 2 +- src/mainboard/jetway/nf81-t56n-lf/acpi/superio.asl | 2 +- src/mainboard/lenovo/t420/acpi/superio.asl | 2 +- src/mainboard/lenovo/t420s/acpi/superio.asl | 2 +- src/mainboard/lenovo/t430s/acpi/superio.asl | 2 +- src/mainboard/lenovo/t520/acpi/superio.asl | 2 +- src/mainboard/lenovo/t530/acpi/superio.asl | 2 +- src/mainboard/lenovo/x201/acpi/superio.asl | 2 +- src/mainboard/lenovo/x220/acpi/superio.asl | 2 +- src/mainboard/lenovo/x230/acpi/superio.asl | 2 +- src/mainboard/packardbell/ms2290/acpi/superio.asl | 2 +- src/mainboard/purism/librem13/acpi/superio.asl | 2 +- src/northbridge/via/vx900/Makefile.inc | 2 +- 52 files changed, 1436 insertions(+), 1392 deletions(-) delete mode 100644 src/drivers/dec/Kconfig delete mode 100644 src/drivers/dec/Makefile.inc delete mode 100644 src/drivers/intel/Kconfig delete mode 100644 src/drivers/intel/Makefile.inc delete mode 100644 src/drivers/pc80/Kconfig delete mode 100644 src/drivers/pc80/Makefile.inc delete mode 100644 src/drivers/pc80/i8254.c delete mode 100644 src/drivers/pc80/i8259.c delete mode 100644 src/drivers/pc80/isa-dma.c delete mode 100644 src/drivers/pc80/keyboard.c delete mode 100644 src/drivers/pc80/mc146818rtc.c delete mode 100644 src/drivers/pc80/mc146818rtc_early.c create mode 100644 src/drivers/pc80/pc/Kconfig create mode 100644 src/drivers/pc80/pc/Makefile.inc create mode 100644 src/drivers/pc80/pc/i8254.c create mode 100644 src/drivers/pc80/pc/i8259.c create mode 100644 src/drivers/pc80/pc/isa-dma.c create mode 100644 src/drivers/pc80/pc/keyboard.c create mode 100644 src/drivers/pc80/pc/ps2_controller.asl create mode 100644 src/drivers/pc80/pc/spkmodem.c create mode 100644 src/drivers/pc80/pc/udelay_io.c delete mode 100644 src/drivers/pc80/ps2_controller.asl create mode 100644 src/drivers/pc80/rtc/Kconfig create mode 100644 src/drivers/pc80/rtc/Makefile.inc create mode 100644 src/drivers/pc80/rtc/mc146818rtc.c create mode 100644 src/drivers/pc80/rtc/mc146818rtc_early.c delete mode 100644 src/drivers/pc80/spkmodem.c delete mode 100644 src/drivers/pc80/udelay_io.c (limited to 'src') diff --git a/src/Kconfig b/src/Kconfig index 0649bf74ec..f9bd661e05 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -432,6 +432,7 @@ source "src/superio/*/Kconfig" comment "Embedded Controllers" source "src/ec/acpi/Kconfig" source "src/ec/*/*/Kconfig" +# FIXME move to vendorcode source "src/drivers/intel/fsp1_0/Kconfig" source "src/southbridge/intel/common/firmware/Kconfig" @@ -445,6 +446,7 @@ source "src/device/Kconfig" menu "Generic Drivers" source "src/drivers/*/Kconfig" +source "src/drivers/*/*/Kconfig" endmenu config RTC diff --git a/src/drivers/dec/21143/Makefile.inc b/src/drivers/dec/21143/Makefile.inc index e99dfad6b5..b7382e40e3 100644 --- a/src/drivers/dec/21143/Makefile.inc +++ b/src/drivers/dec/21143/Makefile.inc @@ -1 +1,5 @@ +ifeq ($(CONFIG_DRIVERS_DEC_21143),y) + ramstage-y += 21143.c + +endif diff --git a/src/drivers/dec/Kconfig b/src/drivers/dec/Kconfig deleted file mode 100644 index c9dfe6483e..0000000000 --- a/src/drivers/dec/Kconfig +++ /dev/null @@ -1 +0,0 @@ -source src/drivers/dec/21143/Kconfig diff --git a/src/drivers/dec/Makefile.inc b/src/drivers/dec/Makefile.inc deleted file mode 100644 index 196c424570..0000000000 --- a/src/drivers/dec/Makefile.inc +++ /dev/null @@ -1 +0,0 @@ -subdirs-$(CONFIG_DRIVERS_DEC_21143) += 21143 diff --git a/src/drivers/intel/Kconfig b/src/drivers/intel/Kconfig deleted file mode 100644 index e5525d8a97..0000000000 --- a/src/drivers/intel/Kconfig +++ /dev/null @@ -1,19 +0,0 @@ -## -## This file is part of the coreboot project. -## -## Copyright (C) 2013 Google Inc. -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; version 2 of the License. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## - -source src/drivers/intel/fsp1_1/Kconfig -source src/drivers/intel/fsp2_0/Kconfig -source src/drivers/intel/gma/Kconfig -source src/drivers/intel/i210/Kconfig diff --git a/src/drivers/intel/Makefile.inc b/src/drivers/intel/Makefile.inc deleted file mode 100644 index 67c1163309..0000000000 --- a/src/drivers/intel/Makefile.inc +++ /dev/null @@ -1,6 +0,0 @@ -subdirs-y += gma -subdirs-$(CONFIG_GENERATE_SMBIOS_TABLES) += wifi -subdirs-$(CONFIG_PLATFORM_USES_FSP1_0) += fsp1_0 -subdirs-$(CONFIG_PLATFORM_USES_FSP1_1) += fsp1_1 -subdirs-$(CONFIG_PLATFORM_USES_FSP2_0) += fsp2_0 -subdirs-$(CONFIG_DRIVER_INTEL_I210) += i210 diff --git a/src/drivers/intel/fsp1_0/Makefile.inc b/src/drivers/intel/fsp1_0/Makefile.inc index ea8f61e95a..4ff10687aa 100644 --- a/src/drivers/intel/fsp1_0/Makefile.inc +++ b/src/drivers/intel/fsp1_0/Makefile.inc @@ -13,6 +13,8 @@ # GNU General Public License for more details. # +ifeq ($(CONFIG_PLATFORM_USES_FSP1_0),y) + ramstage-y += fsp_util.c hob.c romstage-y += fsp_util.c hob.c @@ -44,3 +46,4 @@ mrc.cache-type := mrc_cache endif endif +endif diff --git a/src/drivers/intel/fsp1_1/Makefile.inc b/src/drivers/intel/fsp1_1/Makefile.inc index f101cc448a..3f214cb4bf 100644 --- a/src/drivers/intel/fsp1_1/Makefile.inc +++ b/src/drivers/intel/fsp1_1/Makefile.inc @@ -14,6 +14,8 @@ # GNU General Public License for more details. # +ifeq ($(CONFIG_PLATFORM_USES_FSP1_1),y) + verstage-y += car.c verstage-y += fsp_util.c verstage-y += verstage.c @@ -53,3 +55,5 @@ fsp.bin-file := $(call strip_quotes,$(CONFIG_FSP_FILE)) fsp.bin-position := $(CONFIG_FSP_LOC) fsp.bin-type := fsp endif + +endif diff --git a/src/drivers/intel/fsp2_0/Makefile.inc b/src/drivers/intel/fsp2_0/Makefile.inc index 61faefa3b0..3e94f2fffb 100644 --- a/src/drivers/intel/fsp2_0/Makefile.inc +++ b/src/drivers/intel/fsp2_0/Makefile.inc @@ -1,3 +1,18 @@ +# +# This file is part of the coreboot project. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# + +ifeq ($(CONFIG_PLATFORM_USES_FSP2_0),y) + romstage-y += hand_off_block.c romstage-y += util.c romstage-y += memory_init.c @@ -9,3 +24,5 @@ ramstage-y += silicon_init.c ramstage-y += util.c CPPFLAGS_common += -I$(src)/drivers/intel/fsp2_0/include + +endif diff --git a/src/drivers/intel/i210/Makefile.inc b/src/drivers/intel/i210/Makefile.inc index a1f15de1c1..a69602246b 100644 --- a/src/drivers/intel/i210/Makefile.inc +++ b/src/drivers/intel/i210/Makefile.inc @@ -1 +1,5 @@ -ramstage-y += i210.c \ No newline at end of file +ifeq ($(CONFIG_DRIVER_INTEL_I210),y) + +ramstage-y += i210.c + +endif diff --git a/src/drivers/intel/wifi/Makefile.inc b/src/drivers/intel/wifi/Makefile.inc index 23f5541b4d..1435f8b7f7 100644 --- a/src/drivers/intel/wifi/Makefile.inc +++ b/src/drivers/intel/wifi/Makefile.inc @@ -1 +1,19 @@ +# +# This file is part of the coreboot project. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# + +# really? +ifeq ($(CONFIG_GENERATE_SMBIOS_TABLES),y) + ramstage-$(CONFIG_PCIEXP_PLUGIN_SUPPORT) += wifi.c + +endif diff --git a/src/drivers/pc80/Kconfig b/src/drivers/pc80/Kconfig deleted file mode 100644 index 18c626c7cb..0000000000 --- a/src/drivers/pc80/Kconfig +++ /dev/null @@ -1,27 +0,0 @@ -# Might be removed (alongside with the PS/2 init code) once payloads -# reliably support PS/2 init themselves. -if PC80_SYSTEM - -config DRIVERS_PS2_KEYBOARD - bool "PS/2 keyboard init" - default n - help - Enable this option to initialize PS/2 keyboards found connected - to the PS/2 port. - - Some payloads (eg, filo) require this option. Other payloads - (eg, GRUB 2, SeaBIOS, Linux) do not require it. - Initializing a PS/2 keyboard can take several hundred milliseconds. - - If you know you will only use a payload which does not require - this option, then you can say N here to speed up boot time. - Otherwise say Y. - -config DRIVERS_MC146818 - bool - default y if ARCH_X86 - select RTC - -source src/drivers/pc80/tpm/Kconfig - -endif diff --git a/src/drivers/pc80/Makefile.inc b/src/drivers/pc80/Makefile.inc deleted file mode 100644 index f468318dd5..0000000000 --- a/src/drivers/pc80/Makefile.inc +++ /dev/null @@ -1,25 +0,0 @@ -ifeq ($(CONFIG_ARCH_X86),y) - -romstage-$(CONFIG_DRIVERS_MC146818) += mc146818rtc.c -ramstage-$(CONFIG_DRIVERS_MC146818) += mc146818rtc.c -ramstage-y += isa-dma.c -ramstage-y += i8254.c -ramstage-y += i8259.c -romstage-$(CONFIG_UDELAY_IO) += udelay_io.c -ramstage-$(CONFIG_UDELAY_IO) += udelay_io.c -ramstage-y += keyboard.c -ramstage-$(CONFIG_SPKMODEM) += spkmodem.c - -romstage-$(CONFIG_DRIVERS_MC146818) += mc146818rtc_early.c - -romstage-$(CONFIG_SPKMODEM) += spkmodem.c - -subdirs-y += tpm vga - -cbfs-files-$(CONFIG_HAVE_CMOS_DEFAULT) += cmos.default -cmos.default-file = $(CONFIG_CMOS_DEFAULT_FILE):nvramtool -cmos.default-type = 0xaa - -smm-$(CONFIG_DRIVERS_MC146818) += mc146818rtc.c - -endif diff --git a/src/drivers/pc80/i8254.c b/src/drivers/pc80/i8254.c deleted file mode 100644 index 5851ec08a0..0000000000 --- a/src/drivers/pc80/i8254.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2009 coresystems GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include - -/* Initialize i8254 timers */ - -void setup_i8254(void) -{ - /* Timer 0 (taken from biosemu) */ - outb(TIMER0_SEL | WORD_ACCESS | MODE3 | BINARY_COUNT, TIMER_MODE_PORT); - outb(0x00, TIMER0_PORT); - outb(0x00, TIMER0_PORT); - - /* Timer 1 */ - outb(TIMER1_SEL | LOBYTE_ACCESS | MODE3 | BINARY_COUNT, - TIMER_MODE_PORT); - outb(0x12, TIMER1_PORT); -} - -#if CONFIG_UDELAY_TIMER2 -static void load_timer2(unsigned int ticks) -{ - /* Set up the timer gate, turn off the speaker */ - outb((inb(PPC_PORTB) & ~PPCB_SPKR) | PPCB_T2GATE, PPC_PORTB); - outb(TIMER2_SEL | WORD_ACCESS | MODE0 | BINARY_COUNT, TIMER_MODE_PORT); - outb(ticks & 0xFF, TIMER2_PORT); - outb(ticks >> 8, TIMER2_PORT); -} - -void udelay(int usecs) -{ - load_timer2((usecs * TICKS_PER_MS) / 1000); - while ((inb(PPC_PORTB) & PPCB_T2OUT) == 0) - ; -} -#endif diff --git a/src/drivers/pc80/i8259.c b/src/drivers/pc80/i8259.c deleted file mode 100644 index 1cb49b1206..0000000000 --- a/src/drivers/pc80/i8259.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2009 coresystems GmbH - * Copyright (C) 2013 Sage Electronic Engineering, LLC. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include - -/* Read the current PIC IRQ mask */ -u16 pic_read_irq_mask(void) -{ - u16 mask; - int i; - - mask = inb(MASTER_PIC_OCW1) | (inb(SLAVE_PIC_OCW1) << 8); - - printk(BIOS_DEBUG, "8259 PIC: OCW1 IRQ Mask: 0x%x\n", mask); - printk(BIOS_SPEW, "\tEnabled IRQs (0 = Unmasked, 1 = Masked off):\n" - "\t\tMaster\t\tSlave\n"); - for(i = 0; i <= 7; i++) { - printk(BIOS_SPEW, "\t\tIRQ%X: %x\t\tIRQ%X: %x\n", - i, (mask >> i) & 1, i + 8, (mask >> (i + 8)) & 1); - } - return mask; -} - -/* - * Write an IRQ mask to the PIC: - * IRQA is bit 0xA in the 16 bit bitmask (OCW1) - */ -void pic_write_irq_mask(u16 mask) -{ - outb(mask, MASTER_PIC_OCW1); - outb(mask >> 8, SLAVE_PIC_OCW1); -} - -/* - * The PIC IRQs default to masked off - * Allow specific IRQs to be enabled (1) - * or disabled by (0) the user - */ -void pic_irq_enable(u8 int_num, u8 mask) -{ - pic_write_irq_mask(pic_read_irq_mask() & ~(mask << int_num)); - pic_read_irq_mask(); -} - -void setup_i8259(void) -{ - /* A write to ICW1 starts the Interrupt Controller Initialization - * Sequence. This implicitly causes the following to happen: - * - Interrupt Mask register is cleared - * - Priority 7 is assigned to IRQ7 input - * - Slave mode address is set to 7 - * - Special mask mode is cleared - * - * We send the initialization sequence to both the master and - * slave i8259 controller. - */ - outb(ICW_SELECT|IC4, MASTER_PIC_ICW1); - outb(ICW_SELECT|IC4, SLAVE_PIC_ICW1); - - /* Now the interrupt controller expects us to write to ICW2. */ - outb(INT_VECTOR_MASTER | IRQ0, MASTER_PIC_ICW2); - outb(INT_VECTOR_SLAVE | IRQ8, SLAVE_PIC_ICW2); - - /* Now the interrupt controller expects us to write to ICW3. - * - * The normal scenario is to set up cascading on IRQ2 on the master - * i8259 and assign the slave ID 2 to the slave i8259. - */ - outb(CASCADED_PIC, MASTER_PIC_ICW3); - outb(SLAVE_ID, SLAVE_PIC_ICW3); - - /* Now the interrupt controller expects us to write to ICW4. - * - * We switch both i8259 to microprocessor mode because they're - * operating as part of an x86 architecture based chipset - */ - outb(MICROPROCESSOR_MODE, MASTER_PIC_ICW2); - outb(MICROPROCESSOR_MODE, SLAVE_PIC_ICW2); - - /* Now clear the interrupts through OCW1. - * First we mask off all interrupts on the slave interrupt controller - * then we mask off all interrupts but interrupt 2 on the master - * controller. This way the cascading stays alive. - */ - outb(ALL_IRQS, SLAVE_PIC_OCW1); - outb(ALL_IRQS & ~IRQ2, MASTER_PIC_OCW1); -} - -/** - * @brief Configure IRQ triggering in the i8259 compatible Interrupt Controller. - * - * Switch a certain interrupt to be level / edge triggered. - * - * @param int_num legacy interrupt number (3-7, 9-15) - * @param is_level_triggered 1 for level triggered interrupt, 0 for edge - * triggered interrupt - */ -void i8259_configure_irq_trigger(int int_num, int is_level_triggered) -{ - u16 int_bits = inb(ELCR1) | (((u16)inb(ELCR2)) << 8); - - if (is_level_triggered) - int_bits |= (1 << int_num); - else - int_bits &= ~(1 << int_num); - - /* Write new values */ - outb((u8)(int_bits & 0xff), ELCR1); - outb((u8)(int_bits >> 8), ELCR2); - -#ifdef PARANOID_IRQ_TRIGGERS - /* Try reading back the new values. This seems like an error but is not ... */ - if (inb(ELCR1) != (int_bits & 0xff)) { - printk(BIOS_ERR, "%s: lower order bits are wrong: want 0x%x, got 0x%x\n", - __func__, (int_bits & 0xff), inb(ELCR1)); - } - - if (inb(ELCR2) != (int_bits >> 8)) { - printk(BIOS_ERR, "%s: higher order bits are wrong: want 0x%x, got 0x%x\n", - __func__, (int_bits>>8), inb(ELCR2)); - } -#endif -} diff --git a/src/drivers/pc80/isa-dma.c b/src/drivers/pc80/isa-dma.c deleted file mode 100644 index b64f125f3a..0000000000 --- a/src/drivers/pc80/isa-dma.c +++ /dev/null @@ -1,44 +0,0 @@ -#include -#include - -/* DMA controller registers */ -#define DMA1_CMD_REG 0x08 /* command register (w) */ -#define DMA1_STAT_REG 0x08 /* status register (r) */ -#define DMA1_REQ_REG 0x09 /* request register (w) */ -#define DMA1_MASK_REG 0x0A /* single-channel mask (w) */ -#define DMA1_MODE_REG 0x0B /* mode register (w) */ -#define DMA1_CLEAR_FF_REG 0x0C /* clear pointer flip-flop (w) */ -#define DMA1_TEMP_REG 0x0D /* Temporary Register (r) */ -#define DMA1_RESET_REG 0x0D /* Master Clear (w) */ -#define DMA1_CLR_MASK_REG 0x0E /* Clear Mask */ -#define DMA1_MASK_ALL_REG 0x0F /* all-channels mask (w) */ - -#define DMA2_CMD_REG 0xD0 /* command register (w) */ -#define DMA2_STAT_REG 0xD0 /* status register (r) */ -#define DMA2_REQ_REG 0xD2 /* request register (w) */ -#define DMA2_MASK_REG 0xD4 /* single-channel mask (w) */ -#define DMA2_MODE_REG 0xD6 /* mode register (w) */ -#define DMA2_CLEAR_FF_REG 0xD8 /* clear pointer flip-flop (w) */ -#define DMA2_TEMP_REG 0xDA /* Temporary Register (r) */ -#define DMA2_RESET_REG 0xDA /* Master Clear (w) */ -#define DMA2_CLR_MASK_REG 0xDC /* Clear Mask */ -#define DMA2_MASK_ALL_REG 0xDE /* all-channels mask (w) */ - -#define DMA_MODE_READ 0x44 /* I/O to memory, no autoinit, increment, single mode */ -#define DMA_MODE_WRITE 0x48 /* memory to I/O, no autoinit, increment, single mode */ -#define DMA_MODE_CASCADE 0xC0 /* pass thru DREQ->HRQ, DACK<-HLDA only */ - -#define DMA_AUTOINIT 0x10 - - -void isa_dma_init(void) -{ - /* slave at 0x00 - 0x0f */ - /* master at 0xc0 - 0xdf */ - /* 0x80 - 0x8f DMA page registers */ - /* DMA: 0x00, 0x02, 0x4, 0x06 base address for DMA channel */ - outb(0, DMA1_RESET_REG); - outb(0, DMA2_RESET_REG); - outb(DMA_MODE_CASCADE, DMA2_MODE_REG); - outb(0, DMA2_MASK_REG); -} diff --git a/src/drivers/pc80/keyboard.c b/src/drivers/pc80/keyboard.c deleted file mode 100644 index 56b1fce93b..0000000000 --- a/src/drivers/pc80/keyboard.c +++ /dev/null @@ -1,381 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2015 Raptor Engineering - * Copyright (C) 2009 coresystems GmbH - * Copyright (C) 2008 Advanced Micro Devices, Inc. - * Copyright (C) 2003 Ollie Lo - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include -#include -#include - -#define KBD_DATA 0x60 -#define KBD_COMMAND 0x64 -#define KBD_STATUS 0x64 -#define KBD_IBF (1 << 1) // 1: input buffer full (data ready for ec) -#define KBD_OBF (1 << 0) // 1: output buffer full (data ready for host) - -// Keyboard Controller Commands -#define KBC_CMD_READ_COMMAND 0x20 // Read command byte -#define KBC_CMD_WRITE_COMMAND 0x60 // Write command byte -#define KBC_CMD_AUX_ENABLE 0xA8 // Auxiliary Interface enable -#define KBC_CMD_AUX_TEST 0xA9 // Auxiliary Interface test -#define KBC_CMD_SELF_TEST 0xAA // Controller self-test -#define KBC_CMD_KBD_TEST 0xAB // Keyboard Interface test - -/* The Keyboard controller command byte - * BIT | Description - * ----+------------------------------------------------------- - * 7 | reserved, must be zero - * 6 | XT Translation, (1 = on, 0 = off) - * 5 | Disable Mouse Port (1 = disable, 0 = enable) - * 4 | Disable Keyboard Port (1 = disable, 0 = enable) - * 3 | reserved, must be zero - * 2 | System Flag (1 = self-test passed. DO NOT SET TO ZERO) - * 1 | Mouse Port Interrupts (1 = enable, 0 = disable) - * 0 | Keyboard Port Interrupts (1 = enable, 0 = disable) - */ - -// Keyboard Controller Replies -#define KBC_REPLY_SELFTEST_OK 0x55 // controller self-test succeeded - -// -// Keyboard Replies -// -#define KBD_REPLY_POR 0xAA // Power on reset -#define KBD_REPLY_ACK 0xFA // Command ACK -#define KBD_REPLY_RESEND 0xFE // Command NACK, send command again - -/* Wait 400ms for keyboard controller answers */ -#define KBC_TIMEOUT_IN_MS 400 - -static int kbc_input_buffer_empty(void) -{ - u32 timeout; - for (timeout = KBC_TIMEOUT_IN_MS; - timeout && (inb(KBD_STATUS) & KBD_IBF); timeout--) - mdelay(1); - - if (!timeout) - printk(BIOS_WARNING, - "Unexpected Keyboard controller input buffer full\n"); - return !!timeout; -} - -static int kbc_output_buffer_full(void) -{ - u32 timeout; - for (timeout = KBC_TIMEOUT_IN_MS; - timeout && ((inb(KBD_STATUS) & KBD_OBF) == 0); timeout--) - mdelay(1); - - if (!timeout) - printk(BIOS_INFO, - "Keyboard controller output buffer result timeout\n"); - return !!timeout; -} - -static int kbc_cleanup_buffers(void) -{ - u32 timeout; - for (timeout = KBC_TIMEOUT_IN_MS; - timeout && (inb(KBD_STATUS) & (KBD_OBF | KBD_IBF)); timeout--) { - mdelay(1); - inb(KBD_DATA); - } - - if (!timeout) { - printk(BIOS_ERR, - "Couldn't cleanup the keyboard controller buffers\n"); - printk(BIOS_ERR, "Status (0x%x): 0x%x, Buffer (0x%x): 0x%x\n", - KBD_STATUS, inb(KBD_STATUS), KBD_DATA, inb(KBD_DATA)); - } - - return !!timeout; -} - -static enum cb_err kbc_self_test(uint8_t probe_aux, uint8_t *aux_probe_result) -{ - uint8_t self_test; - uint8_t byte; - - /* Set initial aux probe output value */ - if (aux_probe_result) - *aux_probe_result = 0; - - /* Clean up any junk that might have been in the KBC. - * Both input and output buffers must be empty. - */ - if (!kbc_cleanup_buffers()) - return CB_KBD_CONTROLLER_FAILURE; - - /* reset/self test 8042 - send cmd 0xAA */ - outb(KBC_CMD_SELF_TEST, KBD_COMMAND); - - if (!kbc_output_buffer_full()) { - /* There probably is no keyboard controller. */ - printk(BIOS_ERR, "Could not reset keyboard controller.\n"); - return CB_KBD_CONTROLLER_FAILURE; - } - - /* read self-test result, 0x55 is returned in the output buffer */ - self_test = inb(KBD_DATA); - - if (self_test != 0x55) { - printk(BIOS_ERR, "Keyboard Controller self-test failed: 0x%x\n", - self_test); - return CB_KBD_CONTROLLER_FAILURE; - } - - /* ensure the buffers are empty */ - kbc_cleanup_buffers(); - - /* keyboard interface test */ - outb(KBC_CMD_KBD_TEST, KBD_COMMAND); - - if (!kbc_output_buffer_full()) { - printk(BIOS_ERR, "Keyboard Interface test timed out.\n"); - return CB_KBD_CONTROLLER_FAILURE; - } - - /* read test result, 0x00 should be returned in case of no failures */ - self_test = inb(KBD_DATA); - - if (self_test != 0x00) { - printk(BIOS_ERR, "Keyboard Interface test failed: 0x%x\n", - self_test); - return CB_KBD_INTERFACE_FAILURE; - } - - if (probe_aux) { - /* aux interface detect */ - outb(KBC_CMD_AUX_ENABLE, KBD_COMMAND); - if (!kbc_input_buffer_empty()) { - printk(BIOS_ERR, "Timeout waiting for controller during aux enable.\n"); - return CB_KBD_CONTROLLER_FAILURE; - } - outb(KBC_CMD_READ_COMMAND, KBD_COMMAND); - if (!kbc_output_buffer_full()) { - printk(BIOS_ERR, "Timeout waiting for controller during aux probe.\n"); - return CB_KBD_CONTROLLER_FAILURE; - } - - byte = inb(KBD_DATA); - if (!(byte & (0x1 << 5))) { - printk(BIOS_DEBUG, "PS/2 auxiliary channel detected...\n"); - - /* auxiliary interface test */ - outb(KBC_CMD_AUX_TEST, KBD_COMMAND); - - if (!kbc_output_buffer_full()) { - printk(BIOS_ERR, "Auxiliary channel probe timed out.\n"); - goto aux_failure; - } - - /* read test result, 0x00 should be returned in case of no failures */ - self_test = inb(KBD_DATA); - - if (self_test != 0x00) { - printk(BIOS_ERR, "No device detected on auxiliary channel: 0x%x\n", - self_test); - goto aux_failure; - } - - printk(BIOS_DEBUG, "PS/2 device detected on auxiliary channel\n"); - if (aux_probe_result) - *aux_probe_result = 1; - } - } - -aux_failure: - - return CB_SUCCESS; -} - -static u8 send_keyboard(u8 command) -{ - u8 regval = 0; - u8 resend = 10; - - do { - if (!kbc_input_buffer_empty()) - return 0; - outb(command, KBD_DATA); - /* the reset command takes much longer then normal commands and - * even worse, some keyboards do send the ACK _after_ doing the - * reset */ - if (command == 0xFF) { - u8 retries; - for (retries = 9; retries && !kbc_output_buffer_full(); - retries--) ; - } - if (!kbc_output_buffer_full()) { - printk(BIOS_ERR, - "Could not send keyboard command %02x\n", - command); - return 0; - } - regval = inb(KBD_DATA); - --resend; - } while (regval == KBD_REPLY_RESEND && resend > 0); - - return regval; -} - -uint8_t pc_keyboard_init(uint8_t probe_aux) -{ - u8 retries; - u8 regval; - enum cb_err err; - uint8_t aux_dev_detected; - - if (!CONFIG_DRIVERS_PS2_KEYBOARD) - return 0; - - if (acpi_is_wakeup_s3()) - return 0; - - printk(BIOS_DEBUG, "Keyboard init...\n"); - - /* Run a keyboard controller self-test */ - err = kbc_self_test(probe_aux, &aux_dev_detected); - /* Ignore iterface failure as it's non-fatal. */ - if (err != CB_SUCCESS && err != CB_KBD_INTERFACE_FAILURE) - return 0; - - /* Enable keyboard interface - No IRQ */ - if (!kbc_input_buffer_empty()) - return 0; - outb(0x60, KBD_COMMAND); - if (!kbc_input_buffer_empty()) - return 0; - outb(0x20, KBD_DATA); /* send cmd: enable keyboard */ - if (!kbc_input_buffer_empty()) { - printk(BIOS_INFO, "Timeout while enabling keyboard\n"); - return 0; - } - - /* clean up any junk that might have been in the keyboard */ - if (!kbc_cleanup_buffers()) - return 0; - - /* reset keyboard and self test (keyboard side) */ - regval = send_keyboard(0xFF); - if (regval == KBD_REPLY_RESEND) { - /* keeps sending RESENDs, probably no keyboard. */ - printk(BIOS_INFO, "No PS/2 keyboard detected.\n"); - return 0; - } - - if (regval != KBD_REPLY_ACK) { - printk(BIOS_ERR, "Keyboard reset failed ACK: 0x%x\n", regval); - return 0; - } - - /* the reset command takes some time, so wait a little longer */ - for (retries = 9; retries && !kbc_output_buffer_full(); retries--) ; - - if (!kbc_output_buffer_full()) { - printk(BIOS_ERR, "Timeout waiting for keyboard after reset.\n"); - return 0; - } - - regval = inb(KBD_DATA); - if (regval != 0xAA) { - printk(BIOS_ERR, "Keyboard reset selftest failed: 0x%x\n", - regval); - return 0; - } - - /* - * The following set scancode stuff is what normal BIOS do. It could be - * argued that coreboot shouldn't set the scan code..... - */ - - /* disable the keyboard */ - regval = send_keyboard(0xF5); - if (regval != KBD_REPLY_ACK) { - printk(BIOS_ERR, "Keyboard disable failed ACK: 0x%x\n", regval); - return 0; - } - - /* Set scancode command */ - regval = send_keyboard(0xF0); - if (regval != KBD_REPLY_ACK) { - printk(BIOS_ERR, "Keyboard set scancode cmd failed ACK: 0x%x\n", - regval); - return 0; - } - /* Set scancode mode 2 */ - regval = send_keyboard(0x02); - if (regval != KBD_REPLY_ACK) { - printk(BIOS_ERR, - "Keyboard set scancode mode failed ACK: 0x%x\n", regval); - return 0; - } - - /* All is well - enable keyboard interface */ - if (!kbc_input_buffer_empty()) - return 0; - outb(0x60, KBD_COMMAND); - if (!kbc_input_buffer_empty()) - return 0; - outb(0x65, KBD_DATA); /* send cmd: enable keyboard and IRQ 1 */ - if (!kbc_input_buffer_empty()) { - printk(BIOS_ERR, "Timeout during keyboard enable\n"); - return 0; - } - - /* enable the keyboard */ - regval = send_keyboard(0xF4); - if (regval != KBD_REPLY_ACK) { - printk(BIOS_ERR, "Keyboard enable failed ACK: 0x%x\n", regval); - return 0; - } - - printk(BIOS_DEBUG, "PS/2 keyboard initialized on primary channel\n"); - - return aux_dev_detected; -} - -/* - * Support PS/2 mode - oddball SIOs(KBC) need this setup - * Not well documented. Google - 0xcb keyboard controller - * This is called before pc_keyboard_init(). - */ -void set_kbc_ps2_mode(void) -{ - enum cb_err err; - - /* Run a keyboard controller self-test */ - err = kbc_self_test(0, NULL); - /* Ignore iterface failure as it's non-fatal. */ - if (err != CB_SUCCESS && err != CB_KBD_INTERFACE_FAILURE) - return; - - /* Support PS/2 mode */ - if (!kbc_input_buffer_empty()) - return; - outb(0xcb, KBD_COMMAND); - - if (!kbc_input_buffer_empty()) - return; - outb(0x01, KBD_DATA); - - kbc_cleanup_buffers(); -} diff --git a/src/drivers/pc80/mc146818rtc.c b/src/drivers/pc80/mc146818rtc.c deleted file mode 100644 index 6c39f812b9..0000000000 --- a/src/drivers/pc80/mc146818rtc.c +++ /dev/null @@ -1,397 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright 2014 The Chromium OS Authors. All rights reserved. - * Copyright (C) 2015 Timothy Pearson , Raptor Engineering - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* There's no way around this include guard. option_table.h is autogenerated */ -#if CONFIG_USE_OPTION_TABLE -#include "option_table.h" -#else -#define LB_CKS_RANGE_START 0 -#define LB_CKS_RANGE_END 0 -#define LB_CKS_LOC 0 -#endif - -#include - -#if (defined(__PRE_RAM__) && \ -IS_ENABLED(CONFIG_HAVE_ROMSTAGE_NVRAM_CBFS_SPINLOCK)) - #define LOCK_NVRAM_CBFS_SPINLOCK spin_lock(romstage_nvram_cbfs_lock()); - #define UNLOCK_NVRAM_CBFS_SPINLOCK spin_unlock(romstage_nvram_cbfs_lock()); -#else - #define LOCK_NVRAM_CBFS_SPINLOCK - #define UNLOCK_NVRAM_CBFS_SPINLOCK -#endif - -static void cmos_reset_date(void) -{ - /* Now setup a default date equals to the build date */ - struct rtc_time time = { - .sec = 0, - .min = 0, - .hour = 1, - .mday = bcd2bin(coreboot_build_date.day), - .mon = bcd2bin(coreboot_build_date.month), - .year = (bcd2bin(coreboot_build_date.century) * 100) + - bcd2bin(coreboot_build_date.year), - .wday = bcd2bin(coreboot_build_date.weekday) - }; - rtc_set(&time); -} - -static int cmos_checksum_valid(int range_start, int range_end, int cks_loc) -{ - if (IS_ENABLED(CONFIG_STATIC_OPTION_TABLE)) - return 1; - - int i; - u16 sum, old_sum; - sum = 0; - for (i = range_start; i <= range_end; i++) - sum += cmos_read(i); - old_sum = ((cmos_read(cks_loc) << 8) | cmos_read(cks_loc + 1)) & - 0x0ffff; - return sum == old_sum; -} - -static void cmos_set_checksum(int range_start, int range_end, int cks_loc) -{ - int i; - u16 sum; - sum = 0; - for (i = range_start; i <= range_end; i++) - sum += cmos_read(i); - cmos_write(((sum >> 8) & 0x0ff), cks_loc); - cmos_write(((sum >> 0) & 0x0ff), cks_loc + 1); -} - -#define RTC_CONTROL_DEFAULT (RTC_24H) -#define RTC_FREQ_SELECT_DEFAULT (RTC_REF_CLCK_32KHZ | RTC_RATE_1024HZ) - -#ifndef __SMM__ -void cmos_init(bool invalid) -{ - bool cmos_invalid = invalid; - bool checksum_invalid = false; - bool clear_cmos; - size_t i; - uint8_t x; - -#ifndef __PRE_RAM__ - /* - * Avoid clearing pending interrupts and resetting the RTC control - * register in the resume path because the Linux kernel relies on - * this to know if it should restart the RTC timer queue if the wake - * was due to the RTC alarm. - */ - if (acpi_is_wakeup_s3()) - return; -#endif /* __PRE_RAM__ */ - - printk(BIOS_DEBUG, "RTC Init\n"); - - if (IS_ENABLED(CONFIG_USE_OPTION_TABLE)) { - /* See if there has been a CMOS power problem. */ - x = cmos_read(RTC_VALID); - cmos_invalid = !(x & RTC_VRT); - - /* See if there is a CMOS checksum error */ - checksum_invalid = !cmos_checksum_valid(PC_CKS_RANGE_START, - PC_CKS_RANGE_END, PC_CKS_LOC); - - clear_cmos = false; - } else { - clear_cmos = true; - } - - if (invalid || cmos_invalid || checksum_invalid) { - if (clear_cmos) { - cmos_write(0, 0x01); - cmos_write(0, 0x03); - cmos_write(0, 0x05); - for (i = 10; i < 128; i++) - cmos_write(0, i); - } - - if (cmos_invalid) - cmos_reset_date(); - - printk(BIOS_WARNING, "RTC:%s%s%s%s\n", - invalid ? " Clear requested":"", - cmos_invalid ? " Power Problem":"", - checksum_invalid ? " Checksum invalid":"", - clear_cmos ? " zeroing cmos":""); - } - - /* Setup the real time clock */ - cmos_write(RTC_CONTROL_DEFAULT, RTC_CONTROL); - /* Setup the frequency it operates at */ - cmos_write(RTC_FREQ_SELECT_DEFAULT, RTC_FREQ_SELECT); - /* Ensure all reserved bits are 0 in register D */ - cmos_write(RTC_VRT, RTC_VALID); - - if (IS_ENABLED(CONFIG_USE_OPTION_TABLE)) { - /* See if there is a LB CMOS checksum error */ - checksum_invalid = !cmos_checksum_valid(LB_CKS_RANGE_START, - LB_CKS_RANGE_END,LB_CKS_LOC); - if (checksum_invalid) - printk(BIOS_DEBUG, "RTC: coreboot checksum invalid\n"); - - /* Make certain we have a valid checksum */ - cmos_set_checksum(PC_CKS_RANGE_START, PC_CKS_RANGE_END, PC_CKS_LOC); - } - - /* Clear any pending interrupts */ - cmos_read(RTC_INTR_FLAGS); -} -#endif /* __SMM__ */ - - -/* - * This routine returns the value of the requested bits. - * input bit = bit count from the beginning of the cmos image - * length = number of bits to include in the value - * ret = a character pointer to where the value is to be returned - * returns CB_SUCCESS = successful, cb_err code if an error occurred - */ -static enum cb_err get_cmos_value(unsigned long bit, unsigned long length, - void *vret) -{ - unsigned char *ret; - unsigned long byte,byte_bit; - unsigned long i; - unsigned char uchar; - - /* - * The table is checked when it is built to ensure all - * values are valid. - */ - ret = vret; - byte = bit / 8; /* find the byte where the data starts */ - byte_bit = bit % 8; /* find the bit in the byte where the data starts */ - if (length < 9) { /* one byte or less */ - uchar = cmos_read(byte); /* load the byte */ - uchar >>= byte_bit; /* shift the bits to byte align */ - /* clear unspecified bits */ - ret[0] = uchar & ((1 << length) - 1); - } else { /* more that one byte so transfer the whole bytes */ - for (i = 0; length; i++, length -= 8, byte++) { - /* load the byte */ - ret[i] = cmos_read(byte); - } - } - return CB_SUCCESS; -} - -enum cb_err get_option(void *dest, const char *name) -{ - struct cmos_option_table *ct; - struct cmos_entries *ce; - size_t namelen; - int found = 0; - - if (!IS_ENABLED(CONFIG_USE_OPTION_TABLE)) - return CB_CMOS_OTABLE_DISABLED; - - LOCK_NVRAM_CBFS_SPINLOCK - - /* Figure out how long name is */ - namelen = strnlen(name, CMOS_MAX_NAME_LENGTH); - - /* find the requested entry record */ - ct = cbfs_boot_map_with_leak("cmos_layout.bin", - CBFS_COMPONENT_CMOS_LAYOUT, NULL); - if (!ct) { - printk(BIOS_ERR, "RTC: cmos_layout.bin could not be found. " - "Options are disabled\n"); - - UNLOCK_NVRAM_CBFS_SPINLOCK - return CB_CMOS_LAYOUT_NOT_FOUND; - } - ce = (struct cmos_entries*)((unsigned char *)ct + ct->header_length); - for(; ce->tag == LB_TAG_OPTION; - ce = (struct cmos_entries*)((unsigned char *)ce + ce->size)) { - if (memcmp(ce->name, name, namelen) == 0) { - found = 1; - break; - } - } - if (!found) { - printk(BIOS_DEBUG, "WARNING: No CMOS option '%s'.\n", name); - UNLOCK_NVRAM_CBFS_SPINLOCK - return CB_CMOS_OPTION_NOT_FOUND; - } - - if (get_cmos_value(ce->bit, ce->length, dest) != CB_SUCCESS) { - UNLOCK_NVRAM_CBFS_SPINLOCK - return CB_CMOS_ACCESS_ERROR; - } - if (!cmos_checksum_valid(LB_CKS_RANGE_START, LB_CKS_RANGE_END, LB_CKS_LOC)) { - UNLOCK_NVRAM_CBFS_SPINLOCK - return CB_CMOS_CHECKSUM_INVALID; - } - UNLOCK_NVRAM_CBFS_SPINLOCK - return CB_SUCCESS; -} - -static enum cb_err set_cmos_value(unsigned long bit, unsigned long length, - void *vret) -{ - unsigned char *ret; - unsigned long byte,byte_bit; - unsigned long i; - unsigned char uchar, mask; - unsigned int chksum_update_needed = 0; - - ret = vret; - byte = bit / 8; /* find the byte where the data starts */ - byte_bit = bit % 8; /* find the bit where the data starts */ - if (length <= 8) { /* one byte or less */ - mask = (1 << length) - 1; - mask <<= byte_bit; - - uchar = cmos_read(byte); - uchar &= ~mask; - uchar |= (ret[0] << byte_bit); - cmos_write(uchar, byte); - if (byte >= LB_CKS_RANGE_START && byte <= LB_CKS_RANGE_END) - chksum_update_needed = 1; - } else { /* more that one byte so transfer the whole bytes */ - if (byte_bit || length % 8) - return CB_ERR_ARG; - - for (i = 0; length; i++, length -= 8, byte++) - cmos_write(ret[i], byte); - if (byte >= LB_CKS_RANGE_START && - byte <= LB_CKS_RANGE_END) - chksum_update_needed = 1; - } - - if (chksum_update_needed) { - cmos_set_checksum(LB_CKS_RANGE_START, LB_CKS_RANGE_END, - LB_CKS_LOC); - } - return CB_SUCCESS; -} - - -enum cb_err set_option(const char *name, void *value) -{ - struct cmos_option_table *ct; - struct cmos_entries *ce; - unsigned long length; - size_t namelen; - int found = 0; - - if (!IS_ENABLED(CONFIG_USE_OPTION_TABLE)) - return CB_CMOS_OTABLE_DISABLED; - - /* Figure out how long name is */ - namelen = strnlen(name, CMOS_MAX_NAME_LENGTH); - - /* find the requested entry record */ - ct = cbfs_boot_map_with_leak("cmos_layout.bin", - CBFS_COMPONENT_CMOS_LAYOUT, NULL); - if (!ct) { - printk(BIOS_ERR, "cmos_layout.bin could not be found. " - "Options are disabled\n"); - return CB_CMOS_LAYOUT_NOT_FOUND; - } - ce = (struct cmos_entries*)((unsigned char *)ct + ct->header_length); - for(; ce->tag == LB_TAG_OPTION; - ce = (struct cmos_entries*)((unsigned char *)ce + ce->size)) { - if (memcmp(ce->name, name, namelen) == 0) { - found = 1; - break; - } - } - if (!found) { - printk(BIOS_DEBUG, "WARNING: No CMOS option '%s'.\n", name); - return CB_CMOS_OPTION_NOT_FOUND; - } - - length = ce->length; - if (ce->config == 's') { - length = MAX(strlen((const char *)value) * 8, ce->length - 8); - /* make sure the string is null terminated */ - if (set_cmos_value(ce->bit + ce->length - 8, 8, &(u8[]){0}) - != CB_SUCCESS) - return (CB_CMOS_ACCESS_ERROR); - } - - if (set_cmos_value(ce->bit, length, value) != CB_SUCCESS) - return (CB_CMOS_ACCESS_ERROR); - - return CB_SUCCESS; -} - -/* - * If the CMOS is cleared, the rtc_reg has the invalid date. That - * hurts some OSes. Even if we don't set USE_OPTION_TABLE, we need - * to make sure the date is valid. - */ -void cmos_check_update_date() -{ - u8 year, century; - - /* Assume hardware always supports RTC_CLK_ALTCENTURY. */ - century = cmos_read(RTC_CLK_ALTCENTURY); - year = cmos_read(RTC_CLK_YEAR); - - /* - * TODO: If century is 0xFF, 100% that the cmos is cleared. - * Other than that, so far rtc_year is the only entry to check - * if the date is valid. - */ - if (century > 0x99 || year > 0x99) /* Invalid date */ - cmos_reset_date(); -} - -int rtc_set(const struct rtc_time *time){ - cmos_write(bin2bcd(time->sec), RTC_CLK_SECOND); - cmos_write(bin2bcd(time->min), RTC_CLK_MINUTE); - cmos_write(bin2bcd(time->hour), RTC_CLK_HOUR); - cmos_write(bin2bcd(time->mday), RTC_CLK_DAYOFMONTH); - cmos_write(bin2bcd(time->mon), RTC_CLK_MONTH); - cmos_write(bin2bcd(time->year % 100), RTC_CLK_YEAR); - /* Same assumption as above: We always have RTC_CLK_ALTCENTURY */ - cmos_write(bin2bcd(time->year / 100), RTC_CLK_ALTCENTURY); - cmos_write(bin2bcd(time->wday + 1), RTC_CLK_DAYOFWEEK); - return 0; -} - -int rtc_get(struct rtc_time *time) -{ - time->sec = bcd2bin(cmos_read(RTC_CLK_SECOND)); - time->min = bcd2bin(cmos_read(RTC_CLK_MINUTE)); - time->hour = bcd2bin(cmos_read(RTC_CLK_HOUR)); - time->mday = bcd2bin(cmos_read(RTC_CLK_DAYOFMONTH)); - time->mon = bcd2bin(cmos_read(RTC_CLK_MONTH)); - time->year = bcd2bin(cmos_read(RTC_CLK_YEAR)); - /* Same assumption as above: We always have RTC_CLK_ALTCENTURY */ - time->year += bcd2bin(cmos_read(RTC_CLK_ALTCENTURY)) * 100; - time->wday = bcd2bin(cmos_read(RTC_CLK_DAYOFWEEK)) - 1; - return 0; -} diff --git a/src/drivers/pc80/mc146818rtc_early.c b/src/drivers/pc80/mc146818rtc_early.c deleted file mode 100644 index 3ff5d4fb3e..0000000000 --- a/src/drivers/pc80/mc146818rtc_early.c +++ /dev/null @@ -1,103 +0,0 @@ -#include -#include -#include -#if CONFIG_USE_OPTION_TABLE -#include "option_table.h" -#endif - -#if CONFIG_MAX_REBOOT_CNT > 15 -#error "CONFIG_MAX_REBOOT_CNT too high" -#endif - -static int cmos_error(void) -{ - unsigned char reg_d; - /* See if the cmos error condition has been flagged */ - reg_d = cmos_read(RTC_REG_D); - return (reg_d & RTC_VRT) == 0; -} - -static int cmos_chksum_valid(void) -{ -#if CONFIG_USE_OPTION_TABLE - unsigned char addr; - u16 sum, old_sum; - sum = 0; - /* Compute the cmos checksum */ - for(addr = LB_CKS_RANGE_START; addr <= LB_CKS_RANGE_END; addr++) { - sum += cmos_read(addr); - } - - /* Read the stored checksum */ - old_sum = cmos_read(LB_CKS_LOC) << 8; - old_sum |= cmos_read(LB_CKS_LOC+1); - - return sum == old_sum; -#else - return 0; -#endif -} - -static inline __attribute__((unused)) int boot_count(uint8_t rtc_byte) -{ - return rtc_byte >> 4; -} - -static inline __attribute__((unused)) uint8_t increment_boot_count(uint8_t rtc_byte) -{ - return rtc_byte + (1 << 4); -} - -static inline __attribute__((unused)) uint8_t boot_set_fallback(uint8_t rtc_byte) -{ - return rtc_byte & ~RTC_BOOT_NORMAL; -} - -static inline __attribute__((unused)) int boot_use_normal(uint8_t rtc_byte) -{ - return rtc_byte & RTC_BOOT_NORMAL; -} - -static inline __attribute__((unused)) int do_normal_boot(void) -{ - unsigned char byte; - - if (cmos_error() || !cmos_chksum_valid()) { - /* Invalid CMOS checksum detected! - * Force fallback boot... - */ - byte = cmos_read(RTC_BOOT_BYTE); - byte &= boot_set_fallback(byte) & 0x0f; - byte |= 0xf << 4; - cmos_write(byte, RTC_BOOT_BYTE); - } - - /* The RTC_BOOT_BYTE is now o.k. see where to go. */ - byte = cmos_read(RTC_BOOT_BYTE); - - /* Are we attempting to boot normally? */ - if (boot_use_normal(byte)) { - /* Are we already at the max count? */ - if (boot_count(byte) < CONFIG_MAX_REBOOT_CNT) - byte = increment_boot_count(byte); - else - byte = boot_set_fallback(byte); - } - - /* Save the boot byte */ - cmos_write(byte, RTC_BOOT_BYTE); - - /* Return selected code path for this boot attempt */ - return boot_use_normal(byte); -} - -unsigned read_option_lowlevel(unsigned start, unsigned size, unsigned def) -{ -#if CONFIG_USE_OPTION_TABLE - unsigned byte; - byte = cmos_read(start/8); - return (byte >> (start & 7U)) & ((1U << size) - 1U); -#else - return def; -#endif -} diff --git a/src/drivers/pc80/pc/Kconfig b/src/drivers/pc80/pc/Kconfig new file mode 100644 index 0000000000..c44cf9144d --- /dev/null +++ b/src/drivers/pc80/pc/Kconfig @@ -0,0 +1,18 @@ +# Might be removed (alongside with the PS/2 init code) once payloads +# reliably support PS/2 init themselves. + +config DRIVERS_PS2_KEYBOARD + bool "PS/2 keyboard init" + default n + depends on PC80_SYSTEM + help + Enable this option to initialize PS/2 keyboards found connected + to the PS/2 port. + + Some payloads (eg, filo) require this option. Other payloads + (eg, GRUB 2, SeaBIOS, Linux) do not require it. + Initializing a PS/2 keyboard can take several hundred milliseconds. + + If you know you will only use a payload which does not require + this option, then you can say N here to speed up boot time. + Otherwise say Y. diff --git a/src/drivers/pc80/pc/Makefile.inc b/src/drivers/pc80/pc/Makefile.inc new file mode 100644 index 0000000000..8c348e323e --- /dev/null +++ b/src/drivers/pc80/pc/Makefile.inc @@ -0,0 +1,12 @@ +ifeq ($(CONFIG_ARCH_X86),y) + +ramstage-y += isa-dma.c +ramstage-y += i8254.c +ramstage-y += i8259.c +ramstage-$(CONFIG_UDELAY_IO) += udelay_io.c +romstage-$(CONFIG_UDELAY_IO) += udelay_io.c +ramstage-y += keyboard.c +ramstage-$(CONFIG_SPKMODEM) += spkmodem.c +romstage-$(CONFIG_SPKMODEM) += spkmodem.c + +endif diff --git a/src/drivers/pc80/pc/i8254.c b/src/drivers/pc80/pc/i8254.c new file mode 100644 index 0000000000..5851ec08a0 --- /dev/null +++ b/src/drivers/pc80/pc/i8254.c @@ -0,0 +1,51 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2009 coresystems GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include + +/* Initialize i8254 timers */ + +void setup_i8254(void) +{ + /* Timer 0 (taken from biosemu) */ + outb(TIMER0_SEL | WORD_ACCESS | MODE3 | BINARY_COUNT, TIMER_MODE_PORT); + outb(0x00, TIMER0_PORT); + outb(0x00, TIMER0_PORT); + + /* Timer 1 */ + outb(TIMER1_SEL | LOBYTE_ACCESS | MODE3 | BINARY_COUNT, + TIMER_MODE_PORT); + outb(0x12, TIMER1_PORT); +} + +#if CONFIG_UDELAY_TIMER2 +static void load_timer2(unsigned int ticks) +{ + /* Set up the timer gate, turn off the speaker */ + outb((inb(PPC_PORTB) & ~PPCB_SPKR) | PPCB_T2GATE, PPC_PORTB); + outb(TIMER2_SEL | WORD_ACCESS | MODE0 | BINARY_COUNT, TIMER_MODE_PORT); + outb(ticks & 0xFF, TIMER2_PORT); + outb(ticks >> 8, TIMER2_PORT); +} + +void udelay(int usecs) +{ + load_timer2((usecs * TICKS_PER_MS) / 1000); + while ((inb(PPC_PORTB) & PPCB_T2OUT) == 0) + ; +} +#endif diff --git a/src/drivers/pc80/pc/i8259.c b/src/drivers/pc80/pc/i8259.c new file mode 100644 index 0000000000..4261d5bec4 --- /dev/null +++ b/src/drivers/pc80/pc/i8259.c @@ -0,0 +1,139 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2009 coresystems GmbH + * Copyright (C) 2013 Sage Electronic Engineering, LLC. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include + +/* Read the current PIC IRQ mask */ +u16 pic_read_irq_mask(void) +{ + u16 mask; + int i; + + mask = inb(MASTER_PIC_OCW1) | (inb(SLAVE_PIC_OCW1) << 8); + + printk(BIOS_DEBUG, "8259 PIC: OCW1 IRQ Mask: 0x%x\n", mask); + printk(BIOS_SPEW, "\tEnabled IRQs (0 = Unmasked, 1 = Masked off):\n" + "\t\tMaster\t\tSlave\n"); + for (i = 0; i <= 7; i++) { + printk(BIOS_SPEW, "\t\tIRQ%X: %x\t\tIRQ%X: %x\n", + i, (mask >> i) & 1, i + 8, (mask >> (i + 8)) & 1); + } + return mask; +} + +/* + * Write an IRQ mask to the PIC: + * IRQA is bit 0xA in the 16 bit bitmask (OCW1) + */ +void pic_write_irq_mask(u16 mask) +{ + outb(mask, MASTER_PIC_OCW1); + outb(mask >> 8, SLAVE_PIC_OCW1); +} + +/* + * The PIC IRQs default to masked off + * Allow specific IRQs to be enabled (1) + * or disabled by (0) the user + */ +void pic_irq_enable(u8 int_num, u8 mask) +{ + pic_write_irq_mask(pic_read_irq_mask() & ~(mask << int_num)); + pic_read_irq_mask(); +} + +void setup_i8259(void) +{ + /* A write to ICW1 starts the Interrupt Controller Initialization + * Sequence. This implicitly causes the following to happen: + * - Interrupt Mask register is cleared + * - Priority 7 is assigned to IRQ7 input + * - Slave mode address is set to 7 + * - Special mask mode is cleared + * + * We send the initialization sequence to both the master and + * slave i8259 controller. + */ + outb(ICW_SELECT|IC4, MASTER_PIC_ICW1); + outb(ICW_SELECT|IC4, SLAVE_PIC_ICW1); + + /* Now the interrupt controller expects us to write to ICW2. */ + outb(INT_VECTOR_MASTER | IRQ0, MASTER_PIC_ICW2); + outb(INT_VECTOR_SLAVE | IRQ8, SLAVE_PIC_ICW2); + + /* Now the interrupt controller expects us to write to ICW3. + * + * The normal scenario is to set up cascading on IRQ2 on the master + * i8259 and assign the slave ID 2 to the slave i8259. + */ + outb(CASCADED_PIC, MASTER_PIC_ICW3); + outb(SLAVE_ID, SLAVE_PIC_ICW3); + + /* Now the interrupt controller expects us to write to ICW4. + * + * We switch both i8259 to microprocessor mode because they're + * operating as part of an x86 architecture based chipset + */ + outb(MICROPROCESSOR_MODE, MASTER_PIC_ICW2); + outb(MICROPROCESSOR_MODE, SLAVE_PIC_ICW2); + + /* Now clear the interrupts through OCW1. + * First we mask off all interrupts on the slave interrupt controller + * then we mask off all interrupts but interrupt 2 on the master + * controller. This way the cascading stays alive. + */ + outb(ALL_IRQS, SLAVE_PIC_OCW1); + outb(ALL_IRQS & ~IRQ2, MASTER_PIC_OCW1); +} + +/** + * @brief Configure IRQ triggering in the i8259 compatible Interrupt Controller. + * + * Switch a certain interrupt to be level / edge triggered. + * + * @param int_num legacy interrupt number (3-7, 9-15) + * @param is_level_triggered 1 for level triggered interrupt, 0 for edge + * triggered interrupt + */ +void i8259_configure_irq_trigger(int int_num, int is_level_triggered) +{ + u16 int_bits = inb(ELCR1) | (((u16)inb(ELCR2)) << 8); + + if (is_level_triggered) + int_bits |= (1 << int_num); + else + int_bits &= ~(1 << int_num); + + /* Write new values */ + outb((u8)(int_bits & 0xff), ELCR1); + outb((u8)(int_bits >> 8), ELCR2); + +#ifdef PARANOID_IRQ_TRIGGERS + /* Try reading back the new values. This seems like an error + * but it is not. */ + if (inb(ELCR1) != (int_bits & 0xff)) { + printk(BIOS_ERR, "%s: lower order bits are wrong: want 0x%x, got 0x%x\n", + __func__, (int_bits & 0xff), inb(ELCR1)); + } + + if (inb(ELCR2) != (int_bits >> 8)) { + printk(BIOS_ERR, "%s: higher order bits are wrong: want 0x%x, got 0x%x\n", + __func__, (int_bits>>8), inb(ELCR2)); + } +#endif +} diff --git a/src/drivers/pc80/pc/isa-dma.c b/src/drivers/pc80/pc/isa-dma.c new file mode 100644 index 0000000000..b64f125f3a --- /dev/null +++ b/src/drivers/pc80/pc/isa-dma.c @@ -0,0 +1,44 @@ +#include +#include + +/* DMA controller registers */ +#define DMA1_CMD_REG 0x08 /* command register (w) */ +#define DMA1_STAT_REG 0x08 /* status register (r) */ +#define DMA1_REQ_REG 0x09 /* request register (w) */ +#define DMA1_MASK_REG 0x0A /* single-channel mask (w) */ +#define DMA1_MODE_REG 0x0B /* mode register (w) */ +#define DMA1_CLEAR_FF_REG 0x0C /* clear pointer flip-flop (w) */ +#define DMA1_TEMP_REG 0x0D /* Temporary Register (r) */ +#define DMA1_RESET_REG 0x0D /* Master Clear (w) */ +#define DMA1_CLR_MASK_REG 0x0E /* Clear Mask */ +#define DMA1_MASK_ALL_REG 0x0F /* all-channels mask (w) */ + +#define DMA2_CMD_REG 0xD0 /* command register (w) */ +#define DMA2_STAT_REG 0xD0 /* status register (r) */ +#define DMA2_REQ_REG 0xD2 /* request register (w) */ +#define DMA2_MASK_REG 0xD4 /* single-channel mask (w) */ +#define DMA2_MODE_REG 0xD6 /* mode register (w) */ +#define DMA2_CLEAR_FF_REG 0xD8 /* clear pointer flip-flop (w) */ +#define DMA2_TEMP_REG 0xDA /* Temporary Register (r) */ +#define DMA2_RESET_REG 0xDA /* Master Clear (w) */ +#define DMA2_CLR_MASK_REG 0xDC /* Clear Mask */ +#define DMA2_MASK_ALL_REG 0xDE /* all-channels mask (w) */ + +#define DMA_MODE_READ 0x44 /* I/O to memory, no autoinit, increment, single mode */ +#define DMA_MODE_WRITE 0x48 /* memory to I/O, no autoinit, increment, single mode */ +#define DMA_MODE_CASCADE 0xC0 /* pass thru DREQ->HRQ, DACK<-HLDA only */ + +#define DMA_AUTOINIT 0x10 + + +void isa_dma_init(void) +{ + /* slave at 0x00 - 0x0f */ + /* master at 0xc0 - 0xdf */ + /* 0x80 - 0x8f DMA page registers */ + /* DMA: 0x00, 0x02, 0x4, 0x06 base address for DMA channel */ + outb(0, DMA1_RESET_REG); + outb(0, DMA2_RESET_REG); + outb(DMA_MODE_CASCADE, DMA2_MODE_REG); + outb(0, DMA2_MASK_REG); +} diff --git a/src/drivers/pc80/pc/keyboard.c b/src/drivers/pc80/pc/keyboard.c new file mode 100644 index 0000000000..415dbd1d13 --- /dev/null +++ b/src/drivers/pc80/pc/keyboard.c @@ -0,0 +1,387 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 Raptor Engineering + * Copyright (C) 2009 coresystems GmbH + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * Copyright (C) 2003 Ollie Lo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define KBD_DATA 0x60 +#define KBD_COMMAND 0x64 +#define KBD_STATUS 0x64 +#define KBD_IBF (1 << 1) // 1: input buffer full (data ready for ec) +#define KBD_OBF (1 << 0) // 1: output buffer full (data ready for host) + +// Keyboard Controller Commands +#define KBC_CMD_READ_COMMAND 0x20 // Read command byte +#define KBC_CMD_WRITE_COMMAND 0x60 // Write command byte +#define KBC_CMD_AUX_ENABLE 0xA8 // Auxiliary Interface enable +#define KBC_CMD_AUX_TEST 0xA9 // Auxiliary Interface test +#define KBC_CMD_SELF_TEST 0xAA // Controller self-test +#define KBC_CMD_KBD_TEST 0xAB // Keyboard Interface test + +/* The Keyboard controller command byte + * BIT | Description + * ----+------------------------------------------------------- + * 7 | reserved, must be zero + * 6 | XT Translation, (1 = on, 0 = off) + * 5 | Disable Mouse Port (1 = disable, 0 = enable) + * 4 | Disable Keyboard Port (1 = disable, 0 = enable) + * 3 | reserved, must be zero + * 2 | System Flag (1 = self-test passed. DO NOT SET TO ZERO) + * 1 | Mouse Port Interrupts (1 = enable, 0 = disable) + * 0 | Keyboard Port Interrupts (1 = enable, 0 = disable) + */ + +// Keyboard Controller Replies +#define KBC_REPLY_SELFTEST_OK 0x55 // controller self-test succeeded + +// +// Keyboard Replies +// +#define KBD_REPLY_POR 0xAA // Power on reset +#define KBD_REPLY_ACK 0xFA // Command ACK +#define KBD_REPLY_RESEND 0xFE // Command NACK, send command again + +/* Wait 400ms for keyboard controller answers */ +#define KBC_TIMEOUT_IN_MS 400 + +static int kbc_input_buffer_empty(void) +{ + u32 timeout; + + for (timeout = KBC_TIMEOUT_IN_MS; + timeout && (inb(KBD_STATUS) & KBD_IBF); timeout--) + mdelay(1); + + if (!timeout) + printk(BIOS_WARNING, + "Unexpected Keyboard controller input buffer full\n"); + return !!timeout; +} + +static int kbc_output_buffer_full(void) +{ + u32 timeout; + + for (timeout = KBC_TIMEOUT_IN_MS; + timeout && ((inb(KBD_STATUS) & KBD_OBF) == 0); timeout--) + mdelay(1); + + if (!timeout) + printk(BIOS_INFO, + "Keyboard controller output buffer result timeout\n"); + return !!timeout; +} + +static int kbc_cleanup_buffers(void) +{ + u32 timeout; + + for (timeout = KBC_TIMEOUT_IN_MS; + timeout && (inb(KBD_STATUS) & (KBD_OBF | KBD_IBF)); timeout--) { + mdelay(1); + inb(KBD_DATA); + } + + if (!timeout) { + printk(BIOS_ERR, + "Couldn't cleanup the keyboard controller buffers\n"); + printk(BIOS_ERR, "Status (0x%x): 0x%x, Buffer (0x%x): 0x%x\n", + KBD_STATUS, inb(KBD_STATUS), KBD_DATA, inb(KBD_DATA)); + } + + return !!timeout; +} + +static enum cb_err kbc_self_test(uint8_t probe_aux, uint8_t *aux_probe_result) +{ + uint8_t self_test; + uint8_t byte; + + /* Set initial aux probe output value */ + if (aux_probe_result) + *aux_probe_result = 0; + + /* Clean up any junk that might have been in the KBC. + * Both input and output buffers must be empty. + */ + if (!kbc_cleanup_buffers()) + return CB_KBD_CONTROLLER_FAILURE; + + /* reset/self test 8042 - send cmd 0xAA */ + outb(KBC_CMD_SELF_TEST, KBD_COMMAND); + + if (!kbc_output_buffer_full()) { + /* There probably is no keyboard controller. */ + printk(BIOS_ERR, "Could not reset keyboard controller.\n"); + return CB_KBD_CONTROLLER_FAILURE; + } + + /* read self-test result, 0x55 is returned in the output buffer */ + self_test = inb(KBD_DATA); + + if (self_test != 0x55) { + printk(BIOS_ERR, "Keyboard Controller self-test failed: 0x%x\n", + self_test); + return CB_KBD_CONTROLLER_FAILURE; + } + + /* ensure the buffers are empty */ + kbc_cleanup_buffers(); + + /* keyboard interface test */ + outb(KBC_CMD_KBD_TEST, KBD_COMMAND); + + if (!kbc_output_buffer_full()) { + printk(BIOS_ERR, "Keyboard Interface test timed out.\n"); + return CB_KBD_CONTROLLER_FAILURE; + } + + /* read test result, 0x00 should be returned in case of no failures */ + self_test = inb(KBD_DATA); + + if (self_test != 0x00) { + printk(BIOS_ERR, "Keyboard Interface test failed: 0x%x\n", + self_test); + return CB_KBD_INTERFACE_FAILURE; + } + + if (probe_aux) { + /* aux interface detect */ + outb(KBC_CMD_AUX_ENABLE, KBD_COMMAND); + if (!kbc_input_buffer_empty()) { + printk(BIOS_ERR, "Timeout waiting for controller during aux enable.\n"); + return CB_KBD_CONTROLLER_FAILURE; + } + outb(KBC_CMD_READ_COMMAND, KBD_COMMAND); + if (!kbc_output_buffer_full()) { + printk(BIOS_ERR, "Timeout waiting for controller during aux probe.\n"); + return CB_KBD_CONTROLLER_FAILURE; + } + + byte = inb(KBD_DATA); + if (!(byte & (0x1 << 5))) { + printk(BIOS_DEBUG, "PS/2 auxiliary channel detected...\n"); + + /* auxiliary interface test */ + outb(KBC_CMD_AUX_TEST, KBD_COMMAND); + + if (!kbc_output_buffer_full()) { + printk(BIOS_ERR, "Auxiliary channel probe timed out.\n"); + goto aux_failure; + } + + /* read test result, 0x00 should be returned in case of no failures */ + self_test = inb(KBD_DATA); + + if (self_test != 0x00) { + printk(BIOS_ERR, "No device detected on auxiliary channel: 0x%x\n", + self_test); + goto aux_failure; + } + + printk(BIOS_DEBUG, "PS/2 device detected on auxiliary channel\n"); + if (aux_probe_result) + *aux_probe_result = 1; + } + } + +aux_failure: + + return CB_SUCCESS; +} + +static u8 send_keyboard(u8 command) +{ + u8 regval = 0; + u8 resend = 10; + + do { + if (!kbc_input_buffer_empty()) + return 0; + outb(command, KBD_DATA); + /* the reset command takes much longer then normal commands and + * even worse, some keyboards do send the ACK _after_ doing the + * reset */ + if (command == 0xFF) { + u8 retries; + + for (retries = 9; retries && !kbc_output_buffer_full(); + retries--) + ; + } + if (!kbc_output_buffer_full()) { + printk(BIOS_ERR, + "Could not send keyboard command %02x\n", + command); + return 0; + } + regval = inb(KBD_DATA); + --resend; + } while (regval == KBD_REPLY_RESEND && resend > 0); + + return regval; +} + +uint8_t pc_keyboard_init(uint8_t probe_aux) +{ + u8 retries; + u8 regval; + enum cb_err err; + uint8_t aux_dev_detected; + + if (!CONFIG_DRIVERS_PS2_KEYBOARD) + return 0; + + if (acpi_is_wakeup_s3()) + return 0; + + printk(BIOS_DEBUG, "Keyboard init...\n"); + + /* Run a keyboard controller self-test */ + err = kbc_self_test(probe_aux, &aux_dev_detected); + /* Ignore iterface failure as it's non-fatal. */ + if (err != CB_SUCCESS && err != CB_KBD_INTERFACE_FAILURE) + return 0; + + /* Enable keyboard interface - No IRQ */ + if (!kbc_input_buffer_empty()) + return 0; + outb(0x60, KBD_COMMAND); + if (!kbc_input_buffer_empty()) + return 0; + outb(0x20, KBD_DATA); /* send cmd: enable keyboard */ + if (!kbc_input_buffer_empty()) { + printk(BIOS_INFO, "Timeout while enabling keyboard\n"); + return 0; + } + + /* clean up any junk that might have been in the keyboard */ + if (!kbc_cleanup_buffers()) + return 0; + + /* reset keyboard and self test (keyboard side) */ + regval = send_keyboard(0xFF); + if (regval == KBD_REPLY_RESEND) { + /* keeps sending RESENDs, probably no keyboard. */ + printk(BIOS_INFO, "No PS/2 keyboard detected.\n"); + return 0; + } + + if (regval != KBD_REPLY_ACK) { + printk(BIOS_ERR, "Keyboard reset failed ACK: 0x%x\n", regval); + return 0; + } + + /* the reset command takes some time, so wait a little longer */ + for (retries = 9; retries && !kbc_output_buffer_full(); retries--) + ; + + if (!kbc_output_buffer_full()) { + printk(BIOS_ERR, "Timeout waiting for keyboard after reset.\n"); + return 0; + } + + regval = inb(KBD_DATA); + if (regval != 0xAA) { + printk(BIOS_ERR, "Keyboard reset selftest failed: 0x%x\n", + regval); + return 0; + } + + /* + * The following set scancode stuff is what normal BIOS do. It could be + * argued that coreboot shouldn't set the scan code..... + */ + + /* disable the keyboard */ + regval = send_keyboard(0xF5); + if (regval != KBD_REPLY_ACK) { + printk(BIOS_ERR, "Keyboard disable failed ACK: 0x%x\n", regval); + return 0; + } + + /* Set scancode command */ + regval = send_keyboard(0xF0); + if (regval != KBD_REPLY_ACK) { + printk(BIOS_ERR, "Keyboard set scancode cmd failed ACK: 0x%x\n", + regval); + return 0; + } + /* Set scancode mode 2 */ + regval = send_keyboard(0x02); + if (regval != KBD_REPLY_ACK) { + printk(BIOS_ERR, + "Keyboard set scancode mode failed ACK: 0x%x\n", regval); + return 0; + } + + /* All is well - enable keyboard interface */ + if (!kbc_input_buffer_empty()) + return 0; + outb(0x60, KBD_COMMAND); + if (!kbc_input_buffer_empty()) + return 0; + outb(0x65, KBD_DATA); /* send cmd: enable keyboard and IRQ 1 */ + if (!kbc_input_buffer_empty()) { + printk(BIOS_ERR, "Timeout during keyboard enable\n"); + return 0; + } + + /* enable the keyboard */ + regval = send_keyboard(0xF4); + if (regval != KBD_REPLY_ACK) { + printk(BIOS_ERR, "Keyboard enable failed ACK: 0x%x\n", regval); + return 0; + } + + printk(BIOS_DEBUG, "PS/2 keyboard initialized on primary channel\n"); + + return aux_dev_detected; +} + +/* + * Support PS/2 mode - oddball SIOs(KBC) need this setup + * Not well documented. Google - 0xcb keyboard controller + * This is called before pc_keyboard_init(). + */ +void set_kbc_ps2_mode(void) +{ + enum cb_err err; + + /* Run a keyboard controller self-test */ + err = kbc_self_test(0, NULL); + /* Ignore iterface failure as it's non-fatal. */ + if (err != CB_SUCCESS && err != CB_KBD_INTERFACE_FAILURE) + return; + + /* Support PS/2 mode */ + if (!kbc_input_buffer_empty()) + return; + outb(0xcb, KBD_COMMAND); + + if (!kbc_input_buffer_empty()) + return; + outb(0x01, KBD_DATA); + + kbc_cleanup_buffers(); +} diff --git a/src/drivers/pc80/pc/ps2_controller.asl b/src/drivers/pc80/pc/ps2_controller.asl new file mode 100644 index 0000000000..a4984cfdb9 --- /dev/null +++ b/src/drivers/pc80/pc/ps2_controller.asl @@ -0,0 +1,46 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (c) 2013 Vladimir Serbinenko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of + * the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + Device (PS2K) // Keyboard + { + Name(_HID, EISAID("PNP0303")) + Name(_CID, EISAID("PNP030B")) + + Name(_CRS, ResourceTemplate() + { + IO (Decode16, 0x60, 0x60, 0x01, 0x01) + IO (Decode16, 0x64, 0x64, 0x01, 0x01) + IRQ (Edge, ActiveHigh, Exclusive) { 0x01 } // IRQ 1 + }) + + Method (_STA, 0) + { + Return (0xf) + } + } + + Device (PS2M) // Mouse + { + Name(_HID, EISAID("PNP0F13")) + Name(_CRS, ResourceTemplate() + { + IRQ (Edge, ActiveHigh, Exclusive) { 0x0c } // IRQ 12 + }) + + Method(_STA, 0) + { + Return (0xf) + } + } diff --git a/src/drivers/pc80/pc/spkmodem.c b/src/drivers/pc80/pc/spkmodem.c new file mode 100644 index 0000000000..df66f6fa62 --- /dev/null +++ b/src/drivers/pc80/pc/spkmodem.c @@ -0,0 +1,126 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 Vladimir Serbinenko + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include + +#define SPEAKER_PIT_FREQUENCY 0x1234dd + + +enum { + PIT_COUNTER_0 = 0x40, + PIT_COUNTER_1 = 0x41, + PIT_COUNTER_2 = 0x42, + PIT_CTRL = 0x43, + PIT_SPEAKER_PORT = 0x61, +}; + + +enum { + PIT_SPK_TMR2 = 0x01, + PIT_SPK_DATA = 0x02, + PIT_SPK_TMR2_LATCH = 0x20 +}; + +enum { + PIT_CTRL_SELECT_MASK = 0xc0, + PIT_CTRL_SELECT_0 = 0x00, + PIT_CTRL_SELECT_1 = 0x40, + PIT_CTRL_SELECT_2 = 0x80, + + PIT_CTRL_READLOAD_MASK = 0x30, + PIT_CTRL_COUNTER_LATCH = 0x00, + PIT_CTRL_READLOAD_LSB = 0x10, + PIT_CTRL_READLOAD_MSB = 0x20, + PIT_CTRL_READLOAD_WORD = 0x30, + + PIT_CTRL_MODE_MASK = 0x0e, + PIT_CTRL_INTR_ON_TERM = 0x00, + PIT_CTRL_PROGR_ONE_SHOT = 0x02, + + PIT_CTRL_RATE_GEN = 0x04, + + PIT_CTRL_SQUAREWAVE_GEN = 0x06, + PIT_CTRL_SOFTSTROBE = 0x08, + + PIT_CTRL_HARDSTROBE = 0x0a, + + + PIT_CTRL_COUNT_MASK = 0x01, + PIT_CTRL_COUNT_BINARY = 0x00, + PIT_CTRL_COUNT_BCD = 0x01 +}; + + +static void +make_tone(uint16_t freq_count, unsigned int duration) +{ + outb(PIT_CTRL_SELECT_2 + | PIT_CTRL_READLOAD_WORD + | PIT_CTRL_SQUAREWAVE_GEN + | PIT_CTRL_COUNT_BINARY, PIT_CTRL); + + outb(freq_count & 0xff, PIT_COUNTER_2); + + outb((freq_count >> 8) & 0xff, PIT_COUNTER_2); + + outb(inb(PIT_SPEAKER_PORT) + | PIT_SPK_TMR2 | PIT_SPK_DATA, + PIT_SPEAKER_PORT); + + for (; duration; duration--) { + unsigned short counter, previous_counter = 0xffff; + + while (1) { + counter = inb(PIT_COUNTER_2); + counter |= ((uint16_t)inb(PIT_COUNTER_2)) << 8; + if (counter > previous_counter) { + previous_counter = counter; + break; + } + previous_counter = counter; + } + } +} + +void spkmodem_tx_byte(unsigned char c) +{ + int i; + + make_tone(SPEAKER_PIT_FREQUENCY / 200, 4); + for (i = 7; i >= 0; i--) { + if ((c >> i) & 1) + make_tone(SPEAKER_PIT_FREQUENCY / 2000, 20); + else + make_tone(SPEAKER_PIT_FREQUENCY / 4000, 40); + make_tone(SPEAKER_PIT_FREQUENCY / 1000, 10); + } + make_tone(SPEAKER_PIT_FREQUENCY / 200, 0); +} + +void spkmodem_init(void) +{ + /* Some cards need time to come online. + * Output some message to get it started. + */ + spkmodem_tx_byte('S'); + spkmodem_tx_byte('P'); + spkmodem_tx_byte('K'); + spkmodem_tx_byte('\r'); + spkmodem_tx_byte('\n'); +} diff --git a/src/drivers/pc80/pc/udelay_io.c b/src/drivers/pc80/pc/udelay_io.c new file mode 100644 index 0000000000..3305e4c3a3 --- /dev/null +++ b/src/drivers/pc80/pc/udelay_io.c @@ -0,0 +1,14 @@ +#include +#include + +void init_timer(void) +{ +} + +void udelay(unsigned usecs) +{ + int i; + + for (i = 0; i < usecs; i++) + inb(0x80); +} diff --git a/src/drivers/pc80/ps2_controller.asl b/src/drivers/pc80/ps2_controller.asl deleted file mode 100644 index a4984cfdb9..0000000000 --- a/src/drivers/pc80/ps2_controller.asl +++ /dev/null @@ -1,46 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (c) 2013 Vladimir Serbinenko - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of - * the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - Device (PS2K) // Keyboard - { - Name(_HID, EISAID("PNP0303")) - Name(_CID, EISAID("PNP030B")) - - Name(_CRS, ResourceTemplate() - { - IO (Decode16, 0x60, 0x60, 0x01, 0x01) - IO (Decode16, 0x64, 0x64, 0x01, 0x01) - IRQ (Edge, ActiveHigh, Exclusive) { 0x01 } // IRQ 1 - }) - - Method (_STA, 0) - { - Return (0xf) - } - } - - Device (PS2M) // Mouse - { - Name(_HID, EISAID("PNP0F13")) - Name(_CRS, ResourceTemplate() - { - IRQ (Edge, ActiveHigh, Exclusive) { 0x0c } // IRQ 12 - }) - - Method(_STA, 0) - { - Return (0xf) - } - } diff --git a/src/drivers/pc80/rtc/Kconfig b/src/drivers/pc80/rtc/Kconfig new file mode 100644 index 0000000000..350863e99a --- /dev/null +++ b/src/drivers/pc80/rtc/Kconfig @@ -0,0 +1,4 @@ +config DRIVERS_MC146818 + bool + default y if ARCH_X86 + depends on PC80_SYSTEM diff --git a/src/drivers/pc80/rtc/Makefile.inc b/src/drivers/pc80/rtc/Makefile.inc new file mode 100644 index 0000000000..d3b3344938 --- /dev/null +++ b/src/drivers/pc80/rtc/Makefile.inc @@ -0,0 +1,15 @@ +ifeq ($(CONFIG_ARCH_X86),y) + +romstage-$(CONFIG_DRIVERS_MC146818) += mc146818rtc_early.c +romstage-$(CONFIG_DRIVERS_MC146818) += mc146818rtc.c + +ramstage-$(CONFIG_DRIVERS_MC146818) += mc146818rtc_early.c +ramstage-$(CONFIG_DRIVERS_MC146818) += mc146818rtc.c + +cbfs-files-$(CONFIG_HAVE_CMOS_DEFAULT) += cmos.default +cmos.default-file = $(CONFIG_CMOS_DEFAULT_FILE):nvramtool +cmos.default-type = 0xaa + +smm-$(CONFIG_DRIVERS_MC146818) += mc146818rtc.c + +endif diff --git a/src/drivers/pc80/rtc/mc146818rtc.c b/src/drivers/pc80/rtc/mc146818rtc.c new file mode 100644 index 0000000000..35dad3256a --- /dev/null +++ b/src/drivers/pc80/rtc/mc146818rtc.c @@ -0,0 +1,400 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2014 The Chromium OS Authors. All rights reserved. + * Copyright (C) 2015 Timothy Pearson , Raptor Engineering + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* There's no way around this include guard. option_table.h is autogenerated */ +#if CONFIG_USE_OPTION_TABLE +#include "option_table.h" +#else +#define LB_CKS_RANGE_START 0 +#define LB_CKS_RANGE_END 0 +#define LB_CKS_LOC 0 +#endif + +#include + +#if (defined(__PRE_RAM__) && \ +IS_ENABLED(CONFIG_HAVE_ROMSTAGE_NVRAM_CBFS_SPINLOCK)) + #define LOCK_NVRAM_CBFS_SPINLOCK() spin_lock(romstage_nvram_cbfs_lock()) + #define UNLOCK_NVRAM_CBFS_SPINLOCK() spin_unlock(romstage_nvram_cbfs_lock()) +#else + #define LOCK_NVRAM_CBFS_SPINLOCK() { } + #define UNLOCK_NVRAM_CBFS_SPINLOCK() { } +#endif + +static void cmos_reset_date(void) +{ + /* Now setup a default date equals to the build date */ + struct rtc_time time = { + .sec = 0, + .min = 0, + .hour = 1, + .mday = bcd2bin(coreboot_build_date.day), + .mon = bcd2bin(coreboot_build_date.month), + .year = (bcd2bin(coreboot_build_date.century) * 100) + + bcd2bin(coreboot_build_date.year), + .wday = bcd2bin(coreboot_build_date.weekday) + }; + rtc_set(&time); +} + +static int cmos_checksum_valid(int range_start, int range_end, int cks_loc) +{ + int i; + u16 sum, old_sum; + + if (IS_ENABLED(CONFIG_STATIC_OPTION_TABLE)) + return 1; + + sum = 0; + for (i = range_start; i <= range_end; i++) + sum += cmos_read(i); + old_sum = ((cmos_read(cks_loc) << 8) | cmos_read(cks_loc + 1)) & + 0x0ffff; + return sum == old_sum; +} + +static void cmos_set_checksum(int range_start, int range_end, int cks_loc) +{ + int i; + u16 sum; + + sum = 0; + for (i = range_start; i <= range_end; i++) + sum += cmos_read(i); + cmos_write(((sum >> 8) & 0x0ff), cks_loc); + cmos_write(((sum >> 0) & 0x0ff), cks_loc + 1); +} + +#define RTC_CONTROL_DEFAULT (RTC_24H) +#define RTC_FREQ_SELECT_DEFAULT (RTC_REF_CLCK_32KHZ | RTC_RATE_1024HZ) + +#ifndef __SMM__ +void cmos_init(bool invalid) +{ + bool cmos_invalid = invalid; + bool checksum_invalid = false; + bool clear_cmos; + size_t i; + uint8_t x; + +#ifndef __PRE_RAM__ + /* + * Avoid clearing pending interrupts and resetting the RTC control + * register in the resume path because the Linux kernel relies on + * this to know if it should restart the RTC timer queue if the wake + * was due to the RTC alarm. + */ + if (acpi_is_wakeup_s3()) + return; +#endif /* __PRE_RAM__ */ + + printk(BIOS_DEBUG, "RTC Init\n"); + + if (IS_ENABLED(CONFIG_USE_OPTION_TABLE)) { + /* See if there has been a CMOS power problem. */ + x = cmos_read(RTC_VALID); + cmos_invalid = !(x & RTC_VRT); + + /* See if there is a CMOS checksum error */ + checksum_invalid = !cmos_checksum_valid(PC_CKS_RANGE_START, + PC_CKS_RANGE_END, PC_CKS_LOC); + + clear_cmos = false; + } else { + clear_cmos = true; + } + + if (invalid || cmos_invalid || checksum_invalid) { + if (clear_cmos) { + cmos_write(0, 0x01); + cmos_write(0, 0x03); + cmos_write(0, 0x05); + for (i = 10; i < 128; i++) + cmos_write(0, i); + } + + if (cmos_invalid) + cmos_reset_date(); + + printk(BIOS_WARNING, "RTC:%s%s%s%s\n", + invalid ? " Clear requested":"", + cmos_invalid ? " Power Problem":"", + checksum_invalid ? " Checksum invalid":"", + clear_cmos ? " zeroing cmos":""); + } + + /* Setup the real time clock */ + cmos_write(RTC_CONTROL_DEFAULT, RTC_CONTROL); + /* Setup the frequency it operates at */ + cmos_write(RTC_FREQ_SELECT_DEFAULT, RTC_FREQ_SELECT); + /* Ensure all reserved bits are 0 in register D */ + cmos_write(RTC_VRT, RTC_VALID); + + if (IS_ENABLED(CONFIG_USE_OPTION_TABLE)) { + /* See if there is a LB CMOS checksum error */ + checksum_invalid = !cmos_checksum_valid(LB_CKS_RANGE_START, + LB_CKS_RANGE_END, LB_CKS_LOC); + if (checksum_invalid) + printk(BIOS_DEBUG, "RTC: coreboot checksum invalid\n"); + + /* Make certain we have a valid checksum */ + cmos_set_checksum(PC_CKS_RANGE_START, PC_CKS_RANGE_END, PC_CKS_LOC); + } + + /* Clear any pending interrupts */ + cmos_read(RTC_INTR_FLAGS); +} +#endif /* __SMM__ */ + + +/* + * This routine returns the value of the requested bits. + * input bit = bit count from the beginning of the cmos image + * length = number of bits to include in the value + * ret = a character pointer to where the value is to be returned + * returns CB_SUCCESS = successful, cb_err code if an error occurred + */ +static enum cb_err get_cmos_value(unsigned long bit, unsigned long length, + void *vret) +{ + unsigned char *ret; + unsigned long byte, byte_bit; + unsigned long i; + unsigned char uchar; + + /* + * The table is checked when it is built to ensure all + * values are valid. + */ + ret = vret; + byte = bit / 8; /* find the byte where the data starts */ + byte_bit = bit % 8; /* find the bit in the byte where the data starts */ + if (length < 9) { /* one byte or less */ + uchar = cmos_read(byte); /* load the byte */ + uchar >>= byte_bit; /* shift the bits to byte align */ + /* clear unspecified bits */ + ret[0] = uchar & ((1 << length) - 1); + } else { /* more that one byte so transfer the whole bytes */ + for (i = 0; length; i++, length -= 8, byte++) { + /* load the byte */ + ret[i] = cmos_read(byte); + } + } + return CB_SUCCESS; +} + +enum cb_err get_option(void *dest, const char *name) +{ + struct cmos_option_table *ct; + struct cmos_entries *ce; + size_t namelen; + int found = 0; + + if (!IS_ENABLED(CONFIG_USE_OPTION_TABLE)) + return CB_CMOS_OTABLE_DISABLED; + + LOCK_NVRAM_CBFS_SPINLOCK(); + + /* Figure out how long name is */ + namelen = strnlen(name, CMOS_MAX_NAME_LENGTH); + + /* find the requested entry record */ + ct = cbfs_boot_map_with_leak("cmos_layout.bin", + CBFS_COMPONENT_CMOS_LAYOUT, NULL); + if (!ct) { + printk(BIOS_ERR, "RTC: cmos_layout.bin could not be found. " + "Options are disabled\n"); + + UNLOCK_NVRAM_CBFS_SPINLOCK(); + return CB_CMOS_LAYOUT_NOT_FOUND; + } + ce = (struct cmos_entries *)((unsigned char *)ct + ct->header_length); + for (; ce->tag == LB_TAG_OPTION; + ce = (struct cmos_entries *)((unsigned char *)ce + ce->size)) { + if (memcmp(ce->name, name, namelen) == 0) { + found = 1; + break; + } + } + if (!found) { + printk(BIOS_DEBUG, "WARNING: No CMOS option '%s'.\n", name); + UNLOCK_NVRAM_CBFS_SPINLOCK(); + return CB_CMOS_OPTION_NOT_FOUND; + } + + if (get_cmos_value(ce->bit, ce->length, dest) != CB_SUCCESS) { + UNLOCK_NVRAM_CBFS_SPINLOCK(); + return CB_CMOS_ACCESS_ERROR; + } + if (!cmos_checksum_valid(LB_CKS_RANGE_START, LB_CKS_RANGE_END, LB_CKS_LOC)) { + UNLOCK_NVRAM_CBFS_SPINLOCK(); + return CB_CMOS_CHECKSUM_INVALID; + } + UNLOCK_NVRAM_CBFS_SPINLOCK(); + return CB_SUCCESS; +} + +static enum cb_err set_cmos_value(unsigned long bit, unsigned long length, + void *vret) +{ + unsigned char *ret; + unsigned long byte, byte_bit; + unsigned long i; + unsigned char uchar, mask; + unsigned int chksum_update_needed = 0; + + ret = vret; + byte = bit / 8; /* find the byte where the data starts */ + byte_bit = bit % 8; /* find the bit where the data starts */ + if (length <= 8) { /* one byte or less */ + mask = (1 << length) - 1; + mask <<= byte_bit; + + uchar = cmos_read(byte); + uchar &= ~mask; + uchar |= (ret[0] << byte_bit); + cmos_write(uchar, byte); + if (byte >= LB_CKS_RANGE_START && byte <= LB_CKS_RANGE_END) + chksum_update_needed = 1; + } else { /* more that one byte so transfer the whole bytes */ + if (byte_bit || length % 8) + return CB_ERR_ARG; + + for (i = 0; length; i++, length -= 8, byte++) + cmos_write(ret[i], byte); + if (byte >= LB_CKS_RANGE_START && + byte <= LB_CKS_RANGE_END) + chksum_update_needed = 1; + } + + if (chksum_update_needed) { + cmos_set_checksum(LB_CKS_RANGE_START, LB_CKS_RANGE_END, + LB_CKS_LOC); + } + return CB_SUCCESS; +} + + +enum cb_err set_option(const char *name, void *value) +{ + struct cmos_option_table *ct; + struct cmos_entries *ce; + unsigned long length; + size_t namelen; + int found = 0; + + if (!IS_ENABLED(CONFIG_USE_OPTION_TABLE)) + return CB_CMOS_OTABLE_DISABLED; + + /* Figure out how long name is */ + namelen = strnlen(name, CMOS_MAX_NAME_LENGTH); + + /* find the requested entry record */ + ct = cbfs_boot_map_with_leak("cmos_layout.bin", + CBFS_COMPONENT_CMOS_LAYOUT, NULL); + if (!ct) { + printk(BIOS_ERR, "cmos_layout.bin could not be found. " + "Options are disabled\n"); + return CB_CMOS_LAYOUT_NOT_FOUND; + } + ce = (struct cmos_entries *)((unsigned char *)ct + ct->header_length); + for (; ce->tag == LB_TAG_OPTION; + ce = (struct cmos_entries *)((unsigned char *)ce + ce->size)) { + if (memcmp(ce->name, name, namelen) == 0) { + found = 1; + break; + } + } + if (!found) { + printk(BIOS_DEBUG, "WARNING: No CMOS option '%s'.\n", name); + return CB_CMOS_OPTION_NOT_FOUND; + } + + length = ce->length; + if (ce->config == 's') { + length = MAX(strlen((const char *)value) * 8, ce->length - 8); + /* make sure the string is null terminated */ + if (set_cmos_value(ce->bit + ce->length - 8, 8, &(u8[]){0}) + != CB_SUCCESS) + return CB_CMOS_ACCESS_ERROR; + } + + if (set_cmos_value(ce->bit, length, value) != CB_SUCCESS) + return CB_CMOS_ACCESS_ERROR; + + return CB_SUCCESS; +} + +/* + * If the CMOS is cleared, the rtc_reg has the invalid date. That + * hurts some OSes. Even if we don't set USE_OPTION_TABLE, we need + * to make sure the date is valid. + */ +void cmos_check_update_date(void) +{ + u8 year, century; + + /* Assume hardware always supports RTC_CLK_ALTCENTURY. */ + century = cmos_read(RTC_CLK_ALTCENTURY); + year = cmos_read(RTC_CLK_YEAR); + + /* + * TODO: If century is 0xFF, 100% that the cmos is cleared. + * Other than that, so far rtc_year is the only entry to check + * if the date is valid. + */ + if (century > 0x99 || year > 0x99) /* Invalid date */ + cmos_reset_date(); +} + +int rtc_set(const struct rtc_time *time) +{ + cmos_write(bin2bcd(time->sec), RTC_CLK_SECOND); + cmos_write(bin2bcd(time->min), RTC_CLK_MINUTE); + cmos_write(bin2bcd(time->hour), RTC_CLK_HOUR); + cmos_write(bin2bcd(time->mday), RTC_CLK_DAYOFMONTH); + cmos_write(bin2bcd(time->mon), RTC_CLK_MONTH); + cmos_write(bin2bcd(time->year % 100), RTC_CLK_YEAR); + /* Same assumption as above: We always have RTC_CLK_ALTCENTURY */ + cmos_write(bin2bcd(time->year / 100), RTC_CLK_ALTCENTURY); + cmos_write(bin2bcd(time->wday + 1), RTC_CLK_DAYOFWEEK); + return 0; +} + +int rtc_get(struct rtc_time *time) +{ + time->sec = bcd2bin(cmos_read(RTC_CLK_SECOND)); + time->min = bcd2bin(cmos_read(RTC_CLK_MINUTE)); + time->hour = bcd2bin(cmos_read(RTC_CLK_HOUR)); + time->mday = bcd2bin(cmos_read(RTC_CLK_DAYOFMONTH)); + time->mon = bcd2bin(cmos_read(RTC_CLK_MONTH)); + time->year = bcd2bin(cmos_read(RTC_CLK_YEAR)); + /* Same assumption as above: We always have RTC_CLK_ALTCENTURY */ + time->year += bcd2bin(cmos_read(RTC_CLK_ALTCENTURY)) * 100; + time->wday = bcd2bin(cmos_read(RTC_CLK_DAYOFWEEK)) - 1; + return 0; +} diff --git a/src/drivers/pc80/rtc/mc146818rtc_early.c b/src/drivers/pc80/rtc/mc146818rtc_early.c new file mode 100644 index 0000000000..8bebc4229d --- /dev/null +++ b/src/drivers/pc80/rtc/mc146818rtc_early.c @@ -0,0 +1,104 @@ +#include +#include +#include +#if CONFIG_USE_OPTION_TABLE +#include "option_table.h" +#endif + +#if CONFIG_MAX_REBOOT_CNT > 15 +#error "CONFIG_MAX_REBOOT_CNT too high" +#endif + +static int cmos_error(void) +{ + unsigned char reg_d; + /* See if the cmos error condition has been flagged */ + reg_d = cmos_read(RTC_REG_D); + return (reg_d & RTC_VRT) == 0; +} + +static int cmos_chksum_valid(void) +{ +#if CONFIG_USE_OPTION_TABLE + unsigned char addr; + u16 sum, old_sum; + + sum = 0; + /* Compute the cmos checksum */ + for (addr = LB_CKS_RANGE_START; addr <= LB_CKS_RANGE_END; addr++) + sum += cmos_read(addr); + + /* Read the stored checksum */ + old_sum = cmos_read(LB_CKS_LOC) << 8; + old_sum |= cmos_read(LB_CKS_LOC+1); + + return sum == old_sum; +#else + return 0; +#endif +} + +static inline __attribute__((unused)) int boot_count(uint8_t rtc_byte) +{ + return rtc_byte >> 4; +} + +static inline __attribute__((unused)) uint8_t increment_boot_count(uint8_t rtc_byte) +{ + return rtc_byte + (1 << 4); +} + +static inline __attribute__((unused)) uint8_t boot_set_fallback(uint8_t rtc_byte) +{ + return rtc_byte & ~RTC_BOOT_NORMAL; +} + +static inline __attribute__((unused)) int boot_use_normal(uint8_t rtc_byte) +{ + return rtc_byte & RTC_BOOT_NORMAL; +} + +static inline __attribute__((unused)) int do_normal_boot(void) +{ + unsigned char byte; + + if (cmos_error() || !cmos_chksum_valid()) { + /* Invalid CMOS checksum detected! + * Force fallback boot... + */ + byte = cmos_read(RTC_BOOT_BYTE); + byte &= boot_set_fallback(byte) & 0x0f; + byte |= 0xf << 4; + cmos_write(byte, RTC_BOOT_BYTE); + } + + /* The RTC_BOOT_BYTE is now o.k. see where to go. */ + byte = cmos_read(RTC_BOOT_BYTE); + + /* Are we attempting to boot normally? */ + if (boot_use_normal(byte)) { + /* Are we already at the max count? */ + if (boot_count(byte) < CONFIG_MAX_REBOOT_CNT) + byte = increment_boot_count(byte); + else + byte = boot_set_fallback(byte); + } + + /* Save the boot byte */ + cmos_write(byte, RTC_BOOT_BYTE); + + /* Return selected code path for this boot attempt */ + return boot_use_normal(byte); +} + +unsigned read_option_lowlevel(unsigned start, unsigned size, unsigned def) +{ +#if CONFIG_USE_OPTION_TABLE + unsigned byte; + + byte = cmos_read(start/8); + return (byte >> (start & 7U)) & ((1U << size) - 1U); +#else + return def; +#endif +} diff --git a/src/drivers/pc80/spkmodem.c b/src/drivers/pc80/spkmodem.c deleted file mode 100644 index fe57e620bc..0000000000 --- a/src/drivers/pc80/spkmodem.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2013 Vladimir Serbinenko - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include - -#define SPEAKER_PIT_FREQUENCY 0x1234dd - - -enum { - PIT_COUNTER_0 = 0x40, - PIT_COUNTER_1 = 0x41, - PIT_COUNTER_2 = 0x42, - PIT_CTRL = 0x43, - PIT_SPEAKER_PORT = 0x61, -}; - - -enum { - PIT_SPK_TMR2 = 0x01, - PIT_SPK_DATA = 0x02, - PIT_SPK_TMR2_LATCH = 0x20 -}; - -enum { - PIT_CTRL_SELECT_MASK = 0xc0, - PIT_CTRL_SELECT_0 = 0x00, - PIT_CTRL_SELECT_1 = 0x40, - PIT_CTRL_SELECT_2 = 0x80, - - PIT_CTRL_READLOAD_MASK= 0x30, - PIT_CTRL_COUNTER_LATCH = 0x00, - PIT_CTRL_READLOAD_LSB = 0x10, - PIT_CTRL_READLOAD_MSB = 0x20, - PIT_CTRL_READLOAD_WORD = 0x30, - - PIT_CTRL_MODE_MASK = 0x0e, - PIT_CTRL_INTR_ON_TERM = 0x00, - PIT_CTRL_PROGR_ONE_SHOT = 0x02, - - PIT_CTRL_RATE_GEN = 0x04, - - PIT_CTRL_SQUAREWAVE_GEN = 0x06, - PIT_CTRL_SOFTSTROBE = 0x08, - - PIT_CTRL_HARDSTROBE = 0x0a, - - - PIT_CTRL_COUNT_MASK = 0x01, - PIT_CTRL_COUNT_BINARY = 0x00, - PIT_CTRL_COUNT_BCD = 0x01 -}; - - -static void -make_tone (uint16_t freq_count, unsigned int duration) -{ - outb (PIT_CTRL_SELECT_2 - | PIT_CTRL_READLOAD_WORD - | PIT_CTRL_SQUAREWAVE_GEN - | PIT_CTRL_COUNT_BINARY, PIT_CTRL); - - outb (freq_count & 0xff, PIT_COUNTER_2); - - outb ((freq_count >> 8) & 0xff, PIT_COUNTER_2); - - outb (inb (PIT_SPEAKER_PORT) - | PIT_SPK_TMR2 | PIT_SPK_DATA, - PIT_SPEAKER_PORT); - - for (; duration; duration--) { - unsigned short counter, previous_counter = 0xffff; - while (1) { - counter = inb (PIT_COUNTER_2); - counter |= ((uint16_t) inb (PIT_COUNTER_2)) << 8; - if (counter > previous_counter) - { - previous_counter = counter; - break; - } - previous_counter = counter; - } - } -} - -void spkmodem_tx_byte(unsigned char c) -{ - int i; - - make_tone (SPEAKER_PIT_FREQUENCY / 200, 4); - for (i = 7; i >= 0; i--) { - if ((c >> i) & 1) - make_tone (SPEAKER_PIT_FREQUENCY / 2000, 20); - else - make_tone (SPEAKER_PIT_FREQUENCY / 4000, 40); - make_tone (SPEAKER_PIT_FREQUENCY / 1000, 10); - } - make_tone (SPEAKER_PIT_FREQUENCY / 200, 0); -} - -void spkmodem_init(void) -{ - /* Some cards need time to come online. Output some message to get it started. */ - spkmodem_tx_byte('S'); - spkmodem_tx_byte('P'); - spkmodem_tx_byte('K'); - spkmodem_tx_byte('\r'); - spkmodem_tx_byte('\n'); -} diff --git a/src/drivers/pc80/tpm/Makefile.inc b/src/drivers/pc80/tpm/Makefile.inc index 697842fa03..0068ff19a6 100644 --- a/src/drivers/pc80/tpm/Makefile.inc +++ b/src/drivers/pc80/tpm/Makefile.inc @@ -1,4 +1,8 @@ +ifeq ($(CONFIG_ARCH_X86),y) + verstage-$(CONFIG_LPC_TPM) += tpm.c romstage-$(CONFIG_LPC_TPM) += tpm.c ramstage-$(CONFIG_LPC_TPM) += tpm.c romstage-$(CONFIG_LPC_TPM) += romstage.c + +endif diff --git a/src/drivers/pc80/udelay_io.c b/src/drivers/pc80/udelay_io.c deleted file mode 100644 index 1cdc6739c1..0000000000 --- a/src/drivers/pc80/udelay_io.c +++ /dev/null @@ -1,13 +0,0 @@ -#include -#include - -void init_timer(void) -{ -} - -void udelay(unsigned usecs) -{ - int i; - for(i = 0; i < usecs; i++) - inb(0x80); -} diff --git a/src/drivers/pc80/vga/Makefile.inc b/src/drivers/pc80/vga/Makefile.inc index d4b726a388..3e31de1ddf 100644 --- a/src/drivers/pc80/vga/Makefile.inc +++ b/src/drivers/pc80/vga/Makefile.inc @@ -1,4 +1,8 @@ +ifeq ($(CONFIG_ARCH_X86),y) + ramstage-$(CONFIG_VGA) += vga_io.c ramstage-$(CONFIG_VGA) += vga_palette.c ramstage-$(CONFIG_VGA) += vga_font_8x16.c ramstage-$(CONFIG_VGA) += vga.c + +endif diff --git a/src/ec/compal/ene932/acpi/superio.asl b/src/ec/compal/ene932/acpi/superio.asl index 5474cdc9f5..8eba623417 100644 --- a/src/ec/compal/ene932/acpi/superio.asl +++ b/src/ec/compal/ene932/acpi/superio.asl @@ -21,6 +21,6 @@ Device (SIO) { // Keyboard or AUX port (a.k.a Mouse) #ifdef SIO_EC_ENABLE_PS2K - #include + #include #endif } diff --git a/src/include/pc80/mc146818rtc.h b/src/include/pc80/mc146818rtc.h index 38f2ad085c..f5630c586b 100644 --- a/src/include/pc80/mc146818rtc.h +++ b/src/include/pc80/mc146818rtc.h @@ -179,7 +179,7 @@ enum cb_err get_option(void *dest, const char *name); unsigned read_option_lowlevel(unsigned start, unsigned size, unsigned def); #else /* defined(__ROMCC__) */ -#include +#include #endif /* !defined(__ROMCC__) */ #define read_option(name, default) read_option_lowlevel(CMOS_VSTART_ ##name, CMOS_VLEN_ ##name, (default)) diff --git a/src/mainboard/dmp/vortex86ex/romstage.c b/src/mainboard/dmp/vortex86ex/romstage.c index d84af32684..a6aa59b5dc 100644 --- a/src/mainboard/dmp/vortex86ex/romstage.c +++ b/src/mainboard/dmp/vortex86ex/romstage.c @@ -21,7 +21,7 @@ #include #include #include -#include "drivers/pc80/i8254.c" +#include "drivers/pc80/pc/i8254.c" #include #include #include "northbridge/dmp/vortex86ex/raminit.c" diff --git a/src/mainboard/jetway/nf81-t56n-lf/acpi/superio.asl b/src/mainboard/jetway/nf81-t56n-lf/acpi/superio.asl index 713a12587b..4f23d99904 100644 --- a/src/mainboard/jetway/nf81-t56n-lf/acpi/superio.asl +++ b/src/mainboard/jetway/nf81-t56n-lf/acpi/superio.asl @@ -15,4 +15,4 @@ * GNU General Public License for more details. */ -#include +#include diff --git a/src/mainboard/lenovo/t420/acpi/superio.asl b/src/mainboard/lenovo/t420/acpi/superio.asl index 03b65bc816..f2b35ba9c1 100644 --- a/src/mainboard/lenovo/t420/acpi/superio.asl +++ b/src/mainboard/lenovo/t420/acpi/superio.asl @@ -1 +1 @@ -#include +#include diff --git a/src/mainboard/lenovo/t420s/acpi/superio.asl b/src/mainboard/lenovo/t420s/acpi/superio.asl index 03b65bc816..f2b35ba9c1 100644 --- a/src/mainboard/lenovo/t420s/acpi/superio.asl +++ b/src/mainboard/lenovo/t420s/acpi/superio.asl @@ -1 +1 @@ -#include +#include diff --git a/src/mainboard/lenovo/t430s/acpi/superio.asl b/src/mainboard/lenovo/t430s/acpi/superio.asl index 03b65bc816..f2b35ba9c1 100644 --- a/src/mainboard/lenovo/t430s/acpi/superio.asl +++ b/src/mainboard/lenovo/t430s/acpi/superio.asl @@ -1 +1 @@ -#include +#include diff --git a/src/mainboard/lenovo/t520/acpi/superio.asl b/src/mainboard/lenovo/t520/acpi/superio.asl index 03b65bc816..f2b35ba9c1 100644 --- a/src/mainboard/lenovo/t520/acpi/superio.asl +++ b/src/mainboard/lenovo/t520/acpi/superio.asl @@ -1 +1 @@ -#include +#include diff --git a/src/mainboard/lenovo/t530/acpi/superio.asl b/src/mainboard/lenovo/t530/acpi/superio.asl index 03b65bc816..f2b35ba9c1 100644 --- a/src/mainboard/lenovo/t530/acpi/superio.asl +++ b/src/mainboard/lenovo/t530/acpi/superio.asl @@ -1 +1 @@ -#include +#include diff --git a/src/mainboard/lenovo/x201/acpi/superio.asl b/src/mainboard/lenovo/x201/acpi/superio.asl index 03b65bc816..f2b35ba9c1 100644 --- a/src/mainboard/lenovo/x201/acpi/superio.asl +++ b/src/mainboard/lenovo/x201/acpi/superio.asl @@ -1 +1 @@ -#include +#include diff --git a/src/mainboard/lenovo/x220/acpi/superio.asl b/src/mainboard/lenovo/x220/acpi/superio.asl index 03b65bc816..f2b35ba9c1 100644 --- a/src/mainboard/lenovo/x220/acpi/superio.asl +++ b/src/mainboard/lenovo/x220/acpi/superio.asl @@ -1 +1 @@ -#include +#include diff --git a/src/mainboard/lenovo/x230/acpi/superio.asl b/src/mainboard/lenovo/x230/acpi/superio.asl index 03b65bc816..f2b35ba9c1 100644 --- a/src/mainboard/lenovo/x230/acpi/superio.asl +++ b/src/mainboard/lenovo/x230/acpi/superio.asl @@ -1 +1 @@ -#include +#include diff --git a/src/mainboard/packardbell/ms2290/acpi/superio.asl b/src/mainboard/packardbell/ms2290/acpi/superio.asl index 03b65bc816..f2b35ba9c1 100644 --- a/src/mainboard/packardbell/ms2290/acpi/superio.asl +++ b/src/mainboard/packardbell/ms2290/acpi/superio.asl @@ -1 +1 @@ -#include +#include diff --git a/src/mainboard/purism/librem13/acpi/superio.asl b/src/mainboard/purism/librem13/acpi/superio.asl index 6b18bb58d5..92c272e4b6 100644 --- a/src/mainboard/purism/librem13/acpi/superio.asl +++ b/src/mainboard/purism/librem13/acpi/superio.asl @@ -13,4 +13,4 @@ * GNU General Public License for more details. */ -#include +#include diff --git a/src/northbridge/via/vx900/Makefile.inc b/src/northbridge/via/vx900/Makefile.inc index 44f0ae01ce..b46f8809d6 100644 --- a/src/northbridge/via/vx900/Makefile.inc +++ b/src/northbridge/via/vx900/Makefile.inc @@ -27,7 +27,7 @@ romstage-y += ./../../../southbridge/via/common/early_smbus_is_busy.c romstage-y += ./../../../southbridge/via/common/early_smbus_print_error.c romstage-y += ./../../../southbridge/via/common/early_smbus_reset.c romstage-y += ./../../../southbridge/via/common/early_smbus_wait_until_ready.c -romstage-y += ./../../../drivers/pc80/udelay_io.c +romstage-y += ./../../../drivers/pc80/pc/udelay_io.c ramstage-y += pci_util.c ramstage-y += pcie.c -- cgit v1.2.3