From 5107174459f581ff9a2f548768df6e1eef3c2d79 Mon Sep 17 00:00:00 2001 From: "Ronald G. Minnich" Date: Thu, 2 Oct 2008 15:42:14 +0000 Subject: [PATCH] This is so that people can see it. This is the sb600 for v3. It almost certainly won't build -- that comes later. I am hoping to get some eyeballs on it for simple errors. rs690 is next. Signed-off-by: Ronald G. Minnich Acked-by: Ronald G. Minnich git-svn-id: svn://svn.coreboot.org/coreboot/trunk@3630 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1 --- src/southbridge/amd/sb600/ac97.c | 60 ++ src/southbridge/amd/sb600/ac97audio.dts | 23 + src/southbridge/amd/sb600/ac97modem.dts | 24 + .../amd/sb600/enable_usbdebug_direct.c | 48 ++ src/southbridge/amd/sb600/hda.c | 265 ++++++++ src/southbridge/amd/sb600/hda.dts | 23 + src/southbridge/amd/sb600/ide.c | 78 +++ src/southbridge/amd/sb600/ide.dts | 26 + src/southbridge/amd/sb600/lpc.c | 222 ++++++ src/southbridge/amd/sb600/lpc.dts | 23 + src/southbridge/amd/sb600/pci.c | 135 ++++ src/southbridge/amd/sb600/pci.dts | 23 + src/southbridge/amd/sb600/sata.c | 200 ++++++ src/southbridge/amd/sb600/sata.dts | 23 + src/southbridge/amd/sb600/sb600.c | 57 +- src/southbridge/amd/sb600/sb600.dts | 23 + src/southbridge/amd/sb600/sb600.h | 3 +- src/southbridge/amd/sb600/sm.c | 387 +++++++++++ src/southbridge/amd/sb600/sm.dts | 23 + src/southbridge/amd/sb600/stage1.c | 640 ++++++++++++++++++ src/southbridge/amd/sb600/stage1_reset.c | 38 ++ src/southbridge/amd/sb600/stage1_smbus.c | 229 +++++++ src/southbridge/amd/sb600/usb.c | 205 ++++++ src/southbridge/amd/sb600/usb.dts | 23 + src/southbridge/amd/sb600/usb2.dts | 23 + 25 files changed, 2798 insertions(+), 26 deletions(-) create mode 100644 src/southbridge/amd/sb600/ac97.c create mode 100644 src/southbridge/amd/sb600/ac97audio.dts create mode 100644 src/southbridge/amd/sb600/ac97modem.dts create mode 100644 src/southbridge/amd/sb600/enable_usbdebug_direct.c create mode 100644 src/southbridge/amd/sb600/hda.c create mode 100644 src/southbridge/amd/sb600/hda.dts create mode 100644 src/southbridge/amd/sb600/ide.c create mode 100644 src/southbridge/amd/sb600/ide.dts create mode 100644 src/southbridge/amd/sb600/lpc.c create mode 100644 src/southbridge/amd/sb600/lpc.dts create mode 100644 src/southbridge/amd/sb600/pci.c create mode 100644 src/southbridge/amd/sb600/pci.dts create mode 100644 src/southbridge/amd/sb600/sata.c create mode 100644 src/southbridge/amd/sb600/sata.dts create mode 100644 src/southbridge/amd/sb600/sb600.dts create mode 100644 src/southbridge/amd/sb600/sm.c create mode 100644 src/southbridge/amd/sb600/sm.dts create mode 100644 src/southbridge/amd/sb600/stage1.c create mode 100644 src/southbridge/amd/sb600/stage1_reset.c create mode 100644 src/southbridge/amd/sb600/stage1_smbus.c create mode 100644 src/southbridge/amd/sb600/usb.c create mode 100644 src/southbridge/amd/sb600/usb.dts create mode 100644 src/southbridge/amd/sb600/usb2.dts diff --git a/src/southbridge/amd/sb600/ac97.c b/src/southbridge/amd/sb600/ac97.c new file mode 100644 index 000000000..0b4f4c988 --- /dev/null +++ b/src/southbridge/amd/sb600/ac97.c @@ -0,0 +1,60 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sb600.h" + +static struct pci_operations lops_pci = { + .set_subsystem = pci_dev_set_subsystem, +}; + +struct device_operations ac97audio = { + .id = {.type = DEVICE_ID_PCI, + {.pci = {.vendor = PCI_VENDOR_ID_AMD, + .device = PCI_DEVICE_ID_ATI_SB600_ACI}}}, + .constructor = default_device_constructor, + .phase3_scan = 0, + .phase4_read_resources = pci_dev_read_resources, + .phase4_set_resources = pci_dev_set_resources, + .phase5_enable_resources = pci_dev_enable_resources, + .phase6_init = NULL, + .ops_pci = &lops_pci, +}; + +struct device_operations ac97modem = { + .id = {.type = DEVICE_ID_PCI, + {.pci = {.vendor = PCI_VENDOR_ID_AMD, + .device = PCI_DEVICE_ID_ATI_SB600_MCI}}}, + .constructor = default_device_constructor, + .phase3_scan = 0, + .phase4_read_resources = pci_dev_read_resources, + .phase4_set_resources = pci_dev_set_resources, + .phase5_enable_resources = pci_dev_enable_resources, + .phase6_init = NULL, + .ops_pci = &lops_pci, +}; + diff --git a/src/southbridge/amd/sb600/ac97audio.dts b/src/southbridge/amd/sb600/ac97audio.dts new file mode 100644 index 000000000..ce6b3f8a4 --- /dev/null +++ b/src/southbridge/amd/sb600/ac97audio.dts @@ -0,0 +1,23 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008 Ronald G. Minnich + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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 + */ +{ + device_operations = "ac97modem"; + /* configuration variables go here */ +}; diff --git a/src/southbridge/amd/sb600/ac97modem.dts b/src/southbridge/amd/sb600/ac97modem.dts new file mode 100644 index 000000000..5a7795bb6 --- /dev/null +++ b/src/southbridge/amd/sb600/ac97modem.dts @@ -0,0 +1,24 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008 Ronald G. Minnich + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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 + */ + +{ + device_operations = "ac97modem"; + /* configuration variables go here */ +}; diff --git a/src/southbridge/amd/sb600/enable_usbdebug_direct.c b/src/southbridge/amd/sb600/enable_usbdebug_direct.c new file mode 100644 index 000000000..bb0e316f6 --- /dev/null +++ b/src/southbridge/amd/sb600/enable_usbdebug_direct.c @@ -0,0 +1,48 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define SMBUS_IO_BASE 0x1000 /* Is it a temporary SMBus I/O base address? */ + /*SIZE 0x40 */ + +#ifndef SB600_DEVN_BASE + +#define SB600_DEVN_BASE 0 + +#endif + +#define EHCI_BAR_INDEX 0x10 +#define EHCI_BAR 0xFEF00000 +#define EHCI_DEBUG_OFFSET 0xE0 + +void sb600_enable_usbdebug_direct(u32 port) +{ + set_debug_port(port); + pci_conf1_write_config32(PCI_BDF(0, SB600_DEVN_BASE + 0x13, 5), + EHCI_BAR_INDEX, EHCI_BAR); + pci_conf1_write_config8(PCI_BDF(0, SB600_DEVN_BASE + 0x13, 5), 0x04, 0x2); /* mem space enable */ +} diff --git a/src/southbridge/amd/sb600/hda.c b/src/southbridge/amd/sb600/hda.c new file mode 100644 index 000000000..e507d21ae --- /dev/null +++ b/src/southbridge/amd/sb600/hda.c @@ -0,0 +1,265 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sb600.h" + +static int set_bits(u8 * port, u32 mask, u32 val) +{ + u32 dword; + int count; + + val &= mask; + dword = readl(port); + dword &= ~mask; + dword |= val; + writel(dword, port); + + count = 50; + do { + dword = readl(port); + dword &= mask; + udelay(100); + } while ((dword != val) && --count); + + 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 */ + 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(BIOS_DEBUG, "No codec!\n"); + return 0; + } + return dword; + +} + +static u32 cim_verb_data[] = { + 0x01471c10, + 0x01471d40, + 0x01471e01, + 0x01471f01, +/* 1 */ + 0x01571c12, + 0x01571d10, + 0x01571e01, + 0x01571f01, +/* 2 */ + 0x01671c11, + 0x01671d60, + 0x01671e01, + 0x01671f01, +/* 3 */ + 0x01771c14, + 0x01771d20, + 0x01771e01, + 0x01771f01, +/* 4 */ + 0x01871c30, + 0x01871d90, + 0x01871ea1, + 0x01871f01, +/* 5 */ + 0x01971cf0, + 0x01971d11, + 0x01971e11, + 0x01971f41, +/* 6 */ + 0x01a71c80, + 0x01a71d30, + 0x01a71e81, + 0x01a71f01, +/* 7 */ + 0x01b71cf0, + 0x01b71d11, + 0x01b71e11, + 0x01b71f41, +/* 8 */ + 0x01c71cf0, + 0x01c71d11, + 0x01c71e11, + 0x01c71f41, +/* 9 */ + 0x01d71cf0, + 0x01d71d11, + 0x01d71e11, + 0x01d71f41, +/* 10 */ + 0x01e71c50, + 0x01e71d11, + 0x01e71e44, + 0x01e71f01, +/* 11 */ + 0x01f71c60, + 0x01f71d61, + 0x01f71ec4, + 0x01f71f01, +}; +static unsigned find_verb(u32 viddid, u32 ** verb) +{ + struct device * azalia_dev = dev_find_slot(0, PCI_DEVFN(0x14, 2)); + struct southbridge_amd_sb600_dts_config *cfg = + (struct southbridge_amd_sb600_config *)azalia_dev->chip_info; + printk(BIOS_DEBUG, "Dev=%s\n", dev_path(azalia_dev)); + printk(BIOS_DEBUG, "Default viddid=%x\n", cfg->hda_viddid); + printk(BIOS_DEBUG, "Reading viddid=%x\n", viddid); + if (!cfg) + return 0; + if (viddid != cfg->hda_viddid) + return 0; + *verb = (u32 *) cim_verb_data; + return sizeof(cim_verb_data) / sizeof(u32); +} + +static void codec_init(u8 * base, int addr) +{ + u32 dword; + u32 *verb; + u32 verb_size; + int i; + + /* 1 */ + do { + dword = readl(base + 0x68); + } while (dword & 1); + + dword = (addr << 28) | 0x000f0000; + writel(dword, base + 0x60); + + do { + dword = readl(base + 0x68); + } while ((dword & 3) != 2); + + dword = readl(base + 0x64); + + /* 2 */ + printk(BIOS_DEBUG, "codec viddid: %08x\n", dword); + verb_size = find_verb(dword, &verb); + + if (!verb_size) { + printk(BIOS_DEBUG, "No verb!\n"); + return; + } + + printk(BIOS_DEBUG, "verb_size: %d\n", verb_size); + /* 3 */ + for (i = 0; i < verb_size; i++) { + do { + dword = readl(base + 0x68); + } while (dword & 1); + + writel(verb[i], base + 0x60); + + do { + dword = readl(base + 0x68); + } while ((dword & 3) != 2); + } + printk(BIOS_DEBUG, "verb loaded!\n"); +} + +static void codecs_init(u8 * base, u32 codec_mask) +{ + int i; + for (i = 2; i >= 0; i--) { + if (codec_mask & (1 << i)) + codec_init(base, i); + } +} + +static void hda_init(struct device *dev) +{ + u8 *base; + struct resource *res; + u32 codec_mask; + + /* SM Setting */ + struct device * hda_dev; + hda_dev = dev_find_slot(0, PCI_DEVFN(0x14, 0)); + /* Set routing pin */ + pci_write_config32(dev, 0xf8, 0x0); + pci_write_config8(dev, 0xfc, 0xAA); + /* Set INTA */ + pci_write_config8(dev, 0x63, 0x0); + /* Enable azalia, disable ac97 */ + pm_iowrite(0x59, 0xB); + + res = find_resource(dev, 0x10); + if (!res) + return; + + base = (u8 *) ((u32)res->base); + printk(BIOS_DEBUG, "base = %08x\n", base); + codec_mask = codec_detect(base); + + if (codec_mask) { + printk(BIOS_DEBUG, "codec_mask = %02x\n", codec_mask); + codecs_init(base, codec_mask); + } +} + +static struct pci_operations lops_pci = { + .set_subsystem = pci_dev_set_subsystem, +}; + +struct device_operations sb600_hda = { + .id = {.type = DEVICE_ID_PCI, + {.pci = {.vendor = PCI_VENDOR_ID_ATI, + .device = PCI_DEVICE_ID_ATI_SB600_HDA}}}, + .constructor = default_device_constructor, + .phase4_read_resources = pci_dev_read_resources, + .phase4_set_resources = pci_dev_set_resources, + .phase5_enable_resources = pci_dev_enable_resources, + .phase6_init = hda_init, + .ops_pci = &lops_pci +}; diff --git a/src/southbridge/amd/sb600/hda.dts b/src/southbridge/amd/sb600/hda.dts new file mode 100644 index 000000000..91b867d39 --- /dev/null +++ b/src/southbridge/amd/sb600/hda.dts @@ -0,0 +1,23 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008 Ronald G. Minnich + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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 + */ + +{ + device_operations = "sb600_hda"; +}; diff --git a/src/southbridge/amd/sb600/ide.c b/src/southbridge/amd/sb600/ide.c new file mode 100644 index 000000000..32cbe75ba --- /dev/null +++ b/src/southbridge/amd/sb600/ide.c @@ -0,0 +1,78 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sb600.h" + +static void ide_init(struct device *dev) +{ + struct southbridge_amd_sb600_ide_dts_config *conf; + /* Enable ide devices so the linux ide driver will work */ + u32 dword; + u8 byte; + conf = dev->device_configuration; + + /* RPR10.1 disable MSI */ + dword = pci_read_config32(dev, 0x70); + dword &= ~(1 << 16); + pci_write_config32(dev, 0x70, dword); + + /* Ultra DMA mode */ + byte = pci_read_config8(dev, 0x54); + byte |= 1 << 0; + pci_write_config8(dev, 0x54, byte); + byte = pci_read_config8(dev, 0x56); + byte &= ~(7 << 0); + byte |= 5 << 0; /* mode 5 */ + pci_write_config8(dev, 0x56, byte); + + /* Enable I/O Access&& Bus Master */ + dword = pci_read_config16(dev, 0x4); + dword |= 1 << 2; + pci_write_config16(dev, 0x4, dword); + +#if CONFIG_PCI_ROM_RUN == 1 + pci_dev_init(dev); +#endif + +} + +static struct pci_operations lops_pci = { + .set_subsystem = pci_dev_set_subsystem, +}; + +struct device_operations sb600_ide = { + .id = {.type = DEVICE_ID_PCI, + {.pci = {.vendor = PCI_VENDOR_ID_ATI, + .device = PCI_DEVICE_ID_ATI_SB600_IDE}}}, + .constructor = default_device_constructor, + .phase4_read_resources = pci_dev_read_resources, + .phase4_set_resources = pci_dev_set_resources, + .phase5_enable_resources = pci_dev_enable_resources, + .phase6_init = ide_init, + .ops_pci = &lops_pci +}; diff --git a/src/southbridge/amd/sb600/ide.dts b/src/southbridge/amd/sb600/ide.dts new file mode 100644 index 000000000..3ebb68efb --- /dev/null +++ b/src/southbridge/amd/sb600/ide.dts @@ -0,0 +1,26 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008 Ronald G. Minnich + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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 + */ + +{ + device_operations = "sb600_ide"; + /* ignored in driver at present! */ + ide0_enable = "0"; + ide1_enable = "1"; +}; diff --git a/src/southbridge/amd/sb600/lpc.c b/src/southbridge/amd/sb600/lpc.c new file mode 100644 index 000000000..982bc8464 --- /dev/null +++ b/src/southbridge/amd/sb600/lpc.c @@ -0,0 +1,222 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sb600.h" + +static void lpc_init(struct device * dev) +{ + u8 byte; + u32 dword; + struct device * sm_dev; + + /* Enable the LPC Controller */ + sm_dev = dev_find_slot(0, PCI_DEVFN(0x14, 0)); + dword = pci_read_config32(sm_dev, 0x64); + dword |= 1 << 20; + pci_write_config32(sm_dev, 0x64, dword); + + /* Initialize isa dma */ + isa_dma_init(); + + /* RPR 7.2 Enable DMA transaction on the LPC bus */ + byte = pci_read_config8(dev, 0x40); + byte |= (1 << 2); + pci_write_config8(dev, 0x40, byte); + + /* RPR 7.3 Disable the timeout mechanism on LPC */ + byte = pci_read_config8(dev, 0x48); + byte &= ~(1 << 7); + pci_write_config8(dev, 0x48, byte); + + /* RPR 7.5 Disable LPC MSI Capability */ + byte = pci_read_config8(dev, 0x78); + byte &= ~(1 << 1); + pci_write_config8(dev, 0x78, byte); + +} + +static void sb600_lpc_read_resources(struct device * dev) +{ + struct resource *res; + + /* Get the normal pci resources of this device */ + pci_dev_read_resources(dev); /* We got one for APIC, or one more for TRAP */ + + pci_get_resource(dev, 0xA0); /* SPI ROM base address */ + + /* Add an extra subtractive resource for both memory and I/O */ + res = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0)); + res->flags = + IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED; + + res = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0)); + res->flags = + IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED; + + compact_resources(dev); +} + +/** + * @brief Enable resources for children devices + * + * @param dev the device whos children's resources are to be enabled + * + * This function is call by the global enable_resources() indirectly via the + * device_operation::enable_resources() method of devices. + * + * Indirect mutual recursion: + * enable_childrens_resources() -> enable_resources() + * enable_resources() -> device_operation::enable_resources() + * device_operation::enable_resources() -> enable_children_resources() + */ +static void sb600_lpc_enable_childrens_resources(struct device * dev) +{ + u32 link; + u32 reg, reg_x; + int i; + int var_num = 0; + u16 reg_var[3]; + + reg = pci_read_config32(dev, 0x44); + reg_x = pci_read_config32(dev, 0x48); + + for (link = 0; link < dev->links; link++) { + struct device * child; + for (child = dev->link[link].children; child; + child = child->sibling) { + enable_resources(child); + if (child->have_resources + && (child->path.type == DEVICE_PATH_PNP)) { + for (i = 0; i < child->resources; i++) { + struct resource *res; + unsigned long base, end; /* don't need long long */ + res = &child->resource[i]; + if (!(res->flags & IORESOURCE_IO)) + continue; + base = res->base; + end = resource_end(res); + printk_debug + ("sb600 lpc decode:%s, base=0x%08x, end=0x%08x\n", + dev_path(child), base, end); + switch (base) { + case 0x60: /* KB */ + case 0x64: /* MS */ + reg |= (1 << 29); + break; + case 0x3f8: /* COM1 */ + reg |= (1 << 6); + break; + case 0x2f8: /* COM2 */ + reg |= (1 << 7); + break; + case 0x378: /* Parallal 1 */ + reg |= (1 << 0); + break; + case 0x3f0: /* FD0 */ + reg |= (1 << 26); + break; + case 0x220: /* Aduio 0 */ + reg |= (1 << 8); + break; + case 0x300: /* Midi 0 */ + reg |= (1 << 18); + break; + case 0x400: + reg_x |= (1 << 16); + break; + case 0x480: + reg_x |= (1 << 17); + break; + case 0x500: + reg_x |= (1 << 18); + break; + case 0x580: + reg_x |= (1 << 19); + break; + case 0x4700: + reg_x |= (1 << 22); + break; + case 0xfd60: + reg_x |= (1 << 23); + break; + default: + if (var_num >= 3) + continue; /* only 3 var ; compact them ? */ + switch (var_num) { + case 0: + reg_x |= (1 << 2); + break; + case 1: + reg_x |= (1 << 24); + break; + case 2: + reg_x |= (1 << 25); + break; + } + reg_var[var_num++] = + base & 0xffff; + } + } + } + } + } + pci_write_config32(dev, 0x44, reg); + pci_write_config32(dev, 0x48, reg_x); + switch (var_num) { + case 2: + pci_write_config16(dev, 0x90, reg_var[2]); + case 1: + pci_write_config16(dev, 0x66, reg_var[1]); + case 0: + pci_write_config16(dev, 0x64, reg_var[0]); + break; + } +} + +static void sb600_lpc_enable_resources(struct device * dev) +{ + pci_dev_enable_resources(dev); + sb600_lpc_enable_childrens_resources(dev); +} + +static struct pci_operations lops_pci = { + .set_subsystem = pci_dev_set_subsystem, +}; + +struct device_operations sb600_lpc = { + .id = {.type = DEVICE_ID_PCI, + {.pci = {.vendor = PCI_VENDOR_ID_AMD, + .device = PCI_DEVICE_ID_AMD_8111_IDE}}}, + .constructor = default_device_constructor, + .phase3_scan_bus = scan_status_bus, + .phase4_read_resources = sb600_lpc_read_resources, + .phase4_set_resources = pci_dev_set_resources, + .phase5_enable_resources = sb600_lpc_enable_resources, + .phase6_init = lpc_init, + .ops_pci = &lops_pci +}; diff --git a/src/southbridge/amd/sb600/lpc.dts b/src/southbridge/amd/sb600/lpc.dts new file mode 100644 index 000000000..2f7178e32 --- /dev/null +++ b/src/southbridge/amd/sb600/lpc.dts @@ -0,0 +1,23 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008 Ronald G. Minnich + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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 + */ + +{ + device_operations = "sb600_lpc"; +}; diff --git a/src/southbridge/amd/sb600/pci.c b/src/southbridge/amd/sb600/pci.c new file mode 100644 index 000000000..b9e993cbb --- /dev/null +++ b/src/southbridge/amd/sb600/pci.c @@ -0,0 +1,135 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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 + */ + +#include +#include +#include +#include +#include +#include "sb600.h" + +static void pci_init(struct device *dev) +{ + u32 dword; + u16 word; + u8 byte; + + /* RPR 4.1 Enables the PCI-bridge subtractive decode */ + /* This setting is strongly recommended since it supports some legacy PCI add-on cards,such as BIOS debug cards */ + byte = pci_read_config8(dev, 0x4B); + byte |= 1 << 7; + pci_write_config8(dev, 0x4B, byte); + byte = pci_read_config8(dev, 0x40); + byte |= 1 << 5; + pci_write_config8(dev, 0x40, byte); + + /* RPR4.2 PCI-bridge upstream dual address window */ + /* this setting is applicable if the system memory is more than 4GB,and the PCI device can support dual address access */ + byte = pci_read_config8(dev, 0x50); + byte |= 1 << 0; + pci_write_config8(dev, 0x50, byte); + + /* RPR 4.3 PCI bus 64-byte DMA read access */ + /* Enhance the PCI bus DMA performance */ + byte = pci_read_config8(dev, 0x4B); + byte |= 1 << 4; + pci_write_config8(dev, 0x4B, byte); + + /* RPR 4.4 Enables the PCIB writes to be cacheline aligned. */ + /* The size of the writes will be set in the Cacheline Register */ + byte = pci_read_config8(dev, 0x40); + byte |= 1 << 1; + pci_write_config8(dev, 0x40, byte); + + /* RPR 4.5 Enables the PCIB to retain ownership of the bus on the Primary side and on the Secondary side when GNT# is deasserted */ + pci_write_config8(dev, 0x0D, 0x40); + pci_write_config8(dev, 0x1B, 0x40); + + /* RPR 4.6 Enable the command matching checking function on "Memory Read" & "Memory Read Line" commands */ + byte = pci_read_config8(dev, 0x4B); + byte |= 1 << 6; + pci_write_config8(dev, 0x4B, byte); + + /* RPR 4.7 When enabled, the PCI arbiter checks for the Bus Idle before asserting GNT# */ + byte = pci_read_config8(dev, 0x4B); + byte |= 1 << 0; + pci_write_config8(dev, 0x4B, byte); + + /* RPR 4.8 Adjusts the GNT# de-assertion time */ + word = pci_read_config16(dev, 0x64); + word |= 1 << 12; + pci_write_config16(dev, 0x64, word); + + /* RPR 4.9 Fast Back to Back transactions support */ + byte = pci_read_config8(dev, 0x48); + byte |= 1 << 2; + pci_write_config8(dev, 0x48, byte); + + /* RPR 4.10 Enable Lock Operation */ + byte = pci_read_config8(dev, 0x48); + byte |= 1 << 3; + pci_write_config8(dev, 0x48, byte); + byte = pci_read_config8(dev, 0x40); + byte |= (1 << 2); + pci_write_config8(dev, 0x40, byte); + + /* RPR 4.11 Enable additional optional PCI clock */ + word = pci_read_config16(dev, 0x64); + word |= 1 << 8; + pci_write_config16(dev, 0x64, word); + + /* rpr4.12 Disable Fewer-Retry Mode for A11-A13 only. 0x64[5:4] clear */ + byte = pci_read_config8(dev, 0x64); + byte &= 0xcf; + pci_write_config8(dev, 0x64, byte); + + /* rpr4.14 Disabling Downstream Flush, for A12 only, 0x64[18]. */ + dword = pci_read_config32(dev, 0x64); + dword |= (1 << 18); + pci_write_config32(dev, 0x64, dword); + + /* RPR 4.13 Enable One-Prefetch-Channel Mode */ + dword = pci_read_config32(dev, 0x64); + dword |= 1 << 20; + pci_write_config32(dev, 0x64, dword); + + /* RPR 4.15 Disable PCIB MSI Capability */ + byte = pci_read_config8(dev, 0x40); + byte &= ~(1 << 3); + pci_write_config8(dev, 0x40, byte); + + /* rpr4.16 Adjusting CLKRUN# */ + dword = pci_read_config32(dev, 0x64); + dword |= (1 << 15); + pci_write_config32(dev, 0x64, dword); +} + +struct device_operations amd8111_pci = { + .id = {.type = DEVICE_ID_PCI, + {.pci = {.vendor = PCI_VENDOR_ID_ATI, + .device = PCI_DEVICE_ID_ATI_SB600_PCI}}}, + .constructor = default_device_constructor, + .phase3_scan = pci_scan_bridge, + .phase4_enable_disable = amd8111_enable, + .phase4_read_resources = pci_bus_read_resources, + .phase4_set_resources = pci_dev_set_resources, + .phase5_enable_resources = pci_bus_enable_resources, + .phase6_init = pci_init, + .reset_bus = pci_bus_reset, +}; diff --git a/src/southbridge/amd/sb600/pci.dts b/src/southbridge/amd/sb600/pci.dts new file mode 100644 index 000000000..91fcb07a8 --- /dev/null +++ b/src/southbridge/amd/sb600/pci.dts @@ -0,0 +1,23 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008 Ronald G. Minnich + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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 + */ + +{ + device_operations = "sb600_pci"; +}; diff --git a/src/southbridge/amd/sb600/sata.c b/src/southbridge/amd/sb600/sata.c new file mode 100644 index 000000000..d291fb7f6 --- /dev/null +++ b/src/southbridge/amd/sb600/sata.c @@ -0,0 +1,200 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sb600.h" + +static void sata_init(struct device *dev) +{ + u8 byte; + u16 word; + u32 dword; + u8 *sata_bar5; + u16 sata_bar0, sata_bar1, sata_bar2, sata_bar3, sata_bar4; + + struct southbridge_ati_sb600_sata_dts_config *conf; + conf = dev->device_configuration; + + struct device * sm_dev; + /* SATA SMBus Disable */ + /* sm_dev = pci_locate_device(PCI_ID(0x1002, 0x4385), 0); */ + sm_dev = dev_find_slot(0, PCI_DEVFN(0x14, 0)); + /* Disable SATA SMBUS */ + byte = pci_read_config8(sm_dev, 0xad); + byte |= (1 << 1); + /* Enable SATA and power saving */ + byte = pci_read_config8(sm_dev, 0xad); + byte |= (1 << 0); + byte |= (1 << 5); + pci_write_config8(sm_dev, 0xad, byte); + /* Set the interrupt Mapping to INTG# */ + byte = pci_read_config8(sm_dev, 0xaf); + byte = 0x6 << 2; + pci_write_config8(sm_dev, 0xaf, byte); + + /* get base addresss */ + sata_bar5 = (u8 *) (pci_read_config32(dev, 0x24) & ~0x3FF); + sata_bar0 = pci_read_config16(dev, 0x10) & ~0x7; + sata_bar1 = pci_read_config16(dev, 0x14) & ~0x7; + sata_bar2 = pci_read_config16(dev, 0x18) & ~0x7; + sata_bar3 = pci_read_config16(dev, 0x1C) & ~0x7; + sata_bar4 = pci_read_config16(dev, 0x20) & ~0x7; + + printk(BIOS_DEBUG, "sata_bar0=%x\n", sata_bar0); /* 3030 */ + printk(BIOS_DEBUG, "sata_bar1=%x\n", sata_bar1); /* 3070 */ + printk(BIOS_DEBUG, "sata_bar2=%x\n", sata_bar2); /* 3040 */ + printk(BIOS_DEBUG, "sata_bar3=%x\n", sata_bar3); /* 3080 */ + printk(BIOS_DEBUG, "sata_bar4=%x\n", sata_bar4); /* 3000 */ + printk(BIOS_DEBUG, "sata_bar5=%x\n", sata_bar5); /* e0309000 */ + + /* Program the 2C to 0x43801002 */ + dword = 0x43801002; + pci_write_config32(dev, 0x2c, dword); + + /* SERR-Enable */ + word = pci_read_config16(dev, 0x04); + word |= (1 << 8); + pci_write_config16(dev, 0x04, word); + + /* Dynamic power saving */ + byte = pci_read_config8(dev, 0x40); + byte |= (1 << 2); + pci_write_config8(dev, 0x40, byte); + + /* Set SATA Operation Mode, Set to IDE mode */ + byte = pci_read_config8(dev, 0x40); + byte |= (1 << 0); + byte |= (1 << 4); + pci_write_config8(dev, 0x40, byte); + + dword = 0x01018f00; + pci_write_config32(dev, 0x8, dword); + + byte = pci_read_config8(dev, 0x40); + byte &= ~(1 << 0); + pci_write_config8(dev, 0x40, byte); + + /* Enable the SATA watchdog counter */ + byte = pci_read_config8(dev, 0x44); + byte |= (1 << 0); + pci_write_config8(dev, 0x44, byte); + + /* Program the watchdog counter to 0x10 */ + byte = 0x10; + pci_write_config8(dev, 0x46, byte); + + /* RPR6.5 Program the PHY Global Control to 0x2C00 for A13 */ + word = 0x2c00; + pci_write_config16(dev, 0x86, word); + + /* RPR6.5 Program the Phy Tuning4Ports */ + dword = 0x00B401D6; + pci_write_config32(dev, 0x88, dword); + pci_write_config32(dev, 0x8c, dword); + pci_write_config32(dev, 0x90, dword); + pci_write_config32(dev, 0x94, dword); + + byte = 0xB8; + pci_write_config8(dev, 0xA5, byte); + pci_write_config8(dev, 0xAD, byte); + pci_write_config8(dev, 0xB5, byte); + pci_write_config8(dev, 0xBD, byte); + + /* RPR 6.8 */ + word = pci_read_config16(dev, 0x42); + word |= 1 << 7; + pci_write_config16(dev, 0x42, word); + /* RPR 6.9 */ + dword = pci_read_config32(dev, 0x40); + dword |= 1 << 25; + pci_write_config32(dev, 0x40, dword); + + /* Enable the I/O ,MM ,BusMaster access for SATA */ + byte = pci_read_config8(dev, 0x4); + byte |= 7 << 0; + pci_write_config8(dev, 0x4, byte); + + /* RPR6.6 SATA drive detection. Currently we detect Primary Master Device only */ + /* Use BAR5+0x1A8,BAR0+0x6 for Primary Slave */ + /* Use BAR5+0x228,BAR0+0x6 for Secondary Master */ + /* Use BAR5+0x2A8,BAR0+0x6 for Secondary Slave */ + + byte = readb(sata_bar5 + 0x128); + printk(BIOS_DEBUG, "byte=%x\n", byte); + byte &= 0xF; + if (byte == 0x3) { + outb(0xA0, sata_bar0 + 0x6); + while ((inb(sata_bar0 + 0x6) != 0xA0) + || ((inb(sata_bar0 + 0x7) & 0x88) != 0)) { + mdelay(10); + printk(BIOS_DEBUG, "0x6=%x,0x7=%x\n", inb(sata_bar0 + 0x6), + inb(sata_bar0 + 0x7)); + printk(BIOS_DEBUG, "drive detection fail,trying...\n"); + } + printk(BIOS_DEBUG, "Primary master device is ready\n"); + } else { + printk(BIOS_DEBUG, "No Primary master SATA drive on Slot0\n"); + } + + /* Below is CIM InitSataLateFar */ + /* Enable interrupts from the HBA */ + byte = readb(sata_bar5 + 0x4); + byte |= 1 << 1; + writeb(byte, (sata_bar5 + 0x4)); + + /* Clear error status */ + writel(0xFFFFFFFF, (sata_bar5 + 0x130)); + writel(0xFFFFFFFF, (sata_bar5 + 0x1b0)); + writel(0xFFFFFFFF, (sata_bar5 + 0x230)); + writel(0xFFFFFFFF, (sata_bar5 + 0x2b0)); + + /* Clear SATA status,Firstly we get the AcpiGpe0BlkAddr */ + /* ????? why CIM does not set the AcpiGpe0BlkAddr , but use it??? */ + + /* word = 0x0000; */ + /* word = pm_ioread(0x28); */ + /* byte = pm_ioread(0x29); */ + /* word |= byte<<8; */ + /* printk(BIOS_DEBUG, "AcpiGpe0Blk addr = %x\n", word); */ + /* writel(0x80000000 , word); */ +} + +static struct pci_operations lops_pci = { + /* .set_subsystem = pci_dev_set_subsystem, */ +}; + +struct device_operations amd8111_ide = { + .id = {.type = DEVICE_ID_PCI, + {.pci = {.vendor = PCI_VENDOR_ID_ATI, + .device = PCI_DEVICE_ID_ATI_SB600_SATA}}}, + .constructor = default_device_constructor, + .phase4_read_resources = pci_dev_read_resources, + .phase4_set_resources = pci_dev_set_resources, + .phase5_enable_resources = pci_dev_enable_resources, + .phase6_init = sata_init, + .ops_pci = &lops_pci +}; \ No newline at end of file diff --git a/src/southbridge/amd/sb600/sata.dts b/src/southbridge/amd/sb600/sata.dts new file mode 100644 index 000000000..959f1747b --- /dev/null +++ b/src/southbridge/amd/sb600/sata.dts @@ -0,0 +1,23 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008 Ronald G. Minnich + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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 + */ + +{ + device_operations = "sb600_sata"; +}; diff --git a/src/southbridge/amd/sb600/sb600.c b/src/southbridge/amd/sb600/sb600.c index b1b17f002..9a65f3830 100644 --- a/src/southbridge/amd/sb600/sb600.c +++ b/src/southbridge/amd/sb600/sb600.c @@ -17,19 +17,20 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include - -#include - -#include +#include +#include +#include #include +#include +#include #include -#include +#include +#include #include "sb600.h" -static device_t find_sm_dev(device_t dev, u32 devfn) +static struct device * find_sm_dev(struct device * dev, u32 devfn) { - device_t sm_dev; + struct device * sm_dev; sm_dev = dev_find_slot(dev->bus->secondary, devfn); if (!sm_dev) @@ -49,7 +50,7 @@ static device_t find_sm_dev(device_t dev, u32 devfn) return sm_dev; } -void set_sm_enable_bits(device_t sm_dev, u32 reg_pos, u32 mask, u32 val) +void set_sm_enable_bits(struct device * sm_dev, u32 reg_pos, u32 mask, u32 val) { u32 reg_old, reg; reg = reg_old = pci_read_config32(sm_dev, reg_pos); @@ -96,7 +97,7 @@ u8 pm2_ioread(u8 reg) return pmio_read_index(port_base, reg); } -static void set_pmio_enable_bits(device_t sm_dev, u32 reg_pos, +static void set_pmio_enable_bits(struct device * sm_dev, u32 reg_pos, u32 mask, u32 val) { u8 reg_old, reg; @@ -108,10 +109,10 @@ static void set_pmio_enable_bits(device_t sm_dev, u32 reg_pos, } } -void sb600_enable(device_t dev) +void sb600_enable(struct device * dev) { - device_t sm_dev = 0; - device_t bus_dev = 0; + struct device * sm_dev = 0; + struct device * bus_dev = 0; int index = -1; u32 deviceid; u32 vendorid; @@ -122,7 +123,7 @@ void sb600_enable(device_t dev) u32 devfn; - printk_debug("sb600_enable()\n"); + printk(BIOS_DEBUG, "sb600_enable()\n"); /* * 0:12.0 SATA bit 8 of sm_dev 0xac : 1 - enable, default + 32 * 3 @@ -150,13 +151,13 @@ void sb600_enable(device_t dev) bus_dev = dev->bus->dev; if ((bus_dev->vendor == PCI_VENDOR_ID_ATI) && (bus_dev->device == PCI_DEVICE_ID_ATI_SB600_PCI)) { - devfn = (bus_dev->path.u.pci.devfn) & ~7; + devfn = (bus_dev->path.pci.devfn) & ~7; sm_dev = find_sm_dev(bus_dev, devfn); if (!sm_dev) return; /* something under 00:01.0 */ - switch (dev->path.u.pci.devfn) { + switch (dev->path.pci.devfn) { case 5 << 3: ; } @@ -164,7 +165,7 @@ void sb600_enable(device_t dev) return; } - i = (dev->path.u.pci.devfn) & ~7; + i = (dev->path.pci.devfn) & ~7; i += (2 << 3); for (devfn = (0x14 << 3); devfn <= i; devfn += (1 << 3)) { sm_dev = find_sm_dev(dev, devfn); @@ -174,7 +175,7 @@ void sb600_enable(device_t dev) if (!sm_dev) return; - switch (dev->path.u.pci.devfn - (devfn - (0x14 << 3))) { + switch (dev->path.pci.devfn - (devfn - (0x14 << 3))) { case (0x12 << 3) | 0: index = 8; set_sm_enable_bits(sm_dev, 0xac, 1 << index, @@ -187,7 +188,7 @@ void sb600_enable(device_t dev) case (0x13 << 3) | 3: case (0x13 << 3) | 4: case (0x13 << 3) | 5: - index = dev->path.u.pci.devfn & 7; + index = dev->path.pci.devfn & 7; index++; index %= 6; set_sm_enable_bits(sm_dev, 0x68, 1 << index, @@ -217,19 +218,27 @@ void sb600_enable(device_t dev) break; case (0x14 << 3) | 5: case (0x14 << 3) | 6: - index = dev->path.u.pci.devfn & 7; + index = dev->path.pci.devfn & 7; index -= 5; set_pmio_enable_bits(sm_dev, 0x59, 1 << index, (dev->enabled ? 0 : 1) << index); index += 32 * 4; break; default: - printk_debug("unknown dev: %s deviceid=%4x\n", dev_path(dev), + printk(BIOS_DEBUG, "unknown dev: %s deviceid=%4x\n", dev_path(dev), deviceid); } } -struct chip_operations southbridge_amd_sb600_ops = { - CHIP_NAME("ATI SB600") - .enable_dev = sb600_enable, +struct device_operations sb600 = { + .id = {.type = DEVICE_ID_PCI, + {.pci = {.vendor = PCI_VENDOR_ID_AMD, + .device = xz}}}, + .constructor = default_device_constructor, + .phase3_scan = 0, + .phase4_enable_disable = sb600_enable, + .phase4_read_resources = pci_dev_read_resources, + .phase4_set_resources = pci_dev_set_resources, + .phase6_init = NULL, + .ops_pci = &pci_dev_ops_pci, }; diff --git a/src/southbridge/amd/sb600/sb600.dts b/src/southbridge/amd/sb600/sb600.dts new file mode 100644 index 000000000..f45a5b54d --- /dev/null +++ b/src/southbridge/amd/sb600/sb600.dts @@ -0,0 +1,23 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008 Ronald G. Minnich + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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 + */ + +{ + device_operations = "sb600"; +}; diff --git a/src/southbridge/amd/sb600/sb600.h b/src/southbridge/amd/sb600/sb600.h index 27d42364a..f29b58ad9 100644 --- a/src/southbridge/amd/sb600/sb600.h +++ b/src/southbridge/amd/sb600/sb600.h @@ -20,8 +20,6 @@ #ifndef SB600_H #define SB600_H -#include "chip.h" - #define PCI_DEVICE_ID_ATI_SB600_LPC 0x438D #define PCI_DEVICE_ID_ATI_SB600_SATA 0x4380 #define PCI_DEVICE_ID_ATI_SB600_IDE 0x438C @@ -36,6 +34,7 @@ #define PCI_DEVICE_ID_ATI_SB600_USB_2 0x4389 #define PCI_DEVICE_ID_ATI_SB600_USB_3 0x438A #define PCI_DEVICE_ID_ATI_SB600_USB_4 0x438B + extern void pm_iowrite(u8 reg, u8 value); extern u8 pm_ioread(u8 reg); extern void pm2_iowrite(u8 reg, u8 value); diff --git a/src/southbridge/amd/sb600/sm.c b/src/southbridge/amd/sb600/sm.c new file mode 100644 index 000000000..755dcefb2 --- /dev/null +++ b/src/southbridge/amd/sb600/sm.c @@ -0,0 +1,387 @@ +/* This file is part of the coreboot project. + * + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sb600.h" +#include "sb600_smbus.c" + +#define NMI_OFF 0 + +#define MAINBOARD_POWER_OFF 0 +#define MAINBOARD_POWER_ON 1 + +#ifndef MAINBOARD_POWER_ON_AFTER_POWER_FAIL +#define MAINBOARD_POWER_ON_AFTER_POWER_FAIL MAINBOARD_POWER_ON +#endif + +struct ioapicreg { + unsigned int reg; + unsigned int value_low, value_high; +}; + +static struct ioapicreg ioapicregvalues[] = { +#define ALL (0xff << 24) +#define NONE (0) +#define DISABLED (1 << 16) +#define ENABLED (0 << 16) +#define TRIGGER_EDGE (0 << 15) +#define TRIGGER_LEVEL (1 << 15) +#define POLARITY_HIGH (0 << 13) +#define POLARITY_LOW (1 << 13) +#define PHYSICAL_DEST (0 << 11) +#define LOGICAL_DEST (1 << 11) +#define ExtINT (7 << 8) +#define NMI (4 << 8) +#define SMI (2 << 8) +#define INT (1 << 8) + /* IO-APIC virtual wire mode configuration */ + /* mask, trigger, polarity, destination, delivery, vector */ + {0, DISABLED, NONE}, + {1, DISABLED, NONE}, + {2, DISABLED, NONE}, + {3, DISABLED, NONE}, + {4, DISABLED, NONE}, + {5, DISABLED, NONE}, + {6, DISABLED, NONE}, + {7, DISABLED, NONE}, + {8, DISABLED, NONE}, + {9, DISABLED, NONE}, + {10, DISABLED, NONE}, + {11, DISABLED, NONE}, + {12, DISABLED, NONE}, + {13, DISABLED, NONE}, + {14, DISABLED, NONE}, + {15, DISABLED, NONE}, + {16, DISABLED, NONE}, + {17, DISABLED, NONE}, + {18, DISABLED, NONE}, + {19, DISABLED, NONE}, + {20, DISABLED, NONE}, + {21, DISABLED, NONE}, + {22, DISABLED, NONE}, + {23, DISABLED, NONE}, + /* Be careful and don't write past the end... */ +}; + +static void setup_ioapic(unsigned long ioapic_base) +{ + int i; + unsigned long value_low, value_high; + volatile unsigned long *l; + struct ioapicreg *a = ioapicregvalues; + + ioapicregvalues[0].value_high = lapicid() << (56 - 32); + + printk(BIOS_DEBUG, "lapicid = %016x\n", ioapicregvalues[0].value_high); + + l = (unsigned long *)ioapic_base; + + for (i = 0; i < ARRAY_SIZE(ioapicregvalues); + i++, a++) { + l[0] = (a->reg * 2) + 0x10; + l[4] = a->value_low; + value_low = l[4]; + l[0] = (a->reg * 2) + 0x11; + l[4] = a->value_high; + value_high = l[4]; + if ((i == 0) && (value_low == 0xffffffff)) { + printk_warning("IO APIC not responding.\n"); + return; + } + } +} + +/* +* SB600 enables all USB controllers by default in SMBUS Control. +* SB600 enables SATA by default in SMBUS Control. +*/ +static void sm_init(struct device * dev) +{ + u8 byte; + u8 byte_old; + u32 dword; + unsigned long ioapic_base; + int on; + int nmi_option; + + printk(BIOS_INFO, "sm_init().\n"); + + ioapic_base = pci_read_config32(dev, 0x74) & (0xffffffe0); /* some like mem resource, but does not have enable bit */ + setup_ioapic(ioapic_base); + + dword = pci_read_config8(dev, 0x62); + dword |= 1 << 2; + pci_write_config8(dev, 0x62, dword); + + dword = pci_read_config32(dev, 0x78); + dword |= 1 << 9; + pci_write_config32(dev, 0x78, dword); /* enable 0xCD6 0xCD7 */ + + /* enable serial irq */ + byte = pci_read_config8(dev, 0x69); + byte |= 1 << 7; /* enable serial irq function */ + byte &= ~(0xF << 2); + byte |= 4 << 2; /* set NumSerIrqBits=4 */ + pci_write_config8(dev, 0x69, byte); + + byte = pm_ioread(0x61); + byte |= 1 << 1; /* Set to enable NB/SB handshake during IOAPIC interrupt for AMD K8/K7 */ + pm_iowrite(0x61, byte); + + /* disable SMI */ + byte = pm_ioread(0x53); + byte |= 1 << 3; + pm_iowrite(0x53, byte); + + /* power after power fail */ + on = MAINBOARD_POWER_ON_AFTER_POWER_FAIL; + get_option(&on, "power_on_after_fail"); + byte = pm_ioread(0x74); + byte &= ~0x03; + if (on) { + byte |= 2; + } + byte |= 1 << 2; + pm_iowrite(0x74, byte); + printk(BIOS_INFO, "set power %s after power fail\n", on ? "on" : "off"); + + /* sb600 rpr:2.3.3: */ + byte = pm_ioread(0x9A); + byte |= 1 << 5 | 1 << 4 | 1 << 2; + pm_iowrite(0x9A, byte); + + byte = pm_ioread(0x8F); + byte |= 1 << 5; + byte &= ~(1 << 4); + pm_iowrite(0x8F, byte); + + pm_iowrite(0x8B, 0x01); + pm_iowrite(0x8A, 0x90); + pm_iowrite(0x88, 0x10); /* A21 */ + + byte = pm_ioread(0x7C); + byte |= 1 << 0; + pm_iowrite(0x7C, byte); + + byte = pm_ioread(0x68); + byte &= ~(1 << 1); + pm_iowrite(0x68, byte); + + byte = pm_ioread(0x8D); + byte &= ~(1 << 6); + pm_iowrite(0x8D, byte); + + byte = pm_ioread(0x61); + byte &= ~(1 << 2); + pm_iowrite(0x61, byte); + + byte = pm_ioread(0x42); + byte &= ~(1 << 2); + pm_iowrite(0x42, byte); + + /* Set up NMI on errors */ + byte = inb(0x70); /* RTC70 */ + byte_old = byte; + nmi_option = NMI_OFF; + get_option(&nmi_option, "nmi"); + if (nmi_option) { + byte &= ~(1 << 7); /* set NMI */ + printk(BIOS_INFO, "++++++++++set NMI+++++\n"); + } else { + byte |= (1 << 7); /* Can not mask NMI from PCI-E and NMI_NOW */ + printk(BIOS_INFO, "++++++++++no set NMI+++++\n"); + } + byte &= ~(1 << 7); + if (byte != byte_old) { + outb(byte, 0x70); + } + + /* 2.10 IO Trap Settings */ + abcfg_reg(0x10090, 1 << 16, 1 << 16); + + /* ab index */ + pci_write_config32(dev, 0xF0, AB_INDX); + /* Initialize the real time clock */ + rtc_init(0); + + /*3.4 Enabling IDE/PCIB Prefetch for Performance Enhancement */ + abcfg_reg(0x10060, 9 << 17, 9 << 17); + abcfg_reg(0x10064, 9 << 17, 9 << 17); + + /* 3.5 Enabling OHCI Prefetch for Performance Enhancement */ + abcfg_reg(0x80, 1 << 0, 1<< 0); + + /* 3.6 B-Link Client's Credit Variable Settings for the Downstream Arbitration Equation */ + /* 3.7 Enabling Additional Address Bits Checking in Downstream */ + abcfg_reg(0x9c, 3 << 0, 3 << 0); + + /* 3.8 Set B-Link Prefetch Mode */ + abcfg_reg(0x80, 3 << 17, 3 << 17); + + /* 3.9 Enabling Detection of Upstream Interrupts */ + abcfg_reg(0x94, 1 << 20,1 << 20); + + /* 3.10: Enabling Downstream Posted Transactions to Pass Non-Posted + * Transactions for the K8 Platform (for All Revisions) */ + abcfg_reg(0x10090, 1 << 8, 1 << 8); + + /* 3.11:Programming Cycle Delay for AB and BIF Clock Gating */ + /* 3.12: Enabling AB and BIF Clock Gating */ + abcfg_reg(0x10054, 0xFFFF0000, 0x1040000); + abcfg_reg(0x54, 0xFF << 16, 4 << 16); + printk(BIOS_INFO, "3.11, ABCFG:0x54\n"); + abcfg_reg(0x54, 1 << 24, 1 << 24); + printk(BIOS_INFO, "3.12, ABCFG:0x54\n"); + abcfg_reg(0x98, 0x0000FF00, 0x00004700); + + /* 3.13:Enabling AB Int_Arbiter Enhancement (for All Revisions) */ + abcfg_reg(0x10054, 0x0000FFFF, 0x07FF); + + /* 3.14:Enabling L1 on A-link Express */ + axcfg_reg(0x68, 0x00000003, 0x2); + axindxp_reg(0xa0, 0x0000F000, 0x6000); + + abcfg_reg(0x10098, 0xFFFFFFFF, 0x4000); + abcfg_reg(0x04, 0xFFFFFFFF, 0x6); + printk(BIOS_INFO, "sm_init() end\n"); + + /* Enable NbSb virtual channel */ + axcfg_reg(0x114, 0x3f << 1, 0 << 1); + axcfg_reg(0x120, 0x7f << 1, 0x7f << 1); + axcfg_reg(0x120, 7 << 24, 1 << 24); + axcfg_reg(0x120, 1 << 31, 1 << 31); + abcfg_reg(0x50, 1 << 3, 1 << 3); +} + +static int lsmbus_recv_byte(struct device * dev) +{ + u32 device; + struct resource *res; + struct bus *pbus; + + device = dev->path.i2c.device; + pbus = get_pbus_smbus(dev); + + res = find_resource(pbus->dev, 0x10); + + return do_smbus_recv_byte(res->base, device); +} + +static int lsmbus_send_byte(struct device * dev, u8 val) +{ + u32 device; + struct resource *res; + struct bus *pbus; + + device = dev->path.i2c.device; + pbus = get_pbus_smbus(dev); + + res = find_resource(pbus->dev, 0x10); + + return do_smbus_send_byte(res->base, device, val); +} + +static int lsmbus_read_byte(struct device * dev, u8 address) +{ + u32 device; + struct resource *res; + struct bus *pbus; + + device = dev->path.i2c.device; + pbus = get_pbus_smbus(dev); + + res = find_resource(pbus->dev, 0x10); + + return do_smbus_read_byte(res->base, device, address); +} + +static int lsmbus_write_byte(struct device * dev, u8 address, u8 val) +{ + u32 device; + struct resource *res; + struct bus *pbus; + + device = dev->path.i2c.device; + pbus = get_pbus_smbus(dev); + + res = find_resource(pbus->dev, 0x10); + + return do_smbus_write_byte(res->base, device, address, val); +} +static struct smbus_bus_operations lops_smbus_bus = { + .recv_byte = lsmbus_recv_byte, + .send_byte = lsmbus_send_byte, + .read_byte = lsmbus_read_byte, + .write_byte = lsmbus_write_byte, +}; + +static void sb600_sm_read_resources(struct device * dev) +{ + struct resource *res; + + /* Get the normal pci resources of this device */ + pci_dev_read_resources(dev); + + /* apic */ + res = new_resource(dev, 0x74); + res->base = 0xfec00000; + res->size = 256 * 0x10; + res->limit = 0xFFFFFFFFUL; /* res->base + res->size -1; */ + res->align = 8; + res->gran = 8; + res->flags = IORESOURCE_MEM | IORESOURCE_FIXED; + + /* dev->command |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; */ + + compact_resources(dev); + +} +static void sb600_sm_set_resources(struct device *dev) +{ + struct resource *res; + + pci_dev_set_resources(dev); + + res = find_resource(dev, 0x74); + pci_write_config32(dev, 0x74, res->base | 1 << 3); +} + +static struct pci_operations lops_pci = { + .set_subsystem = pci_dev_set_subsystem, +}; +struct device_operations sb600_sm = { + .id = {.type = DEVICE_ID_PCI, + {.pci = {.vendor = PCI_VENDOR_ID_ATI, + .device = PCI_DEVICE_ID_ATI_SB600_SM}}}, + .constructor = default_device_constructor, + .phase3_scan = 0, + .phase4_read_resources = sb600_sm_read_resources, + .phase4_set_resources = sb600_sm_set_resources, + .phase5_enable_resources = pci_dev_enable_resources, + .phase6_init = sm_init, + .ops_pci = &lops_pci + .ops_smbus_bus = &lops_smbus_bus, +}; \ No newline at end of file diff --git a/src/southbridge/amd/sb600/sm.dts b/src/southbridge/amd/sb600/sm.dts new file mode 100644 index 000000000..625f9b3aa --- /dev/null +++ b/src/southbridge/amd/sb600/sm.dts @@ -0,0 +1,23 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008 Ronald G. Minnich + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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 + */ + +{ + device_operations = "sb600_sm"; +}; diff --git a/src/southbridge/amd/sb600/stage1.c b/src/southbridge/amd/sb600/stage1.c new file mode 100644 index 000000000..500ec16f5 --- /dev/null +++ b/src/southbridge/amd/sb600/stage1.c @@ -0,0 +1,640 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +BORKED +#define SMBUS_IO_BASE 0x1000 /* Is it a temporary SMBus I/O base address? */ + /*SIZE 0x40 */ + +/* Get SB ASIC Revision.*/ +static u8 get_sb600_revision() +{ + u32 dev; + pci_conf1_find_device(0x1002, 0x4385, &dev); + + if (dev == PCI_DEV_INVALID) { + die("SMBUS controller not found\r\n"); + } + return pci_conf1_read_config8(dev, 0x08); +} + + +/*************************************** +* Legacy devices are mapped to LPC space. +* serial port 0 +* KBC Port +* ACPI Micro-controller port +* LPC ROM size, +* NOTE: Call me ASAP, because I will reset LPC ROM size! +***************************************/ +static void sb600_lpc_init(void) +{ + u8 reg8; + u32 reg32; + u32 dev; + + /* Enable lpc controller */ + pci_conf1_find_device(0x1002, 0x4385, &dev); /* SMBUS controller */ + reg32 = pci_conf1_read_config32(dev, 0x64); + reg32 |= 0x00100000; + pci_conf1_write_config32(dev, 0x64, reg32); + + pci_conf1_find_device(0x1002, 0x438d, &dev); /* LPC Controller */ + /* Serial 0 */ + reg8 = pci_conf1_read_config8(dev, 0x44); + reg8 |= (1 << 6); + pci_conf1_write_config8(dev, 0x44, reg8); + + /* PS/2 keyboard, ACPI */ + reg8 = pci_conf1_read_config8(dev, 0x47); + reg8 |= (1 << 5) | (1 << 6); + pci_conf1_write_config8(dev, 0x47, reg8); + + /* SuperIO, LPC ROM */ + reg8 = pci_conf1_read_config8(dev, 0x48); + reg8 |= (1 << 1) | (1 << 0); /* enable Super IO config port 2e-2h, 4e-4f */ + reg8 |= (1 << 3) | (1 << 4); /* enable for LPC ROM address range1&2, Enable 512KB rom access at 0xFFF80000 - 0xFFFFFFFF */ + reg8 |= 1 << 6; /* enable for RTC I/O range */ + pci_conf1_write_config8(dev, 0x48, reg8); + + /* hardware should enable LPC ROM by pin strapes */ + /* rom access at 0xFFF80000/0xFFF00000 - 0xFFFFFFFF */ + /* See detail in BDG-215SB600-03.pdf page 15. */ + pci_conf1_write_config16(dev, 0x68, 0x000e); /* enable LPC ROM range, 0xfff8: 512KB, 0xfff0: 1MB; */ + pci_conf1_write_config16(dev, 0x6c, 0xfff0); /* enable LPC ROM range, 0xfff8: 512KB, 0xfff0: 1MB */ +} + +/* what is its usage? */ +static u32 get_sbdn(u32 bus) +{ + u32 dev; + + /* Find the device. */ + pci_conf1_find_on_bus(bus, 0x1002, 0x4385, &dev); + return (dev >> 15) & 0x1f; +} + + +static u8 dual_core() +{ + if(((cpuid_eax(0x80000000) & ~0xff) >= 8)) { + if(cpuid_ecx(0x80000008) & 1) + return 1; + } + return 0; +} + +/* +SB600 VFSMAF (VID/FID System Management Action Field) is 010b by default. +RPR 2.3.3 C-state and VID/FID change for the K8 platform. +*/ +static void enable_fid_change_on_sb(u32 sbbusn, u32 sbdn) +{ + u8 byte; + byte = pmio_read(0x9a); + byte &= ~0x34; + if(dual_core()) + byte |= 0x34; + else + byte |= 0x04; + pmio_write(0x9a, byte); + + byte = pmio_read(0x8f); + byte &= ~0x30; + byte |= 0x20; + pmio_write(0x8f, byte); + + pmio_write(0x8b, 0x01); + pmio_write(0x8a, 0x90); + + if(get_sb600_revision() > 0x13) + pmio_write(0x88, 0x10); + else + pmio_write(0x88, 0x06); + + byte = pmio_read(0x7c); + byte &= ~0x01; + byte |= 0x01; + pmio_write(0x7c, byte); + + /*Must be 0 for K8 platform.*/ + byte = pmio_read(0x68); + byte &= ~0x01; + pmio_write(0x68, byte); + /*Must be 0 for K8 platform.*/ + byte = pmio_read(0x8d); + byte &= ~(1<<6); + pmio_write(0x8d, byte); + + byte = pmio_read(0x61); + byte &= ~0x04; + pmio_write(0x61, byte); + + byte = pmio_read(0x42); + byte &= ~0x04; + pmio_write(0x42, byte); + + if(get_sb600_revision() == 0x14) { + pmio_write(0x89, 0x10); + + byte = pmio_read(0x52); + byte |= 0x80; + pmio_write(0x52, byte); + } +} + + +static void hard_reset(void) +{ + set_bios_reset(); + + /* full reset */ + outb(0x0a, 0x0cf9); + outb(0x0e, 0x0cf9); +} + +static void soft_reset(void) +{ + set_bios_reset(); + /* link reset */ + outb(0x06, 0x0cf9); +} + + +static void sb600_pci_port80() +{ + u8 byte; + u32 dev; + + /* P2P Bridge */ + pci_conf1_find_device(0x1002, 0x4384, &dev); + + byte = pci_conf1_read_config8(dev, 0x40); + byte |= 1 << 5; + pci_conf1_write_config8(dev, 0x40, byte); + + byte = pci_conf1_read_config8(dev, 0x4B); + byte |= 1 << 7; + pci_conf1_write_config8(dev, 0x4B, byte); + + byte = pci_conf1_read_config8(dev, 0x1C); + byte |= 0xF << 4; + pci_conf1_write_config8(dev, 0x1C, byte); + + byte = pci_conf1_read_config8(dev, 0x1D); + byte |= 0xF << 4; + pci_conf1_write_config8(dev, 0x1D, byte); + + byte = pci_conf1_read_config8(dev, 0x04); + byte |= 1 << 0; + pci_conf1_write_config8(dev, 0x04, byte); + + pci_conf1_find_device(0x1002, 0x438D, &dev); + + byte = pci_conf1_read_config8(dev, 0x4A); + byte &= ~(1 << 5); /* disable lpc port 80 */ + pci_conf1_write_config8(dev, 0x4A, byte); +} + +static void sb600_lpc_port80(void) +{ + u8 byte; + u32 dev; + u32 reg32; + + /* enable lpc controller */ + pci_conf1_find_device(0x1002, 0x4385, &dev); + reg32 = pci_conf1_read_config32(dev, 0x64); + reg32 |= 0x00100000; /* lpcEnable */ + pci_conf1_write_config32(dev, 0x64, reg32); + + /* enable prot80 LPC decode in pci function 3 configuration space. */ + pci_conf1_find_device(0x1002, 0x438d, &dev); + byte = pci_conf1_read_config8(dev, 0x4a); + byte |= 1 << 5; /* enable port 80 */ + pci_conf1_write_config8(dev, 0x4a, byte); +} + + +/* sbDevicesPorInitTable */ +static void sb600_devices_por_init() +{ + u32 dev; + u8 byte; + + printk(BIOS_INFO, "sb600_devices_por_init()\n"); + /* SMBus Device, BDF:0-20-0 */ + printk(BIOS_INFO, "sb600_devices_por_init(): SMBus Device, BDF:0-20-0\n"); + pci_conf1_find_device(0x1002, 0x4385, &dev); + + if (dev == PCI_DEV_INVALID) { + die("SMBUS controller not found\r\n"); + } + printk(BIOS_INFO, "SMBus controller enabled, sb revision is 0x%x\r\n", + get_sb600_revision()); + + /* sbPorAtStartOfTblCfg */ + /* Set A-Link bridge access address. This address is set at device 14h, function 0, register 0xf0. + * This is an I/O address. The I/O address must be on 16-byte boundry. */ + pci_conf1_write_config32(dev, 0xf0, AB_INDX); + + /* To enable AB/BIF DMA access, a specific register inside the BIF register space needs to be configured first. */ + /*Enables the SB600 to send transactions upstream over A-Link Express interface. */ + axcfg_reg(0x04, 1 << 2, 1 << 2); + axindxc_reg(0x21, 0xff, 0); + + /* 2.3.5:Enabling Non-Posted Memory Write for the K8 Platform */ + axindxc_reg(0x10, 1 << 9, 1 << 9); + /* END of sbPorAtStartOfTblCfg */ + + /* sbDevicesPorInitTables */ + /* set smbus iobase */ + pci_conf1_write_config32(dev, 0x10, SMBUS_IO_BASE | 1); + + /* enable smbus controller interface */ + byte = pci_conf1_read_config8(dev, 0xd2); + byte |= (1 << 0); + pci_conf1_write_config8(dev, 0xd2, byte); + + /* set smbus 1, ASF 2.0 (Alert Standard Format), iobase */ + pci_conf1_write_config16(dev, 0x58, SMBUS_IO_BASE | 0x11); + + /* TODO: I don't know the useage of followed two lines. I copied them from CIM. */ + pci_conf1_write_config8(dev, 0x0a, 0x1); + pci_conf1_write_config8(dev, 0x0b, 0x6); + + /* KB2RstEnable */ + pci_conf1_write_config8(dev, 0x40, 0xd4); + + /* Enable ISA Address 0-960K decoding */ + pci_conf1_write_config8(dev, 0x48, 0x0f); + + /* Enable ISA Address 0xC0000-0xDFFFF decode */ + pci_conf1_write_config8(dev, 0x49, 0xff); + + /* Enable decode cycles to IO C50, C51, C52 GPM controls. */ + byte = pci_conf1_read_config8(dev, 0x41); + byte &= 0x80; + byte |= 0x33; + pci_conf1_write_config8(dev, 0x41, byte); + + /* Legacy DMA Prefetch Enhancement, CIM masked it. */ + /* pci_conf1_write_config8(dev, 0x43, 0x1); */ + + /* Disabling Legacy USB Fast SMI# */ + byte = pci_conf1_read_config8(dev, 0x62); + byte |= 0x24; + pci_conf1_write_config8(dev, 0x62, byte); + + /* Features Enable */ + pci_conf1_write_config32(dev, 0x64, 0x829E79BF); + + /* SerialIrq Control */ + pci_conf1_write_config8(dev, 0x69, 0x90); + + /* Test Mode, PCIB_SReset_En Mask is set. */ + pci_conf1_write_config8(dev, 0x6c, 0x20); + + /* IO Address Enable, CIM set 0x78 only and masked 0x79. */ + /*pci_conf1_write_config8(dev, 0x79, 0x4F); */ + pci_conf1_write_config8(dev, 0x78, 0xFF); + + /* This register is not used on sb600. It came from older chipset. */ + /*pci_conf1_write_config8(dev, 0x95, 0xFF); */ + + /* Set smbus iospace enable, I don't know why write 0x04 into reg5 that is reserved */ + pci_conf1_write_config16(dev, 0x4, 0x0407); + + /* clear any lingering errors, so the transaction will run */ + outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT); + + /* IDE Device, BDF:0-20-1 */ + printk(BIOS_INFO, "sb600_devices_por_init(): IDE Device, BDF:0-20-1\n"); + pci_conf1_find_device(0x1002, 0x438C, &dev); + /* Disable prefetch */ + byte = pci_conf1_read_config8(dev, 0x63); + byte |= 0x1; + pci_conf1_write_config8(dev, 0x63, byte); + + /* LPC Device, BDF:0-20-3 */ + printk(BIOS_INFO, "sb600_devices_por_init(): LPC Device, BDF:0-20-3\n"); + pci_conf1_find_device(0x1002, 0x438D, &dev); + /* DMA enable */ + pci_conf1_write_config8(dev, 0x40, 0x04); + + /* IO Port Decode Enable */ + pci_conf1_write_config8(dev, 0x44, 0xFF); + pci_conf1_write_config8(dev, 0x45, 0xFF); + pci_conf1_write_config8(dev, 0x46, 0xC3); + pci_conf1_write_config8(dev, 0x47, 0xFF); + + /* IO/Mem Port Decode Enable, I don't know why CIM disable some ports. + * Disable LPC TimeOut counter, enable SuperIO Configuration Port (2e/2f), + * Alternate SuperIO Configuration Port (4e/4f), Wide Generic IO Port (64/65). + * Enable bits for LPC ROM memory address range 1&2 for 1M ROM setting.*/ + byte = pci_conf1_read_config8(dev, 0x48); + byte |= (1 << 1) | (1 << 0); /* enable Super IO config port 2e-2h, 4e-4f */ + byte |= (1 << 3) | (1 << 4); /* enable for LPC ROM address range1&2, Enable 512KB rom access at 0xFFF80000 - 0xFFFFFFFF */ + byte |= 1 << 6; /* enable for RTC I/O range */ + pci_conf1_write_config8(dev, 0x48, byte); + pci_conf1_write_config8(dev, 0x49, 0xFF); + /* Enable 0x480-0x4bf, 0x4700-0x470B */ + byte = pci_conf1_read_config8(dev, 0x4A); + byte |= ((1 << 1) + (1 << 6)); /*0x42, save the configuraion for port 0x80. */ + pci_conf1_write_config8(dev, 0x4A, byte); + + /* Set LPC ROM size, it has been done in sb600_lpc_init(). + * enable LPC ROM range, 0xfff8: 512KB, 0xfff0: 1MB; + * enable LPC ROM range, 0xfff8: 512KB, 0xfff0: 1MB + * pci_conf1_write_config16(dev, 0x68, 0x000e) + * pci_conf1_write_config16(dev, 0x6c, 0xfff0);*/ + + /* Enable Tpm12_en and Tpm_legacy. I don't know what is its usage and copied from CIM. */ + pci_conf1_write_config8(dev, 0x7C, 0x05); + + /* P2P Bridge, BDF:0-20-4, the configuration of the registers in this dev are copied from CIM, + * TODO: I don't know what are their mean? */ + printk(BIOS_INFO, "sb600_devices_por_init(): P2P Bridge, BDF:0-20-4\n"); + pci_conf1_find_device(0x1002, 0x4384, &dev); + /* I don't know why CIM tried to write into a read-only reg! */ + /*pci_conf1_write_config8(dev, 0x0c, 0x20) */ ; + + /* Arbiter enable. */ + pci_conf1_write_config8(dev, 0x43, 0xff); + + /* Set PCDMA request into hight priority list. */ + /* pci_conf1_write_config8(dev, 0x49, 0x1) */ ; + + pci_conf1_write_config8(dev, 0x40, 0x26); + + /* I don't know why CIM set reg0x1c as 0x11. + * System will block at sdram_initialize() if I set it before call sdram_initialize(). + * If it is necessary to set reg0x1c as 0x11, please call this function after sdram_initialize(). + * pci_conf1_write_config8(dev, 0x1c, 0x11); + * pci_conf1_write_config8(dev, 0x1d, 0x11);*/ + + /*CIM set this register; but I didn't find its description in RPR. + On DBM690T platform, I didn't find different between set and skip this register. + But on Filbert platform, the DEBUG message from serial port on Peanut board can't be displayed + after the bit0 of this register is set. + pci_conf1_write_config8(dev, 0x04, 0x21); + */ + pci_conf1_write_config8(dev, 0x0d, 0x40); + pci_conf1_write_config8(dev, 0x1b, 0x40); + /* Enable PCIB_DUAL_EN_UP will fix potential problem with PCI cards. */ + pci_conf1_write_config8(dev, 0x50, 0x01); + + /* SATA Device, BDF:0-18-0, Non-Raid-5 SATA controller */ + printk(BIOS_INFO, "sb600_devices_por_init(): SATA Device, BDF:0-18-0\n"); + pci_conf1_find_device(0x1002, 0x4380, &dev); + + /*PHY Global Control, we are using A14. + * default: 0x2c40 for ASIC revision A12 and below + * 0x2c00 for ASIC revision A13 and above.*/ + pci_conf1_write_config16(dev, 0x86, 0x2C00); + + /* PHY Port0-3 Control */ + pci_conf1_write_config32(dev, 0x88, 0xB400DA); + pci_conf1_write_config32(dev, 0x8c, 0xB400DA); + pci_conf1_write_config32(dev, 0x90, 0xB400DA); + pci_conf1_write_config32(dev, 0x94, 0xB400DA); + + /* Port0-3 BIST Control/Status */ + pci_conf1_write_config8(dev, 0xa5, 0xB8); + pci_conf1_write_config8(dev, 0xad, 0xB8); + pci_conf1_write_config8(dev, 0xb5, 0xB8); + pci_conf1_write_config8(dev, 0xbd, 0xB8); +} + +/* sbPmioPorInitTable, Pre-initializing PMIO register space +* The power management (PM) block is resident in the PCI/LPC/ISA bridge. +* The PM regs are accessed via IO mapped regs 0xcd6 and 0xcd7. +* The index address is first programmed into IO reg 0xcd6. +* Read or write values are accessed through IO reg 0xcd7. +*/ +static void sb600_pmio_por_init() +{ + u8 byte; + + printk(BIOS_INFO, "sb600_pmio_por_init()\n"); + /* K8KbRstEn, KB_RST# control for K8 system. */ + byte = pmio_read(0x66); + byte |= 0x20; + pmio_write(0x66, byte); + + /* RPR2.3.4 S3/S4/S5 Function for the K8 Platform. */ + byte = pmio_read(0x52); + byte &= 0xc0; + byte |= 0x08; + pmio_write(0x52, byte); + + /* C state enable and SLP enable in C states. */ + byte = pmio_read(0x67); + byte |= 0x6; + pmio_write(0x67, byte); + + /* CIM sets 0x0e, but bit2 is for P4 system. */ + byte = pmio_read(0x68); + byte &= 0xf0; + byte |= 0x0c; + pmio_write(0x68, byte); + + /* Watch Dog Timer Control + * Set watchdog time base to 0xfec000f0 to avoid SCSI card boot failure. + * But I don't find WDT is enabled in SMBUS 0x41 bit3 in CIM. + */ + pmio_write(0x6c, 0xf0); + pmio_write(0x6d, 0x00); + pmio_write(0x6e, 0xc0); + pmio_write(0x6f, 0xfe); + + /* rpr2.14: Enables HPET periodical mode */ + byte = pmio_read(0x9a); + byte |= 1 << 7; + pmio_write(0x9a, byte); + byte = pmio_read(0x9f); + byte |= 1 << 5; + pmio_write(0x9f, byte); + byte = pmio_read(0x9e); + byte |= (1 << 6) | (1 << 7); + pmio_write(0x9e, byte); + + /* rpr2.14: Hides SM bus controller Bar1 where stores HPET MMIO base address */ + byte = pmio_read(0x55); + byte |= 1 << 7; + pmio_write(0x55, byte); + + /* rpr2.14: Make HPET MMIO decoding controlled by the memory enable bit in command register of LPC ISA bridage */ + byte = pmio_read(0x52); + byte |= 1 << 6; + pmio_write(0x52, byte); + + /* rpr2.22: PLL Reset */ + byte = pmio_read(0x86); + byte |= 1 << 7; + pmio_write(0x86, byte); + + /* rpr2.3.3 */ + /* This provides 16us delay before the assertion of LDTSTP# when C3 is entered. + * The delay will allow USB DMA to go on in a continuous manner + */ + pmio_write(0x89, 0x10); + /* Set this bit to allow pop-up request being latched during the minimum LDTSTP# assertion time */ + byte = pmio_read(0x52); + byte |= 1 << 7; + pmio_write(0x52, byte); + + /* rpr2.15: ASF Remote Control Action */ + byte = pmio_read(0x9f); + byte |= 1 << 6; + pmio_write(0x9f, byte); + + /* rpr2.19: Enabling Spread Spectrum */ + byte = pmio_read(0x42); + byte |= 1 << 7; + pmio_write(0x42, byte); +} + +/* +* Compliant with CIM_48's sbPciCfg. +* Add any south bridge setting. +*/ +static void sb600_pci_cfg() +{ + u32 dev; + u8 byte; + + /* SMBus Device, BDF:0-20-0 */ + pci_conf1_find_device(0x1002, 0x4385, &dev); + /* Eable the hidden revision ID, available after A13. */ + byte = pci_conf1_read_config8(dev, 0x70); + byte |= (1 << 8); + pci_conf1_write_config8(dev, 0x70, byte); + /* rpr2.20 Disable Timer IRQ Enhancement for proper operation of the 8254 timer, 0xae[5]. */ + byte = pci_conf1_read_config8(dev, 0xae); + byte |= (1 << 5); + pci_conf1_write_config8(dev, 0xae, byte); + + /* Enable watchdog decode timer */ + byte = pci_conf1_read_config8(dev, 0x41); + byte |= (1 << 3); + pci_conf1_write_config8(dev, 0x41, byte); + + /* Set to 1 to reset USB on the software (such as IO-64 or IO-CF9 cycles) + * generated PCIRST#. */ + byte = pmio_read(0x65); + byte |= (1 << 4); + pmio_write(0x65, byte); + /*For A13 and above. */ + if (get_sb600_revision() > 0x12) { + /* rpr2.16 C-State Reset, PMIO 0x9f[7]. */ + byte = pmio_read(0x9f); + byte |= (1 << 7); + pmio_write(0x9f, byte); + /* rpr2.17 PCI Clock Period will increase to 30.8ns. 0x53[7]. */ + byte = pmio_read(0x53); + byte |= (1 << 7); + pmio_write(0x53, byte); + } + + /* IDE Device, BDF:0-20-1 */ + pci_conf1_find_device(0x1002, 0x438C, &dev); + /* Enable IDE Explicit prefetch, 0x63[0] clear */ + byte = pci_conf1_read_config8(dev, 0x63); + byte &= 0xfe; + pci_conf1_write_config8(dev, 0x63, byte); + + /* LPC Device, BDF:0-20-3 */ + pci_conf1_find_device(0x1002, 0x438D, &dev); + /* rpr7.2 Enabling LPC DMA function. */ + byte = pci_conf1_read_config8(dev, 0x40); + byte |= (1 << 2); + pci_conf1_write_config8(dev, 0x40, byte); + /* rpr7.3 Disabling LPC TimeOut. 0x48[7] clear. */ + byte = pci_conf1_read_config8(dev, 0x48); + byte &= 0x7f; + pci_conf1_write_config8(dev, 0x48, byte); + /* rpr7.5 Disabling LPC MSI Capability, 0x78[1] clear. */ + byte = pci_conf1_read_config8(dev, 0x78); + byte &= 0xfd; + pci_conf1_write_config8(dev, 0x78, byte); + + /* SATA Device, BDF:0-18-0, Non-Raid-5 SATA controller */ + pci_conf1_find_device(0x1002, 0x4380, &dev); + /* rpr6.8 Disabling SATA MSI Capability, for A13 and above, 0x42[7]. */ + if (0x12 < get_sb600_revision()) { + u32 reg32; + reg32 = pci_conf1_read_config32(dev, 0x40); + reg32 |= (1 << 23); + pci_conf1_write_config32(dev, 0x40, reg32); + } + + /* EHCI Device, BDF:0-19-5, ehci usb controller */ + pci_conf1_find_device(0x1002, 0x4386, &dev); + /* rpr5.10 Disabling USB EHCI MSI Capability. 0x50[6]. */ + byte = pci_conf1_read_config8(dev, 0x50); + byte |= (1 << 6); + pci_conf1_write_config8(dev, 0x50, byte); + + /* OHCI0 Device, BDF:0-19-0, ohci usb controller #0 */ + pci_conf1_find_device(0x1002, 0x4387, &dev); + /* rpr5.11 Disabling USB OHCI MSI Capability. 0x40[12:8]=0x1f. */ + byte = pci_conf1_read_config8(dev, 0x41); + byte |= 0x1f; + pci_conf1_write_config8(dev, 0x41, byte); + +} + +/* +* Compliant with CIM_48's ATSBPowerOnResetInitJSP +*/ +static void sb600_por_init() +{ + /* sbDevicesPorInitTable + sbK8PorInitTable */ + sb600_devices_por_init(); + + /* sbPmioPorInitTable + sbK8PmioPorInitTable */ + sb600_pmio_por_init(); +} + +/* +* Compliant with CIM_48's AtiSbBeforePciInit +* It should be called during early POST after memory detection and BIOS shadowing but before PCI bus enumeration. +*/ +static void sb600_before_pci_init() +{ + sb600_pci_cfg(); +} + +/* +* This function should be called after enable_sb600_smbus(). +*/ +static void sb600_stage1(void) +{ + printk(BIOS_INFO, "sb600_early_setup()\n"); + sb600_por_init(); +} diff --git a/src/southbridge/amd/sb600/stage1_reset.c b/src/southbridge/amd/sb600/stage1_reset.c new file mode 100644 index 000000000..cc069e5a4 --- /dev/null +++ b/src/southbridge/amd/sb600/stage1_reset.c @@ -0,0 +1,38 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void hard_reset(void) +{ + set_bios_reset(); + /* Try rebooting through port 0xcf9 */ + /* Actually it is not a real hard_reset --- it only resets coherent link table, but + * does not reset link freq and width */ + outb((0 << 3) | (0 << 2) | (1 << 1), 0xcf9); + outb((0 << 3) | (1 << 2) | (1 << 1), 0xcf9); +} diff --git a/src/southbridge/amd/sb600/stage1_smbus.c b/src/southbridge/amd/sb600/stage1_smbus.c new file mode 100644 index 000000000..57f399f60 --- /dev/null +++ b/src/southbridge/amd/sb600/stage1_smbus.c @@ -0,0 +1,229 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sb600_smbus.h" + +void smbus_delay(void) +{ + inb(0x80); +} + +int smbus_wait_until_ready(u32 smbus_io_base) +{ + unsigned long loops; + loops = SMBUS_TIMEOUT; + do { + u8 val; + val = inb(smbus_io_base + SMBHSTSTAT); + val &= 0x1f; + if (val == 0) { /* ready now */ + return 0; + } + outb(val, smbus_io_base + SMBHSTSTAT); + } while (--loops); + return -2; /* time out */ +} + +int smbus_wait_until_done(u32 smbus_io_base) +{ + unsigned long loops; + loops = SMBUS_TIMEOUT; + do { + u8 val; + + val = inb(smbus_io_base + SMBHSTSTAT); + val &= 0x1f; /* mask off reserved bits */ + if (val & 0x1c) { + return -5; /* error */ + } + if (val == 0x02) { + outb(val, smbus_io_base + SMBHSTSTAT); /* clear status */ + return 0; + } + } while (--loops); + return -3; /* timeout */ +} + +int do_smbus_recv_byte(u32 smbus_io_base, u32 device) +{ + u8 byte; + + if (smbus_wait_until_ready(smbus_io_base) < 0) { + return -2; /* not ready */ + } + + /* set the device I'm talking too */ + outb(((device & 0x7f) << 1) | 1, smbus_io_base + SMBHSTADDR); + + byte = inb(smbus_io_base + SMBHSTCTRL); + byte &= 0xe3; /* Clear [4:2] */ + byte |= (1 << 2) | (1 << 6); /* Byte data read/write command, start the command */ + outb(byte, smbus_io_base + SMBHSTCTRL); + + /* poll for transaction completion */ + if (smbus_wait_until_done(smbus_io_base) < 0) { + return -3; /* timeout or error */ + } + + /* read results of transaction */ + byte = inb(smbus_io_base + SMBHSTCMD); + + return byte; +} + +int do_smbus_send_byte(u32 smbus_io_base, u32 device, + u8 val) +{ + u8 byte; + + if (smbus_wait_until_ready(smbus_io_base) < 0) { + return -2; /* not ready */ + } + + /* set the command... */ + outb(val, smbus_io_base + SMBHSTCMD); + + /* set the device I'm talking too */ + outb(((device & 0x7f) << 1) | 0, smbus_io_base + SMBHSTADDR); + + byte = inb(smbus_io_base + SMBHSTCTRL); + byte &= 0xe3; /* Clear [4:2] */ + byte |= (1 << 2) | (1 << 6); /* Byte data read/write command, start the command */ + outb(byte, smbus_io_base + SMBHSTCTRL); + + /* poll for transaction completion */ + if (smbus_wait_until_done(smbus_io_base) < 0) { + return -3; /* timeout or error */ + } + + return 0; +} + +int do_smbus_read_byte(u32 smbus_io_base, u32 device, + u32 address) +{ + u8 byte; + + if (smbus_wait_until_ready(smbus_io_base) < 0) { + return -2; /* not ready */ + } + + /* set the command/address... */ + outb(address & 0xff, smbus_io_base + SMBHSTCMD); + + /* set the device I'm talking to */ + outb(((device & 0x7f) << 1) | 1, smbus_io_base + SMBHSTADDR); + + byte = inb(smbus_io_base + SMBHSTCTRL); + byte &= 0xe3; /* Clear [4:2] */ + byte |= (1 << 3) | (1 << 6); /* Byte data read/write command, start the command */ + outb(byte, smbus_io_base + SMBHSTCTRL); + + /* poll for transaction completion */ + if (smbus_wait_until_done(smbus_io_base) < 0) { + return -3; /* timeout or error */ + } + + /* read results of transaction */ + byte = inb(smbus_io_base + SMBHSTDAT0); + + return byte; +} + +int do_smbus_write_byte(u32 smbus_io_base, u32 device, + u32 address, u8 val) +{ + u8 byte; + + if (smbus_wait_until_ready(smbus_io_base) < 0) { + return -2; /* not ready */ + } + + /* set the command/address... */ + outb(address & 0xff, smbus_io_base + SMBHSTCMD); + + /* set the device I'm talking to */ + outb(((device & 0x7f) << 1) | 0, smbus_io_base + SMBHSTADDR); + + /* output value */ + outb(val, smbus_io_base + SMBHSTDAT0); + + byte = inb(smbus_io_base + SMBHSTCTRL); + byte &= 0xe3; /* Clear [4:2] */ + byte |= (1 << 3) | (1 << 6); /* Byte data read/write command, start the command */ + outb(byte, smbus_io_base + SMBHSTCTRL); + + /* poll for transaction completion */ + if (smbus_wait_until_done(smbus_io_base) < 0) { + return -3; /* timeout or error */ + } + + return 0; +} + +void alink_ab_indx(unsigned int reg_space, unsigned int reg_addr, + unsigned int mask, unsigned int val) +{ + unsigned int tmp; + outl((reg_space & 0x3) << 30 | reg_addr, AB_INDX); + tmp = inl(AB_DATA); + + tmp &= ~mask; + tmp |= val; + + /* printk_debug("about write %x, index=%x", tmp, (reg_space&0x3)<<30 | reg_addr); */ + outl((reg_space & 0x3) << 30 | reg_addr, AB_INDX); /* probably we dont have to do it again. */ + outl(tmp, AB_DATA); +} + +/* space = 0: AX_INDXC, AX_DATAC +* space = 1: AX_INDXP, AX_DATAP + */ +void alink_ax_indx(unsigned int space /*c or p? */ , unsigned int axindc, + unsigned int mask, unsigned int val) +{ + unsigned int tmp; + + /* read axindc to tmp */ + outl(space << 30 | space << 3 | 0x30, AB_INDX); + outl(axindc, AB_DATA); + outl(space << 30 | space << 3 | 0x34, AB_INDX); + tmp = inl(AB_DATA); + + tmp &= ~mask; + tmp |= val; + + /* write tmp */ + outl(space << 30 | space << 3 | 0x30, AB_INDX); + outl(axindc, AB_DATA); + outl(space << 30 | space << 3 | 0x34, AB_INDX); + outl(tmp, AB_DATA); +} + + + diff --git a/src/southbridge/amd/sb600/usb.c b/src/southbridge/amd/sb600/usb.c new file mode 100644 index 000000000..d8ef2c2b0 --- /dev/null +++ b/src/southbridge/amd/sb600/usb.c @@ -0,0 +1,205 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include "sb600.h" + +static struct pci_operations lops_pci = { + .set_subsystem = pci_dev_set_subsystem, +}; + +static void usb_init(struct device *dev) +{ + u8 byte; + u16 word; + u32 dword; + + /* Enable OHCI0-4 and EHCI Controllers */ + struct device * sm_dev; + sm_dev = dev_find_slot(0, PCI_DEVFN(0x14, 0)); + byte = pci_read_config8(sm_dev, 0x68); + byte |= 0x3F; + pci_write_config8(sm_dev, 0x68, byte); + + /* RPR 5.2 Enables the USB PME Event,Enable USB resume support */ + byte = pm_ioread(0x61); + byte |= 1 << 6; + pm_iowrite(0x61, byte); + byte = pm_ioread(0x65); + byte |= 1 << 2; + pm_iowrite(0x65, byte); + + /* RPR 5.3 Support USB device wakeup from the S4/S5 state */ + byte = pm_ioread(0x65); + byte &= ~(1 << 0); + pm_iowrite(0x65, byte); + + /* RPR 5.6 Enable the USB controller to get reset by any software that generate a PCIRst# condition */ + byte = pm_ioread(0x65); + byte |= (1 << 4); + pm_iowrite(0x65, byte); + + /* RPR 5.11 Disable OHCI MSI Capability */ + word = pci_read_config16(dev, 0x40); + word |= (0x1F << 8); + pci_write_config16(dev, 0x40, word); + + /* RPR 5.8 Disable the OHCI Dynamic Power Saving feature */ + dword = pci_read_config32(dev, 0x50); + dword &= ~(1 << 16); + pci_write_config32(dev, 0x50, dword); + + /* RPR 5.12 Enable prevention of OHCI accessing the invalid system memory address range */ + word = pci_read_config16(dev, 0x50); + word |= 1 << 15; + pci_write_config16(dev, 0x50, word); + + /* RPR 5.15 Disable SMI handshake in between USB and ACPI for USB legacy support. */ + /* The BIOS should always set this bit to prevent the malfunction on USB legacy keyboard/mouse support */ + word = pci_read_config16(dev, 0x50); + word |= 1 << 12; + pci_write_config16(dev, 0x50, word); +} + +static void usb_init2(struct device *dev) +{ + u8 byte; + u16 word; + u32 dword; + u8 *usb2_bar0; + /* dword = pci_read_config32(dev, 0xf8); */ + /* dword |= 40; */ + /* pci_write_config32(dev, 0xf8, dword); */ + + usb2_bar0 = (u8 *) (pci_read_config32(dev, 0x10) & ~0xFF); + printk_info("usb2_bar0=%x\n", usb2_bar0); + + /* RPR5.4 Enables the USB PHY auto calibration resister to match 45ohm resistence */ + dword = 0x00020F00; + writel(dword, usb2_bar0 + 0xC0); + + /* RPR5.5 Sets In/OUT FIFO threshold for best performance */ + dword = 0x00200040; + writel(dword, usb2_bar0 + 0xA4); + + /* RPR5.9 Disable the EHCI Dynamic Power Saving feature */ + word = readl(usb2_bar0 + 0xBC); + word &= ~(1 << 12); + writew(word, usb2_bar0 + 0xBC); + + /* RPR5.10 Disable EHCI MSI support */ + byte = pci_read_config8(dev, 0x50); + byte |= (1 << 6); + pci_write_config8(dev, 0x50, byte); + + /* RPR5.13 Disable C3 time enhancement feature */ + dword = pci_read_config32(dev, 0x50); + dword &= ~(1 << 28); + pci_write_config32(dev, 0x50, dword); + + /* RPR5.14 Disable USB PHY PLL Reset signal to come from ACPI */ + byte = pci_read_config8(dev, 0x54); + byte &= ~(1 << 0); + pci_write_config8(dev, 0x54, byte); +} + +static void usb_set_resources(struct device *dev) +{ +#ifdef CONFIG_USBDEBUG_DIRECT + struct resource *res; + u32 base; + u32 old_debug; + + old_debug = get_ehci_debug(); + set_ehci_debug(0); +#endif + pci_dev_set_resources(dev); + +#ifdef CONFIG_USBDEBUG_DIRECT + res = find_resource(dev, 0x10); + set_ehci_debug(old_debug); + if (!res) + return; + base = res->base; + set_ehci_base(base); + report_resource_stored(dev, res, ""); +#endif + +} + +/* note that below there are a lot of usb drivers. But we don't support linker sets + * What we need to do is has a phase 2 function that puts the many usb devices into the device tree. + * That's one of the purposes of phase 2. We will write this later. + * + */ +#warning need USB phase 2 function to populate device tree +struct device_operations sb600_usb = { + .id = {.type = DEVICE_ID_PCI, + {.pci = {.vendor = PCI_VENDOR_ID_ATI, + .device = PCI_DEVICE_ID_ATI_SB600_USB_0}}}, + .constructor = default_device_constructor, + .phase3_scan = scan_static_bus, + .phase4_read_resources = pci_dev_read_resources, + .phase4_set_resources = usb_set_resources, + .phase5_enable_resources = pci_dev_enable_resources, + .phase6_init = usb_init, + .ops_pci = &lops_pci +}; + +#if 0 +static struct pci_driver usb_1_driver __pci_driver = { + .ops = &usb_ops, + .vendor = PCI_VENDOR_ID_ATI, + .device = PCI_DEVICE_ID_ATI_SB600_USB_1, +}; +static struct pci_driver usb_2_driver __pci_driver = { + .ops = &usb_ops, + .vendor = PCI_VENDOR_ID_ATI, + .device = PCI_DEVICE_ID_ATI_SB600_USB_2, +}; +static struct pci_driver usb_3_driver __pci_driver = { + .ops = &usb_ops, + .vendor = PCI_VENDOR_ID_ATI, + .device = PCI_DEVICE_ID_ATI_SB600_USB_3, +}; +static struct pci_driver usb_4_driver __pci_driver = { + .ops = &usb_ops, + .vendor = PCI_VENDOR_ID_ATI, + .device = PCI_DEVICE_ID_ATI_SB600_USB_4, +}; +#endif + +struct device_operations sb600_usb2 = { + .id = {.type = DEVICE_ID_PCI, + {.pci = {.vendor = PCI_VENDOR_ID_ATI, + .device = PCI_DEVICE_ID_ATI_SB600_USB2}}}, + .constructor = default_device_constructor, + .phase3_scan = scan_static_bus, + .phase4_read_resources = pci_dev_read_resources, + .phase4_set_resources = usb_set_resources, + .phase5_enable_resources = pci_dev_enable_resources, + .phase6_init = usb_init, + .ops_pci = &lops_pci +}; diff --git a/src/southbridge/amd/sb600/usb.dts b/src/southbridge/amd/sb600/usb.dts new file mode 100644 index 000000000..1a1e88234 --- /dev/null +++ b/src/southbridge/amd/sb600/usb.dts @@ -0,0 +1,23 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008 Ronald G. Minnich + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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 + */ + +{ + device_operations = "sb600_usb"; +}; diff --git a/src/southbridge/amd/sb600/usb2.dts b/src/southbridge/amd/sb600/usb2.dts new file mode 100644 index 000000000..c149c0f10 --- /dev/null +++ b/src/southbridge/amd/sb600/usb2.dts @@ -0,0 +1,23 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2008 Ronald G. Minnich + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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 + */ + +{ + device_operations = "sb600_usb2"; +}; -- 2.25.1