diff options
author | Kyösti Mälkki <kyosti.malkki@gmail.com> | 2022-11-08 04:43:41 +0000 |
---|---|---|
committer | Kyösti Mälkki <kyosti.malkki@gmail.com> | 2022-11-09 18:10:54 +0000 |
commit | 7b73e85283bea7f456ab2f86ed1d1099eb88bc2f (patch) | |
tree | a5aba9ebe735e4f904b5edad8f6b6ddf6122d607 /src/southbridge/intel/i82801dx | |
parent | c8a20b9d3b8939e4b7d259c5857631c9690657de (diff) |
Revert "mb/aopen/dxplplusu: Remove board"
This reverts commit eb76a455cd39ec59b7f2ba28baeec9538befd59e
and applies minor fixes to make it build again.
PARALLEL_MP was working prior to board removal and no
relevant SMI handlers were implemented. So NO_SMM choice
is now selected.
Change-Id: Ia1cd02278240d1b5d006fb2a7730d3d86390f85b
Signed-off-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/69339
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
Diffstat (limited to 'src/southbridge/intel/i82801dx')
-rw-r--r-- | src/southbridge/intel/i82801dx/Kconfig | 21 | ||||
-rw-r--r-- | src/southbridge/intel/i82801dx/Makefile.inc | 17 | ||||
-rw-r--r-- | src/southbridge/intel/i82801dx/ac97.c | 262 | ||||
-rw-r--r-- | src/southbridge/intel/i82801dx/bootblock.c | 11 | ||||
-rw-r--r-- | src/southbridge/intel/i82801dx/chip.h | 28 | ||||
-rw-r--r-- | src/southbridge/intel/i82801dx/early_smbus.c | 9 | ||||
-rw-r--r-- | src/southbridge/intel/i82801dx/fadt.c | 80 | ||||
-rw-r--r-- | src/southbridge/intel/i82801dx/i82801dx.c | 67 | ||||
-rw-r--r-- | src/southbridge/intel/i82801dx/i82801dx.h | 171 | ||||
-rw-r--r-- | src/southbridge/intel/i82801dx/ide.c | 64 | ||||
-rw-r--r-- | src/southbridge/intel/i82801dx/lpc.c | 328 | ||||
-rw-r--r-- | src/southbridge/intel/i82801dx/usb.c | 45 | ||||
-rw-r--r-- | src/southbridge/intel/i82801dx/usb2.c | 32 |
13 files changed, 1135 insertions, 0 deletions
diff --git a/src/southbridge/intel/i82801dx/Kconfig b/src/southbridge/intel/i82801dx/Kconfig new file mode 100644 index 0000000000..98c1a477ff --- /dev/null +++ b/src/southbridge/intel/i82801dx/Kconfig @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config SOUTHBRIDGE_INTEL_I82801DX + bool + select ACPI_INTEL_HARDWARE_SLEEP_VALUES + select SOUTHBRIDGE_INTEL_COMMON_SMBUS + select SOUTHBRIDGE_INTEL_COMMON_EARLY_SMBUS + select SOUTHBRIDGE_INTEL_COMMON_RTC + select SOUTHBRIDGE_INTEL_COMMON_RESET + select SOUTHBRIDGE_INTEL_COMMON_USB_DEBUG + select HAVE_POWER_STATE_AFTER_FAILURE + select HAVE_POWER_STATE_PREVIOUS_AFTER_FAILURE + select BOOT_DEVICE_NOT_SPI_FLASH + +if SOUTHBRIDGE_INTEL_I82801DX + +config EHCI_BAR + hex + default 0xfef00000 + +endif diff --git a/src/southbridge/intel/i82801dx/Makefile.inc b/src/southbridge/intel/i82801dx/Makefile.inc new file mode 100644 index 0000000000..c352e3e9e8 --- /dev/null +++ b/src/southbridge/intel/i82801dx/Makefile.inc @@ -0,0 +1,17 @@ +## SPDX-License-Identifier: GPL-2.0-only + +ifeq ($(CONFIG_SOUTHBRIDGE_INTEL_I82801DX),y) + +ramstage-y += i82801dx.c +ramstage-y += ac97.c +ramstage-y += fadt.c +ramstage-y += ide.c +ramstage-y += lpc.c +ramstage-y += usb.c +ramstage-y += usb2.c + +romstage-y += early_smbus.c + +bootblock-y += bootblock.c + +endif diff --git a/src/southbridge/intel/i82801dx/ac97.c b/src/southbridge/intel/i82801dx/ac97.c new file mode 100644 index 0000000000..bca35eb7c9 --- /dev/null +++ b/src/southbridge/intel/i82801dx/ac97.c @@ -0,0 +1,262 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <arch/io.h> +#include <device/pci_ops.h> +#include <delay.h> +#include "i82801dx.h" + +#define NAMBAR 0x10 +#define MASTER_VOL 0x02 +#define PAGING 0x24 +#define EXT_AUDIO 0x28 +#define FUNC_SEL 0x66 +#define INFO_IO 0x68 +#define CONNECTOR 0x6a +#define VENDOR_ID1 0x7c +#define VENDOR_ID2 0x7e +#define SEC_VENDOR_ID1 0xfc +#define SEC_VENDOR_ID2 0xfe + +#define NABMBAR 0x14 +#define GLOB_CNT 0x2c +#define GLOB_STA 0x30 +#define CAS 0x34 + +#define MMBAR 0x10 +#define EXT_MODEM_ID1 0x3c +#define EXT_MODEM_ID2 0xbc + +#define MBAR 0x14 +#define SEC_CODEC 0x40 + +/* FIXME. This table is probably mainboard specific */ +static u16 ac97_function[16*2][4] = { + { (1 << 5), (2 << 11), (1 << 10), (3 << 13) }, + { (1 << 5), (2 << 11), (1 << 10), (3 << 13) }, + { (1 << 5), (2 << 11), (1 << 10), (3 << 13) }, + { (1 << 5), (2 << 11), (1 << 10), (3 << 13) }, + { (1 << 5), (2 << 11), (1 << 10), (3 << 13) }, + { (1 << 5), (2 << 11), (1 << 10), (3 << 13) }, + { (1 << 5), (2 << 11), (1 << 10), (3 << 13) }, + { (1 << 5), (2 << 11), (1 << 10), (3 << 13) }, + { (1 << 5), (2 << 11), (1 << 10), (3 << 13) }, + { (1 << 5), (2 << 11), (1 << 10), (3 << 13) }, + { (1 << 5), (2 << 11), (1 << 10), (3 << 13) }, + { (1 << 5), (2 << 11), (1 << 10), (3 << 13) }, + { (1 << 5), (2 << 11), (1 << 10), (3 << 13) }, + { (1 << 5), (2 << 11), (1 << 10), (3 << 13) }, + { (1 << 5), (2 << 11), (1 << 10), (3 << 13) }, + { (1 << 5), (2 << 11), (1 << 10), (3 << 13) }, + { (1 << 5), (2 << 11), (1 << 10), (3 << 13) }, + { (1 << 5), (2 << 11), (1 << 10), (3 << 13) }, + { (1 << 5), (2 << 11), (1 << 10), (3 << 13) }, + { (1 << 5), (2 << 11), (1 << 10), (3 << 13) }, + { (1 << 5), (2 << 11), (1 << 10), (3 << 13) }, + { (1 << 5), (2 << 11), (1 << 10), (3 << 13) }, + { (1 << 5), (2 << 11), (1 << 10), (3 << 13) }, + { (1 << 5), (2 << 11), (1 << 10), (3 << 13) }, + { (1 << 5), (2 << 11), (1 << 10), (3 << 13) }, + { (1 << 5), (2 << 11), (1 << 10), (3 << 13) }, + { (1 << 5), (2 << 11), (1 << 10), (3 << 13) }, + { (1 << 5), (2 << 11), (1 << 10), (3 << 13) }, + { (1 << 5), (2 << 11), (1 << 10), (3 << 13) }, + { (1 << 5), (2 << 11), (1 << 10), (3 << 13) }, + { (1 << 5), (2 << 11), (1 << 10), (3 << 13) }, + { (1 << 5), (2 << 11), (1 << 10), (3 << 13) } +}; + +static u16 nabmbar; +static u16 nambar; + +static int ac97_semaphore(void) +{ + int timeout; + u8 reg8; + + timeout = 0xffff; + do { + reg8 = inb(nabmbar + CAS); + timeout--; + } while ((reg8 & 1) && timeout); + if (!timeout) + printk(BIOS_DEBUG, "Timeout!\n"); + + return (!timeout); +} + +static void init_cnr(void) +{ + // TODO +} + +static void program_sigid(struct device *dev, u32 id) +{ + pci_write_config32(dev, 0x2c, id); +} + +static void ac97_audio_init(struct device *dev) +{ + u16 reg16; + u32 reg32; + int i; + + printk(BIOS_DEBUG, "Initializing AC'97 Audio.\n"); + + /* top 16 bits are zero, so don't read them */ + nabmbar = pci_read_config16(dev, NABMBAR) & 0xfffe; + nambar = pci_read_config16(dev, NAMBAR) & 0xfffe; + + reg16 = inw(nabmbar + GLOB_CNT); + reg16 |= (1 << 1); /* Remove AC_RESET# */ + outw(reg16, nabmbar + GLOB_CNT); + + /* Wait 600ms. Ouch. */ + udelay(600 * 1000); + + init_cnr(); + + /* Detect Primary AC'97 Codec */ + reg32 = inl(nabmbar + GLOB_STA); + if ((reg32 & ((1 << 28) | (1 << 9) | (1 << 8))) == 0) { + /* Primary Codec not found */ + printk(BIOS_DEBUG, "No primary codec. Disabling AC'97 Audio.\n"); + return; + } + + ac97_semaphore(); + + /* Detect if codec is programmable */ + outw(0x8000, nambar + MASTER_VOL); + ac97_semaphore(); + if (inw(nambar + MASTER_VOL) != 0x8000) { + printk(BIOS_DEBUG, "Codec not programmable. Disabling AC'97 Audio.\n"); + return; + } + + /* Program Vendor IDs */ + reg32 = inw(nambar + VENDOR_ID1); + reg32 <<= 16; + reg32 |= (u16)inw(nambar + VENDOR_ID2); + + program_sigid(dev, reg32); + + /* Is Codec AC'97 2.3 compliant? */ + reg16 = inw(nambar + EXT_AUDIO); + /* [11:10] = 10b -> AC'97 2.3 */ + if ((reg16 & 0x0c00) != 0x0800) { + /* No 2.3 Codec. We're done */ + return; + } + + /* Select Page 1 */ + reg16 = inw(nambar + PAGING); + reg16 &= 0xfff0; + reg16 |= 0x0001; + outw(reg16, nambar + PAGING); + + for (i = 0x0a * 2; i > 0; i--) { + outw(i, nambar + FUNC_SEL); + + /* Function could not be selected. Next one */ + if (inw(nambar + FUNC_SEL) != i) + continue; + + reg16 = inw(nambar + INFO_IO); + + /* Function Information present? */ + if (!(reg16 & (1 << 0))) + continue; + + /* Function Information valid? */ + if (!(reg16 & (1 << 4))) + continue; + + /* Program Buffer Delay [9:5] */ + reg16 &= 0x03e0; + reg16 |= ac97_function[i][0]; + + /* Program Gain [15:11] */ + reg16 |= ac97_function[i][1]; + + /* Program Inversion [10] */ + reg16 |= ac97_function[i][2]; + + outw(reg16, nambar + INFO_IO); + + /* Program Connector / Jack Location */ + reg16 = inw(nambar + CONNECTOR); + reg16 &= 0x1fff; + reg16 |= ac97_function[i][3]; + outw(reg16, nambar + CONNECTOR); + } +} + +static void ac97_modem_init(struct device *dev) +{ + u16 reg16; + u32 reg32; + u16 mmbar, mbar; + + mmbar = pci_read_config16(dev, MMBAR) & 0xfffe; + mbar = pci_read_config16(dev, MBAR) & 0xfffe; + + reg16 = inw(mmbar + EXT_MODEM_ID1); + if ((reg16 & 0xc000) != 0xc000) { + if (reg16 & (1 << 0)) { + reg32 = inw(mmbar + VENDOR_ID2); + reg32 <<= 16; + reg32 |= (u16)inw(mmbar + VENDOR_ID1); + program_sigid(dev, reg32); + return; + } + } + + /* Secondary codec? */ + reg16 = inw(mbar + SEC_CODEC); + if ((reg16 & (1 << 9)) == 0) + return; + + reg16 = inw(mmbar + EXT_MODEM_ID2); + if ((reg16 & 0xc000) == 0x4000) { + if (reg16 & (1 << 0)) { + reg32 = inw(mmbar + SEC_VENDOR_ID2); + reg32 <<= 16; + reg32 |= (u16)inw(mmbar + SEC_VENDOR_ID1); + program_sigid(dev, reg32); + return; + } + } +} + +static struct device_operations ac97_audio_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .enable = i82801dx_enable, + .init = ac97_audio_init, +}; + +static struct device_operations ac97_modem_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .enable = i82801dx_enable, + .init = ac97_modem_init, +}; + +/* 82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) */ +static const struct pci_driver i82801db_ac97_audio __pci_driver = { + .ops = &ac97_audio_ops, + .vendor = PCI_VID_INTEL, + .device = PCI_DID_INTEL_82801DB_AC97_AUDIO, +}; + +static const struct pci_driver i82801db_ac97_modem __pci_driver = { + .ops = &ac97_modem_ops, + .vendor = PCI_VID_INTEL, + .device = PCI_DID_INTEL_82801DB_AC97_MODEM, +}; diff --git a/src/southbridge/intel/i82801dx/bootblock.c b/src/southbridge/intel/i82801dx/bootblock.c new file mode 100644 index 0000000000..6cda0a87a4 --- /dev/null +++ b/src/southbridge/intel/i82801dx/bootblock.c @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <arch/bootblock.h> +#include <device/pci_ops.h> + +void bootblock_early_southbridge_init(void) +{ + /* Set FWH IDs for 2 MB flash part. */ + if (CONFIG_ROM_SIZE == 0x200000) + pci_write_config32(PCI_DEV(0, 0x1f, 0), 0xe8, 0x00001111); +} diff --git a/src/southbridge/intel/i82801dx/chip.h b/src/southbridge/intel/i82801dx/chip.h new file mode 100644 index 0000000000..50f4f1c998 --- /dev/null +++ b/src/southbridge/intel/i82801dx/chip.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef I82801DX_CHIP_H +#define I82801DX_CHIP_H + +#include <stdint.h> + +struct southbridge_intel_i82801dx_config { + int enable_usb; + int enable_native_ide; + /** + * Interrupt Routing configuration + * If bit7 is 1, the interrupt is disabled. + */ + uint8_t pirqa_routing; + uint8_t pirqb_routing; + uint8_t pirqc_routing; + uint8_t pirqd_routing; + uint8_t pirqe_routing; + uint8_t pirqf_routing; + uint8_t pirqg_routing; + uint8_t pirqh_routing; + + uint8_t ide0_enable; + uint8_t ide1_enable; +}; + +#endif /* I82801DX_CHIP_H */ diff --git a/src/southbridge/intel/i82801dx/early_smbus.c b/src/southbridge/intel/i82801dx/early_smbus.c new file mode 100644 index 0000000000..76ef1b8a15 --- /dev/null +++ b/src/southbridge/intel/i82801dx/early_smbus.c @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <device/smbus_host.h> +#include "i82801dx.h" + +void i82801dx_early_init(void) +{ + enable_smbus(); +} diff --git a/src/southbridge/intel/i82801dx/fadt.c b/src/southbridge/intel/i82801dx/fadt.c new file mode 100644 index 0000000000..e12b2cae1f --- /dev/null +++ b/src/southbridge/intel/i82801dx/fadt.c @@ -0,0 +1,80 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <device/pci_ops.h> +#include <acpi/acpi.h> +#include <version.h> + +/* FIXME: This needs to go into a separate .h file + * to be included by the ich7 smi handler, ich7 smi init + * code and the mainboard fadt. + */ +#define APM_CNT 0x0 /* ACPI mode only */ +#define CST_CONTROL 0x85 +#define PST_CONTROL 0x0 +#define ACPI_DISABLE 0xAA +#define ACPI_ENABLE 0x55 +#define S4_BIOS 0x77 +#define GNVS_UPDATE 0xea + +void acpi_fill_fadt(acpi_fadt_t *fadt) +{ + u16 pmbase = pci_read_config16(pcidev_on_root(0x1f, 0), 0x40) & 0xfffe; + + fadt->sci_int = 0x9; + + if (permanent_smi_handler()) { + fadt->smi_cmd = APM_CNT; + fadt->acpi_enable = ACPI_ENABLE; + fadt->acpi_disable = ACPI_DISABLE; + fadt->pstate_cnt = PST_CONTROL; + } + + fadt->pm1a_evt_blk = pmbase; + fadt->pm1a_cnt_blk = pmbase + 0x4; + fadt->pm_tmr_blk = pmbase + 0x8; + fadt->gpe0_blk = pmbase + 0x28; + + fadt->pm1_evt_len = 4; + fadt->pm1_cnt_len = 2; + fadt->pm_tmr_len = 4; + fadt->gpe0_blk_len = 8; + fadt->p_lvl2_lat = 1; + fadt->p_lvl3_lat = 85; + fadt->duty_offset = 1; + fadt->duty_width = 0; + fadt->day_alrm = 0xd; + fadt->mon_alrm = 0x00; + fadt->iapc_boot_arch = ACPI_FADT_LEGACY_DEVICES | ACPI_FADT_8042; + + fadt->flags |= ACPI_FADT_WBINVD | ACPI_FADT_C1_SUPPORTED | + ACPI_FADT_C2_MP_SUPPORTED | ACPI_FADT_SLEEP_BUTTON | + ACPI_FADT_S4_RTC_WAKE | ACPI_FADT_PLATFORM_CLOCK; + + fadt->x_pm1a_evt_blk.space_id = ACPI_ADDRESS_SPACE_IO; + fadt->x_pm1a_evt_blk.bit_width = fadt->pm1_evt_len * 8; + fadt->x_pm1a_evt_blk.bit_offset = 0; + fadt->x_pm1a_evt_blk.access_size = ACPI_ACCESS_SIZE_UNDEFINED; + fadt->x_pm1a_evt_blk.addrl = fadt->pm1a_evt_blk; + fadt->x_pm1a_evt_blk.addrh = 0x0; + + fadt->x_pm1a_cnt_blk.space_id = ACPI_ADDRESS_SPACE_IO; + fadt->x_pm1a_cnt_blk.bit_width = fadt->pm1_cnt_len * 8; + fadt->x_pm1a_cnt_blk.bit_offset = 0; + fadt->x_pm1a_cnt_blk.access_size = ACPI_ACCESS_SIZE_UNDEFINED; + fadt->x_pm1a_cnt_blk.addrl = fadt->pm1a_cnt_blk; + fadt->x_pm1a_cnt_blk.addrh = 0x0; + + fadt->x_pm_tmr_blk.space_id = ACPI_ADDRESS_SPACE_IO; + fadt->x_pm_tmr_blk.bit_width = fadt->pm_tmr_len * 8; + fadt->x_pm_tmr_blk.bit_offset = 0; + fadt->x_pm_tmr_blk.access_size = ACPI_ACCESS_SIZE_UNDEFINED; + fadt->x_pm_tmr_blk.addrl = fadt->pm_tmr_blk; + fadt->x_pm_tmr_blk.addrh = 0x0; + + fadt->x_gpe0_blk.space_id = ACPI_ADDRESS_SPACE_IO; + fadt->x_gpe0_blk.bit_width = fadt->gpe0_blk_len * 8; + fadt->x_gpe0_blk.bit_offset = 0; + fadt->x_gpe0_blk.access_size = ACPI_ACCESS_SIZE_UNDEFINED; + fadt->x_gpe0_blk.addrl = fadt->gpe0_blk; + fadt->x_gpe0_blk.addrh = 0x0; +} diff --git a/src/southbridge/intel/i82801dx/i82801dx.c b/src/southbridge/intel/i82801dx/i82801dx.c new file mode 100644 index 0000000000..921cb1c8aa --- /dev/null +++ b/src/southbridge/intel/i82801dx/i82801dx.c @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ops.h> +#include "i82801dx.h" + +void i82801dx_enable(struct device *dev) +{ + unsigned int index = 0; + uint8_t bHasDisableBit = 0; + uint16_t cur_disable_mask, new_disable_mask; + +// all 82801dbm devices are in bus 0 + unsigned int devfn = PCI_DEVFN(0x1f, 0); // lpc + struct device *lpc_dev = pcidev_path_on_root(devfn); // 0 + if (!lpc_dev) + return; + + // Calculate disable bit position for specified device:function + // NOTE: For ICH-4, only the following devices can be disabled: + // D31: F0, F1, F3, F5, F6, + // D29: F0, F1, F2, F7 + + if (PCI_SLOT(dev->path.pci.devfn) == 31) { + index = PCI_FUNC(dev->path.pci.devfn); + + switch (index) { + case 0: + case 1: + case 3: + case 5: + case 6: + bHasDisableBit = 1; + break; + + default: + break; + }; + + if (index == 0) + index = 14; // D31:F0 bit is an exception + + } else if (PCI_SLOT(dev->path.pci.devfn) == 29) { + index = 8 + PCI_FUNC(dev->path.pci.devfn); + + if ((PCI_FUNC(dev->path.pci.devfn) < 3) + || (PCI_FUNC(dev->path.pci.devfn) == 7)) + bHasDisableBit = 1; + } + + if (bHasDisableBit) { + cur_disable_mask = pci_read_config16(lpc_dev, FUNC_DIS); + new_disable_mask = cur_disable_mask & ~(1 << index); // enable it + if (!dev->enabled) { + new_disable_mask |= (1 << index); // disable it + } + if (new_disable_mask != cur_disable_mask) { + pci_write_config16(lpc_dev, FUNC_DIS, new_disable_mask); + } + } +} + +struct chip_operations southbridge_intel_i82801dx_ops = { + CHIP_NAME("Intel ICH4/ICH4-M (82801Dx) Series Southbridge") + .enable_dev = i82801dx_enable, +}; diff --git a/src/southbridge/intel/i82801dx/i82801dx.h b/src/southbridge/intel/i82801dx/i82801dx.h new file mode 100644 index 0000000000..e63327c01e --- /dev/null +++ b/src/southbridge/intel/i82801dx/i82801dx.h @@ -0,0 +1,171 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* the problem: we have 82801dbm support in fb1, and 82801er in fb2. + * fb1 code is what we want, fb2 structure is needed however. + * so we need to get fb1 code for 82801dbm into fb2 structure. + */ +/* What I did: took the 80801er stuff from fb2, verify it against the + * db stuff in fb1, and made sure it was right. + */ + +#ifndef I82801DX_H +#define I82801DX_H + +#include <acpi/acpi.h> + +#if !defined(__ASSEMBLER__) + +#include <device/device.h> + +void i82801dx_enable(struct device *dev); +void i82801dx_early_init(void); + +#endif + +#define DEBUG_PERIODIC_SMIS 0 + +#define MAINBOARD_POWER_OFF 0 +#define MAINBOARD_POWER_ON 1 +#define MAINBOARD_POWER_KEEP 2 + +/* + * 000 = Non-combined. P0 is primary master. P1 is secondary master. + * 001 = Non-combined. P0 is secondary master. P1 is primary master. + * 100 = Combined. P0 is primary master. P1 is primary slave. IDE is secondary; + * Primary IDE channel disabled. + * 101 = Combined. P0 is primary slave. P1 is primary master. IDE is secondary. + * 110 = Combined. IDE is primary. P0 is secondary master. P1 is secondary + * slave; Secondary IDE channel disabled. + * 111 = Combined. IDE is primary. P0 is secondary slave. P1 is secondary master. + */ +/* PCI Configuration Space (D31:F1) */ +#define IDE_TIM_PRI 0x40 /* IDE timings, primary */ +#define IDE_TIM_SEC 0x42 /* IDE timings, secondary */ + +/* IDE_TIM bits */ +#define IDE_DECODE_ENABLE (1 << 15) + +#define PCI_DMA_CFG 0x90 +#define SERIRQ_CNTL 0x64 +#define GEN_CNTL 0xd0 +#define GEN_STS 0xd4 +#define RTC_CONF 0xd8 +#define GEN_PMCON_3 0xa4 + +#define PCICMD 0x04 +#define PMBASE 0x40 +#define PMBASE_ADDR 0x0400 +#define DEFAULT_PMBASE PMBASE_ADDR +#define ACPI_CNTL 0x44 +#define ACPI_EN (1 << 4) +#define BIOS_CNTL 0x4E +#define GPIO_BASE 0x58 +#define GPIO_CNTL 0x5C +#define GPIOBASE_ADDR 0x0500 +#define PIRQA_ROUT 0x60 +#define PIRQB_ROUT 0x61 +#define PIRQC_ROUT 0x62 +#define PIRQD_ROUT 0x63 +#define PIRQE_ROUT 0x68 +#define PIRQF_ROUT 0x69 +#define PIRQG_ROUT 0x6A +#define PIRQH_ROUT 0x6B +#define COM_DEC 0xE0 +#define LPC_EN 0xE6 +#define FUNC_DIS 0xF2 + +/* 1e f0 244e */ + +#define CMD 0x04 +#define SBUS_NUM 0x19 +#define SUB_BUS_NUM 0x1A +#define SMLT 0x1B +#define IOBASE 0x1C +#define IOLIM 0x1D +#define MEMBASE 0x20 +#define MEMLIM 0x22 +#define CNF 0x50 +#define MTT 0x70 +#define PCI_MAST_STS 0x82 + +#define RTC_FAILED (1 << 2) + +#define PM1_STS 0x00 +#define WAK_STS (1 << 15) +#define PCIEXPWAK_STS (1 << 14) +#define PRBTNOR_STS (1 << 11) +#define RTC_STS (1 << 10) +#define PWRBTN_STS (1 << 8) +#define GBL_STS (1 << 5) +#define BM_STS (1 << 4) +#define TMROF_STS (1 << 0) +#define PM1_EN 0x02 +#define PCIEXPWAK_DIS (1 << 14) +#define RTC_EN (1 << 10) +#define PWRBTN_EN (1 << 8) +#define GBL_EN (1 << 5) +#define TMROF_EN (1 << 0) +#define PM1_CNT 0x04 +#define GBL_RLS (1 << 2) +#define BM_RLD (1 << 1) +#define SCI_EN (1 << 0) +#define PM1_TMR 0x08 +#define PROC_CNT 0x10 +#define LV2 0x14 +#define LV3 0x15 +#define LV4 0x16 +#define PM2_CNT 0x20 // mobile only +#define GPE0_STS 0x28 +#define PME_B0_STS (1 << 13) +#define USB3_STS (1 << 12) +#define PME_STS (1 << 11) +#define BATLOW_STS (1 << 10) +#define GST_STS (1 << 9) +#define RI_STS (1 << 8) +#define SMB_WAK_STS (1 << 7) +#define TCOSCI_STS (1 << 6) +#define AC97_STS (1 << 5) +#define USB2_STS (1 << 4) +#define USB1_STS (1 << 3) +#define SWGPE_STS (1 << 2) +#define HOT_PLUG_STS (1 << 1) +#define THRM_STS (1 << 0) +#define GPE0_EN 0x2c +#define PME_B0_EN (1 << 13) +#define PME_EN (1 << 11) +#define SMI_EN 0x30 +#define EL_SMI_EN (1 << 25) // Intel Quick Resume Technology +#define INTEL_USB2_EN (1 << 18) // Intel-Specific USB2 SMI logic +#define LEGACY_USB2_EN (1 << 17) // Legacy USB2 SMI logic +#define PERIODIC_EN (1 << 14) // SMI on PERIODIC_STS in SMI_STS +#define TCO_EN (1 << 13) // Enable TCO Logic (BIOSWE et al) +#define MCSMI_EN (1 << 11) // Trap microcontroller range access +#define BIOS_RLS (1 << 7) // asserts SCI on bit set +#define SWSMI_TMR_EN (1 << 6) // start software smi timer on bit set +#define APMC_EN (1 << 5) // Writes to APM_CNT cause SMI# +#define SLP_SMI_EN (1 << 4) // Write to SLP_EN in PM1_CNT asserts SMI# +#define LEGACY_USB_EN (1 << 3) // Legacy USB circuit SMI logic +#define BIOS_EN (1 << 2) // Assert SMI# on setting GBL_RLS bit +#define EOS (1 << 1) // End of SMI (deassert SMI#) +#define GBL_SMI_EN (1 << 0) // SMI# generation at all? +#define SMI_STS 0x34 +#define ALT_GP_SMI_EN 0x38 +#define ALT_GP_SMI_STS 0x3a +#define GPE_CNTL 0x42 +#define DEVACT_STS 0x44 +#define SS_CNT 0x50 +#define C3_RES 0x54 + +#define TCOBASE 0x60 /* TCO Base Address Register */ +#define TCO1_CNT 0x08 /* TCO1 Control Register */ + +#define GEN_PMCON_1 0xa0 +#define GEN_PMCON_2 0xa2 +#define GEN_PMCON_3 0xa4 + +/* GEN_PMCON_3 bits */ +#define RTC_BATTERY_DEAD (1 << 2) +#define RTC_POWER_FAILED (1 << 1) +#define SLEEP_AFTER_POWER_FAIL (1 << 0) + +#endif /* I82801DX_H */ diff --git a/src/southbridge/intel/i82801dx/ide.c b/src/southbridge/intel/i82801dx/ide.c new file mode 100644 index 0000000000..a54e49781e --- /dev/null +++ b/src/southbridge/intel/i82801dx/ide.c @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include "chip.h" +#include "i82801dx.h" + +typedef struct southbridge_intel_i82801dx_config config_t; + +static void ide_init(struct device *dev) +{ + /* Get the chip configuration */ + config_t *config = dev->chip_info; + + /* Enable IDE devices so the Linux IDE driver will work. */ + uint16_t ideTimingConfig; + + ideTimingConfig = pci_read_config16(dev, IDE_TIM_PRI); + ideTimingConfig &= ~IDE_DECODE_ENABLE; + if (!config || config->ide0_enable) { + /* Enable primary IDE interface. */ + ideTimingConfig |= IDE_DECODE_ENABLE; + printk(BIOS_DEBUG, "IDE0: Primary IDE interface is enabled\n"); + } else { + printk(BIOS_INFO, "IDE0: Primary IDE interface is disabled\n"); + } + pci_write_config16(dev, IDE_TIM_PRI, ideTimingConfig); + + ideTimingConfig = pci_read_config16(dev, IDE_TIM_SEC); + ideTimingConfig &= ~IDE_DECODE_ENABLE; + if (!config || config->ide1_enable) { + /* Enable secondary IDE interface. */ + ideTimingConfig |= IDE_DECODE_ENABLE; + printk(BIOS_DEBUG, "IDE1: Secondary IDE interface is enabled\n"); + } else { + printk(BIOS_INFO, "IDE1: Secondary IDE interface is disabled\n"); + } + pci_write_config16(dev, IDE_TIM_SEC, ideTimingConfig); +} + +static struct device_operations ide_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = ide_init, + .enable = i82801dx_enable, +}; + +/* 82801DB */ +static const struct pci_driver i82801db_ide __pci_driver = { + .ops = &ide_ops, + .vendor = PCI_VID_INTEL, + .device = 0x24cb, +}; + +/* 82801DBM */ +static const struct pci_driver i82801dbm_ide __pci_driver = { + .ops = &ide_ops, + .vendor = PCI_VID_INTEL, + .device = 0x24ca, +}; diff --git a/src/southbridge/intel/i82801dx/lpc.c b/src/southbridge/intel/i82801dx/lpc.c new file mode 100644 index 0000000000..1de3766563 --- /dev/null +++ b/src/southbridge/intel/i82801dx/lpc.c @@ -0,0 +1,328 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <arch/hpet.h> +#include <arch/io.h> +#include <arch/ioapic.h> +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include <option.h> +#include <pc80/mc146818rtc.h> +#include <pc80/isa-dma.h> +#include <pc80/i8259.h> +#include "chip.h" +#include "i82801dx.h" + +#define NMI_OFF 0 + +typedef struct southbridge_intel_i82801dx_config config_t; + +/** + * Enable ACPI I/O range. + * + * @param dev PCI device with ACPI and PM BAR's + */ +static void i82801dx_enable_acpi(struct device *dev) +{ + /* Set ACPI base address (I/O space). */ + pci_write_config32(dev, PMBASE, (PMBASE_ADDR | 1)); + + /* Enable ACPI I/O range decode and ACPI power management. */ + pci_write_config8(dev, ACPI_CNTL, ACPI_EN); +} + +/** + * Set miscellaneous static southbridge features. + * + * @param dev PCI device with I/O APIC control registers + */ +static void i82801dx_enable_ioapic(struct device *dev) +{ + u32 reg32; + + reg32 = pci_read_config32(dev, GEN_CNTL); + reg32 |= (1 << 13); /* Coprocessor error enable (COPR_ERR_EN) */ + reg32 |= (3 << 7); /* IOAPIC enable (APIC_EN) */ + reg32 |= (1 << 2); /* DMA collection buffer enable (DCB_EN) */ + reg32 |= (1 << 1); /* Delayed transaction enable (DTE) */ + pci_write_config32(dev, GEN_CNTL, reg32); + printk(BIOS_DEBUG, "IOAPIC Southbridge enabled %x\n", reg32); + + setup_ioapic(VIO_APIC_VADDR, 0x02); + + ioapic_set_boot_config(VIO_APIC_VADDR, true); +} + +static void i82801dx_enable_serial_irqs(struct device *dev) +{ + /* Set packet length and toggle silent mode bit. */ + pci_write_config8(dev, SERIRQ_CNTL, + (1 << 7) | (1 << 6) | ((21 - 17) << 2) | (0 << 0)); + pci_write_config8(dev, SERIRQ_CNTL, + (1 << 7) | (0 << 6) | ((21 - 17) << 2) | (0 << 0)); +} + +static void i82801dx_pirq_init(struct device *dev) +{ + /* Get the chip configuration */ + config_t *config = dev->chip_info; + + pci_write_config8(dev, PIRQA_ROUT, config->pirqa_routing); + pci_write_config8(dev, PIRQB_ROUT, config->pirqb_routing); + pci_write_config8(dev, PIRQC_ROUT, config->pirqc_routing); + pci_write_config8(dev, PIRQD_ROUT, config->pirqd_routing); + pci_write_config8(dev, PIRQE_ROUT, config->pirqe_routing); + pci_write_config8(dev, PIRQF_ROUT, config->pirqf_routing); + pci_write_config8(dev, PIRQG_ROUT, config->pirqg_routing); + pci_write_config8(dev, PIRQH_ROUT, config->pirqh_routing); +} + +static void i82801dx_power_options(struct device *dev) +{ + u8 reg8; + u16 reg16, pmbase; + u32 reg32; + const char *state; + + /* Which state do we want to goto after g3 (power restored)? + * 0 == S0 Full On + * 1 == S5 Soft Off + * + * If the option is not existent (Laptops), use MAINBOARD_POWER_ON. + */ + const unsigned int pwr_on = get_uint_option("power_on_after_fail", MAINBOARD_POWER_ON); + + reg8 = pci_read_config8(dev, GEN_PMCON_3); + reg8 &= 0xfe; + switch (pwr_on) { + case MAINBOARD_POWER_OFF: + reg8 |= 1; + state = "off"; + break; + case MAINBOARD_POWER_ON: + reg8 &= ~1; + state = "on"; + break; + case MAINBOARD_POWER_KEEP: + reg8 &= ~1; + state = "state keep"; + break; + default: + state = "undefined"; + } + + reg8 &= ~(1 << 3); /* minimum assertion is 1 to 2 RTCCLK */ + + pci_write_config8(dev, GEN_PMCON_3, reg8); + printk(BIOS_INFO, "Set power %s after power failure.\n", state); + + /* Set up NMI on errors. */ + reg8 = inb(0x61); + reg8 &= 0x0f; /* Higher Nibble must be 0 */ + reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */ + // reg8 &= ~(1 << 2); /* PCI SERR# Enable */ + reg8 |= (1 << 2); /* PCI SERR# Disable for now */ + outb(reg8, 0x61); + + reg8 = inb(0x70); + const unsigned int nmi_option = get_uint_option("nmi", NMI_OFF); + if (nmi_option) { + printk(BIOS_INFO, "NMI sources enabled.\n"); + reg8 &= ~(1 << 7); /* Set NMI. */ + } else { + printk(BIOS_INFO, "NMI sources disabled.\n"); + reg8 |= (1 << 7); /* Disable NMI. */ + } + outb(reg8, 0x70); + + /* Set SMI# rate down and enable CPU_SLP# */ + reg16 = pci_read_config16(dev, GEN_PMCON_1); + reg16 &= ~(3 << 0); // SMI# rate 1 minute + reg16 |= (1 << 5); // CPUSLP_EN Desktop only + pci_write_config16(dev, GEN_PMCON_1, reg16); + + pmbase = pci_read_config16(dev, 0x40) & 0xfffe; + + /* Set up power management block and determine sleep mode */ + reg32 = inl(pmbase + 0x04); // PM1_CNT + + reg32 &= ~(7 << 10); // SLP_TYP + reg32 |= (1 << 0); // SCI_EN + outl(reg32, pmbase + 0x04); +} + +static void gpio_init(struct device *dev) +{ + /* This should be done in romstage.c already */ + pci_write_config32(dev, GPIO_BASE, (GPIOBASE_ADDR | 1)); + pci_write_config8(dev, GPIO_CNTL, 0x10); +} + +static void i82801dx_rtc_init(struct device *dev) +{ + u8 reg8; + u32 reg32; + int rtc_failed; + + reg8 = pci_read_config8(dev, GEN_PMCON_3); + rtc_failed = reg8 & RTC_BATTERY_DEAD; + if (rtc_failed) { + reg8 &= ~(1 << 1); /* Preserve the power fail state. */ + pci_write_config8(dev, GEN_PMCON_3, reg8); + } + reg32 = pci_read_config32(dev, GEN_STS); + rtc_failed |= reg32 & (1 << 2); + cmos_init(rtc_failed); + + /* Enable access to the upper 128 byte bank of CMOS RAM. */ + pci_write_config8(dev, RTC_CONF, 0x04); +} + +static void i82801dx_lpc_route_dma(struct device *dev, u8 mask) +{ + u16 reg16; + int i; + + reg16 = pci_read_config16(dev, PCI_DMA_CFG); + reg16 &= 0x300; + for (i = 0; i < 8; i++) { + if (i == 4) + continue; + reg16 |= ((mask & (1 << i)) ? 3 : 1) << (i * 2); + } + pci_write_config16(dev, PCI_DMA_CFG, reg16); +} + +static void i82801dx_lpc_decode_en(struct device *dev) +{ + /* Decode 0x3F8-0x3FF (COM1) for COMA port, 0x2F8-0x2FF (COM2) for COMB. + * LPT decode defaults to 0x378-0x37F and 0x778-0x77F. + * Floppy decode defaults to 0x3F0-0x3F5, 0x3F7. + * We also need to set the value for LPC I/F Enables Register. + */ + pci_write_config8(dev, COM_DEC, 0x10); + pci_write_config16(dev, LPC_EN, 0x300F); +} + +/* ICH4 does not mention HPET in the docs, but + * all ICH3 and ICH4 do have HPETs built in. + */ +static void enable_hpet(struct device *dev) +{ + u32 reg32, hpet, val; + + /* Set HPET base address and enable it */ + printk(BIOS_DEBUG, "Enabling HPET at 0x%x\n", HPET_BASE_ADDRESS); + reg32 = pci_read_config32(dev, GEN_CNTL); + /* + * Bit 17 is HPET enable bit. + * Bit 16:15 control the HPET base address. + */ + reg32 &= ~(3 << 15); /* Clear it */ + + hpet = HPET_BASE_ADDRESS >> 12; + hpet &= 0x3; + + reg32 |= (hpet << 15); + reg32 |= (1 << 17); /* Enable HPET. */ + pci_write_config32(dev, GEN_CNTL, reg32); + + /* Check to see whether it took */ + reg32 = pci_read_config32(dev, GEN_CNTL); + val = reg32 >> 15; + val &= 0x7; + + if ((val & 0x4) && (hpet == (val & 0x3))) { + printk(BIOS_INFO, "HPET enabled at 0x%x\n", HPET_BASE_ADDRESS); + } else { + printk(BIOS_WARNING, "HPET was not enabled correctly\n"); + reg32 &= ~(1 << 17); /* Clear Enable */ + pci_write_config32(dev, GEN_CNTL, reg32); + } +} + +static void lpc_init(struct device *dev) +{ + i82801dx_enable_acpi(dev); + /* IO APIC initialization. */ + i82801dx_enable_ioapic(dev); + + i82801dx_enable_serial_irqs(dev); + + /* Setup the PIRQ. */ + i82801dx_pirq_init(dev); + + /* Setup power options. */ + i82801dx_power_options(dev); + + /* Set the state of the GPIO lines. */ + gpio_init(dev); + + /* Initialize the real time clock. */ + i82801dx_rtc_init(dev); + + /* Route DMA. */ + i82801dx_lpc_route_dma(dev, 0xff); + + /* Initialize ISA DMA. */ + isa_dma_init(); + + /* Setup decode ports and LPC I/F enables. */ + i82801dx_lpc_decode_en(dev); + + /* Initialize the High Precision Event Timers */ + enable_hpet(dev); + + setup_i8259(); +} + +static void i82801dx_lpc_read_resources(struct device *dev) +{ + struct resource *res; + + /* Get the normal PCI resources of this device. */ + pci_dev_read_resources(dev); + + /* Add an extra subtractive resource for both memory and I/O. */ + res = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0)); + res->base = 0; + res->size = 0x1000; + res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | + IORESOURCE_ASSIGNED | IORESOURCE_FIXED; + + res = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0)); + res->base = 0xff800000; + res->size = 0x00800000; /* 8 MB for flash */ + res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | + IORESOURCE_ASSIGNED | IORESOURCE_FIXED; + + res = new_resource(dev, 3); /* IOAPIC */ + res->base = IO_APIC_ADDR; + res->size = 0x00001000; + res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED; +} + +static struct device_operations lpc_ops = { + .read_resources = i82801dx_lpc_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = lpc_init, + .scan_bus = scan_static_bus, + .enable = i82801dx_enable, +}; + +/* 82801DB/DBL */ +static const struct pci_driver lpc_driver_db __pci_driver = { + .ops = &lpc_ops, + .vendor = PCI_VID_INTEL, + .device = PCI_DID_INTEL_82801DB_LPC, +}; + +/* 82801DBM */ +static const struct pci_driver lpc_driver_dbm __pci_driver = { + .ops = &lpc_ops, + .vendor = PCI_VID_INTEL, + .device = PCI_DID_INTEL_82801DBM_LPC, +}; diff --git a/src/southbridge/intel/i82801dx/usb.c b/src/southbridge/intel/i82801dx/usb.c new file mode 100644 index 0000000000..16ec3077e9 --- /dev/null +++ b/src/southbridge/intel/i82801dx/usb.c @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include "i82801dx.h" + +static void usb_init(struct device *dev) +{ + printk(BIOS_DEBUG, "USB: Setting up controller.. "); + pci_or_config16(dev, PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE); + printk(BIOS_DEBUG, "done.\n"); +} + +static struct device_operations usb_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = usb_init, + .enable = i82801dx_enable, +}; + +/* 82801DB/DBL/DBM USB1 */ +static const struct pci_driver usb_driver_1 __pci_driver = { + .ops = &usb_ops, + .vendor = PCI_VID_INTEL, + .device = PCI_DID_INTEL_82801DB_USB1, +}; + +/* 82801DB/DBL/DBM USB2 */ +static const struct pci_driver usb_driver_2 __pci_driver = { + .ops = &usb_ops, + .vendor = PCI_VID_INTEL, + .device = PCI_DID_INTEL_82801DB_USB2, +}; + +/* 82801DB/DBL/DBM USB3 */ +static const struct pci_driver usb_driver_3 __pci_driver = { + .ops = &usb_ops, + .vendor = PCI_VID_INTEL, + .device = PCI_DID_INTEL_82801DB_USB3, +}; diff --git a/src/southbridge/intel/i82801dx/usb2.c b/src/southbridge/intel/i82801dx/usb2.c new file mode 100644 index 0000000000..0fe7c9399b --- /dev/null +++ b/src/southbridge/intel/i82801dx/usb2.c @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include <device/pci_ehci.h> +#include "i82801dx.h" + +static void usb2_init(struct device *dev) +{ + printk(BIOS_DEBUG, "USB: Setting up controller.. "); + pci_or_config16(dev, PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE); + printk(BIOS_DEBUG, "done.\n"); +} + +static struct device_operations usb2_ops = { + .read_resources = pci_ehci_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = usb2_init, + .enable = i82801dx_enable, +}; + +/* 82801DB/DBM USB 2.0 */ +static const struct pci_driver usb2_driver __pci_driver = { + .ops = &usb2_ops, + .vendor = PCI_VID_INTEL, + .device = PCI_DID_INTEL_82801DB_EHCI, +}; |