diff options
author | Yinghai Lu <yinghai.lu@amd.com> | 2007-02-01 00:10:05 +0000 |
---|---|---|
committer | Stefan Reinauer <stepan@openbios.org> | 2007-02-01 00:10:05 +0000 |
commit | c65bd562a8653cdf7e273917a9f5dcea1f5f99b7 (patch) | |
tree | 4a4fbc4a4cd005c99c49c93efa48c8e3653ad39e /src/southbridge | |
parent | 097d9a2d57fce2bd1bbe0d9c3628b75c1a25a934 (diff) |
Add support for the NVIDIA MCP55 southbridge.
Signed-off-by: Yinghai Lu <yinghai.lu@amd.com>
Signed-off-by: Ronald G. Minnich <rminnich@gmail.com>
Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
Acked-by: Yinghai Lu <yinghai.lu@amd.com>
Acked-by: Stefan Reinauer <stepan@coresystems.de>
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@2540 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'src/southbridge')
27 files changed, 3267 insertions, 0 deletions
diff --git a/src/southbridge/nvidia/mcp55/Config.lb b/src/southbridge/nvidia/mcp55/Config.lb new file mode 100644 index 0000000000..e5f2c279b9 --- /dev/null +++ b/src/southbridge/nvidia/mcp55/Config.lb @@ -0,0 +1,35 @@ +## +## This file is part of the LinuxBIOS project. +## +## Copyright (C) 2007 AMD +## Written by Yinghai Lu <yinghai.lu@amd.com> for AMD. +## +## 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 +## + +config chip.h +driver mcp55.o +driver mcp55_usb.o +driver mcp55_lpc.o +driver mcp55_smbus.o +driver mcp55_ide.o +driver mcp55_sata.o +driver mcp55_usb2.o +driver mcp55_aza.o +driver mcp55_nic.o +driver mcp55_pci.o +driver mcp55_pcie.o +driver mcp55_ht.o +object mcp55_reset.o diff --git a/src/southbridge/nvidia/mcp55/chip.h b/src/southbridge/nvidia/mcp55/chip.h new file mode 100644 index 0000000000..1bb0f5faa5 --- /dev/null +++ b/src/southbridge/nvidia/mcp55/chip.h @@ -0,0 +1,37 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2007 AMD + * Written by Yinghai Lu <yinghai.lu@amd.com> for AMD. + * + * 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 + */ + +#ifndef MCP55_CHIP_H +#define MCP55_CHIP_H + +struct southbridge_nvidia_mcp55_config +{ + unsigned int ide0_enable : 1; + unsigned int ide1_enable : 1; + unsigned int sata0_enable : 1; + unsigned int sata1_enable : 1; + unsigned int mac_eeprom_smbus; + unsigned int mac_eeprom_addr; +}; +struct chip_operations; +extern struct chip_operations southbridge_nvidia_mcp55_ops; + +#endif /* MCP55_CHIP_H */ diff --git a/src/southbridge/nvidia/mcp55/id.inc b/src/southbridge/nvidia/mcp55/id.inc new file mode 100644 index 0000000000..5d3a16063f --- /dev/null +++ b/src/southbridge/nvidia/mcp55/id.inc @@ -0,0 +1,36 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2007 AMD + * Written by Yinghai Lu <yinghai.lu@amd.com> for AMD. + * + * 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 + */ + + .section ".id", "a", @progbits + + .globl __id_start +__id_start: +vendor: + .asciz MAINBOARD_VENDOR +part: + .asciz MAINBOARD_PART_NUMBER +.long __id_end + 0x80 - vendor /* Reverse offset to the vendor id */ +.long __id_end + 0x80 - part /* Reverse offset to the part number */ +.long PAYLOAD_SIZE + ROM_IMAGE_SIZE /* Size of this romimage */ + .globl __id_end + +__id_end: +.previous diff --git a/src/southbridge/nvidia/mcp55/id.lds b/src/southbridge/nvidia/mcp55/id.lds new file mode 100644 index 0000000000..5fc740fdc2 --- /dev/null +++ b/src/southbridge/nvidia/mcp55/id.lds @@ -0,0 +1,27 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2007 AMD + * Written by Yinghai Lu <yinghai.lu@amd.com> for AMD. + * + * 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 + */ + +SECTIONS { + . = (_ROMBASE + ROM_IMAGE_SIZE - 0x80) - (__id_end - __id_start); + .id (.): { + *(.id) + } +} diff --git a/src/southbridge/nvidia/mcp55/mcp55.c b/src/southbridge/nvidia/mcp55/mcp55.c new file mode 100644 index 0000000000..c7d9ae9616 --- /dev/null +++ b/src/southbridge/nvidia/mcp55/mcp55.c @@ -0,0 +1,248 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2004 Tyan Computer + * Written by Yinghai Lu <yhlu@tyan.com> for Tyan Computer. + * Copyright (C) 2006,2007 AMD + * Written by Yinghai Lu <yinghai.lu@amd.com> for AMD. + * + * 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 + */ + +#include <console/console.h> + +#include <arch/io.h> + +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include "mcp55.h" + +static uint32_t final_reg; + +static device_t find_lpc_dev( device_t dev, unsigned devfn) +{ + + device_t lpc_dev; + + lpc_dev = dev_find_slot(dev->bus->secondary, devfn); + + if ( !lpc_dev ) return lpc_dev; + + if ((lpc_dev->vendor != PCI_VENDOR_ID_NVIDIA) || ( + (lpc_dev->device < PCI_DEVICE_ID_NVIDIA_MCP55_LPC) || + (lpc_dev->device > PCI_DEVICE_ID_NVIDIA_MCP55_PRO) + ) ) { + uint32_t id; + id = pci_read_config32(lpc_dev, PCI_VENDOR_ID); + if ( (id < (PCI_VENDOR_ID_NVIDIA | (PCI_DEVICE_ID_NVIDIA_MCP55_LPC << 16))) || + (id > (PCI_VENDOR_ID_NVIDIA | (PCI_DEVICE_ID_NVIDIA_MCP55_PRO << 16))) + ) { + lpc_dev = 0; + } + } + + return lpc_dev; +} + +void mcp55_enable(device_t dev) +{ + device_t lpc_dev = 0; + device_t sm_dev = 0; + unsigned index = 0; + unsigned index2 = 0; + uint32_t reg_old, reg; + uint8_t byte; + unsigned deviceid; + unsigned vendorid; + + struct southbridge_nvidia_mcp55_config *conf; + conf = dev->chip_info; + int i; + + unsigned devfn; + + if(dev->device==0x0000) { + vendorid = pci_read_config32(dev, PCI_VENDOR_ID); + deviceid = (vendorid>>16) & 0xffff; +// vendorid &= 0xffff; + } else { +// vendorid = dev->vendor; + deviceid = dev->device; + } + + devfn = (dev->path.u.pci.devfn) & ~7; + switch(deviceid) { + case PCI_DEVICE_ID_NVIDIA_MCP55_HT: + return; + + case PCI_DEVICE_ID_NVIDIA_MCP55_SM2://? + index = 16; + break; + case PCI_DEVICE_ID_NVIDIA_MCP55_USB: + devfn -= (1<<3); + index = 8; + break; + case PCI_DEVICE_ID_NVIDIA_MCP55_USB2: + devfn -= (1<<3); + index = 20; + break; + case PCI_DEVICE_ID_NVIDIA_MCP55_NIC: //two + case PCI_DEVICE_ID_NVIDIA_MCP55_NIC_BRIDGE://two + devfn -= (7<<3); + index = 10; + for(i=0;i<2;i++) { + lpc_dev = find_lpc_dev(dev, devfn - (i<<3)); + if(!lpc_dev) continue; + index -= i; + devfn -= (i<<3); + break; + } + break; + case PCI_DEVICE_ID_NVIDIA_MCP55_AZA: + devfn -= (5<<3); + index = 11; + break; + case PCI_DEVICE_ID_NVIDIA_MCP55_IDE: + devfn -= (3<<3); + index = 14; + break; + case PCI_DEVICE_ID_NVIDIA_MCP55_SATA0: //three + case PCI_DEVICE_ID_NVIDIA_MCP55_SATA1: //three + devfn -= (4<<3); + index = 22; + i = (dev->path.u.pci.devfn) & 7; + if(i>0) { + index -= (i+3); + } + break; + case PCI_DEVICE_ID_NVIDIA_MCP55_PCI: + devfn -= (5<<3); + index = 15; + break; + case PCI_DEVICE_ID_NVIDIA_MCP55_PCIE_A: + devfn -= (0x9<<3); // to LPC + index2 = 9; + break; + case PCI_DEVICE_ID_NVIDIA_MCP55_PCIE_B_C: //two + devfn -= (0xa<<3); // to LPC + index2 = 8; + for(i=0;i<2;i++) { + lpc_dev = find_lpc_dev(dev, devfn - (i<<3)); + if(!lpc_dev) continue; + index2 -= i; + devfn -= (i<<3); + break; + } + break; + case PCI_DEVICE_ID_NVIDIA_MCP55_PCIE_D: + devfn -= (0xc<<3); // to LPC + index2 = 6; + break; + case PCI_DEVICE_ID_NVIDIA_MCP55_PCIE_E: + devfn -= (0xd<<3); // to LPC + index2 = 5; + break; + case PCI_DEVICE_ID_NVIDIA_MCP55_PCIE_F: + devfn -= (0xe<<3); // to LPC + index2 = 4; + break; + default: + index = 0; + } + + if(!lpc_dev) + lpc_dev = find_lpc_dev(dev, devfn); + + if ( !lpc_dev ) return; + + if(index2!=0) { + sm_dev = dev_find_slot(dev->bus->secondary, devfn + 1); + if(!sm_dev) return; + + if ( sm_dev ) { + reg_old = reg = pci_read_config32(sm_dev, 0xe4); + + if (!dev->enabled) { //disable it + reg |= (1<<index2); + } + + if (reg != reg_old) { + pci_write_config32(sm_dev, 0xe4, reg); + } + } + + index2 = 0; + return; + } + + + if ( index == 0) { // for LPC + + // expose ioapic base + byte = pci_read_config8(lpc_dev, 0x74); + byte |= ((1<<1)); // expose the BAR + pci_write_config8(dev, 0x74, byte); + + // expose trap base + byte = pci_read_config8(lpc_dev, 0xdd); + byte |= ((1<<0)|(1<<3)); // expose the BAR and enable write + pci_write_config8(dev, 0xdd, byte); + + return; + + } + + if( index == 16) { + sm_dev = dev_find_slot(dev->bus->secondary, devfn + 1); + if(!sm_dev) return; + + final_reg = pci_read_config32(sm_dev, 0xe8); + final_reg &= ~((1<<16)|(1<<8)|(1<<20)|(1<<14)|(1<<22)|(1<<18)|(1<<17)|(1<<15)|(1<<11)|(1<<10)|(1<<9)); + pci_write_config32(sm_dev, 0xe8, final_reg); //enable all at first +#if 0 + reg_old = reg = pci_read_config32(sm_dev, 0xe4); +// reg |= (1<<0); + reg &= ~(0x3f<<4); + if (reg != reg_old) { + printk_debug("mcp55.c pcie enabled\n"); + pci_write_config32(sm_dev, 0xe4, reg); + } +#endif + } + + if (!dev->enabled) { + final_reg |= (1 << index);// disable it + //The reason for using final_reg, if diable func 1, the func 2 will be func 1 so We need disable them one time. + } + + if(index == 9 ) { //NIC1 is the final, We need update final reg to 0xe8 + sm_dev = dev_find_slot(dev->bus->secondary, devfn + 1); + if(!sm_dev) return; + reg_old = pci_read_config32(sm_dev, 0xe8); + if (final_reg != reg_old) { + pci_write_config32(sm_dev, 0xe8, final_reg); + } + + } + + +} + +struct chip_operations southbridge_nvidia_mcp55_ops = { + CHIP_NAME("Nvidia mcp55") + .enable_dev = mcp55_enable, +}; diff --git a/src/southbridge/nvidia/mcp55/mcp55.h b/src/southbridge/nvidia/mcp55/mcp55.h new file mode 100644 index 0000000000..f35d7ee4e4 --- /dev/null +++ b/src/southbridge/nvidia/mcp55/mcp55.h @@ -0,0 +1,29 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2007 AMD + * Written by Yinghai Lu <yinghai.lu@amd.com> for AMD. + * + * 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 + */ + +#ifndef MCP55_H +#define MCP55_H + +#include "chip.h" + +void mcp55_enable(device_t dev); + +#endif /* MCP55_H */ diff --git a/src/southbridge/nvidia/mcp55/mcp55_aza.c b/src/southbridge/nvidia/mcp55/mcp55_aza.c new file mode 100644 index 0000000000..e39454e90a --- /dev/null +++ b/src/southbridge/nvidia/mcp55/mcp55_aza.c @@ -0,0 +1,267 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2004 Tyan Computer + * Written by Yinghai Lu <yhlu@tyan.com> for Tyan Computer. + * Copyright (C) 2006,2007 AMD + * Written by Yinghai Lu <yinghai.lu@amd.com> for AMD. + * + * 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 + */ + +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include <arch/io.h> +#include "mcp55.h" + +static int set_bits(uint8_t *port, uint32_t mask, uint32_t val) +{ + uint32_t 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(uint8_t *base) +{ + uint32_t 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_debug("No codec!\n"); + return 0; + } + return dword; + +} + +static uint32_t verb_data[] = { +#if 0 + 0x00172001, + 0x001721e6, + 0x00172200, + 0x00172300, +#endif + + 0x01471c10, + 0x01471d44, + 0x01471e01, + 0x01471f01, +//1 + 0x01571c12, + 0x01571d14, + 0x01571e01, + 0x01571f01, +//2 + 0x01671c11, + 0x01671d60, + 0x01671e01, + 0x01671f01, +//3 + 0x01771c14, + 0x01771d20, + 0x01771e01, + 0x01771f01, +//4 + 0x01871c30, + 0x01871d9c, + 0x01871ea1, + 0x01871f01, +//5 + 0x01971c40, + 0x01971d9c, + 0x01971ea1, + 0x01971f02, +//6 + 0x01a71c31, + 0x01a71d34, + 0x01a71e81, + 0x01a71f01, +//7 + 0x01b71c1f, + 0x01b71d44, + 0x01b71e21, + 0x01b71f02, +//8 + 0x01c71cf0, + 0x01c71d11, + 0x01c71e11, + 0x01c71f41, +//9 + 0x01d71c3e, + 0x01d71d01, + 0x01d71e83, + 0x01d71f99, +//10 + 0x01e71c20, + 0x01e71d41, + 0x01e71e45, + 0x01e71f01, +//11 + 0x01f71c50, + 0x01f71d91, + 0x01f71ec5, + 0x01f71f01, +}; + +static unsigned find_verb(uint32_t viddid, uint32_t **verb) +{ + if(viddid != 0x10ec0880) return 0; + *verb = (uint32_t *)verb_data; + return sizeof(verb_data)/sizeof(uint32_t); +} + + +static void codec_init(uint8_t *base, int addr) +{ + uint32_t dword; + uint32_t *verb; + unsigned 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_debug("codec viddid: %08x\n", dword); + verb_size = find_verb(dword, &verb); + + if(!verb_size) { + printk_debug("No verb!\n"); + return; + } + + printk_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_debug("verb loaded!\n"); +} + +static void codecs_init(uint8_t *base, uint32_t codec_mask) +{ + int i; + for(i=2; i>=0; i--) { + if( codec_mask & (1<<i) ) + codec_init(base, i); + } +} + +static void aza_init(struct device *dev) +{ + uint8_t *base; + struct resource *res; + uint32_t codec_mask; + + res = find_resource(dev, 0x10); + if(!res) + return; + + base =(uint8_t *) res->base; + printk_debug("base = %08x\n", base); + + codec_mask = codec_detect(base); + + if(codec_mask) { + printk_debug("codec_mask = %02x\n", codec_mask); + codecs_init(base, codec_mask); + } +} + +static void lpci_set_subsystem(device_t dev, unsigned vendor, unsigned device) +{ + pci_write_config32(dev, 0x40, + ((device & 0xffff) << 16) | (vendor & 0xffff)); +} + +static struct pci_operations lops_pci = { + .set_subsystem = lpci_set_subsystem, +}; + +static struct device_operations aza_audio_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, +// .enable = mcp55_enable, + .init = aza_init, + .scan_bus = 0, + .ops_pci = &lops_pci, +}; + +static struct pci_driver azaaudio_driver __pci_driver = { + .ops = &aza_audio_ops, + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_MCP55_AZA, +}; + diff --git a/src/southbridge/nvidia/mcp55/mcp55_early_ctrl.c b/src/southbridge/nvidia/mcp55/mcp55_early_ctrl.c new file mode 100644 index 0000000000..422f7f548e --- /dev/null +++ b/src/southbridge/nvidia/mcp55/mcp55_early_ctrl.c @@ -0,0 +1,60 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2007 AMD + * Written by Yinghai Lu <yinghai.lu@amd.com> for AMD. + * + * 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 + */ + +static unsigned get_sbdn(unsigned bus) +{ + device_t dev; + + /* Find the device. + */ + dev = pci_locate_device_on_bus( + PCI_ID(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_MCP55_HT), + bus); + + return (dev>>15) & 0x1f; + +} + +static void hard_reset(void) +{ + set_bios_reset(); + + /* full reset */ + outb(0x0a, 0x0cf9); + outb(0x0e, 0x0cf9); +} +static void enable_fid_change_on_sb(unsigned sbbusn, unsigned sbdn) +{ +/* default value for mcp55 is good */ + /* set VFSMAF ( VID/FID System Management Action Field) to 2 */ + +} + +static void soft_reset(void) +{ + set_bios_reset(); +#if 1 + /* link reset */ + outb(0x02, 0x0cf9); + outb(0x06, 0x0cf9); +#endif +} + diff --git a/src/southbridge/nvidia/mcp55/mcp55_early_setup_car.c b/src/southbridge/nvidia/mcp55/mcp55_early_setup_car.c new file mode 100644 index 0000000000..99124da6b9 --- /dev/null +++ b/src/southbridge/nvidia/mcp55/mcp55_early_setup_car.c @@ -0,0 +1,427 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2006 AMD + * Written by Yinghai Lu <yinghai.lu@amd.com> for AMD. + * + * 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 + */ + +static int set_ht_link_mcp55(uint8_t ht_c_num) +{ + unsigned vendorid = 0x10de; + unsigned val = 0x01610109; + /* Nvidia mcp55 hardcode, hw can not set it automatically */ + return set_ht_link_buffer_counts_chain(ht_c_num, vendorid, val); +} + +static void setup_ss_table(unsigned index, unsigned where, unsigned control, const unsigned int *register_values, int max) +{ + int i; + + unsigned val; + + val = inl(control); + val &= 0xfffffffe; + outl(val, control); + + outl(0, index); //index + for(i = 0; i < max; i++) { + unsigned long reg; + reg = register_values[i]; + outl(reg, where); + } + + val = inl(control); + val |= 1; + outl(val, control); + +} + +/* SIZE 0x100 */ +#define ANACTRL_IO_BASE 0x2800 +#define ANACTRL_REG_POS 0x68 + +/* SIZE 0x100 */ +#define SYSCTRL_IO_BASE 0x2400 +#define SYSCTRL_REG_POS 0x64 + +/* SIZE 0x100 */ +#define ACPICTRL_IO_BASE 0x2000 +#define ACPICTRL_REG_POS 0x60 + +/* + 16 1 1 1 1 8 :0 + 16 0 4 0 0 8 :1 + 16 0 4 2 2 4 :2 + 4 4 4 4 4 8 :3 + 8 8 4 0 0 8 :4 + 8 0 4 4 4 8 :5 +*/ + +#ifndef MCP55_PCI_E_X_0 + #define MCP55_PCI_E_X_0 4 +#endif +#ifndef MCP55_PCI_E_X_1 + #define MCP55_PCI_E_X_1 4 +#endif +#ifndef MCP55_PCI_E_X_2 + #define MCP55_PCI_E_X_2 4 +#endif +#ifndef MCP55_PCI_E_X_3 + #define MCP55_PCI_E_X_3 4 +#endif + +#ifndef MCP55_USE_NIC + #define MCP55_USE_NIC 0 +#endif + +#ifndef MCP55_USE_AZA + #define MCP55_USE_AZA 0 +#endif + +#define MCP55_CHIP_REV 3 + +static void mcp55_early_set_port(unsigned mcp55_num, unsigned *busn, unsigned *devn, unsigned *io_base) +{ + + static const unsigned int ctrl_devport_conf[] = { + PCI_ADDR(0, 1, 1, ANACTRL_REG_POS), ~(0x0000ff00), ANACTRL_IO_BASE, + PCI_ADDR(0, 1, 1, SYSCTRL_REG_POS), ~(0x0000ff00), SYSCTRL_IO_BASE, + PCI_ADDR(0, 1, 1, ACPICTRL_REG_POS), ~(0x0000ff00), ACPICTRL_IO_BASE, + }; + + int j; + for(j = 0; j < mcp55_num; j++ ) { + setup_resource_map_offset(ctrl_devport_conf, + sizeof(ctrl_devport_conf)/sizeof(ctrl_devport_conf[0]), + PCI_DEV(busn[j], devn[j], 0) , io_base[j]); + } +} + +static void mcp55_early_clear_port(unsigned mcp55_num, unsigned *busn, unsigned *devn, unsigned *io_base) +{ + + static const unsigned int ctrl_devport_conf_clear[] = { + PCI_ADDR(0, 1, 1, ANACTRL_REG_POS), ~(0x0000ff00), 0, + PCI_ADDR(0, 1, 1, SYSCTRL_REG_POS), ~(0x0000ff00), 0, + PCI_ADDR(0, 1, 1, ACPICTRL_REG_POS), ~(0x0000ff00), 0, + }; + + int j; + for(j = 0; j < mcp55_num; j++ ) { + setup_resource_map_offset(ctrl_devport_conf_clear, + sizeof(ctrl_devport_conf_clear)/sizeof(ctrl_devport_conf_clear[0]), + PCI_DEV(busn[j], devn[j], 0) , io_base[j]); + } + + +} +static void delayx(uint8_t value) { +#if 1 + int i; + for(i=0;i<0x8000;i++) { + outb(value, 0x80); + } +#endif +} + +static void mcp55_early_pcie_setup(unsigned busnx, unsigned devnx, unsigned anactrl_io_base, unsigned pci_e_x) +{ + uint32_t tgio_ctrl; + uint32_t pll_ctrl; + uint32_t dword; + int i; + device_t dev; + dev = PCI_DEV(busnx, devnx+1, 1); + dword = pci_read_config32(dev, 0xe4); + dword |= 0x3f0; // disable it at first + pci_write_config32(dev, 0xe4, dword); + + for(i=0; i<3; i++) { + tgio_ctrl = inl(anactrl_io_base + 0xcc); + tgio_ctrl &= ~(3<<9); + tgio_ctrl |= (i<<9); + outl(tgio_ctrl, anactrl_io_base + 0xcc); + pll_ctrl = inl(anactrl_io_base + 0x30); + pll_ctrl |= (1<<31); + outl(pll_ctrl, anactrl_io_base + 0x30); + do { + pll_ctrl = inl(anactrl_io_base + 0x30); + } while (!(pll_ctrl & 1)); + } + tgio_ctrl = inl(anactrl_io_base + 0xcc); + tgio_ctrl &= ~((7<<4)|(1<<8)); + tgio_ctrl |= (pci_e_x<<4)|(1<<8); + outl(tgio_ctrl, anactrl_io_base + 0xcc); + +// wait 100us + delayx(1); + + dword = pci_read_config32(dev, 0xe4); + dword &= ~(0x3f0); // enable + pci_write_config32(dev, 0xe4, dword); + +// need to wait 100ms + delayx(1000); +} + +static void mcp55_early_setup(unsigned mcp55_num, unsigned *busn, unsigned *devn, unsigned *io_base, unsigned *pci_e_x) +{ + + static const unsigned int ctrl_conf_1[] = { + RES_PORT_IO_32, ACPICTRL_IO_BASE + 0x10, 0x0007ffff, 0xff78000, + RES_PORT_IO_32, ACPICTRL_IO_BASE + 0xa4, 0xffedffff, 0x0012000, + RES_PORT_IO_32, ACPICTRL_IO_BASE + 0xac, 0xfffffdff, 0x0000200, + RES_PORT_IO_32, ACPICTRL_IO_BASE + 0xb4, 0xfffffffd, 0x0000002, + + RES_PORT_IO_32, ANACTRL_IO_BASE + 0x24, 0xc0f0f08f, 0x26020230, + RES_PORT_IO_32, ANACTRL_IO_BASE + 0x34, 0x00000000, 0x22222222, + RES_PORT_IO_32, ANACTRL_IO_BASE + 0x08, 0x7FFFFFFF, 0x00000000, + RES_PORT_IO_32, ANACTRL_IO_BASE + 0x2C, 0x7FFFFFFF, 0x80000000, + RES_PORT_IO_32, ANACTRL_IO_BASE + 0xCC, 0xFFFFF9FF, 0x00000000, + RES_PORT_IO_32, ANACTRL_IO_BASE + 0x30, 0x8FFFFFFF, 0x40000000, + RES_PORT_IO_32, ANACTRL_IO_BASE + 0xCC, 0xFFFFF9FF, 0x00000200, + RES_PORT_IO_32, ANACTRL_IO_BASE + 0x30, 0x8FFFFFFF, 0x40000000, + RES_PORT_IO_32, ANACTRL_IO_BASE + 0xCC, 0xFFFFF9FF, 0x00000400, + RES_PORT_IO_32, ANACTRL_IO_BASE + 0x30, 0x8FFFFFFF, 0x40000000, + RES_PORT_IO_32, ANACTRL_IO_BASE + 0x74, 0xFFFF0FF5, 0x0000F000, + RES_PORT_IO_32, ANACTRL_IO_BASE + 0x78, 0xFF00FF00, 0x00100010, + RES_PORT_IO_32, ANACTRL_IO_BASE + 0x7C, 0xFF0FF0FF, 0x00500500, + RES_PORT_IO_32, ANACTRL_IO_BASE + 0x80, 0xFFFFFFE7, 0x00000000, + RES_PORT_IO_32, ANACTRL_IO_BASE + 0x60, 0xFFCFFFFF, 0x00300000, + RES_PORT_IO_32, ANACTRL_IO_BASE + 0x90, 0xFFFF00FF, 0x0000FF00, + RES_PORT_IO_32, ANACTRL_IO_BASE + 0x9C, 0xFF00FFFF, 0x00070000, + + RES_PCI_IO, PCI_ADDR(0, 0, 0, 0x40), 0x00000000, 0xCB8410DE, + RES_PCI_IO, PCI_ADDR(0, 0, 0, 0x48), 0xFFFFDCED, 0x00002002, + RES_PCI_IO, PCI_ADDR(0, 0, 0, 0x78), 0xFFFFFF8E, 0x00000011, + RES_PCI_IO, PCI_ADDR(0, 0, 0, 0x80), 0xFFFF0000, 0x00009923, + RES_PCI_IO, PCI_ADDR(0, 0, 0, 0x88), 0xFFFFFFFE, 0x00000000, + RES_PCI_IO, PCI_ADDR(0, 0, 0, 0x8C), 0xFFFF0000, 0x0000007F, + RES_PCI_IO, PCI_ADDR(0, 0, 0, 0xDC), 0xFFFEFFFF, 0x00010000, + + RES_PCI_IO, PCI_ADDR(0, 1, 0, 0x40), 0x00000000, 0xCB8410DE, + RES_PCI_IO, PCI_ADDR(0, 1, 0, 0x74), 0xFFFFFF7B, 0x00000084, + RES_PCI_IO, PCI_ADDR(0, 1, 0, 0xF8), 0xFFFFFFCF, 0x00000010, + + RES_PCI_IO, PCI_ADDR(0, 1, 1, 0xC4), 0xFFFFFFFE, 0x00000001, + RES_PCI_IO, PCI_ADDR(0, 1, 1, 0xF0), 0x7FFFFFFD, 0x00000002, + RES_PCI_IO, PCI_ADDR(0, 1, 1, 0xF8), 0xFFFFFFCF, 0x00000010, + + RES_PCI_IO, PCI_ADDR(0, 8, 0, 0x40), 0x00000000, 0xCB8410DE, + RES_PCI_IO, PCI_ADDR(0, 8, 0, 0x68), 0xFFFFFF00, 0x000000FF, + RES_PCI_IO, PCI_ADDR(0, 8, 0, 0xF8), 0xFFFFFFBF, 0x00000040,//Enable bridge mode + + RES_PCI_IO, PCI_ADDR(0, 9, 0, 0x40), 0x00000000, 0xCB8410DE, + RES_PCI_IO, PCI_ADDR(0, 9, 0, 0x68), 0xFFFFFF00, 0x000000FF, + RES_PCI_IO, PCI_ADDR(0, 9, 0, 0xF8), 0xFFFFFFBF, 0x00000040,//Enable bridge mode + }; + + static const unsigned int ctrl_conf_1_1[] = { + RES_PCI_IO, PCI_ADDR(0, 5, 0, 0x40), 0x00000000, 0xCB8410DE, + RES_PCI_IO, PCI_ADDR(0, 5, 0, 0x50), 0xFFFFFFFC, 0x00000003, + RES_PCI_IO, PCI_ADDR(0, 5, 0, 0x64), 0xFFFFFFFE, 0x00000001, + RES_PCI_IO, PCI_ADDR(0, 5, 0, 0x70), 0xFFF0FFFF, 0x00040000, + RES_PCI_IO, PCI_ADDR(0, 5, 0, 0xAC), 0xFFFFF0FF, 0x00000100, + RES_PCI_IO, PCI_ADDR(0, 5, 0, 0x7C), 0xFFFFFFEF, 0x00000000, + RES_PCI_IO, PCI_ADDR(0, 5, 0, 0xC8), 0xFF00FF00, 0x000A000A, + RES_PCI_IO, PCI_ADDR(0, 5, 0, 0xD0), 0xF0FFFFFF, 0x03000000, + RES_PCI_IO, PCI_ADDR(0, 5, 0, 0xE0), 0xF0FFFFFF, 0x03000000, + }; + + + static const unsigned int ctrl_conf_mcp55_only[] = { + RES_PCI_IO, PCI_ADDR(0, 1, 1, 0x40), 0x00000000, 0xCB8410DE, + RES_PCI_IO, PCI_ADDR(0, 1, 1, 0xE0), 0xFFFFFEFF, 0x00000000, + RES_PCI_IO, PCI_ADDR(0, 1, 1, 0xE4), 0xFFFFFFFB, 0x00000000, + RES_PCI_IO, PCI_ADDR(0, 1, 1, 0xE8), 0xFFA9C8FF, 0x00003000, + + RES_PCI_IO, PCI_ADDR(0, 4, 0, 0x40), 0x00000000, 0xCB8410DE, + RES_PCI_IO, PCI_ADDR(0, 4, 0, 0xF8), 0xFFFFFFCF, 0x00000010, + + RES_PCI_IO, PCI_ADDR(0, 2, 0, 0x40), 0x00000000, 0xCB8410DE, + + RES_PCI_IO, PCI_ADDR(0, 2, 1, 0x40), 0x00000000, 0xCB8410DE, + RES_PCI_IO, PCI_ADDR(0, 2, 1, 0x64), 0xF87FFFFF, 0x05000000, + RES_PCI_IO, PCI_ADDR(0, 2, 1, 0x78), 0xFFC07FFF, 0x00360000, + RES_PCI_IO, PCI_ADDR(0, 2, 1, 0x68), 0xFE00D03F, 0x013F2C00, + RES_PCI_IO, PCI_ADDR(0, 2, 1, 0x70), 0xFFF7FFFF, 0x00080000, + RES_PCI_IO, PCI_ADDR(0, 2, 1, 0x7C), 0xFFFFF00F, 0x00000570, + RES_PCI_IO, PCI_ADDR(0, 2, 1, 0xF8), 0xFFFFFFCF, 0x00000010, + + RES_PCI_IO, PCI_ADDR(0, 6, 0, 0x04), 0xFFFFFEFB, 0x00000104, + RES_PCI_IO, PCI_ADDR(0, 6, 0, 0x3C), 0xF5FFFFFF, 0x0A000000, + RES_PCI_IO, PCI_ADDR(0, 6, 0, 0x40), 0x00C8FFFF, 0x07330000, + RES_PCI_IO, PCI_ADDR(0, 6, 0, 0x48), 0xFFFFFFF8, 0x00000005, + RES_PCI_IO, PCI_ADDR(0, 6, 0, 0x4C), 0xFE02FFFF, 0x004C0000, + RES_PCI_IO, PCI_ADDR(0, 6, 0, 0x74), 0xFFFFFFC0, 0x00000000, + RES_PCI_IO, PCI_ADDR(0, 6, 0, 0xC0), 0x00000000, 0xCB8410DE, + RES_PCI_IO, PCI_ADDR(0, 6, 0, 0xC4), 0xFFFFFFF8, 0x00000007, + +#if MCP55_USE_AZA == 1 + RES_PCI_IO, PCI_ADDR(0, 6, 1, 0x40), 0x00000000, 0xCB8410DE, + +// RES_PCI_IO, PCI_ADDR(0, 1, 1, 0xE4), ~(1<<14), 1<<14, +#endif +// play a while with GPIO in MCP55 +#ifdef MCP55_MB_SETUP + MCP55_MB_SETUP +#endif + +#if MCP55_USE_AZA == 1 + RES_PORT_IO_8, SYSCTRL_IO_BASE + 0xc0+ 21, ~(3<<2), (2<<2), + RES_PORT_IO_8, SYSCTRL_IO_BASE + 0xc0+ 22, ~(3<<2), (2<<2), + RES_PORT_IO_8, SYSCTRL_IO_BASE + 0xc0+ 46, ~(3<<2), (2<<2), +#endif + + + }; + + static const unsigned int ctrl_conf_master_only[] = { + + RES_PORT_IO_32, ACPICTRL_IO_BASE + 0x80, 0xEFFFFFF, 0x01000000, + + RES_PCI_IO, PCI_ADDR(0, 1, 0, 0x78), 0xC0FFFFFF, 0x19000000, + + //Master MCP55 ????YHLU + RES_PORT_IO_8, SYSCTRL_IO_BASE + 0xc0+ 0, ~(3<<2), (0<<2), + + }; + + static const unsigned int ctrl_conf_2[] = { + /* I didn't put pcie related stuff here */ + + RES_PCI_IO, PCI_ADDR(0, 0, 0, 0x74), 0xFFFFF00F, 0x000009D0, + RES_PCI_IO, PCI_ADDR(0, 1, 0, 0x74), 0xFFFF7FFF, 0x00008000, + + RES_PORT_IO_32, SYSCTRL_IO_BASE + 0x48, 0xFFFEFFFF, 0x00010000, + + RES_PORT_IO_32, ANACTRL_IO_BASE + 0x60, 0xFFFFFF00, 0x00000012, + + +#if MCP55_USE_NIC == 1 + RES_PCI_IO, PCI_ADDR(0, 1, 1, 0xe4), ~((1<<22)|(1<<20)), (1<<22)|(1<<20), + + RES_PORT_IO_8, SYSCTRL_IO_BASE + 0xc0+ 4, ~(0xff), ((0<<4)|(1<<2)|(0<<0)), + RES_PORT_IO_8, SYSCTRL_IO_BASE + 0xc0+ 4, ~(0xff), ((0<<4)|(1<<2)|(1<<0)), +#endif + + }; + + + int j, i; + + for(j=0; j<mcp55_num; j++) { + mcp55_early_pcie_setup(busn[j], devn[j], io_base[j] + ANACTRL_IO_BASE, pci_e_x[j]); + + setup_resource_map_x_offset(ctrl_conf_1, sizeof(ctrl_conf_1)/sizeof(ctrl_conf_1[0]), + PCI_DEV(busn[j], devn[j], 0), io_base[j]); + for(i=0; i<3; i++) { // three SATA + setup_resource_map_x_offset(ctrl_conf_1_1, sizeof(ctrl_conf_1_1)/sizeof(ctrl_conf_1_1[0]), + PCI_DEV(busn[j], devn[j], i), io_base[j]); + } + if(busn[j] == 0) { + setup_resource_map_x_offset(ctrl_conf_mcp55_only, sizeof(ctrl_conf_mcp55_only)/sizeof(ctrl_conf_mcp55_only[0]), + PCI_DEV(busn[j], devn[j], 0), io_base[j]); + } + + if( (busn[j] == 0) && (mcp55_num>1) ) { + setup_resource_map_x_offset(ctrl_conf_master_only, sizeof(ctrl_conf_master_only)/sizeof(ctrl_conf_master_only[0]), + PCI_DEV(busn[j], devn[j], 0), io_base[j]); + } + + setup_resource_map_x_offset(ctrl_conf_2, sizeof(ctrl_conf_2)/sizeof(ctrl_conf_2[0]), + PCI_DEV(busn[j], devn[j], 0), io_base[j]); + + } + +#if 0 + for(j=0; j< mcp55_num; j++) { + // PCI-E (XSPLL) SS table 0x40, x044, 0x48 + // SATA (SPPLL) SS table 0xb0, 0xb4, 0xb8 + // CPU (PPLL) SS table 0xc0, 0xc4, 0xc8 + setup_ss_table(io_base[j] + ANACTRL_IO_BASE+0x40, io_base[j] + ANACTRL_IO_BASE+0x44, + io_base[j] + ANACTRL_IO_BASE+0x48, pcie_ss_tbl, 64); + setup_ss_table(io_base[j] + ANACTRL_IO_BASE+0xb0, io_base[j] + ANACTRL_IO_BASE+0xb4, + io_base[j] + ANACTRL_IO_BASE+0xb8, sata_ss_tbl, 64); + setup_ss_table(io_base[j] + ANACTRL_IO_BASE+0xc0, io_base[j] + ANACTRL_IO_BASE+0xc4, + io_base[j] + ANACTRL_IO_BASE+0xc8, cpu_ss_tbl, 64); + } +#endif + +} + +#ifndef HT_CHAIN_NUM_MAX + +#define HT_CHAIN_NUM_MAX 4 +#define HT_CHAIN_BUSN_D 0x40 +#define HT_CHAIN_IOBASE_D 0x4000 + +#endif + +static int mcp55_early_setup_x(void) +{ + /*find out how many mcp55 we have */ + unsigned busn[HT_CHAIN_NUM_MAX]; + unsigned devn[HT_CHAIN_NUM_MAX]; + unsigned io_base[HT_CHAIN_NUM_MAX]; + /* + FIXME: May have problem if there is different MCP55 HTX card with different PCI_E lane allocation + Need to use same trick about pci1234 to verify node/link connection + */ + unsigned pci_e_x[HT_CHAIN_NUM_MAX] = {MCP55_PCI_E_X_0, MCP55_PCI_E_X_1, MCP55_PCI_E_X_2, MCP55_PCI_E_X_3 }; + int mcp55_num = 0; + unsigned busnx; + unsigned devnx; + int ht_c_index,j; + + /* FIXME: multi pci segment handling */ + + /* Any system that only have IO55 without MCP55? */ + for(ht_c_index = 0; ht_c_index<HT_CHAIN_NUM_MAX; ht_c_index++) { + busnx = ht_c_index * HT_CHAIN_BUSN_D; + for(devnx=0;devnx<0x20;devnx++) { + uint32_t id; + device_t dev; + dev = PCI_DEV(busnx, devnx, 0); + id = pci_read_config32(dev, PCI_VENDOR_ID); + if(id == 0x036910de) { + busn[mcp55_num] = busnx; + devn[mcp55_num] = devnx; + io_base[mcp55_num] = ht_c_index * HT_CHAIN_IOBASE_D; // we may have ht chain other than MCP55 + mcp55_num++; + if(mcp55_num == MCP55_NUM) goto out; + break; // only one MCP55 on one chain + } + } + } + +out: + print_debug("mcp55_num:"); print_debug_hex8(mcp55_num); print_debug("\r\n"); + + mcp55_early_set_port(mcp55_num, busn, devn, io_base); + mcp55_early_setup(mcp55_num, busn, devn, io_base, pci_e_x); + + mcp55_early_clear_port(mcp55_num, busn, devn, io_base); + +// set_ht_link_mcp55(HT_CHAIN_NUM_MAX); + + return 0; + +} + + + diff --git a/src/southbridge/nvidia/mcp55/mcp55_early_setup_ss.h b/src/southbridge/nvidia/mcp55/mcp55_early_setup_ss.h new file mode 100644 index 0000000000..77e8a5fb1c --- /dev/null +++ b/src/southbridge/nvidia/mcp55/mcp55_early_setup_ss.h @@ -0,0 +1,222 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2004 Tyan Computer + * Written by Yinghai Lu <yhlu@tyan.com> for Tyan Computer. + * + * 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 + */ + +static const unsigned int pcie_ss_tbl[] = { + 0x0C504103f, + 0x0C504103f, + 0x0C504103f, + 0x0C5042040, + 0x0C5042040, + 0x0C5042040, + 0x0C5043041, + 0x0C5043041, + 0x0C5043041, + 0x0C5043041, + 0x0C5044042, + 0x0C5044042, + 0x0C5044042, + 0x0C5045043, + 0x0C5045043, + 0x0C5045043, + 0x0C5045043, + 0x0C5045043, + 0x0C5046044, + 0x0C5046044, + 0x0C5046044, + 0x0C5046044, + 0x0C5047045, + 0x0C5047045, + 0x0C5047045, + 0x0C5047045, + 0x0C5047045, + 0x0C5048046, + 0x0C5048046, + 0x0C5048046, + 0x0C5048046, + 0x0C5049047, + 0x0C5049047, + 0x0C5049047, + 0x0C504a048, + 0x0C504a048, + 0x0C504b049, + 0x0C504b049, + 0x0C504a048, + 0x0C504a048, + 0x0C5049047, + 0x0C5049047, + 0x0C5048046, + 0x0C5048046, + 0x0C5048046, + 0x0C5047045, + 0x0C5047045, + 0x0C5047045, + 0x0C5047045, + 0x0C5047045, + 0x0C5046044, + 0x0C5046044, + 0x0C5046044, + 0x0C5046044, + 0x0C5045043, + 0x0C5045043, + 0x0C5045043, + 0x0C5044042, + 0x0C5044042, + 0x0C5044042, + 0x0C5043041, + 0x0C5043041, + 0x0C5042040, + 0x0C5042040, +}; +static const unsigned int sata_ss_tbl[] = { + 0x0c9044042, + 0x0c9044042, + 0x0c9044042, + 0x0c9045043, + 0x0c9045043, + 0x0c9045043, + 0x0c9045043, + 0x0c9045043, + 0x0c9046044, + 0x0c9046044, + 0x0c9046044, + 0x0c9046044, + 0x0c9047045, + 0x0c9047045, + 0x0c9047045, + 0x0c9047045, + 0x0c9047045, + 0x0c9048046, + 0x0c9048046, + 0x0c9048046, + 0x0c9048046, + 0x0c9049047, + 0x0c9049047, + 0x0c9049047, + 0x0c9049047, + 0x0c904a048, + 0x0c904a048, + 0x0c904a048, + 0x0c904a048, + 0x0c904b049, + 0x0c904b049, + 0x0c904b049, + 0x0c904b049, + 0x0c904b049, + 0x0c904b049, + 0x0c904a048, + 0x0c904a048, + 0x0c904a048, + 0x0c904a048, + 0x0c9049047, + 0x0c9049047, + 0x0c9049047, + 0x0c9049047, + 0x0c9048046, + 0x0c9048046, + 0x0c9048046, + 0x0c9048046, + 0x0c9047045, + 0x0c9047045, + 0x0c9047045, + 0x0c9047045, + 0x0c9047045, + 0x0c9046044, + 0x0c9046044, + 0x0c9046044, + 0x0c9046044, + 0x0c9045043, + 0x0c9045043, + 0x0c9045043, + 0x0c9045043, + 0x0c9045043, + 0x0c9044042, + 0x0c9044042, + 0x0c9044042, +}; + +static const unsigned int cpu_ss_tbl[] = { + 0x0C5038036, + 0x0C5038036, + 0x0C5038036, + 0x0C5037035, + 0x0C5037035, + 0x0C5037035, + 0x0C5037035, + 0x0C5036034, + 0x0C5036034, + 0x0C5036034, + 0x0C5036034, + 0x0C5036034, + 0x0C5035033, + 0x0C5035033, + 0x0C5035033, + 0x0C5035033, + 0x0C5035033, + 0x0C5035033, + 0x0C5034032, + 0x0C5034032, + 0x0C5034032, + 0x0C5034032, + 0x0C5034032, + 0x0C5034032, + 0x0C5035033, + 0x0C5035033, + 0x0C5035033, + 0x0C5035033, + 0x0C5035033, + 0x0C5036034, + 0x0C5036034, + 0x0C5036034, + 0x0C5036034, + 0x0C5036034, + 0x0C5037035, + 0x0C5037035, + 0x0C5037035, + 0x0C5037035, + 0x0C5038036, + 0x0C5038036, + 0x0C5038036, + 0x0C5038036, + 0x0C5039037, + 0x0C5039037, + 0x0C5039037, + 0x0C5039037, + 0x0C503a038, + 0x0C503a038, + 0x0C503a038, + 0x0C503a038, + 0x0C503b039, + 0x0C503b039, + 0x0C503b039, + 0x0C503b039, + 0x0C503b039, + 0x0C503a038, + 0x0C503a038, + 0x0C503a038, + 0x0C503a038, + 0x0C503a038, + 0x0C5039037, + 0x0C5039037, + 0x0C5039037, + 0x0C5039037, +}; + + diff --git a/src/southbridge/nvidia/mcp55/mcp55_early_smbus.c b/src/southbridge/nvidia/mcp55/mcp55_early_smbus.c new file mode 100644 index 0000000000..cf77bc17bf --- /dev/null +++ b/src/southbridge/nvidia/mcp55/mcp55_early_smbus.c @@ -0,0 +1,84 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2004 Tyan Computer + * Written by Yinghai Lu <yhlu@tyan.com> for Tyan Computer. + * Copyright (C) 2006,2007 AMD + * Written by Yinghai Lu <yinghai.lu@amd.com> for AMD. + * + * 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 + */ + +#include "mcp55_smbus.h" + +#define SMBUS0_IO_BASE 0x1000 +#define SMBUS1_IO_BASE (0x1000+(1<<8)) +/*SIZE 0x40 */ + +static void enable_smbus(void) +{ + device_t dev; + dev = pci_locate_device(PCI_ID(0x10de, 0x0368), 0); +#if 0 + if (dev == PCI_DEV_INVALID) { + die("SMBUS controller not found\r\n"); + } + + print_debug("SMBus controller enabled\r\n"); +#endif + /* set smbus iobase */ + pci_write_config32(dev, 0x20, SMBUS0_IO_BASE | 1); + pci_write_config32(dev, 0x24, SMBUS1_IO_BASE | 1); + /* Set smbus iospace enable */ + pci_write_config16(dev, 0x4, 0x01); + /* clear any lingering errors, so the transaction will run */ + outb(inb(SMBUS0_IO_BASE + SMBHSTSTAT), SMBUS0_IO_BASE + SMBHSTSTAT); + outb(inb(SMBUS1_IO_BASE + SMBHSTSTAT), SMBUS1_IO_BASE + SMBHSTSTAT); +} + +static int smbus_recv_byte(unsigned device) +{ + return do_smbus_recv_byte(SMBUS0_IO_BASE, device); +} +static int smbus_send_byte(unsigned device, unsigned char val) +{ + return do_smbus_send_byte(SMBUS0_IO_BASE, device, val); +} +static int smbus_read_byte(unsigned device, unsigned address) +{ + return do_smbus_read_byte(SMBUS0_IO_BASE, device, address); +} +static int smbus_write_byte(unsigned device, unsigned address, unsigned char val) +{ + return do_smbus_write_byte(SMBUS0_IO_BASE, device, address, val); +} + +static int smbusx_recv_byte(unsigned smb_index, unsigned device) +{ + return do_smbus_recv_byte(SMBUS0_IO_BASE + (smb_index<<8), device); +} +static int smbusx_send_byte(unsigned smb_index, unsigned device, unsigned char val) +{ + return do_smbus_send_byte(SMBUS0_IO_BASE + (smb_index<<8), device, val); +} +static int smbusx_read_byte(unsigned smb_index, unsigned device, unsigned address) +{ + return do_smbus_read_byte(SMBUS0_IO_BASE + (smb_index<<8), device, address); +} +static int smbusx_write_byte(unsigned smb_index, unsigned device, unsigned address, unsigned char val) +{ + return do_smbus_write_byte(SMBUS0_IO_BASE + (smb_index<<8), device, address, val); +} + diff --git a/src/southbridge/nvidia/mcp55/mcp55_enable_rom.c b/src/southbridge/nvidia/mcp55/mcp55_enable_rom.c new file mode 100644 index 0000000000..6a2697537e --- /dev/null +++ b/src/southbridge/nvidia/mcp55/mcp55_enable_rom.c @@ -0,0 +1,55 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2004 Tyan Computer + * Written by Yinghai Lu <yhlu@tyan.com> for Tyan Computer. + * Copyright (C) 2006,2007 AMD + * Written by Yinghai Lu <yinghai.lu@amd.com> for AMD. + * + * 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 + */ + +#if HT_CHAIN_END_UNITID_BASE < HT_CHAIN_UNITID_BASE + #define MCP55_DEVN_BASE HT_CHAIN_END_UNITID_BASE +#else + #define MCP55_DEVN_BASE HT_CHAIN_UNITID_BASE +#endif + +static void mcp55_enable_rom(void) +{ + uint8_t byte; + uint16_t word; + device_t addr; + + /* Enable 4MB rom access at 0xFFC00000 - 0xFFFFFFFF */ +#if 0 + /* default MCP55 LPC single */ + addr = pci_locate_device(PCI_ID(0x10de, 0x0367), 0); +#else +// addr = pci_locate_device(PCI_ID(0x10de, 0x0360), 0); + addr = PCI_DEV(0, (MCP55_DEVN_BASE+1), 0); +#endif + + /* Set the 4MB enable bit bit */ + byte = pci_read_config8(addr, 0x88); + byte |= 0xff; //256K + pci_write_config8(addr, 0x88, byte); + byte = pci_read_config8(addr, 0x8c); + byte |= 0xff; //1M + pci_write_config8(addr, 0x8c, byte); + word = pci_read_config16(addr, 0x90); + word |= 0x7fff; //15M + pci_write_config16(addr, 0x90, word); +} diff --git a/src/southbridge/nvidia/mcp55/mcp55_enable_usbdebug_direct.c b/src/southbridge/nvidia/mcp55/mcp55_enable_usbdebug_direct.c new file mode 100644 index 0000000000..c431724c5c --- /dev/null +++ b/src/southbridge/nvidia/mcp55/mcp55_enable_usbdebug_direct.c @@ -0,0 +1,50 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2004 Tyan Computer + * Written by Yinghai Lu <yhlu@tyan.com> for Tyan Computer. + * Copyright (C) 2006,2007 AMD + * Written by Yinghai Lu <yinghai.lu@amd.com> for AMD. + * + * 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 + */ + +#if HT_CHAIN_END_UNITID_BASE < HT_CHAIN_UNITID_BASE + #define MCP55_DEVN_BASE HT_CHAIN_END_UNITID_BASE +#else + #define MCP55_DEVN_BASE HT_CHAIN_UNITID_BASE +#endif + +#define EHCI_BAR_INDEX 0x10 +#define EHCI_BAR 0xFEF00000 +#define EHCI_DEBUG_OFFSET 0x98 + +static void set_debug_port(unsigned port) +{ + uint32_t dword; + dword = pci_read_config32(PCI_DEV(0, MCP55_DEVN_BASE+2, 1), 0x74); + dword &= ~(0xf<<12); + dword |= (port<<12); + pci_write_config32(PCI_DEV(0, MCP55_DEVN_BASE+2, 1), 0x74, dword); + +} + +static void mcp55_enable_usbdebug_direct(unsigned port) +{ + set_debug_port(port); + pci_write_config32(PCI_DEV(0, MCP55_DEVN_BASE+2, 1), EHCI_BAR_INDEX, EHCI_BAR); + pci_write_config8(PCI_DEV(0, MCP55_DEVN_BASE+2, 1), 0x04, 0x2); // mem space enabe +} + diff --git a/src/southbridge/nvidia/mcp55/mcp55_ht.c b/src/southbridge/nvidia/mcp55/mcp55_ht.c new file mode 100644 index 0000000000..f6c5400b85 --- /dev/null +++ b/src/southbridge/nvidia/mcp55/mcp55_ht.c @@ -0,0 +1,54 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2004 Tyan Computer + * Written by Yinghai Lu <yhlu@tyan.com> for Tyan Computer. + * Copyright (C) 2006,2007 AMD + * Written by Yinghai Lu <yinghai.lu@amd.com> for AMD. + * + * 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 + */ + +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include "mcp55.h" + +static void lpci_set_subsystem(device_t dev, unsigned vendor, unsigned device) +{ + pci_write_config32(dev, 0x40, + ((device & 0xffff) << 16) | (vendor & 0xffff)); +} +static struct pci_operations lops_pci = { + .set_subsystem = lpci_set_subsystem, +}; + +static struct device_operations ht_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = 0, + .scan_bus = 0, + .ops_pci = &lops_pci, +}; + +static struct pci_driver ht_driver __pci_driver = { + .ops = &ht_ops, + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_MCP55_HT, +}; + diff --git a/src/southbridge/nvidia/mcp55/mcp55_ide.c b/src/southbridge/nvidia/mcp55/mcp55_ide.c new file mode 100644 index 0000000000..2a2101df6f --- /dev/null +++ b/src/southbridge/nvidia/mcp55/mcp55_ide.c @@ -0,0 +1,96 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2004 Tyan Computer + * Written by Yinghai Lu <yhlu@tyan.com> for Tyan Computer. + * Copyright (C) 2006,2007 AMD + * Written by Yinghai Lu <yinghai.lu@amd.com> for AMD. + * + * 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 + */ + +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include "mcp55.h" + +static void ide_init(struct device *dev) +{ + struct southbridge_nvidia_mcp55_config *conf; + /* Enable ide devices so the linux ide driver will work */ + uint32_t dword; + uint16_t word; + uint8_t byte; + conf = dev->chip_info; + + word = pci_read_config16(dev, 0x50); + /* Ensure prefetch is disabled */ + word &= ~((1 << 15) | (1 << 13)); + if (conf->ide1_enable) { + /* Enable secondary ide interface */ + word |= (1<<0); + printk_debug("IDE1 \t"); + } + if (conf->ide0_enable) { + /* Enable primary ide interface */ + word |= (1<<1); + printk_debug("IDE0\n"); + } + + word |= (1<<12); + word |= (1<<14); + + pci_write_config16(dev, 0x50, word); + + + byte = 0x20 ; // Latency: 64-->32 + pci_write_config8(dev, 0xd, byte); + + dword = pci_read_config32(dev, 0xf8); + dword |= 12; + pci_write_config32(dev, 0xf8, dword); +#if CONFIG_PCI_ROM_RUN == 1 + pci_dev_init(dev); +#endif + +} + +static void lpci_set_subsystem(device_t dev, unsigned vendor, unsigned device) +{ + pci_write_config32(dev, 0x40, + ((device & 0xffff) << 16) | (vendor & 0xffff)); +} +static struct pci_operations lops_pci = { + .set_subsystem = lpci_set_subsystem, +}; + +static struct device_operations ide_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = ide_init, + .scan_bus = 0, +// .enable = mcp55_enable, + .ops_pci = &lops_pci, +}; + +static struct pci_driver ide_driver __pci_driver = { + .ops = &ide_ops, + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_MCP55_IDE, +}; + diff --git a/src/southbridge/nvidia/mcp55/mcp55_lpc.c b/src/southbridge/nvidia/mcp55/mcp55_lpc.c new file mode 100644 index 0000000000..8ed8e21581 --- /dev/null +++ b/src/southbridge/nvidia/mcp55/mcp55_lpc.c @@ -0,0 +1,402 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2003 Linux Networx + * Copyright (C) 2003 SuSE Linux AG + * Copyright (C) 2004 Tyan Computer + * Written by Yinghai Lu <yhlu@tyan.com> for Tyan Computer. + * Copyright (C) 2006,2007 AMD + * Written by Yinghai Lu <yinghai.lu@amd.com> for AMD. + * + * 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 + */ + +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pnp.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include <pc80/mc146818rtc.h> +#include <pc80/isa-dma.h> +#include <bitops.h> +#include <arch/io.h> +#include <cpu/x86/lapic.h> +#include "mcp55.h" + +#define NMI_OFF 0 + +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, ENABLED | TRIGGER_EDGE | POLARITY_HIGH | PHYSICAL_DEST | ExtINT, 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; +// unsigned long ioapic_base = 0xfec00000; + volatile unsigned long *l; + struct ioapicreg *a = ioapicregvalues; + + ioapicregvalues[0].value_high = lapicid()<<(56-32); + + l = (unsigned long *) ioapic_base; + + for (i = 0; i < sizeof(ioapicregvalues) / sizeof(ioapicregvalues[0]); + 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; + } + printk_spew("for IRQ, reg 0x%08x value 0x%08x 0x%08x\n", + a->reg, a->value_low, a->value_high); + } +} + +// 0x7a or e3 +#define PREVIOUS_POWER_STATE 0x7A + +#define MAINBOARD_POWER_OFF 0 +#define MAINBOARD_POWER_ON 1 +#define SLOW_CPU_OFF 0 +#define SLOW_CPU__ON 1 + +#ifndef MAINBOARD_POWER_ON_AFTER_POWER_FAIL +#define MAINBOARD_POWER_ON_AFTER_POWER_FAIL MAINBOARD_POWER_ON +#endif + +static void lpc_common_init(device_t dev) +{ + uint8_t byte; + uint32_t dword; + + /* IO APIC initialization */ + byte = pci_read_config8(dev, 0x74); + byte |= (1<<0); // enable APIC + pci_write_config8(dev, 0x74, byte); + dword = pci_read_config32(dev, PCI_BASE_ADDRESS_1); // 0x14 + + setup_ioapic(dword); + +} + +static void lpc_slave_init(device_t dev) +{ + lpc_common_init(dev); +} + +#if 0 +static void enable_hpet(struct device *dev) +{ + unsigned long hpet_address; + + pci_write_config32(dev,0x44, 0xfed00001); + hpet_address=pci_read_config32(dev,0x44)& 0xfffffffe; + printk_debug("enabling HPET @0x%x\n", hpet_address); +} +#endif + +static void lpc_init(device_t dev) +{ + uint8_t byte; + uint8_t byte_old; + int on; + int nmi_option; + + lpc_common_init(dev); + +#if 0 + /* posted memory write enable */ + byte = pci_read_config8(dev, 0x46); + pci_write_config8(dev, 0x46, byte | (1<<0)); + +#endif + /* power after power fail */ + +#if 1 + on = MAINBOARD_POWER_ON_AFTER_POWER_FAIL; + get_option(&on, "power_on_after_fail"); + byte = pci_read_config8(dev, PREVIOUS_POWER_STATE); + byte &= ~0x40; + if (!on) { + byte |= 0x40; + } + pci_write_config8(dev, PREVIOUS_POWER_STATE, byte); + printk_info("set power %s after power fail\n", on?"on":"off"); +#endif + /* Throttle the CPU speed down for testing */ + on = SLOW_CPU_OFF; + get_option(&on, "slow_cpu"); + if(on) { + uint16_t pm10_bar; + uint32_t dword; + pm10_bar = (pci_read_config16(dev, 0x60)&0xff00); + outl(((on<<1)+0x10) ,(pm10_bar + 0x10)); + dword = inl(pm10_bar + 0x10); + on = 8-on; + printk_debug("Throttling CPU %2d.%1.1d percent.\n", + (on*12)+(on>>1),(on&1)*5); + } + +#if 0 +// default is enabled + /* Enable Port 92 fast reset */ + byte = pci_read_config8(dev, 0xe8); + byte |= ~(1 << 3); + pci_write_config8(dev, 0xe8, byte); +#endif + + /* Enable Error reporting */ + /* Set up sync flood detected */ + byte = pci_read_config8(dev, 0x47); + byte |= (1 << 1); + pci_write_config8(dev, 0x47, 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 */ + } else { + byte |= ( 1 << 7); // Can not mask NMI from PCI-E and NMI_NOW + } + if( byte != byte_old) { + outb(0x70, byte); + } + + /* Initialize the real time clock */ + rtc_init(0); + + /* Initialize isa dma */ + isa_dma_init(); + + /* Initialize the High Precision Event Timers */ +// enable_hpet(dev); + +} + +static void mcp55_lpc_read_resources(device_t dev) +{ + struct resource *res; + unsigned long index; + + /* Get the normal pci resources of this device */ + pci_dev_read_resources(dev); // We got one for APIC, or one more for TRAP + + /* 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; + +} + +/** + * @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 mcp55_lpc_enable_childrens_resources(device_t dev) +{ + unsigned link; + uint32_t reg, reg_var[4]; + int i; + int var_num = 0; + + reg = pci_read_config32(dev, 0xa0); + + for (link = 0; link < dev->links; link++) { + device_t 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("mcp55 lpc decode:%s, base=0x%08x, end=0x%08x\n",dev_path(child),base, end); + switch(base) { + case 0x3f8: // COM1 + reg |= (1<<0); break; + case 0x2f8: // COM2 + reg |= (1<<1); break; + case 0x378: // Parallal 1 + reg |= (1<<24); break; + case 0x3f0: // FD0 + reg |= (1<<20); break; + case 0x220: // Aduio 0 + reg |= (1<<8); break; + case 0x300: // Midi 0 + reg |= (1<<12); break; + } + if( (base == 0x290) || (base >= 0x400)) { + if(var_num>=4) continue; // only 4 var ; compact them ? + reg |= (1<<(28+var_num)); + reg_var[var_num++] = (base & 0xffff)|((end & 0xffff)<<16); + } + } + } + } + } + pci_write_config32(dev, 0xa0, reg); + for(i=0;i<var_num;i++) { + pci_write_config32(dev, 0xa8 + i*4, reg_var[i]); + } + + +} + +static void mcp55_lpc_enable_resources(device_t dev) +{ + pci_dev_enable_resources(dev); + mcp55_lpc_enable_childrens_resources(dev); +} + +static void lpci_set_subsystem(device_t dev, unsigned vendor, unsigned device) +{ + pci_write_config32(dev, 0x40, + ((device & 0xffff) << 16) | (vendor & 0xffff)); +} + +static struct pci_operations lops_pci = { + .set_subsystem = lpci_set_subsystem, +}; + +static struct device_operations lpc_ops = { + .read_resources = mcp55_lpc_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = mcp55_lpc_enable_resources, + .init = lpc_init, + .scan_bus = scan_static_bus, +// .enable = mcp55_enable, + .ops_pci = &lops_pci, +}; +static struct pci_driver lpc_driver __pci_driver = { + .ops = &lpc_ops, + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_MCP55_LPC, +}; + +static struct pci_driver lpc_driver_pro __pci_driver = { + .ops = &lpc_ops, + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_MCP55_PRO, +}; + +static struct pci_driver lpc_driver_lpc2 __pci_driver = { + .ops = &lpc_ops, + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_MCP55_LPC_2, +}; +static struct pci_driver lpc_driver_lpc3 __pci_driver = { + .ops = &lpc_ops, + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_MCP55_LPC_3, +}; +static struct pci_driver lpc_driver_lpc4 __pci_driver = { + .ops = &lpc_ops, + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_MCP55_LPC_4, +}; +static struct pci_driver lpc_driver_lpc5 __pci_driver = { + .ops = &lpc_ops, + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_MCP55_LPC_5, +}; +static struct pci_driver lpc_driver_lpc6 __pci_driver = { + .ops = &lpc_ops, + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_MCP55_LPC_6, +}; + +static struct device_operations lpc_slave_ops = { + .read_resources = mcp55_lpc_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = lpc_slave_init, +// .enable = mcp55_enable, + .ops_pci = &lops_pci, +}; + +static struct pci_driver lpc_driver_slave __pci_driver = { + .ops = &lpc_slave_ops, + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_MCP55_SLAVE, +}; diff --git a/src/southbridge/nvidia/mcp55/mcp55_nic.c b/src/southbridge/nvidia/mcp55/mcp55_nic.c new file mode 100644 index 0000000000..26e769984c --- /dev/null +++ b/src/southbridge/nvidia/mcp55/mcp55_nic.c @@ -0,0 +1,211 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2004 Tyan Computer + * Written by Yinghai Lu <yhlu@tyan.com> for Tyan Computer. + * Copyright (C) 2006,2007 AMD + * Written by Yinghai Lu <yinghai.lu@amd.com> for AMD. + * + * 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 + */ + +#include <console/console.h> +#include <device/device.h> +#include <device/smbus.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include <arch/io.h> +#include "mcp55.h" + +static int phy_read(uint8_t *base, unsigned phy_addr, unsigned phy_reg) +{ + uint32_t dword; + unsigned loop = 0x100; + writel(0x8000, base+0x190); //Clear MDIO lock bit + mdelay(1); + dword = readl(base+0x190); + if(dword & (1<<15)) return -1; + + writel(1, base+0x180); + writel((phy_addr<<5) | (phy_reg),base + 0x190); + do{ + dword = readl(base + 0x190); + if(--loop==0) return -4; + } while ((dword & (1<<15)) ); + + dword = readl(base + 0x180); + if(dword & 1) return -3; + + dword = readl(base + 0x194); + + return dword; + +} + +static int phy_detect(uint8_t *base) +{ + uint32_t dword; + int i; + int val; + unsigned id; + dword = readl(base+0x188); + dword &= ~(1<<20); + writel(dword, base+0x188); + + phy_read(base, 0, 1); + + for(i=1; i<=32; i++) { + int phyaddr = i & 0x1f; + val = phy_read(base, phyaddr, 1); + if(val<0) continue; + if((val & 0xffff) == 0xfffff) continue; + if((val & 0xffff) == 0) continue; + if(!(val & 1)) { + break; // Ethernet PHY + } + val = phy_read(base, phyaddr, 3); + if (val < 0 || val == 0xffff) continue; + id = val & 0xfc00; + val = phy_read(base, phyaddr, 2); + if (val < 0 || val == 0xffff) continue; + id |= ((val & 0xffff)<<16); + printk_debug("MCP55 MAC PHY ID 0x%08x PHY ADDR %d\n", id, i); +// if((id == 0xe0180000) || (id==0x0032cc00)) + break; + } + + if(i>32) { + printk_debug("MCP55 MAC PHY not found\n"); + } + +} +static void nic_init(struct device *dev) +{ + uint32_t dword, old; + uint32_t mac_h, mac_l; + int eeprom_valid = 0; + struct southbridge_nvidia_mcp55_config *conf; + + static uint32_t nic_index = 0; + + uint8_t *base; + struct resource *res; + + res = find_resource(dev, 0x10); + + if(!res) return; + + base = res->base; + + phy_detect(base); + +#define NvRegPhyInterface 0xC0 +#define PHY_RGMII 0x10000000 + + writel(PHY_RGMII, base + NvRegPhyInterface); + + conf = dev->chip_info; + + if(conf->mac_eeprom_smbus != 0) { +// read MAC address from EEPROM at first + struct device *dev_eeprom; + dev_eeprom = dev_find_slot_on_smbus(conf->mac_eeprom_smbus, conf->mac_eeprom_addr); + + if(dev_eeprom) { + // if that is valid we will use that + unsigned char dat[6]; + int status; + int i; + for(i=0;i<6;i++) { + status = smbus_read_byte(dev_eeprom, i); + if(status < 0) break; + dat[i] = status & 0xff; + } + if(status >= 0) { + mac_l = 0; + for(i=3;i>=0;i--) { + mac_l <<= 8; + mac_l += dat[i]; + } + if(mac_l != 0xffffffff) { + mac_l += nic_index; + mac_h = 0; + for(i=5;i>=4;i--) { + mac_h <<= 8; + mac_h += dat[i]; + } + eeprom_valid = 1; + } + } + } + } +// if that is invalid we will read that from romstrap + if(!eeprom_valid) { + unsigned long mac_pos; + mac_pos = 0xffffffd0; // refer to romstrap.inc and romstrap.lds + mac_l = readl(mac_pos) + nic_index; // overflow? + mac_h = readl(mac_pos + 4); + + } +#if 1 +// set that into NIC MMIO +#define NvRegMacAddrA 0xA8 +#define NvRegMacAddrB 0xAC + writel(mac_l, base + NvRegMacAddrA); + writel(mac_h, base + NvRegMacAddrB); +#else +// set that into NIC + pci_write_config32(dev, 0xa8, mac_l); + pci_write_config32(dev, 0xac, mac_h); +#endif + + nic_index++; + +#if CONFIG_PCI_ROM_RUN == 1 + pci_dev_init(dev);// it will init option rom +#endif + +} + +static void lpci_set_subsystem(device_t dev, unsigned vendor, unsigned device) +{ + pci_write_config32(dev, 0x40, + ((device & 0xffff) << 16) | (vendor & 0xffff)); +} + +static struct pci_operations lops_pci = { + .set_subsystem = lpci_set_subsystem, +}; + +static struct device_operations nic_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = nic_init, + .scan_bus = 0, +// .enable = mcp55_enable, + .ops_pci = &lops_pci, +}; +static struct pci_driver nic_driver __pci_driver = { + .ops = &nic_ops, + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_MCP55_NIC, +}; +static struct pci_driver nic_bridge_driver __pci_driver = { + .ops = &nic_ops, + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_MCP55_NIC_BRIDGE, +}; diff --git a/src/southbridge/nvidia/mcp55/mcp55_pci.c b/src/southbridge/nvidia/mcp55/mcp55_pci.c new file mode 100644 index 0000000000..24a1cb20f6 --- /dev/null +++ b/src/southbridge/nvidia/mcp55/mcp55_pci.c @@ -0,0 +1,107 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2004 Tyan Computer + * Written by Yinghai Lu <yhlu@tyan.com> for Tyan Computer. + * Copyright (C) 2006,2007 AMD + * Written by Yinghai Lu <yinghai.lu@amd.com> for AMD. + * + * 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 + */ + +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include "mcp55.h" + +static void pci_init(struct device *dev) +{ + + uint32_t dword; + uint16_t word; +#if CONFIG_PCI_64BIT_PREF_MEM == 1 + device_t pci_domain_dev; + struct resource *mem1, *mem2; +#endif + + /* System error enable */ + dword = pci_read_config32(dev, 0x04); + dword |= (1<<8); /* System error enable */ + dword |= (1<<30); /* Clear possible errors */ + pci_write_config32(dev, 0x04, dword); + +#if 1 + //only need (a01,xx] + word = pci_read_config16(dev, 0x48); + word |= (1<<0); /* MRL2MRM */ + word |= (1<<2); /* MR2MRM */ + pci_write_config16(dev, 0x48, word); +#endif + +#if 1 + dword = pci_read_config32(dev, 0x4c); + dword |= 0x00440000; /*TABORT_SER_ENABLE Park Last Enable.*/ + pci_write_config32(dev, 0x4c, dword); +#endif + +#if CONFIG_PCI_64BIT_PREF_MEM == 1 + pci_domain_dev = dev->bus->dev; + while(pci_domain_dev) { + if(pci_domain_dev->path.type == DEVICE_PATH_PCI_DOMAIN) break; + pci_domain_dev = pci_domain_dev->bus->dev; + } + + if(!pci_domain_dev) return; // impossiable + mem1 = find_resource(pci_domain_dev, 1); // prefmem, it could be 64bit + mem2 = find_resource(pci_domain_dev, 2); // mem + if(mem1->base > mem2->base) { + dword = mem2->base & (0xffff0000UL); + printk_debug("PCI DOMAIN mem2 base = 0x%010Lx\n", mem2->base); + } else { + dword = mem1->base & (0xffff0000UL); + printk_debug("PCI DOMAIN mem1 (prefmem) base = 0x%010Lx\n", mem1->base); + } +#else + dword = dev_root.resource[1].base & (0xffff0000UL); + printk_debug("dev_root mem base = 0x%010Lx\n", dev_root.resource[1].base); +#endif + printk_debug("[0x50] <-- 0x%08x\n", dword); + pci_write_config32(dev, 0x50, dword); //TOM + +} + +static struct pci_operations lops_pci = { + .set_subsystem = 0, +}; + +static struct device_operations pci_ops = { + .read_resources = pci_bus_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_bus_enable_resources, + .init = pci_init, + .scan_bus = pci_scan_bridge, +// .enable = mcp55_enable, + .reset_bus = pci_bus_reset, + .ops_pci = &lops_pci, +}; + +static struct pci_driver pci_driver __pci_driver = { + .ops = &pci_ops, + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_MCP55_PCI, +}; + diff --git a/src/southbridge/nvidia/mcp55/mcp55_pcie.c b/src/southbridge/nvidia/mcp55/mcp55_pcie.c new file mode 100644 index 0000000000..4bdee3d957 --- /dev/null +++ b/src/southbridge/nvidia/mcp55/mcp55_pcie.c @@ -0,0 +1,84 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2004 Tyan Computer + * Written by Yinghai Lu <yhlu@tyan.com> for Tyan Computer. + * Copyright (C) 2006,2007 AMD + * Written by Yinghai Lu <yinghai.lu@amd.com> for AMD. + * + * 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 + */ + +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include "mcp55.h" + +static void pcie_init(struct device *dev) +{ + + /* Enable pci error detecting */ + uint32_t dword; + + /* System error enable */ + dword = pci_read_config32(dev, 0x04); + dword |= (1<<8); /* System error enable */ + dword |= (1<<30); /* Clear possible errors */ + pci_write_config32(dev, 0x04, dword); + +} + +static struct pci_operations lops_pci = { + .set_subsystem = 0, +}; + +static struct device_operations pcie_ops = { + .read_resources = pci_bus_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_bus_enable_resources, + .init = pcie_init, + .scan_bus = pci_scan_bridge, +// .enable = mcp55_enable, + .ops_pci = &lops_pci, +}; + +static struct pci_driver pciebc_driver __pci_driver = { + .ops = &pcie_ops, + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_MCP55_PCIE_B_C, +}; +static struct pci_driver pciee_driver __pci_driver = { + .ops = &pcie_ops, + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_MCP55_PCIE_E, +}; +static struct pci_driver pciea_driver __pci_driver = { + .ops = &pcie_ops, + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_MCP55_PCIE_A, +}; +static struct pci_driver pcief_driver __pci_driver = { + .ops = &pcie_ops, + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_MCP55_PCIE_F, +}; +static struct pci_driver pcied_driver __pci_driver = { + .ops = &pcie_ops, + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_MCP55_PCIE_D, +}; + diff --git a/src/southbridge/nvidia/mcp55/mcp55_reset.c b/src/southbridge/nvidia/mcp55/mcp55_reset.c new file mode 100644 index 0000000000..3c08e79615 --- /dev/null +++ b/src/southbridge/nvidia/mcp55/mcp55_reset.c @@ -0,0 +1,59 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2004 Tyan Computer + * Written by Yinghai Lu <yhlu@tyan.com> for Tyan Computer. + * Copyright (C) 2006,2007 AMD + * Written by Yinghai Lu <yinghai.lu@amd.com> for AMD. + * + * 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 + */ + +#include <arch/io.h> + +#define PCI_DEV(BUS, DEV, FN) ( \ + (((BUS) & 0xFFF) << 20) | \ + (((DEV) & 0x1F) << 15) | \ + (((FN) & 0x7) << 12)) + +typedef unsigned device_t; + +static void pci_write_config32(device_t dev, unsigned where, unsigned value) +{ + unsigned addr; + addr = (dev>>4) | where; + outl(0x80000000 | (addr & ~3), 0xCF8); + outl(value, 0xCFC); +} + +static unsigned pci_read_config32(device_t dev, unsigned where) +{ + unsigned addr; + addr = (dev>>4) | where; + outl(0x80000000 | (addr & ~3), 0xCF8); + return inl(0xCFC); +} + +#include "../../../northbridge/amd/amdk8/reset_test.c" + +void hard_reset(void) +{ + set_bios_reset(); + /* Try rebooting through port 0xcf9 */ + /* Actually it is not a real hard_reset --- it only reset coherent link table, but 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/nvidia/mcp55/mcp55_sata.c b/src/southbridge/nvidia/mcp55/mcp55_sata.c new file mode 100644 index 0000000000..1281f5939c --- /dev/null +++ b/src/southbridge/nvidia/mcp55/mcp55_sata.c @@ -0,0 +1,101 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2004 Tyan Computer + * Written by Yinghai Lu <yhlu@tyan.com> for Tyan Computer. + * Copyright (C) 2006,2007 AMD + * Written by Yinghai Lu <yinghai.lu@amd.com> for AMD. + * + * 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 + */ + +#include <console/console.h> +#include <device/device.h> +#include <delay.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include "mcp55.h" + +static void sata_init(struct device *dev) +{ + uint32_t dword; + + struct southbridge_nvidia_mcp55_config *conf; + conf = dev->chip_info; + + dword = pci_read_config32(dev, 0x50); + /* Ensure prefetch is disabled */ + dword &= ~((1 << 15) | (1 << 13)); + if(conf) { + if (conf->sata1_enable) { + /* Enable secondary SATA interface */ + dword |= (1<<0); + printk_debug("SATA S \t"); + } + if (conf->sata0_enable) { + /* Enable primary SATA interface */ + dword |= (1<<1); + printk_debug("SATA P \n"); + } + } else { + dword |= (1<<1) | (1<<0); + printk_debug("SATA P and S \n"); + } + + +#if 1 + dword &= ~(0x1f<<24); + dword |= (0x15<<24); +#endif + pci_write_config32(dev, 0x50, dword); + + dword = pci_read_config32(dev, 0xf8); + dword |= 2; + pci_write_config32(dev, 0xf8, dword); + + +} + +static void lpci_set_subsystem(device_t dev, unsigned vendor, unsigned device) +{ + pci_write_config32(dev, 0x40, + ((device & 0xffff) << 16) | (vendor & 0xffff)); +} +static struct pci_operations lops_pci = { + .set_subsystem = lpci_set_subsystem, +}; + +static struct device_operations sata_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, +// .enable = mcp55_enable, + .init = sata_init, + .scan_bus = 0, + .ops_pci = &lops_pci, +}; + +static struct pci_driver sata0_driver __pci_driver = { + .ops = &sata_ops, + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_MCP55_SATA0, +}; + +static struct pci_driver sata1_driver __pci_driver = { + .ops = &sata_ops, + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_MCP55_SATA1, +}; diff --git a/src/southbridge/nvidia/mcp55/mcp55_smbus.c b/src/southbridge/nvidia/mcp55/mcp55_smbus.c new file mode 100644 index 0000000000..c6f0a7dc84 --- /dev/null +++ b/src/southbridge/nvidia/mcp55/mcp55_smbus.c @@ -0,0 +1,152 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2004 Tyan Computer + * Written by Yinghai Lu <yhlu@tyan.com> for Tyan Computer. + * Copyright (C) 2006,2007 AMD + * Written by Yinghai Lu <yinghai.lu@amd.com> for AMD. + * + * 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 + */ + +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include <device/smbus.h> +#include <bitops.h> +#include <arch/io.h> +#include "mcp55.h" +#include "mcp55_smbus.h" + +static int lsmbus_recv_byte(device_t dev) +{ + unsigned device; + struct resource *res; + struct bus *pbus; + + device = dev->path.u.i2c.device; + pbus = get_pbus_smbus(dev); + + res = find_resource(pbus->dev, 0x20 + (pbus->link * 4)); + + return do_smbus_recv_byte(res->base, device); +} + +static int lsmbus_send_byte(device_t dev, uint8_t val) +{ + unsigned device; + struct resource *res; + struct bus *pbus; + + device = dev->path.u.i2c.device; + pbus = get_pbus_smbus(dev); + + res = find_resource(pbus->dev, 0x20 + (pbus->link * 4)); + + return do_smbus_send_byte(res->base, device, val); +} + +static int lsmbus_read_byte(device_t dev, uint8_t address) +{ + unsigned device; + struct resource *res; + struct bus *pbus; + + device = dev->path.u.i2c.device; + pbus = get_pbus_smbus(dev); + + res = find_resource(pbus->dev, 0x20 + (pbus->link * 4)); + + return do_smbus_read_byte(res->base, device, address); +} + +static int lsmbus_write_byte(device_t dev, uint8_t address, uint8_t val) +{ + unsigned device; + struct resource *res; + struct bus *pbus; + + device = dev->path.u.i2c.device; + pbus = get_pbus_smbus(dev); + + res = find_resource(pbus->dev, 0x20 + (pbus->link * 4)); + + 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, +}; + +#if HAVE_ACPI_TABLES == 1 +unsigned pm_base; +#endif + +static void mcp55_sm_read_resources(device_t dev) +{ + struct resource *res; + unsigned long index; + + /* Get the normal pci resources of this device */ + pci_dev_read_resources(dev); + + for (index = 0x60; index <= 0x68; index+=4) { // We got another 3. + pci_get_resource(dev, index); + } + compact_resources(dev); + +} + +static void mcp55_sm_init(device_t dev) +{ +#if HAVE_ACPI_TABLES == 1 + struct resource *res; + + res = find_resource(dev, 0x60); + + if (res) + pm_base = res->base; +#endif +} + +static void lpci_set_subsystem(device_t dev, unsigned vendor, unsigned device) +{ + pci_write_config32(dev, 0x40, + ((device & 0xffff) << 16) | (vendor & 0xffff)); +} + +static struct pci_operations lops_pci = { + .set_subsystem = lpci_set_subsystem, +}; +static struct device_operations smbus_ops = { + .read_resources = mcp55_sm_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = mcp55_sm_init, + .scan_bus = scan_static_bus, +// .enable = mcp55_enable, + .ops_pci = &lops_pci, + .ops_smbus_bus = &lops_smbus_bus, +}; +static struct pci_driver smbus_driver __pci_driver = { + .ops = &smbus_ops, + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_MCP55_SM2, +}; + diff --git a/src/southbridge/nvidia/mcp55/mcp55_smbus.h b/src/southbridge/nvidia/mcp55/mcp55_smbus.h new file mode 100644 index 0000000000..9896b7ba4e --- /dev/null +++ b/src/southbridge/nvidia/mcp55/mcp55_smbus.h @@ -0,0 +1,195 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2004 Tyan Computer + * Written by Yinghai Lu <yhlu@tyan.com> for Tyan Computer. + * Copyright (C) 2006,2007 AMD + * Written by Yinghai Lu <yinghai.lu@amd.com> for AMD. + * + * 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 + */ + +#include <device/smbus_def.h> + +#define SMBHSTSTAT 0x1 +#define SMBHSTPRTCL 0x0 +#define SMBHSTCMD 0x3 +#define SMBXMITADD 0x2 +#define SMBHSTDAT0 0x4 +#define SMBHSTDAT1 0x5 + +/* Between 1-10 seconds, We should never timeout normally + * Longer than this is just painful when a timeout condition occurs. + */ +#define SMBUS_TIMEOUT (100*1000*10) + +static inline void smbus_delay(void) +{ + outb(0x80, 0x80); +} + +static int smbus_wait_until_ready(unsigned smbus_io_base) +{ + unsigned long loops; + loops = SMBUS_TIMEOUT; + do { + unsigned char val; + smbus_delay(); + val = inb(smbus_io_base + SMBHSTSTAT); + val &= 0x1f; + if (val == 0) { + return 0; + } + outb(val,smbus_io_base + SMBHSTSTAT); + } while(--loops); + return -2; +} + +static int smbus_wait_until_done(unsigned smbus_io_base) +{ + unsigned long loops; + loops = SMBUS_TIMEOUT; + do { + unsigned char val; + smbus_delay(); + + val = inb(smbus_io_base + SMBHSTSTAT); + if ( (val & 0xff) != 0) { + return 0; + } + } while(--loops); + return -3; +} +static int do_smbus_recv_byte(unsigned smbus_io_base, unsigned device) +{ + unsigned char global_status_register; + unsigned char byte; + + /* set the device I'm talking too */ + outb(((device & 0x7f) << 1)|1 , smbus_io_base + SMBXMITADD); + smbus_delay(); + /* set the command/address... */ + outb(0, smbus_io_base + SMBHSTCMD); + smbus_delay(); + /* byte data recv */ + outb(0x05, smbus_io_base + SMBHSTPRTCL); + smbus_delay(); + + /* poll for transaction completion */ + if (smbus_wait_until_done(smbus_io_base) < 0) { + return -3; + } + + global_status_register = inb(smbus_io_base + SMBHSTSTAT) & 0x80; /* lose check */ + + /* read results of transaction */ + byte = inb(smbus_io_base + SMBHSTDAT0); + + if (global_status_register != 0x80) { // lose check, otherwise it should be 0 + return -1; + } + return byte; +} +static int do_smbus_send_byte(unsigned smbus_io_base, unsigned device, unsigned char val) +{ + unsigned global_status_register; + + outb(val, smbus_io_base + SMBHSTDAT0); + smbus_delay(); + + /* set the device I'm talking too */ + outb(((device & 0x7f) << 1) | 0, smbus_io_base + SMBXMITADD); + smbus_delay(); + + outb(0, smbus_io_base + SMBHSTCMD); + smbus_delay(); + + /* set up for a byte data write */ + outb(0x04, smbus_io_base + SMBHSTPRTCL); + smbus_delay(); + + /* poll for transaction completion */ + if (smbus_wait_until_done(smbus_io_base) < 0) { + return -3; + } + global_status_register = inb(smbus_io_base + SMBHSTSTAT) & 0x80; /* lose check */; + + if (global_status_register != 0x80) { + return -1; + } + return 0; +} +static int do_smbus_read_byte(unsigned smbus_io_base, unsigned device, unsigned address) +{ + unsigned char global_status_register; + unsigned char byte; + + /* set the device I'm talking too */ + outb(((device & 0x7f) << 1)|1 , smbus_io_base + SMBXMITADD); + smbus_delay(); + /* set the command/address... */ + outb(address & 0xff, smbus_io_base + SMBHSTCMD); + smbus_delay(); + /* byte data read */ + outb(0x07, smbus_io_base + SMBHSTPRTCL); + smbus_delay(); + + /* poll for transaction completion */ + if (smbus_wait_until_done(smbus_io_base) < 0) { + return -3; + } + + global_status_register = inb(smbus_io_base + SMBHSTSTAT) & 0x80; /* lose check */ + + /* read results of transaction */ + byte = inb(smbus_io_base + SMBHSTDAT0); + + if (global_status_register != 0x80) { // lose check, otherwise it should be 0 + return -1; + } + return byte; +} + + +static int do_smbus_write_byte(unsigned smbus_io_base, unsigned device, unsigned address, unsigned char val) +{ + unsigned global_status_register; + + outb(val, smbus_io_base + SMBHSTDAT0); + smbus_delay(); + + /* set the device I'm talking too */ + outb(((device & 0x7f) << 1) | 0, smbus_io_base + SMBXMITADD); + smbus_delay(); + + outb(address & 0xff, smbus_io_base + SMBHSTCMD); + smbus_delay(); + + /* set up for a byte data write */ + outb(0x06, smbus_io_base + SMBHSTPRTCL); + smbus_delay(); + + /* poll for transaction completion */ + if (smbus_wait_until_done(smbus_io_base) < 0) { + return -3; + } + global_status_register = inb(smbus_io_base + SMBHSTSTAT) & 0x80; /* lose check */; + + if (global_status_register != 0x80) { + return -1; + } + return 0; +} + diff --git a/src/southbridge/nvidia/mcp55/mcp55_usb.c b/src/southbridge/nvidia/mcp55/mcp55_usb.c new file mode 100644 index 0000000000..c8f60903ee --- /dev/null +++ b/src/southbridge/nvidia/mcp55/mcp55_usb.c @@ -0,0 +1,55 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2004 Tyan Computer + * Written by Yinghai Lu <yhlu@tyan.com> for Tyan Computer. + * Copyright (C) 2006,2007 AMD + * Written by Yinghai Lu <yinghai.lu@amd.com> for AMD. + * + * 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 + */ + +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include "mcp55.h" + +static void lpci_set_subsystem(device_t dev, unsigned vendor, unsigned device) +{ + pci_write_config32(dev, 0x40, + ((device & 0xffff) << 16) | (vendor & 0xffff)); +} +static struct pci_operations lops_pci = { + .set_subsystem = lpci_set_subsystem, +}; + +static struct device_operations usb_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = 0, +// .enable = mcp55_enable, + .scan_bus = 0, + .ops_pci = &lops_pci, +}; + +static struct pci_driver usb_driver __pci_driver = { + .ops = &usb_ops, + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_MCP55_USB, +}; + diff --git a/src/southbridge/nvidia/mcp55/mcp55_usb2.c b/src/southbridge/nvidia/mcp55/mcp55_usb2.c new file mode 100644 index 0000000000..0132bb1cb9 --- /dev/null +++ b/src/southbridge/nvidia/mcp55/mcp55_usb2.c @@ -0,0 +1,88 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2004 Tyan Computer + * Written by Yinghai Lu <yhlu@tyan.com> for Tyan Computer. + * Copyright (C) 2006,2007 AMD + * Written by Yinghai Lu <yinghai.lu@amd.com> for AMD. + * + * 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 + */ + +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include "mcp55.h" +#include <usbdebug_direct.h> + +extern struct ehci_debug_info dbg_info; + +static void usb2_init(struct device *dev) +{ + uint32_t dword; + dword = pci_read_config32(dev, 0xf8); + dword |= 40; + pci_write_config32(dev, 0xf8, dword); +} + +static void usb2_set_resources(struct device *dev) +{ +#if CONFIG_USBDEBUG_DIRECT + struct resource *res; + unsigned base; + unsigned old_debug; + + old_debug = get_ehci_debug(); + set_ehci_debug(0); +#endif + pci_dev_set_resources(dev); + +#if CONFIG_USBDEBUG_DIRECT + res = find_resource(dev, 0x10); + set_ehci_debug(old_debug); + if (!res) return; + base = res->base; + set_ehci_base(base); + report_resource_stored(dev, res, ""); +#endif + +} + +static void lpci_set_subsystem(device_t dev, unsigned vendor, unsigned device) +{ + pci_write_config32(dev, 0x40, + ((device & 0xffff) << 16) | (vendor & 0xffff)); +} +static struct pci_operations lops_pci = { + .set_subsystem = lpci_set_subsystem, +}; + +static struct device_operations usb2_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = usb2_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = usb2_init, +// .enable = mcp55_enable, + .scan_bus = 0, + .ops_pci = &lops_pci, +}; + +static struct pci_driver usb2_driver __pci_driver = { + .ops = &usb2_ops, + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_MCP55_USB2, +}; diff --git a/src/southbridge/nvidia/mcp55/romstrap.inc b/src/southbridge/nvidia/mcp55/romstrap.inc new file mode 100644 index 0000000000..43e93b01cd --- /dev/null +++ b/src/southbridge/nvidia/mcp55/romstrap.inc @@ -0,0 +1,59 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2004 Tyan Computer + * Written by Yinghai Lu <yhlu@tyan.com> for Tyan Computer. + * + * 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 + */ + + .section ".romstrap", "a", @progbits + + + .globl __romstrap_start +__romstrap_start: +rstables: + .long 0x2b16d065 + .long 0x0 + .long 0x0 + .long linkedlist + +linkedlist: + .long 0x0003001C // 10h + .long 0x08000000 // 14h + .long 0x00000000 // 18h + .long 0xFFFFFFFF // 1Ch + + .long 0xFFFFFFFF // 20h + .long 0xFFFFFFFF // 24h + .long 0xFFFFFFFF // 28h + .long 0xFFFFFFFF // 2Ch + + .long 0x81543266 // 30h, MAC address low 4 byte ---> keep it in 0xffffffd0 + .long 0x000000E0 // 34h, MAC address high 4 byte + + .long 0x002309CE // 38h, UUID low 4 byte + .long 0x00E08100 // 3Ch, UUID high 4 byte + +rspointers: + .long rstables // It will be 0xffffffe0 + .long rstables + .long rstables + .long rstables + + .globl __romstrap_end + +__romstrap_end: +.previous diff --git a/src/southbridge/nvidia/mcp55/romstrap.lds b/src/southbridge/nvidia/mcp55/romstrap.lds new file mode 100644 index 0000000000..e100570cf2 --- /dev/null +++ b/src/southbridge/nvidia/mcp55/romstrap.lds @@ -0,0 +1,27 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2007 AMD + * Written by Yinghai Lu <yinghai.lu@amd.com> for AMD. + * + * 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 + */ + +SECTIONS { + . = (_ROMBASE + ROM_IMAGE_SIZE - 0x10) - (__romstrap_end - __romstrap_start); + .romstrap (.): { + *(.romstrap) + } +} |