diff options
author | Stefan Reinauer <stepan@coresystems.de> | 2009-03-11 14:54:18 +0000 |
---|---|---|
committer | Stefan Reinauer <stepan@openbios.org> | 2009-03-11 14:54:18 +0000 |
commit | a8e1168064b34b46494b58480411a11bc98340f6 (patch) | |
tree | 7d8c27e67ed67a3b96356581bad604b496f7cdd5 /src/southbridge | |
parent | 6df0c62b688d1c4157bc151f98a2feeeca79fee8 (diff) |
This patch contains some significant updates to the i82801gx component and will
be required for a series of later patches. Roughly it contains:
* fixed SMBus driver (was not compiled in before)
* fixed S-ATA/P-ATA combination
* Added warnings to drivers being called with a NULL dev->chip_info
* Set subsystem ids for those boards that have none specified in Options.lb
* Fix license headers. The code was originally released under GPL v2 but
some files sneaked in with a v2 or later header.
* some attempts to fix azalia/Intel HDA.. not working yet
* clean up and fix pci bridge handling code
* Add Config based GPI handling to LPC driver
* Add HPET enable function
* Enable clock gating where appropriate
* first attempt at USB debug console support (not working yet)
* Add required options to kontron board
* many other minor changes
Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
Acked-by: Myles Watson <mylesgw@gmail.com>
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@3991 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'src/southbridge')
22 files changed, 733 insertions, 388 deletions
diff --git a/src/southbridge/intel/i82801gx/Config.lb b/src/southbridge/intel/i82801gx/Config.lb index 6e5cba2338..53186ed293 100644 --- a/src/southbridge/intel/i82801gx/Config.lb +++ b/src/southbridge/intel/i82801gx/Config.lb @@ -5,8 +5,7 @@ ## ## 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. +## 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 @@ -30,6 +29,7 @@ driver i82801gx_nic.o driver i82801gx_pci.o driver i82801gx_pcie.o driver i82801gx_sata.o +driver i82801gx_smbus.o driver i82801gx_usb.o driver i82801gx_usb_ehci.o diff --git a/src/southbridge/intel/i82801gx/IOMAP b/src/southbridge/intel/i82801gx/IOMAP deleted file mode 100644 index 6c20f667d7..0000000000 --- a/src/southbridge/intel/i82801gx/IOMAP +++ /dev/null @@ -1,35 +0,0 @@ -Non-automatic IO-Addresses --------------------------- - -The following dynamic IO BARs are used on the ICH7 for the Kontron Default BIOS: - -GPIOBASE 0x480 (64 bytes) -PMBASE 0x800 (128 bytes) -SMBASE 0x400 (32 bytes) -HWMON 0xa00 (??) - -The following dynamic IO BARs are used on the ICH7 for the Getac Default BIOS: - -GPIOBASE 0x1180 (64 bytes) -PMBASE 0x1000 (128 bytes) -SMBASE 0x18e0 (32 bytes) - -The Getac also needs an IO Trapped area of 0x0C bytes (defaults to 0x800) - -coreboot: -GPIOBASE 0x480 (64 bytes) -PMBASE 0x500 (128 bytes) -SMBASE 0x400 (32 bytes) -HWMON 0xa00 (??) - - - -NOTE: Coreboot sets the SMBASE to 0xf00 in auto.c. But it gets relocated -in stage2 because its a "normal BAR" (to 0x2080 in one case here). - -This is not unhealthy but at least confusing. We should provide a method to -nail down certain resources for stage2. - -For a list of static I/O space allocation look at 6.3.1 of the ICH7 Family -Datasheet. - diff --git a/src/southbridge/intel/i82801gx/chip.h b/src/southbridge/intel/i82801gx/chip.h index 45c011a1c0..7fca7ca9f3 100644 --- a/src/southbridge/intel/i82801gx/chip.h +++ b/src/southbridge/intel/i82801gx/chip.h @@ -3,10 +3,10 @@ * * Copyright (C) 2008-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; either version 2 of the License, or - * (at your option) any later version. + * 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 @@ -22,7 +22,10 @@ #define SOUTHBRIDGE_INTEL_I82801GX_CHIP_H struct southbridge_intel_i82801gx_config { - /* LPC configuration */ + /** + * Interrupt Routing configuration + * If bit7 is 1, the interrupt is disabled. + */ uint8_t pirqa_routing; uint8_t pirqb_routing; uint8_t pirqc_routing; @@ -32,6 +35,32 @@ struct southbridge_intel_i82801gx_config { uint8_t pirqg_routing; uint8_t pirqh_routing; + /** + * GPI Routing configuration + * + * Only the lower two bits have a meaning: + * 00: No effect + * 01: SMI# (if corresponding ALT_GPI_SMI_EN bit is also set) + * 10: SCI (if corresponding GPIO_EN bit is also set) + * 11: reserved + */ + uint8_t gpi0_routing; + uint8_t gpi1_routing; + uint8_t gpi2_routing; + uint8_t gpi3_routing; + uint8_t gpi4_routing; + uint8_t gpi5_routing; + uint8_t gpi6_routing; + uint8_t gpi7_routing; + uint8_t gpi8_routing; + uint8_t gpi9_routing; + uint8_t gpi10_routing; + uint8_t gpi11_routing; + uint8_t gpi12_routing; + uint8_t gpi13_routing; + uint8_t gpi14_routing; + uint8_t gpi15_routing; + /* IDE configuration */ uint32_t ide_legacy_combined; uint32_t ide_enable_primary; @@ -39,7 +68,7 @@ struct southbridge_intel_i82801gx_config { uint32_t sata_ahci; /* Azalia Configuration */ - unsigned long hda_viddid; + uint32_t hda_viddid; }; extern struct chip_operations southbridge_intel_i82801gx_ops; diff --git a/src/southbridge/intel/i82801gx/cmos_failover.c b/src/southbridge/intel/i82801gx/cmos_failover.c index ec5ec6a34b..0765404ceb 100644 --- a/src/southbridge/intel/i82801gx/cmos_failover.c +++ b/src/southbridge/intel/i82801gx/cmos_failover.c @@ -1,10 +1,12 @@ /* * 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; either version 2 of the License, or - * (at your option) any later version. + * (C) 2008-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 diff --git a/src/southbridge/intel/i82801gx/i82801gx.c b/src/southbridge/intel/i82801gx/i82801gx.c index 9d504fbe0b..fb8e952eed 100644 --- a/src/southbridge/intel/i82801gx/i82801gx.c +++ b/src/southbridge/intel/i82801gx/i82801gx.c @@ -1,12 +1,12 @@ /* * This file is part of the coreboot project. * - * Copyright (C) 2008 coresystems GmbH + * Copyright (C) 2008-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; either version 2 of the License, or - * (at your option) any later version. + * 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 @@ -25,6 +25,12 @@ void i82801gx_enable(device_t dev) { + u32 reg32; + + /* Enable SERR */ + reg32 = pci_read_config32(dev, PCI_COMMAND); + reg32 |= PCI_COMMAND_SERR; + pci_write_config32(dev, PCI_COMMAND, reg32); } struct chip_operations southbridge_intel_i82801gx_ops = { diff --git a/src/southbridge/intel/i82801gx/i82801gx.h b/src/southbridge/intel/i82801gx/i82801gx.h index 9ea0f1fee9..a1771230fc 100644 --- a/src/southbridge/intel/i82801gx/i82801gx.h +++ b/src/southbridge/intel/i82801gx/i82801gx.h @@ -1,12 +1,12 @@ /* * This file is part of the coreboot project. * - * Copyright (C) 2008 coresystems GmbH + * Copyright (C) 2008-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; either version 2 of the License, or - * (at your option) any later version. + * 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 diff --git a/src/southbridge/intel/i82801gx/i82801gx_ac97.c b/src/southbridge/intel/i82801gx/i82801gx_ac97.c index 4253284452..e78b1eb282 100644 --- a/src/southbridge/intel/i82801gx/i82801gx_ac97.c +++ b/src/southbridge/intel/i82801gx/i82801gx_ac97.c @@ -3,10 +3,10 @@ * * Copyright (C) 2008-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; either version 2 of the License, or - * (at your option) any later version. + * 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 @@ -119,7 +119,6 @@ static void program_sigid(struct device *dev, u32 id) static void ac97_audio_init(struct device *dev) { - u8 reg8; u16 reg16; u32 reg32; int i; diff --git a/src/southbridge/intel/i82801gx/i82801gx_azalia.c b/src/southbridge/intel/i82801gx/i82801gx_azalia.c index 067d0f3980..fba46bae7c 100644 --- a/src/southbridge/intel/i82801gx/i82801gx_azalia.c +++ b/src/southbridge/intel/i82801gx/i82801gx_azalia.c @@ -31,61 +31,63 @@ #define HDA_ICII_BUSY (1 << 0) #define HDA_ICII_VALID (1 << 1) +typedef struct southbridge_intel_i82801gx_config config_t; + static int set_bits(u8 * port, u32 mask, u32 val) { - u32 dword; + u32 reg32; int count; + /* Write (val & mask) to port */ val &= mask; - dword = readl(port); - dword &= ~mask; - dword |= val; - writel(dword, port); - + reg32 = readl(port); + reg32 &= ~mask; + reg32 |= val; + writel(reg32, port); + + /* Wait for readback of register to + * match what was just written to it + */ count = 50; do { - dword = readl(port); - dword &= mask; - udelay(100); - } while ((dword != val) && --count); + /* Wait 1ms based on BKDG wait time */ + mdelay(1); + reg32 = readl(port); + reg32 &= mask; + } while ((reg32 != val) && --count); + /* Timeout occured */ if (!count) return -1; - - udelay(540); return 0; } static int codec_detect(u8 * base) { - u32 dword; - - /* 1 */ - set_bits(base + 0x08, 1, 1); - - /* 2 */ - dword = readl(base + 0x0e); - dword |= 7; - writel(dword, base + 0x0e); - - /* 3 */ + u32 reg32; + + /* Set Bit0 to 0 to enter reset state (BAR + 0x8)[0] */ + if (set_bits(base + 0x08, 1, 0) == -1) + goto no_codec; + + /* Set Bit 0 to 1 to exit reset state (BAR + 0x8)[0] */ + if (set_bits(base + 0x08, 1, 1) == -1) + goto no_codec; + + /* Read in Codec location (BAR + 0xe)[2..0]*/ + reg32 = readl(base + 0xe); + reg32 &= 0x0f; + if (!reg32) + goto no_codec; + + return reg32; + +no_codec: + /* Codec Not found */ + /* Put HDA back in reset (BAR + 0x8) [0] */ set_bits(base + 0x08, 1, 0); - - /* 4 */ - set_bits(base + 0x08, 1, 1); - - /* 5 */ - dword = readl(base + 0xe); - dword &= 7; - - /* 6 */ - if (!dword) { - set_bits(base + 0x08, 1, 0); - printk_debug("No codec!\n"); - return 0; - } - return dword; - + printk_debug("Azalia: No codec!\n"); + return 0; } static u32 cim_verb_data[] = { @@ -156,19 +158,24 @@ static u32 cim_verb_data[] = { 0x01F71F41, }; -static unsigned find_verb(u32 viddid, u32 ** verb) +static unsigned find_verb(struct device *dev, u32 viddid, u32 ** verb) { - device_t azalia_dev = dev_find_slot(0, PCI_DEVFN(0x14, 2)); - struct southbridge_intel_i82801gx_config *cfg = - (struct southbridge_intel_i82801gx_config *)azalia_dev->chip_info; - printk_debug("Dev=%s\n", dev_path(azalia_dev)); - printk_debug("Default viddid=%x\n", cfg->hda_viddid); - printk_debug("Reading viddid=%x\n", viddid); - if (!cfg) + config_t *config = dev->chip_info; + + if (config == NULL) { + printk_err("\ni82801gx_azalia: Not mentioned in mainboard's Config.lb!\n"); return 0; - if (viddid != cfg->hda_viddid) + } + + printk_debug("Azalia: dev=%s\n", dev_path(dev)); + printk_debug("Azalia: Default viddid=%x\n", (u32)config->hda_viddid); + printk_debug("Azalia: Reading viddid=%x\n", viddid); + + if (viddid != config->hda_viddid) return 0; + *verb = (u32 *) cim_verb_data; + return sizeof(cim_verb_data) / sizeof(u32); } @@ -185,8 +192,8 @@ static int wait_for_ready(u8 *base) int timeout = 50; while(timeout--) { - u32 dword=readl(base + HDA_ICII_REG); - if (!(dword & HDA_ICII_BUSY)) + u32 reg32 = readl(base + HDA_ICII_REG); + if (!(reg32 & HDA_ICII_BUSY)) return 0; udelay(1); } @@ -207,8 +214,8 @@ static int wait_for_valid(u8 *base) int timeout = 50; while(timeout--) { - u32 dword = readl(base + HDA_ICII_REG); - if ((dword & (HDA_ICII_VALID | HDA_ICII_BUSY)) == + u32 reg32 = readl(base + HDA_ICII_REG); + if ((reg32 & (HDA_ICII_VALID | HDA_ICII_BUSY)) == HDA_ICII_VALID) return 0; udelay(1); @@ -217,9 +224,9 @@ static int wait_for_valid(u8 *base) return 1; } -static void codec_init(u8 * base, int addr) +static void codec_init(struct device *dev, u8 * base, int addr) { - u32 dword; + u32 reg32; u32 *verb; u32 verb_size; int i; @@ -228,24 +235,24 @@ static void codec_init(u8 * base, int addr) if (wait_for_ready(base) == -1) return; - dword = (addr << 28) | 0x000f0000; - writel(dword, base + 0x60); + reg32 = (addr << 28) | 0x000f0000; + writel(reg32, base + 0x60); if (wait_for_valid(base) == -1) return; - dword = readl(base + 0x64); + reg32 = readl(base + 0x64); /* 2 */ - printk_debug("codec viddid: %08x\n", dword); - verb_size = find_verb(dword, &verb); + printk_debug("Azalia: codec viddid: %08x\n", reg32); + verb_size = find_verb(dev, reg32, &verb); if (!verb_size) { - printk_debug("No verb!\n"); + printk_debug("Azalia: No verb!\n"); return; } - printk_debug("verb_size: %d\n", verb_size); + printk_debug("Azalia: verb_size: %d\n", verb_size); /* 3 */ for (i = 0; i < verb_size; i++) { if (wait_for_ready(base) == -1) @@ -256,15 +263,15 @@ static void codec_init(u8 * base, int addr) if (wait_for_valid(base) == -1) return; } - printk_debug("verb loaded!\n"); + printk_debug("Azalia: verb loaded.\n"); } -static void codecs_init(u8 * base, u32 codec_mask) +static void codecs_init(struct device *dev, u8 * base, u32 codec_mask) { int i; for (i = 2; i >= 0; i--) { if (codec_mask & (1 << i)) - codec_init(base, i); + codec_init(dev, base, i); } } @@ -273,7 +280,71 @@ static void azalia_init(struct device *dev) u8 *base; struct resource *res; u32 codec_mask; - + u8 reg8; + u32 reg32; + +#if MMCONF_SUPPORT + // ESD + reg32 = pci_mmio_read_config32(dev, 0x134); + reg32 &= 0xff00ffff; + reg32 |= (2 << 16); + pci_mmio_write_config32(dev, 0x134, reg32); + + // Link1 description + reg32 = pci_mmio_read_config32(dev, 0x140); + reg32 &= 0xff00ffff; + reg32 |= (2 << 16); + pci_mmio_write_config32(dev, 0x140, reg32); + + // Port VC0 Resource Control Register + reg32 = pci_mmio_read_config32(dev, 0x114); + reg32 &= 0xffffff00; + reg32 |= 1; + pci_mmio_write_config32(dev, 0x114, reg32); + + // VCi traffic class + reg8 = pci_mmio_read_config8(dev, 0x44); + reg8 |= (7 << 0); // TC7 + pci_mmio_write_config8(dev, 0x44, reg8); + + // VCi Resource Control + reg32 = pci_mmio_read_config32(dev, 0x120); + reg32 |= (1 << 31); + reg32 |= (1 << 24); // VCi ID + reg32 |= (0x80 << 0); // VCi map + pci_mmio_write_config32(dev, 0x120, reg32); +#else +#error ICH7 Azalia required MMCONF_SUPPORT +#endif + + /* Set Bus Master */ + reg32 = pci_read_config32(dev, PCI_COMMAND); + pci_write_config32(dev, PCI_COMMAND, reg32 | PCI_COMMAND_MASTER); + + pci_write_config8(dev, 0x3c, 0x0a); // unused? + + // TODO Actually check if we're AC97 or HDA instead of hardcoding this + // here, in Config.lb and/or auto.c. + reg8 = pci_read_config8(dev, 0x40); + reg8 |= (1 << 3); // Clear Clock Detect Bit + pci_write_config8(dev, 0x40, reg8); + reg8 &= ~(1 << 3); // Keep CLKDETCLR from clearing the bit over and over + pci_write_config8(dev, 0x40, reg8); + reg8 |= (1 << 2); // Enable clock detection + pci_write_config8(dev, 0x40, reg8); + mdelay(1); + reg8 = pci_read_config8(dev, 0x40); + printk_debug("Azalia: codec type: %s\n", (reg8 & (1 << 1))?"Azalia":"AC97"); + + // + reg8 = pci_read_config8(dev, 0x40); // Audio Control + reg8 |= 1; // Select Azalia mode. This needs to be controlled via Config.lb + pci_write_config8(dev, 0x40, reg8); + + reg8 = pci_read_config8(dev, 0x4d); // Docking Status + reg8 &= ~(1 << 7); // Docking not supported + pci_write_config8(dev, 0x4d, reg8); +#if 0 /* Set routing pin */ pci_write_config32(dev, 0xf8, 0x0); pci_write_config8(dev, 0xfc, 0xAA); @@ -283,21 +354,39 @@ static void azalia_init(struct device *dev) /* Enable azalia, disable ac97 */ // pm_iowrite(0x59, 0xB); +#endif res = find_resource(dev, 0x10); if (!res) return; + // NOTE this will break as soon as the Azalia get's a bar above + // 4G. Is there anything we can do about it? base = (u8 *) ((u32)res->base); - printk_debug("base = %08x\n", base); + printk_debug("Azalia: base = %08x\n", (u32)base); codec_mask = codec_detect(base); if (codec_mask) { - printk_debug("codec_mask = %02x\n", codec_mask); - codecs_init(base, codec_mask); + printk_debug("Azalia: codec_mask = %02x\n", codec_mask); + codecs_init(dev, base, codec_mask); } } +static void azalia_set_subsystem(device_t dev, unsigned vendor, unsigned device) +{ + if (!vendor || !device) { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + pci_read_config32(dev, PCI_VENDOR_ID)); + } else { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + ((device & 0xffff) << 16) | (vendor & 0xffff)); + } +} + +static struct pci_operations azalia_pci_ops = { + .set_subsystem = azalia_set_subsystem, +}; + static struct device_operations azalia_ops = { .read_resources = pci_dev_read_resources, .set_resources = pci_dev_set_resources, @@ -305,6 +394,7 @@ static struct device_operations azalia_ops = { .init = azalia_init, .scan_bus = 0, .enable = i82801gx_enable, + .ops_pci = &azalia_pci_ops, }; /* 82801GB/GR/GDH/GBM/GHM (ICH7/ICH7R/ICH7DH/ICH7-M/ICH7-M DH) */ diff --git a/src/southbridge/intel/i82801gx/i82801gx_early_smbus.c b/src/southbridge/intel/i82801gx/i82801gx_early_smbus.c index 5fe1daa279..7c0d97d2c8 100644 --- a/src/southbridge/intel/i82801gx/i82801gx_early_smbus.c +++ b/src/southbridge/intel/i82801gx/i82801gx_early_smbus.c @@ -1,12 +1,12 @@ /* * This file is part of the coreboot project. * - * Copyright (C) 2008 coresystems GmbH + * Copyright (C) 2008-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; either version 2 of the License, or - * (at your option) any later version. + * 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 @@ -54,6 +54,6 @@ static void enable_smbus(void) static inline int smbus_read_byte(unsigned device, unsigned address) { - return do_smbus_read_byte(device, address); + return do_smbus_read_byte(SMBUS_IO_BASE, device, address); } diff --git a/src/southbridge/intel/i82801gx/i82801gx_ide.c b/src/southbridge/intel/i82801gx/i82801gx_ide.c index 0074cc7b2a..c29e678a69 100644 --- a/src/southbridge/intel/i82801gx/i82801gx_ide.c +++ b/src/southbridge/intel/i82801gx/i82801gx_ide.c @@ -1,12 +1,12 @@ /* * This file is part of the coreboot project. * - * Copyright (C) 2008 coresystems GmbH + * Copyright (C) 2008-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; either version 2 of the License, or - * (at your option) any later version. + * 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 @@ -30,12 +30,20 @@ static void ide_init(struct device *dev) { u16 ideTimingConfig; u32 reg32; + u32 enable_primary, enable_secondary; /* Get the chip configuration */ config_t *config = dev->chip_info; - int enable_primary = config->ide_enable_primary; - int enable_secondary = config->ide_enable_secondary; + printk_debug("i82801gx_ide: initializing... "); + if (config == NULL) { + printk_err("\ni82801gx_ide: Not mentioned in mainboard's Config.lb!\n"); + // Trying to set somewhat save defaults instead of bailing out. + enable_primary = enable_secondary = 1; + } else { + enable_primary = config->ide_enable_primary; + enable_secondary = config->ide_enable_secondary; + } reg32 = pci_read_config32(dev, PCI_COMMAND); pci_write_config32(dev, PCI_COMMAND, reg32 | PCI_COMMAND_IO | PCI_COMMAND_MASTER); @@ -81,8 +89,25 @@ static void ide_init(struct device *dev) /* Set Interrupt Line */ /* Interrupt Pin is set by D31IP.PIP */ pci_write_config32(dev, INTR_LN, 0xff); /* Int 15 */ + + printk_debug("\n"); +} + +static void ide_set_subsystem(device_t dev, unsigned vendor, unsigned device) +{ + if (!vendor || !device) { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + pci_read_config32(dev, PCI_VENDOR_ID)); + } else { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + ((device & 0xffff) << 16) | (vendor & 0xffff)); + } } +static struct pci_operations ide_pci_ops = { + .set_subsystem = ide_set_subsystem, +}; + static struct device_operations ide_ops = { .read_resources = pci_dev_read_resources, .set_resources = pci_dev_set_resources, @@ -90,6 +115,7 @@ static struct device_operations ide_ops = { .init = ide_init, .scan_bus = 0, .enable = i82801gx_enable, + .ops_pci = &ide_pci_ops, }; /* 82801GB/GR/GDH/GBM/GHM/GU (ICH7/ICH7R/ICH7DH/ICH7-M/ICH7-M DH/ICH7-U) */ diff --git a/src/southbridge/intel/i82801gx/i82801gx_lpc.c b/src/southbridge/intel/i82801gx/i82801gx_lpc.c index 78c4efe3b0..241d610bdd 100644 --- a/src/southbridge/intel/i82801gx/i82801gx_lpc.c +++ b/src/southbridge/intel/i82801gx/i82801gx_lpc.c @@ -3,10 +3,10 @@ * * Copyright (C) 2008-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; either version 2 of the License, or - * (at your option) any later version. + * 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 @@ -151,6 +151,35 @@ static void i82801gx_pirq_init(device_t dev) } } +static void i82801gx_gpi_routing(device_t dev) +{ + /* Get the chip configuration */ + config_t *config = dev->chip_info; + u32 reg32 = 0; + + /* An array would be much nicer here, or some + * other method of doing this. + */ + reg32 |= (config->gpi0_routing & 0x03) << 0; + reg32 |= (config->gpi1_routing & 0x03) << 2; + reg32 |= (config->gpi2_routing & 0x03) << 4; + reg32 |= (config->gpi3_routing & 0x03) << 6; + reg32 |= (config->gpi4_routing & 0x03) << 8; + reg32 |= (config->gpi5_routing & 0x03) << 10; + reg32 |= (config->gpi6_routing & 0x03) << 12; + reg32 |= (config->gpi7_routing & 0x03) << 14; + reg32 |= (config->gpi8_routing & 0x03) << 16; + reg32 |= (config->gpi9_routing & 0x03) << 18; + reg32 |= (config->gpi10_routing & 0x03) << 20; + reg32 |= (config->gpi11_routing & 0x03) << 22; + reg32 |= (config->gpi12_routing & 0x03) << 24; + reg32 |= (config->gpi13_routing & 0x03) << 26; + reg32 |= (config->gpi14_routing & 0x03) << 28; + reg32 |= (config->gpi15_routing & 0x03) << 30; + + pci_write_config32(dev, 0xb8, reg32); +} + static void i82801gx_power_options(device_t dev) { u8 reg8; @@ -172,6 +201,7 @@ static void i82801gx_power_options(device_t dev) reg8 |= 1; } reg8 |= (3 << 4); /* avoid #S4 assertions */ + reg8 &= ~(1 << 3); /* minimum asssertion is 1 to 2 RTCCLK */ pci_write_config8(dev, GEN_PMCON_3, reg8); printk_info("Set power %s after power failure.\n", pwr_on ? "on" : "off"); @@ -198,19 +228,34 @@ static void i82801gx_power_options(device_t dev) // Enable CPU_SLP# and Intel Speedstep, set SMI# rate down reg16 = pci_read_config16(dev, GEN_PMCON_1); - reg16 &= ~3; - reg16 |= (1 << 3) | (1 << 5) | (1 << 10); + reg16 &= ~((3 << 0) | (1 << 10)); + reg16 |= (1 << 3) | (1 << 5); + reg16 |= (1 << 2); // CLKRUN_EN pci_write_config16(dev, GEN_PMCON_1, reg16); - // Set GPIO13 to SCI (?) - // This might be board specific - pci_write_config32(dev, 0xb8, 0x08000000); + // Set the board's GPI routing. + i82801gx_gpi_routing(dev); } -void i82801gx_rtc_init(struct device *dev) +static void i82801gx_configure_cstates(device_t dev) +{ + u8 reg8; + + reg8 = pci_read_config8(dev, 0xa9); // Cx state configuration + reg8 |= (1 << 4) | (1 << 3) | (1 << 2); // Enable Popup & Popdown + pci_write_config8(dev, 0xa9, reg8); + + // Set Deeper Sleep configuration to recommended values + reg8 = pci_read_config8(dev, 0xaa); + reg8 &= 0xf0; + reg8 |= (2 << 2); // Deeper Sleep to Stop CPU: 34-40us + reg8 |= (2 << 0); // Deeper Sleep to Sleep: 15us + pci_write_config8(dev, 0xaa, reg8); +} + +static void i82801gx_rtc_init(struct device *dev) { u8 reg8; - u32 reg32; int rtc_failed; reg8 = pci_read_config8(dev, GEN_PMCON_3); @@ -224,17 +269,40 @@ void i82801gx_rtc_init(struct device *dev) rtc_init(rtc_failed); } -static void enable_hpet(struct device *dev) +static void enable_hpet(void) { - /* TODO */ + u32 reg32; + + /* Leave HPET at default address, but enable it */ + reg32 = RCBA32(0x3404); + reg32 |= (1 << 7); // HPET Address Enable + RCBA32(0x3404) = reg32; } +static void enable_clock_gating(void) +{ + u32 reg32; + + /* Enable Clock Gating for most devices */ + reg32 = RCBA32(0x341c); + reg32 |= (1 << 31); // LPC clock gating + reg32 |= (1 << 30); // PATA clock gating + // SATA clock gating + reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24); + reg32 |= (1 << 23); // AC97 clock gating + reg32 |= (1 << 20) | (1 << 19); // USB EHCI clock gating + reg32 |= (1 << 3) | (1 << 1); // DMI clock gating + reg32 |= (1 << 2); // PCIe clock gating; + RCBA32(0x341c) = reg32; +} #if HAVE_SMI_HANDLER static void i82801gx_lock_smm(struct device *dev) { void smm_lock(void); +#if TEST_SMM_FLASH_LOCKDOWN u8 reg8; +#endif #if ENABLE_ACPI_MODE_IN_COREBOOT printk_debug("Enabling ACPI via APMC:\n"); @@ -279,6 +347,22 @@ static void i82801gx_lock_smm(struct device *dev) } #endif +#define SPIBASE 0x3020 +static void i82801gx_spi_init(void) +{ + u16 spicontrol; + + spicontrol = RCBA16(SPIBASE + 2); + spicontrol &= ~(1 << 0); // SPI Access Request + RCBA16(SPIBASE + 2) = spicontrol; +} + +static void i82801gx_fixups(void) +{ + /* This needs to happen after PCI enumeration */ + RCBA32(0x1d40) |= 1; +} + static void lpc_init(struct device *dev) { printk_debug("i82801gx: lpc_init\n"); @@ -297,6 +381,9 @@ static void lpc_init(struct device *dev) /* Setup power options. */ i82801gx_power_options(dev); + /* Configure Cx state registers */ + i82801gx_configure_cstates(dev); + /* Set the state of the GPIO lines. */ //gpio_init(dev); @@ -307,13 +394,20 @@ static void lpc_init(struct device *dev) isa_dma_init(); /* Initialize the High Precision Event Timers, if present. */ - enable_hpet(dev); + enable_hpet(); + + /* Initialize Clock Gating */ + enable_clock_gating(); setup_i8259(); #if HAVE_SMI_HANDLER i82801gx_lock_smm(dev); #endif + + i82801gx_spi_init(); + + i82801gx_fixups(); } static void i82801gx_lpc_read_resources(device_t dev) @@ -341,9 +435,13 @@ static void i82801gx_lpc_enable_resources(device_t dev) static void set_subsystem(device_t dev, unsigned vendor, unsigned device) { - printk_debug("Setting LPC bridge subsystem ID\n"); - pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, - pci_read_config32(dev, 0)); + if (!vendor || !device) { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + pci_read_config32(dev, PCI_VENDOR_ID)); + } else { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + ((device & 0xffff) << 16) | (vendor & 0xffff)); + } } static struct pci_operations pci_ops = { diff --git a/src/southbridge/intel/i82801gx/i82801gx_nic.c b/src/southbridge/intel/i82801gx/i82801gx_nic.c index 9790dac85f..0405294cb7 100644 --- a/src/southbridge/intel/i82801gx/i82801gx_nic.c +++ b/src/southbridge/intel/i82801gx/i82801gx_nic.c @@ -1,12 +1,12 @@ /* * This file is part of the coreboot project. * - * Copyright (C) 2008 coresystems GmbH + * Copyright (C) 2008-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; either version 2 of the License, or - * (at your option) any later version. + * 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 diff --git a/src/southbridge/intel/i82801gx/i82801gx_pci.c b/src/southbridge/intel/i82801gx/i82801gx_pci.c index b2e4ce5561..2bf228b135 100644 --- a/src/southbridge/intel/i82801gx/i82801gx_pci.c +++ b/src/southbridge/intel/i82801gx/i82801gx_pci.c @@ -3,10 +3,10 @@ * * Copyright (C) 2008-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; either version 2 of the License, or - * (at your option) any later version. + * 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 @@ -26,31 +26,42 @@ static void pci_init(struct device *dev) { u16 reg16; + u8 reg8; -#if 0 - /* Commented out for now because it will break on some machines. */ - /* Set latency timer to 32. */ - pci_write_config16(dev, 0x1b, 0x20); -#endif + /* Enable Bus Master */ + reg16 = pci_read_config16(dev, PCI_COMMAND); + reg16 |= PCI_COMMAND_MASTER; + pci_write_config16(dev, PCI_COMMAND, reg16); + + /* This device has no interrupt */ + pci_write_config8(dev, 0x3c, 0xff); - /* disable parity error response */ + /* disable parity error response and SERR */ reg16 = pci_read_config16(dev, 0x3e); reg16 &= ~(1 << 0); + reg16 &= ~(1 << 1); pci_write_config16(dev, 0x3e, reg16); + /* Master Latency Count must be set to 0x04! */ + reg8 = pci_read_config8(dev, 0x1b); + reg8 &= 0x07; + reg8 |= (0x04 << 3); + pci_write_config8(dev, 0x1b, reg8); + + /* Will this improve throughput of bus masters? */ + pci_write_config8(dev, PCI_MIN_GNT, 0x06); + /* Clear errors in status registers */ reg16 = pci_read_config16(dev, 0x06); - reg16 |= 0xf900; + //reg16 |= 0xf900; pci_write_config16(dev, 0x06, reg16); reg16 = pci_read_config16(dev, 0x1e); - reg16 |= 0xf900; + // reg16 |= 0xf900; pci_write_config16(dev, 0x1e, reg16); - - /* Will this improve throughput of bus masters? */ - pci_write_config8(dev, PCI_MIN_GNT, 0x06); } +#undef PCI_BRIDGE_UPDATE_COMMAND static void ich_pci_dev_enable_resources(struct device *dev) { const struct pci_operations *ops; @@ -68,15 +79,17 @@ static void ich_pci_dev_enable_resources(struct device *dev) MAINBOARD_PCI_SUBSYSTEM_DEVICE_ID); } -#if 0 + command = pci_read_config16(dev, PCI_COMMAND); + command |= dev->command; +#if PCI_BRIDGE_UPDATE_COMMAND /* If we write to PCI_COMMAND, on some systems * this will cause the ROM and APICs not being visible * anymore. */ - command = pci_read_config16(dev, PCI_COMMAND); - command |= dev->command; printk_debug("%s cmd <- %02x\n", dev_path(dev), command); pci_write_config16(dev, PCI_COMMAND, command); +#else + printk_debug("%s cmd <- %02x (NOT WRITTEN!)\n", dev_path(dev), command); #endif } @@ -102,16 +115,14 @@ static void ich_pci_bus_enable_resources(struct device *dev) static void set_subsystem(device_t dev, unsigned vendor, unsigned device) { -#if 0 - /* Currently disabled because it causes a "BAR 9" memory resource - * conflict: - */ - u32 pci_id; - - printk_debug("Setting PCI bridge subsystem ID\n"); - pci_id = pci_read_config32(dev, 0); - pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, pci_id ); -#endif + /* NOTE: This is not the default position! */ + if (!vendor || !device) { + pci_write_config32(dev, 0x54, + pci_read_config32(dev, PCI_VENDOR_ID)); + } else { + pci_write_config32(dev, 0x54, + ((device & 0xffff) << 16) | (vendor & 0xffff)); + } } static struct pci_operations pci_ops = { diff --git a/src/southbridge/intel/i82801gx/i82801gx_pcie.c b/src/southbridge/intel/i82801gx/i82801gx_pcie.c index 882c3e4a78..6965b30972 100644 --- a/src/southbridge/intel/i82801gx/i82801gx_pcie.c +++ b/src/southbridge/intel/i82801gx/i82801gx_pcie.c @@ -3,10 +3,10 @@ * * Copyright (C) 2008-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; either version 2 of the License, or - * (at your option) any later version. + * 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 @@ -29,29 +29,53 @@ static void pci_init(struct device *dev) u32 reg32; printk_debug("Initializing ICH7 PCIe bridge.\n"); -#if 0 - // When the latency of the PCIe(!) bridge is set to 0x20 - // all devices on the secondary bus of the PCI(!) bridge - // suddenly vanish. If you know why, please explain here. + + /* Enable Bus Master */ + reg32 = pci_read_config32(dev, PCI_COMMAND); + reg32 |= PCI_COMMAND_MASTER; + pci_write_config32(dev, PCI_COMMAND, reg32); - /* Set latency timer to 32. */ - pci_write_config16(dev, 0x1b, 0x20); -#endif + /* Set Cache Line Size to 0x10 */ + // This has no effect but the OS might expect it + pci_write_config8(dev, 0x0c, 0x10); - /* disable parity error response */ reg16 = pci_read_config16(dev, 0x3e); - reg16 &= ~(1 << 0); + reg16 &= ~(1 << 0); /* disable parity error response */ + // reg16 &= ~(1 << 1); /* disable SERR */ + reg16 |= (1 << 2); /* ISA enable */ pci_write_config16(dev, 0x3e, reg16); - /* Clear errors in status registers */ - reg16 = pci_read_config16(dev, 0x06); - reg16 |= 0xf900; - pci_write_config16(dev, 0x06, reg16); - - reg16 = pci_read_config16(dev, 0x1e); - reg16 |= 0xf900; - pci_write_config16(dev, 0x1e, reg16); + /* Enable IO xAPIC on this PCIe port */ + reg32 = pci_read_config32(dev, 0xd8); + reg32 |= (1 << 7); + pci_write_config32(dev, 0xd8, reg32); + + /* Enable Backbone Clock Gating */ + reg32 = pci_read_config32(dev, 0xe1); + reg32 |= (1 << 3) | (1 << 2) | (1 << 1) | (1 << 0); + pci_write_config32(dev, 0xe1, reg32); + +#if MMCONF_SUPPORT + /* Set VC0 transaction class */ + reg32 = pci_mmio_read_config32(dev, 0x114); + reg32 &= 0xffffff00; + reg32 |= 1; + pci_mmio_write_config32(dev, 0x114, reg32); + + /* Mask completion timeouts */ + reg32 = pci_mmio_read_config32(dev, 0x148); + reg32 |= (1 << 14); + pci_mmio_write_config32(dev, 0x148, reg32); +#else +#error "MMIO needed for ICH7 PCIe" +#endif + /* Enable common clock configuration */ + // Are there cases when we don't want that? + reg16 = pci_read_config16(dev, 0x50); + reg16 |= (1 << 6); + pci_write_config16(dev, 0x50, reg16); +#if EVEN_MORE_DEBUG reg32 = pci_read_config32(dev, 0x20); printk_spew(" MBL = 0x%08x\n", reg32); reg32 = pci_read_config32(dev, 0x24); @@ -60,19 +84,32 @@ static void pci_init(struct device *dev) printk_spew(" PMBU32 = 0x%08x\n", reg32); reg32 = pci_read_config32(dev, 0x2c); printk_spew(" PMLU32 = 0x%08x\n", reg32); +#endif + + /* Clear errors in status registers */ + reg16 = pci_read_config16(dev, 0x06); + //reg16 |= 0xf900; + pci_write_config16(dev, 0x06, reg16); + + reg16 = pci_read_config16(dev, 0x1e); + //reg16 |= 0xf900; + pci_write_config16(dev, 0x1e, reg16); } -static void set_subsystem(device_t dev, unsigned vendor, unsigned device) +static void pcie_set_subsystem(device_t dev, unsigned vendor, unsigned device) { - u32 pci_id; - - printk_debug("Setting PCIe bridge subsystem ID.\n"); - pci_id = pci_read_config32(dev, 0); - pci_write_config32(dev, 0x94, pci_id ); + /* NOTE: This is not the default position! */ + if (!vendor || !device) { + pci_write_config32(dev, 0x94, + pci_read_config32(dev, 0)); + } else { + pci_write_config32(dev, 0x94, + ((device & 0xffff) << 16) | (vendor & 0xffff)); + } } static struct pci_operations pci_ops = { - .set_subsystem = set_subsystem, + .set_subsystem = pcie_set_subsystem, }; static struct device_operations device_ops = { diff --git a/src/southbridge/intel/i82801gx/i82801gx_reset.c b/src/southbridge/intel/i82801gx/i82801gx_reset.c index 5ebb75607f..1facb08105 100644 --- a/src/southbridge/intel/i82801gx/i82801gx_reset.c +++ b/src/southbridge/intel/i82801gx/i82801gx_reset.c @@ -1,12 +1,12 @@ /* * This file is part of the coreboot project. * - * Copyright (C) 2008 coresystems GmbH + * Copyright (C) 2008-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; either version 2 of the License, or - * (at your option) any later version. + * 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 diff --git a/src/southbridge/intel/i82801gx/i82801gx_sata.c b/src/southbridge/intel/i82801gx/i82801gx_sata.c index 7f17b73b0a..0f092e9204 100644 --- a/src/southbridge/intel/i82801gx/i82801gx_sata.c +++ b/src/southbridge/intel/i82801gx/i82801gx_sata.c @@ -3,10 +3,10 @@ * * Copyright (C) 2008-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; either version 2 of the License, or - * (at your option) any later version. + * 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 @@ -29,16 +29,29 @@ typedef struct southbridge_intel_i82801gx_config config_t; static void sata_init(struct device *dev) { u32 reg32; + u16 reg16; /* Get the chip configuration */ config_t *config = dev->chip_info; printk_debug("i82801gx_sata: initializing...\n"); + + if (config == NULL) + printk_err("i82801gx_sata: error: device not in Config.lb!\n"); + /* SATA configuration */ /* Enable BARs */ - pci_write_config16(dev, 0x04, 0x0007); + pci_write_config16(dev, PCI_COMMAND, 0x0007); if (config->ide_legacy_combined) { + printk_debug("SATA controller in combined mode.\n"); + /* No AHCI: clear AHCI base */ + pci_write_config32(dev, 0x24, 0x00000000); + /* And without AHCI BAR no memory decoding */ + reg16 = pci_read_config16(dev, PCI_COMMAND); + reg16 &= ~PCI_COMMAND_MEMORY; + pci_write_config16(dev, PCI_COMMAND, reg16); + pci_write_config8(dev, 0x09, 0x80); /* Set timings */ @@ -49,6 +62,10 @@ static void sata_init(struct device *dev) pci_write_config16(dev, 0x48, 0x0004); pci_write_config16(dev, 0x4a, 0x0200); + /* Set IDE I/O Configuration */ + reg32 = SIG_MODE_NORMAL | FAST_PCB1 | FAST_PCB0 | PCB1 | PCB0; + pci_write_config32(dev, IDE_CONFIG, reg32); + /* Combine IDE - SATA configuration */ pci_write_config8(dev, 0x90, 0x02); @@ -56,8 +73,9 @@ static void sata_init(struct device *dev) pci_write_config8(dev, 0x92, 0x0f); /* SATA Initialization register */ - pci_write_config32(dev, 0x94, 0x40000180); + pci_write_config32(dev, 0x94, 0x5a000180); } else if(config->sata_ahci) { + printk_debug("SATA controller in AHCI mode.\n"); /* Allow both Legacy and Native mode */ pci_write_config8(dev, 0x09, 0x8f); @@ -86,6 +104,18 @@ static void sata_init(struct device *dev) /* SATA Initialization register */ pci_write_config32(dev, 0x94, 0x1a000180); } else { + printk_debug("SATA controller in plain mode.\n"); + /* Set Sata Controller Mode. No Mapping(?) */ + pci_write_config8(dev, 0x90, 0x00); + + /* No AHCI: clear AHCI base */ + pci_write_config32(dev, 0x24, 0x00000000); + + /* And without AHCI BAR no memory decoding */ + reg16 = pci_read_config16(dev, PCI_COMMAND); + reg16 &= ~PCI_COMMAND_MEMORY; + pci_write_config16(dev, PCI_COMMAND, reg16); + /* Native mode capable on both primary and secondary (0xa) * or'ed with enabled (0x50) = 0xf */ @@ -107,9 +137,6 @@ static void sata_init(struct device *dev) reg32 = SIG_MODE_NORMAL | FAST_PCB1 | FAST_PCB0 | PCB1 | PCB0; pci_write_config32(dev, IDE_CONFIG, reg32); - /* Set Sata Controller Mode. */ - pci_write_config8(dev, 0x90, 0x02); - /* Port 0 & 1 enable XXX */ pci_write_config8(dev, 0x92, 0x15); @@ -135,8 +162,28 @@ static void sata_init(struct device *dev) pci_write_config8(dev, 0xa0, 0x00); pci_write_config8(dev, PCI_INTERRUPT_LINE, 0); + + /* Sata Initialization Register */ + reg32 = pci_read_config32(dev, 0x94); + reg32 |= (1 << 30); // due to some bug + pci_write_config32(dev, 0x94, reg32); +} + +static void sata_set_subsystem(device_t dev, unsigned vendor, unsigned device) +{ + if (!vendor || !device) { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + pci_read_config32(dev, PCI_VENDOR_ID)); + } else { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + ((device & 0xffff) << 16) | (vendor & 0xffff)); + } } +static struct pci_operations sata_pci_ops = { + .set_subsystem = sata_set_subsystem, +}; + static struct device_operations sata_ops = { .read_resources = pci_dev_read_resources, .set_resources = pci_dev_set_resources, @@ -144,6 +191,7 @@ static struct device_operations sata_ops = { .init = sata_init, .scan_bus = 0, .enable = i82801gx_enable, + .ops_pci = &sata_pci_ops, }; /* Desktop Non-AHCI and Non-RAID Mode */ @@ -154,6 +202,15 @@ static const struct pci_driver i82801gx_sata_normal_driver __pci_driver = { .device = 0x27c0, }; +/* Mobile Non-AHCI and Non-RAID Mode */ +/* 82801GBM/GHM (ICH7-M/ICH7-M DH) */ +static const struct pci_driver i82801gx_sata_mobile_normal_driver __pci_driver = { + .ops = &sata_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x27c4, +}; + + /* NOTE: Any of the below are not properly supported yet. */ /* Desktop AHCI Mode */ @@ -172,14 +229,6 @@ static const struct pci_driver i82801gx_sata_raid_driver __pci_driver = { .device = 0x27c3, }; -/* Mobile Non-AHCI and Non-RAID Mode */ -/* 82801GBM/GHM (ICH7-M/ICH7-M DH) */ -static const struct pci_driver i82801gx_sata_mobile_normal_driver __pci_driver = { - .ops = &sata_ops, - .vendor = PCI_VENDOR_ID_INTEL, - .device = 0x27c4, -}; - /* Mobile AHCI Mode */ /* 82801GBM/GHM (ICH7-M/ICH7-M DH) */ static const struct pci_driver i82801gx_sata_mobile_ahci_driver __pci_driver = { diff --git a/src/southbridge/intel/i82801gx/i82801gx_smbus.c b/src/southbridge/intel/i82801gx/i82801gx_smbus.c index bc14cc39f2..e9f9c7d918 100644 --- a/src/southbridge/intel/i82801gx/i82801gx_smbus.c +++ b/src/southbridge/intel/i82801gx/i82801gx_smbus.c @@ -1,12 +1,12 @@ /* * This file is part of the coreboot project. * - * Copyright (C) 2008 coresystems GmbH + * Copyright (C) 2008-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; either version 2 of the License, or - * (at your option) any later version. + * 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 @@ -18,27 +18,47 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <stdint.h> -#include <smbus.h> -#include <pci.h> -#include <pci_ids.h> +#include <console/console.h> +#include <device/device.h> +#include <device/path.h> +#include <device/smbus.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> #include <arch/io.h> #include "i82801gx.h" -#include "i82801_smbus.h" - -static int smbus_read_byte(struct bus *bus, device_t dev, u8 address) +#include "i82801gx_smbus.h" + +static int lsmbus_read_byte(device_t dev, u8 address) { u16 device; struct resource *res; + struct bus *pbus; device = dev->path.i2c.device; - res = find_resource(bus->dev, 0x20); + pbus = get_pbus_smbus(dev); + res = find_resource(pbus->dev, 0x20); return do_smbus_read_byte(res->base, device, address); } static struct smbus_bus_operations lops_smbus_bus = { - .read_byte = smbus_read_byte, + .read_byte = lsmbus_read_byte, +}; + +static void smbus_set_subsystem(device_t dev, unsigned vendor, unsigned device) +{ + if (!vendor || !device) { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + pci_read_config32(dev, PCI_VENDOR_ID)); + } else { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + ((device & 0xffff) << 16) | (vendor & 0xffff)); + } +} + +static struct pci_operations smbus_pci_ops = { + .set_subsystem = smbus_set_subsystem, }; static struct device_operations smbus_ops = { @@ -49,6 +69,7 @@ static struct device_operations smbus_ops = { .scan_bus = scan_static_bus, .enable = i82801gx_enable, .ops_smbus_bus = &lops_smbus_bus, + .ops_pci = &smbus_pci_ops, }; /* 82801GB/GR/GDH/GBM/GHM/GU (ICH7/ICH7R/ICH7DH/ICH7-M/ICH7-M DH/ICH7-U) */ diff --git a/src/southbridge/intel/i82801gx/i82801gx_smbus.h b/src/southbridge/intel/i82801gx/i82801gx_smbus.h index 13272cb552..ac327783ef 100644 --- a/src/southbridge/intel/i82801gx/i82801gx_smbus.h +++ b/src/southbridge/intel/i82801gx/i82801gx_smbus.h @@ -2,11 +2,12 @@ * This file is part of the coreboot project. * * Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com> + * 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; either version 2 of the License, or - * (at your option) any later version. + * 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 @@ -25,7 +26,7 @@ static void smbus_delay(void) inb(0x80); } -static int smbus_wait_until_ready(void) +static int smbus_wait_until_ready(u16 smbus_base) { unsigned loops = SMBUS_TIMEOUT; unsigned char byte; @@ -33,12 +34,12 @@ static int smbus_wait_until_ready(void) smbus_delay(); if (--loops == 0) break; - byte = inb(SMBUS_IO_BASE + SMBHSTSTAT); + byte = inb(smbus_base + SMBHSTSTAT); } while (byte & 1); return loops ? 0 : -1; } -static int smbus_wait_until_done(void) +static int smbus_wait_until_done(u16 smbus_base) { unsigned loops = SMBUS_TIMEOUT; unsigned char byte; @@ -46,142 +47,54 @@ static int smbus_wait_until_done(void) smbus_delay(); if (--loops == 0) break; - byte = inb(SMBUS_IO_BASE + SMBHSTSTAT); + byte = inb(smbus_base + SMBHSTSTAT); } while ((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0); return loops ? 0 : -1; } -static int smbus_wait_until_blk_done(void) -{ - unsigned loops = SMBUS_TIMEOUT; - unsigned char byte; - do { - smbus_delay(); - if (--loops == 0) - break; - byte = inb(SMBUS_IO_BASE + SMBHSTSTAT); - } while ((byte & (1 << 7)) == 0); - return loops ? 0 : -1; -} - -static int do_smbus_read_byte(unsigned device, unsigned address) +static int do_smbus_read_byte(unsigned smbus_base, unsigned device, unsigned address) { unsigned char global_status_register; unsigned char byte; - if (smbus_wait_until_ready() < 0) { + if (smbus_wait_until_ready(smbus_base) < 0) { return SMBUS_WAIT_UNTIL_READY_TIMEOUT; } /* Setup transaction */ /* Disable interrupts */ - outb(inb(SMBUS_IO_BASE + SMBHSTCTL) & (~1), SMBUS_IO_BASE + SMBHSTCTL); + outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL); /* Set the device I'm talking too */ - outb(((device & 0x7f) << 1) | 1, SMBUS_IO_BASE + SMBXMITADD); + outb(((device & 0x7f) << 1) | 1, smbus_base + SMBXMITADD); /* Set the command/address... */ - outb(address & 0xff, SMBUS_IO_BASE + SMBHSTCMD); + outb(address & 0xff, smbus_base + SMBHSTCMD); /* Set up for a byte data read */ - outb((inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xe3) | (0x2 << 2), - (SMBUS_IO_BASE + SMBHSTCTL)); + outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2), + (smbus_base + SMBHSTCTL)); /* Clear any lingering errors, so the transaction will run */ - outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT); + outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT); /* Clear the data byte... */ - outb(0, SMBUS_IO_BASE + SMBHSTDAT0); + outb(0, smbus_base + SMBHSTDAT0); /* Start the command */ - outb((inb(SMBUS_IO_BASE + SMBHSTCTL) | 0x40), - SMBUS_IO_BASE + SMBHSTCTL); + outb((inb(smbus_base + SMBHSTCTL) | 0x40), + smbus_base + SMBHSTCTL); /* Poll for transaction completion */ - if (smbus_wait_until_done() < 0) { + if (smbus_wait_until_done(smbus_base) < 0) { return SMBUS_WAIT_UNTIL_DONE_TIMEOUT; } - global_status_register = inb(SMBUS_IO_BASE + SMBHSTSTAT); + global_status_register = inb(smbus_base + SMBHSTSTAT); /* Ignore the "In Use" status... */ global_status_register &= ~(3 << 5); /* Read results of transaction */ - byte = inb(SMBUS_IO_BASE + SMBHSTDAT0); + byte = inb(smbus_base + SMBHSTDAT0); if (global_status_register != (1 << 1)) { return SMBUS_ERROR; } return byte; } -/* This function is neither used nor tested by me (Corey Osgood), the author -(Yinghai) probably tested/used it on i82801er */ -static int do_smbus_write_block(unsigned device, unsigned length, unsigned cmd, - unsigned data1, unsigned data2) -{ - unsigned char byte; - unsigned char stat; - int i; - -#if CONFIG_USE_PRINTK_IN_CAR - printk_err("Untested smbus_write_block called\r\n"); -#else - print_err("Untested smbus_write_block called\r\n"); -#endif - - /* Clear the PM timeout flags, SECOND_TO_STS */ - outw(inw(0x0400 + 0x66), 0x0400 + 0x66); - - if (smbus_wait_until_ready() < 0) { - return -2; - } - - /* Setup transaction */ - /* Obtain ownership */ - outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT); - for (stat = 0; (stat & 0x40) == 0;) { - stat = inb(SMBUS_IO_BASE + SMBHSTSTAT); - } - /* Clear the done bit */ - outb(0x80, SMBUS_IO_BASE + SMBHSTSTAT); - /* Disable interrupts */ - outb(inb(SMBUS_IO_BASE + SMBHSTCTL) & (~1), SMBUS_IO_BASE + SMBHSTCTL); - - /* Set the device I'm talking too */ - outb(((device & 0x7f) << 1), SMBUS_IO_BASE + SMBXMITADD); - - /* Set the command address */ - outb(cmd & 0xff, SMBUS_IO_BASE + SMBHSTCMD); - - /* Set the block length */ - outb(length & 0xff, SMBUS_IO_BASE + SMBHSTDAT0); - - /* Try sending out the first byte of data here */ - byte = (data1 >> (0)) & 0x0ff; - outb(byte, SMBUS_IO_BASE + SMBBLKDAT); - /* Issue a block write command */ - outb((inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xe3) | (0x5 << 2) | 0x40, - SMBUS_IO_BASE + SMBHSTCTL); - - for (i = 0; i < length; i++) { - - /* Poll for transaction completion */ - if (smbus_wait_until_blk_done() < 0) { - return -3; - } - - /* Load the next byte */ - if (i > 3) - byte = (data2 >> (i % 4)) & 0x0ff; - else - byte = (data1 >> (i)) & 0x0ff; - outb(byte, SMBUS_IO_BASE + SMBBLKDAT); - - /* Clear the done bit */ - outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), - SMBUS_IO_BASE + SMBHSTSTAT); - } - -#if CONFIG_USE_PRINTK_IN_CAR - printk_debug("SMBUS Block complete\r\n"); -#else - print_debug("SMBUS Block complete\r\n"); -#endif - return 0; -} diff --git a/src/southbridge/intel/i82801gx/i82801gx_usb.c b/src/southbridge/intel/i82801gx/i82801gx_usb.c index 22aad92a4e..a753202f72 100644 --- a/src/southbridge/intel/i82801gx/i82801gx_usb.c +++ b/src/southbridge/intel/i82801gx/i82801gx_usb.c @@ -1,12 +1,12 @@ /* * This file is part of the coreboot project. * - * Copyright (C) 2008 coresystems GmbH + * Copyright (C) 2008-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; either version 2 of the License, or - * (at your option) any later version. + * 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 @@ -42,6 +42,21 @@ static void usb_init(struct device *dev) printk_debug("done.\n"); } +static void usb_set_subsystem(device_t dev, unsigned vendor, unsigned device) +{ + if (!vendor || !device) { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + pci_read_config32(dev, PCI_VENDOR_ID)); + } else { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + ((device & 0xffff) << 16) | (vendor & 0xffff)); + } +} + +static struct pci_operations usb_pci_ops = { + .set_subsystem = usb_set_subsystem, +}; + static struct device_operations usb_ops = { .read_resources = pci_dev_read_resources, .set_resources = pci_dev_set_resources, @@ -49,6 +64,7 @@ static struct device_operations usb_ops = { .init = usb_init, .scan_bus = 0, .enable = i82801gx_enable, + .ops_pci = &usb_pci_ops, }; /* 82801GB/GR/GDH/GBM/GHM/GU (ICH7/ICH7R/ICH7DH/ICH7-M/ICH7-M DH/ICH7-U) */ diff --git a/src/southbridge/intel/i82801gx/i82801gx_usb_debug.c b/src/southbridge/intel/i82801gx/i82801gx_usb_debug.c new file mode 100644 index 0000000000..be524cabaa --- /dev/null +++ b/src/southbridge/intel/i82801gx/i82801gx_usb_debug.c @@ -0,0 +1,36 @@ +/* + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +// An arbitrary address for the BAR +#define EHCI_BAR 0xFEF00000 +// These could be read from DEBUG_BASE (0:1d.7 R 0x5A 16bit) +#define EHCI_BAR_INDEX 0x10 +#define EHCI_DEBUG_OFFSET 0xA0 + +static void set_debug_port(unsigned port) +{ + // Nothing for now? +} + +static void i82801gx_enable_usbdebug_direct(unsigned port) +{ + pci_write_config32(PCI_DEV(0, 0x1d, 7), EHCI_BAR_INDEX, EHCI_BAR); + pci_write_config8(PCI_DEV(0, 0x1d, 7), 0x04, 0x2); // Memory Space Enable +} + diff --git a/src/southbridge/intel/i82801gx/i82801gx_usb_ehci.c b/src/southbridge/intel/i82801gx/i82801gx_usb_ehci.c index 5ac7a1a97c..39a5799ed9 100644 --- a/src/southbridge/intel/i82801gx/i82801gx_usb_ehci.c +++ b/src/southbridge/intel/i82801gx/i82801gx_usb_ehci.c @@ -1,12 +1,12 @@ /* * This file is part of the coreboot project. * - * Copyright (C) 2008 coresystems GmbH + * Copyright (C) 2008-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; either version 2 of the License, or - * (at your option) any later version. + * 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 @@ -23,14 +23,23 @@ #include <device/pci.h> #include <device/pci_ids.h> #include "i82801gx.h" +#if CONFIG_USBDEBUG_DIRECT +#include <usbdebug_direct.h> +#endif +#include <arch/io.h> static void usb_ehci_init(struct device *dev) { + struct resource *res; + u8 *base; u32 reg32; + u8 reg8; printk_debug("EHCI: Setting up controller.. "); reg32 = pci_read_config32(dev, PCI_COMMAND); - pci_write_config32(dev, PCI_COMMAND, reg32 | PCI_COMMAND_MASTER); + reg32 |= PCI_COMMAND_MASTER; + reg32 |= PCI_COMMAND_SERR; + pci_write_config32(dev, PCI_COMMAND, reg32); reg32 = pci_read_config32(dev, 0xdc); reg32 |= (1 << 31) | (1 << 27); @@ -41,11 +50,21 @@ static void usb_ehci_init(struct device *dev) reg32 |= (2 << 2) | (1 << 29) | (1 << 17); pci_write_config32(dev, 0xfc, reg32); + /* Clear any pending port changes */ + res = find_resource(dev, 0x10); + base =(u8 *)res->base; + reg32 = readl(base + 0x24) | (1 << 2); + writel(base + 0x24, reg32); + + /* workaround */ + reg8 = pci_read_config8(dev, 0x84); + reg8 |= (1 << 4); + pci_write_config8(dev, 0x84, reg8); + printk_debug("done.\n"); } -static void usb_ehci_set_subsystem(device_t dev, unsigned vendor, - unsigned device) +static void usb_ehci_set_subsystem(device_t dev, unsigned vendor, unsigned device) { u8 access_cntl; @@ -54,14 +73,42 @@ static void usb_ehci_set_subsystem(device_t dev, unsigned vendor, /* Enable writes to protected registers. */ pci_write_config8(dev, 0x80, access_cntl | 1); - /* Write the subsystem vendor and device ID. */ - pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, - ((device & 0xffff) << 16) | (vendor & 0xffff)); + if (!vendor || !device) { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + pci_read_config32(dev, PCI_VENDOR_ID)); + } else { + pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, + ((device & 0xffff) << 16) | (vendor & 0xffff)); + } /* Restore protection. */ pci_write_config8(dev, 0x80, access_cntl); } +static void usb_ehci_set_resources(struct device *dev) +{ +#if CONFIG_USBDEBUG_DIRECT + struct resource *res; + u32 base; + u32 usb_debug; + + usb_debug = get_ehci_debug(); + set_ehci_debug(0); +#endif + pci_dev_set_resources(dev); + +#if CONFIG_USBDEBUG_DIRECT + res = find_resource(dev, 0x10); + set_ehci_debug(usb_debug); + if (!res) return; + base = res->base; + set_ehci_base(base); + report_resource_stored(dev, res, ""); +#endif +} + + + static struct pci_operations lops_pci = { .set_subsystem = &usb_ehci_set_subsystem, }; diff --git a/src/southbridge/intel/i82801gx/i82801gx_watchdog.c b/src/southbridge/intel/i82801gx/i82801gx_watchdog.c index 474a2d7cb3..9304ffc705 100644 --- a/src/southbridge/intel/i82801gx/i82801gx_watchdog.c +++ b/src/southbridge/intel/i82801gx/i82801gx_watchdog.c @@ -1,12 +1,12 @@ /* * This file is part of the coreboot project. * - * Copyright (C) 2008 coresystems GmbH + * Copyright (C) 2008-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; either version 2 of the License, or - * (at your option) any later version. + * 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 |