aboutsummaryrefslogtreecommitdiff
path: root/src/southbridge/intel/i82801gx/i82801gx_azalia.c
diff options
context:
space:
mode:
authorStefan Reinauer <stepan@coresystems.de>2009-03-11 14:54:18 +0000
committerStefan Reinauer <stepan@openbios.org>2009-03-11 14:54:18 +0000
commita8e1168064b34b46494b58480411a11bc98340f6 (patch)
tree7d8c27e67ed67a3b96356581bad604b496f7cdd5 /src/southbridge/intel/i82801gx/i82801gx_azalia.c
parent6df0c62b688d1c4157bc151f98a2feeeca79fee8 (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/intel/i82801gx/i82801gx_azalia.c')
-rw-r--r--src/southbridge/intel/i82801gx/i82801gx_azalia.c226
1 files changed, 158 insertions, 68 deletions
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) */