diff options
author | Yinghai Lu <yinghailu@gmail.com> | 2006-02-16 17:22:19 +0000 |
---|---|---|
committer | Yinghai Lu <yinghailu@gmail.com> | 2006-02-16 17:22:19 +0000 |
commit | afd34e61ace6476946f9f30af92e0f714c901013 (patch) | |
tree | 82e1e5673992e2150bb87de3f1d5b6ee955b2b36 /src/southbridge/broadcom/bcm5785 | |
parent | 4d5865d3d48259f43a1d78af8107d46c7a3a73f3 (diff) |
serverworks HT1000/HT2000, bcm5785/5780 support
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@2176 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'src/southbridge/broadcom/bcm5785')
-rw-r--r-- | src/southbridge/broadcom/bcm5785/Config.lb | 8 | ||||
-rw-r--r-- | src/southbridge/broadcom/bcm5785/bcm5785.c | 80 | ||||
-rw-r--r-- | src/southbridge/broadcom/bcm5785/bcm5785.h | 8 | ||||
-rw-r--r-- | src/southbridge/broadcom/bcm5785/bcm5785_early_setup.c | 193 | ||||
-rw-r--r-- | src/southbridge/broadcom/bcm5785/bcm5785_early_smbus.c | 45 | ||||
-rw-r--r-- | src/southbridge/broadcom/bcm5785/bcm5785_ide.c | 58 | ||||
-rw-r--r-- | src/southbridge/broadcom/bcm5785/bcm5785_lpc.c | 137 | ||||
-rw-r--r-- | src/southbridge/broadcom/bcm5785/bcm5785_reset.c | 41 | ||||
-rw-r--r-- | src/southbridge/broadcom/bcm5785/bcm5785_sata.c | 78 | ||||
-rw-r--r-- | src/southbridge/broadcom/bcm5785/bcm5785_sb_pci_main.c | 153 | ||||
-rw-r--r-- | src/southbridge/broadcom/bcm5785/bcm5785_smbus.h | 184 | ||||
-rw-r--r-- | src/southbridge/broadcom/bcm5785/bcm5785_usb.c | 49 | ||||
-rw-r--r-- | src/southbridge/broadcom/bcm5785/chip.h | 14 |
13 files changed, 1048 insertions, 0 deletions
diff --git a/src/southbridge/broadcom/bcm5785/Config.lb b/src/southbridge/broadcom/bcm5785/Config.lb new file mode 100644 index 0000000000..7cbc0667df --- /dev/null +++ b/src/southbridge/broadcom/bcm5785/Config.lb @@ -0,0 +1,8 @@ +config chip.h +driver bcm5785.o +driver bcm5785_usb.o +driver bcm5785_lpc.o +driver bcm5785_sb_pci_main.o +driver bcm5785_ide.o +driver bcm5785_sata.o +object bcm5785_reset.o diff --git a/src/southbridge/broadcom/bcm5785/bcm5785.c b/src/southbridge/broadcom/bcm5785/bcm5785.c new file mode 100644 index 0000000000..ebb7e8e729 --- /dev/null +++ b/src/southbridge/broadcom/bcm5785/bcm5785.c @@ -0,0 +1,80 @@ +/* + * Copyright 2005 AMD + * by yinghai.lu@amd.com + */ +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include "bcm5785.h" + +void bcm5785_enable(device_t dev) +{ + device_t sb_pci_main_dev; + device_t bus_dev; + unsigned index; + unsigned reg_old, reg; + + /* See if we are on the behind the pcix bridge */ + bus_dev = dev->bus->dev; + if ((bus_dev->vendor == PCI_VENDOR_ID_SERVERWORKS) && + (bus_dev->device == 0x0036 )) // device under PCI-X Bridge + { + unsigned devfn; + devfn = bus_dev->path.u.pci.devfn + (1 << 3); + sb_pci_main_dev = dev_find_slot(bus_dev->bus->secondary, devfn); +// index = ((dev->path.u.pci.devfn & ~7) >> 3) + 8; + } else if ((bus_dev->vendor == PCI_VENDOR_ID_SERVERWORKS) && + (bus_dev->device == 0x0104)) // device under PCI Bridge( under PCI-X ) + { + unsigned devfn; + devfn = bus_dev->bus->dev->path.u.pci.devfn + (1 << 3); + sb_pci_main_dev = dev_find_slot(bus_dev->bus->dev->bus->secondary, devfn); +// index = ((dev->path.u.pci.devfn & ~7) >> 3) + 8; + } + else { // same bus + unsigned devfn; + uint32_t id; + devfn = (dev->path.u.pci.devfn) & ~7; + if( dev->vendor == PCI_VENDOR_ID_SERVERWORKS ) { + if(dev->device == 0x0036) //PCI-X Bridge + { devfn += (1<<3); } + else if(dev->device == 0x0223) // USB + { devfn -= (1<<3); } + } + sb_pci_main_dev = dev_find_slot(dev->bus->secondary, devfn); +// index = dev->path.u.pci.devfn & 7; + } + if (!sb_pci_main_dev) { + return; + } + + // get index now +#if 0 + if (index < 16) { + reg = reg_old = pci_read_config16(sb_pci_main_dev, 0x48); + reg &= ~(1 << index); + if (dev->enabled) { + reg |= (1 << index); + } + if (reg != reg_old) { + pci_write_config16(sb_pci_main_dev, 0x48, reg); + } + } + else if (index == 16) { + reg = reg_old = pci_read_config8(sb_pci_main_dev, 0x47); + reg &= ~(1 << 7); + if (!dev->enabled) { + reg |= (1 << 7); + } + if (reg != reg_old) { + pci_write_config8(sb_pci_main_dev, 0x47, reg); + } + } +#endif +} + +struct chip_operations southbridge_broadcom_bcm5785_ops = { + CHIP_NAME("Serverworks bcm5785") + .enable_dev = bcm5785_enable, +}; diff --git a/src/southbridge/broadcom/bcm5785/bcm5785.h b/src/southbridge/broadcom/bcm5785/bcm5785.h new file mode 100644 index 0000000000..5f7f94f5e2 --- /dev/null +++ b/src/southbridge/broadcom/bcm5785/bcm5785.h @@ -0,0 +1,8 @@ +#ifndef BCM5785_H +#define BCM5785_H + +#include "chip.h" + +void bcm5785_enable(device_t dev); + +#endif /* BCM5785_H */ diff --git a/src/southbridge/broadcom/bcm5785/bcm5785_early_setup.c b/src/southbridge/broadcom/bcm5785/bcm5785_early_setup.c new file mode 100644 index 0000000000..ab94327481 --- /dev/null +++ b/src/southbridge/broadcom/bcm5785/bcm5785_early_setup.c @@ -0,0 +1,193 @@ +/* + * Copyright 2005 AMD + * by yinghai.lu@amd.com + */ + +#if USE_FALLBACK_IMAGE == 1 + +static void bcm5785_enable_rom(void) +{ + unsigned char byte; + uint32_t dword; + uint16_t word; + device_t addr; + + /* Enable 4MB rom access at 0xFFC00000 - 0xFFFFFFFF */ + /* Locate the BCM 5785 SB PCI Main */ + addr = pci_locate_device(PCI_ID(0x1166, 0x0205), 0); // 0x0201? + + /* Set the 4MB enable bit bit */ + byte = pci_read_config8(addr, 0x41); + byte |= 0x0e; + pci_write_config8(addr, 0x41, byte); +} + +static void bcm5785_enable_lpc(void) +{ + + uint8_t byte; + device_t dev; + + dev = pci_locate_device(PCI_ID(0x1166, 0x0234), 0); + + /* LPC Control 0 */ + byte = pci_read_config8(dev, 0x44); + /* Serial 0 */ + byte |= (1<<6); + pci_write_config8(dev, 0x44, byte); + + /* LPC Control 4 */ + byte = pci_read_config8(dev, 0x48); + /* superio port 0x2e/4e enable */ + byte |=(1<<1)|(1<<0); + pci_write_config8(dev, 0x48, byte); +} +#endif /* USE_FALLBACK_IMAGE == 1 */ + + +static void bcm5785_enable_wdt_port_cf9(void) +{ + device_t dev; + uint32_t dword; + uint32_t dword_old; + + dev = pci_locate_device(PCI_ID(0x1166, 0x0205), 0); + + dword_old = pci_read_config32(dev, 0x4c); + dword = dword_old | (1<<4); //enable Timer Func + if(dword != dword_old ) { + pci_write_config32(dev, 0x4c, dword); + } + + dword_old = pci_read_config32(dev, 0x6c); + dword = dword_old | (1<<9); //unhide Timer Func in pci space + if(dword != dword_old ) { + pci_write_config32(dev, 0x6c, dword); + } + + dev = pci_locate_device(PCI_ID(0x1166, 0x0238), 0); + + /* enable cf9 */ + pci_write_config8(dev, 0x40, (1<<2)); +} + +static void hard_reset(void) +{ + bcm5785_enable_wdt_port_cf9(); + + set_bios_reset(); + + /* full reset */ + outb(0x0a, 0x0cf9); + outb(0x0e, 0x0cf9); +} + +static void soft_reset(void) +{ + bcm5785_enable_wdt_port_cf9(); + + set_bios_reset(); +#if 1 + /* link reset */ +// outb(0x02, 0x0cf9); + outb(0x06, 0x0cf9); +#endif +} + + + +static void bcm5785_enable_msg(void) +{ + device_t dev; + uint32_t dword; + uint32_t dword_old; + uint8_t byte; + + dev = pci_locate_device(PCI_ID(0x1166, 0x0205), 0); + + byte = pci_read_config8(dev, 0x42); + byte = (1<<1); //enable a20 + pci_write_config8(dev, 0x42, byte); + + dword_old = pci_read_config32(dev, 0x6c); + // bit 5: enable A20 Message + // bit 4: enable interrupt messages + // bit 3: enable reset init message + // bit 2: enable keyboard init message + // bit 1: enable upsteam messages + // bit 0: enable shutdowm message to init generation + dword = dword_old | (1<<5) | (1<<3) | (1<<2) | (1<<1) | (1<<0); // bit 1 and bit 4 must be set, otherwise interrupt msg will not be delivered to the processor + if(dword != dword_old ) { + pci_write_config32(dev, 0x6c, dword); + } + +} + +static void bcm5785_early_setup(void) +{ + uint8_t byte; + uint16_t word; + uint32_t dword; + device_t dev; + +//F0 + // enable device on bcm5785 at first + dev = pci_locate_device(PCI_ID(0x1166, 0x0205), 0); + dword = pci_read_config32(dev, 0x64); + dword |= (1<<15) | (1<<11) | (1<<3); // ioapci enable + dword |= (1<<8); // USB enable + dword |= /* (1<<27)|*/(1<<14); // IDE enable + pci_write_config32(dev, 0x64, dword); + + byte = pci_read_config8(dev, 0x84); + byte |= (1<<0); // SATA enable + pci_write_config8(dev, 0x84, byte); + +// wdt and cf9 for later in linuxbios_ram to call hard_reset + bcm5785_enable_wdt_port_cf9(); + + bcm5785_enable_msg(); + + +#if 1 +// IDE related + //F0 + byte = pci_read_config8(dev, 0x4e); + byte |= (1<<4); //enable IDE ext regs + pci_write_config8(dev, 0x4e, byte); + + //F1 + dev = pci_locate_device(PCI_ID(0x1166, 0x0214), 0); + byte = pci_read_config8(dev, 0x48); + byte &= ~1; // disable pri channel + pci_write_config8(dev, 0x48, byte); + pci_write_config8(dev, 0xb0, 0x01); + pci_write_config8(dev, 0xb2, 0x02); + byte = pci_read_config8(dev, 0x06); + byte |= (1<<4); // so b0, b2 can not be changed from now + pci_write_config8(dev, 0x06, byte); + byte = pci_read_config8(dev, 0x49); + byte |= 1; // enable second channel + pci_write_config8(dev, 0x49, byte); +#endif + +//F2 + dev = pci_locate_device(PCI_ID(0x1166, 0x0234), 0); + + byte = pci_read_config8(dev, 0x40); + byte |= (1<<3)|(1<<2); // LPC Retry, LPC to PCI DMA enable + pci_write_config8(dev, 0x40, byte); + + pci_write_config32(dev, 0x60, 0x0000ffff); // LPC Memory hole start and end + +#if 1 +// USB related + pci_write_config8(dev, 0x90, 0x40); + pci_write_config8(dev, 0x92, 0x06); + pci_write_config8(dev, 0x9c, 0x7c); //PHY timinig register + pci_write_config8(dev, 0xa4, 0x02); //mask reg - low/full speed func + pci_write_config8(dev, 0xa5, 0x02); //mask reg - low/full speed func + pci_write_config8(dev, 0xa6, 0x00); //mask reg - high speed func + pci_write_config8(dev, 0xb4, 0x40); +#endif +} diff --git a/src/southbridge/broadcom/bcm5785/bcm5785_early_smbus.c b/src/southbridge/broadcom/bcm5785/bcm5785_early_smbus.c new file mode 100644 index 0000000000..b6a2fe506e --- /dev/null +++ b/src/southbridge/broadcom/bcm5785/bcm5785_early_smbus.c @@ -0,0 +1,45 @@ +/* + * Copyright 2005 AMD + * by yinghai.lu@amd.com + */ + +#include "bcm5785_smbus.h" + +#define SMBUS_IO_BASE 0x1000 + +static void enable_smbus(void) +{ + device_t dev; + dev = pci_locate_device(PCI_ID(0x1166, 0x0205), 0); // 0x0201? + + if (dev == PCI_DEV_INVALID) { + die("SMBUS controller not found\r\n"); + } + + print_debug("SMBus controller enabled\r\n"); + /* set smbus iobase */ + pci_write_config32(dev, 0x90, SMBUS_IO_BASE | 1); + /* Set smbus iospace enable */ + pci_write_config8(dev, 0xd2, 0x03); + /* clear any lingering errors, so the transaction will run */ + outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT); +} + +static int smbus_recv_byte(unsigned device) +{ + return do_smbus_recv_byte(SMBUS_IO_BASE, device); +} + +static int smbus_send_byte(unsigned device, unsigned char val) +{ + return do_smbus_send_byte(SMBUS_IO_BASE, device, val); +} + +static int smbus_read_byte(unsigned device, unsigned address) +{ + return do_smbus_read_byte(SMBUS_IO_BASE, device, address); +} +static int smbus_write_byte(unsigned device, unsigned address, unsigned char val) +{ + return do_smbus_write_byte(SMBUS_IO_BASE, device, address, val); +} diff --git a/src/southbridge/broadcom/bcm5785/bcm5785_ide.c b/src/southbridge/broadcom/bcm5785/bcm5785_ide.c new file mode 100644 index 0000000000..b3cc493f5b --- /dev/null +++ b/src/southbridge/broadcom/bcm5785/bcm5785_ide.c @@ -0,0 +1,58 @@ +/* + * Copyright 2005 AMD + * by yinghai.lu@amd.com + */ + +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include "bcm5785.h" + +static void bcm5785_ide_read_resources(device_t dev) +{ + struct resource *res; + unsigned long index; + + /* Get the normal pci resources of this device */ + pci_dev_read_resources(dev); + + /* BAR */ + pci_get_resource(dev, 0x64); + + compact_resources(dev); +} + +static void ide_init(struct device *dev) +{ + uint16_t word; + + +} + +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 = bcm5785_ide_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = ide_init, + .scan_bus = 0, +// .enable = bcm5785_enable, + .ops_pci = &lops_pci, +}; + +static struct pci_driver ide_driver __pci_driver = { + .ops = &ide_ops, + .vendor = PCI_VENDOR_ID_SERVERWORKS, + .device = PCI_DEVICE_ID_SERVERWORKS_BCM5785_IDE, +}; + diff --git a/src/southbridge/broadcom/bcm5785/bcm5785_lpc.c b/src/southbridge/broadcom/bcm5785/bcm5785_lpc.c new file mode 100644 index 0000000000..5c061dbe86 --- /dev/null +++ b/src/southbridge/broadcom/bcm5785/bcm5785_lpc.c @@ -0,0 +1,137 @@ +/* + * Copyright 2005 AMD + * by yinghai.lu@amd.com + */ + +#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 "bcm5785.h" + +static void lpc_init(device_t dev) +{ + + /* Initialize the real time clock */ + rtc_init(0); + + /* Initialize isa dma */ + isa_dma_init(); + +} + +static void bcm5785_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); + + /* 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 bcm5785_lpc_enable_childrens_resources(device_t dev) +{ + unsigned link; + uint32_t reg; + int i; + int var_num = 0; + + reg = pci_read_config8(dev, 0x44); + + 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("bcm5785lpc decode:%s, base=0x%08x, end=0x%08x\r\n",dev_path(child),base, end); + switch(base) { + case 0x60: //KBC + case 0x64: + reg |= (1<<29); + case 0x3f8: // COM1 + reg |= (1<<6); break; + case 0x2f8: // COM2 + reg |= (1<<7); break; + case 0x378: // Parallal 1 + reg |= (1<<0); break; + case 0x3f0: // FD0 + reg |= (1<<26); break; + case 0x220: // Aduio 0 + reg |= (1<<14); break; + case 0x300: // Midi 0 + reg |= (1<<18); break; + } + } + } + } + } + pci_write_config32(dev, 0x44, reg); + + +} + +static void bcm5785_lpc_enable_resources(device_t dev) +{ + pci_dev_enable_resources(dev); + bcm5785_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 = bcm5785_lpc_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = bcm5785_lpc_enable_resources, + .init = lpc_init, + .scan_bus = scan_static_bus, +// .enable = bcm5785_enable, + .ops_pci = &lops_pci, +}; +static struct pci_driver lpc_driver __pci_driver = { + .ops = &lpc_ops, + .vendor = PCI_VENDOR_ID_SERVERWORKS, + .device = PCI_DEVICE_ID_SERVERWORKS_BCM5785_LPC, +}; + diff --git a/src/southbridge/broadcom/bcm5785/bcm5785_reset.c b/src/southbridge/broadcom/bcm5785/bcm5785_reset.c new file mode 100644 index 0000000000..b6fc5926b3 --- /dev/null +++ b/src/southbridge/broadcom/bcm5785/bcm5785_reset.c @@ -0,0 +1,41 @@ +/* + * Copyright 2005 AMD + * by yinghai.lu@amd.com + */ + +#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/broadcom/bcm5785/bcm5785_sata.c b/src/southbridge/broadcom/bcm5785/bcm5785_sata.c new file mode 100644 index 0000000000..470bc47c73 --- /dev/null +++ b/src/southbridge/broadcom/bcm5785/bcm5785_sata.c @@ -0,0 +1,78 @@ +/* + * Copyright 2005 AMD + * by yinghai.lu@amd.com + */ + +#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 <arch/io.h> +#include "bcm5785.h" + + +static void sata_init(struct device *dev) +{ + + uint8_t byte; + + uint8_t *base; + uint8_t *mmio; + struct resource *res; + int i; + + if(!(dev->path.u.pci.devfn & 7)) { // only set it in Func0 + byte = pci_read_config8(dev, 0x78); + byte |= (1<<7); + pci_write_config8(dev, 0x78, byte); + + res = find_resource(dev, 0x24); + base = res->base; + //init PHY + + printk_debug("init PHY...\n"); + for(i=0; i<4; i++) { + mmio = base + 0x100 * i; + byte = readb(mmio + 0x40); + printk_debug("port %d PHY status = %02x\r\n", i, byte); + if(byte & 0x4) {// bit 2 is set + byte = readb(mmio+0x48); + writeb(byte | 1, mmio + 0x48); + writeb(byte & (~1), mmio + 0x48); + byte = readb(mmio + 0x40); + printk_debug("after reset port %d PHY status = %02x\r\n", i, byte); + } + } + + } + + +} + +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 = bcm5785_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_SERVERWORKS, + .device = PCI_DEVICE_ID_SERVERWORKS_BCM5785_SATA, +}; + diff --git a/src/southbridge/broadcom/bcm5785/bcm5785_sb_pci_main.c b/src/southbridge/broadcom/bcm5785/bcm5785_sb_pci_main.c new file mode 100644 index 0000000000..5db13d636d --- /dev/null +++ b/src/southbridge/broadcom/bcm5785/bcm5785_sb_pci_main.c @@ -0,0 +1,153 @@ +/* + * Copyright 2005 AMD + * by yinghai.lu@amd.com + */ + +#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 <device/smbus.h> +#include "bcm5785.h" +#include "bcm5785_smbus.h" + +#define NMI_OFF 0 + +static void sb_init(device_t dev) +{ + uint8_t byte; + uint8_t byte_old; + int nmi_option; + + uint32_t dword; + + /* 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); + } + + +} + +static void bcm5785_sb_read_resources(device_t dev) +{ + struct resource *res; + unsigned long index; + + /* Get the normal pci resources of this device */ + pci_dev_read_resources(dev); + + /* Get Resource for SMBUS */ + pci_get_resource(dev, 0x90); + + compact_resources(dev); + + /* 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; + +} +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, 0x90); + + 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, 0x90); + + 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, 0x90); + + 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, 0x90); + + return do_smbus_write_byte(res->base, device, address, val); +} +static struct smbus_bus_operations lops_smbus_bus = { + .recv_byte = lsmbus_recv_byte, + .send_byte = lsmbus_send_byte, + .read_byte = lsmbus_read_byte, + .write_byte = lsmbus_write_byte, +}; + +static void lpci_set_subsystem(device_t dev, unsigned vendor, unsigned device) +{ + pci_write_config32(dev, 0x2c, + ((device & 0xffff) << 16) | (vendor & 0xffff)); +} + +static struct pci_operations lops_pci = { + .set_subsystem = lpci_set_subsystem, +}; + +static struct device_operations sb_ops = { + .read_resources = bcm5785_sb_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = sb_init, + .scan_bus = scan_static_bus, +// .enable = bcm5785_enable, + .ops_pci = &lops_pci, + .ops_smbus_bus = &lops_smbus_bus, +}; +static struct pci_driver sb_driver __pci_driver = { + .ops = &sb_ops, + .vendor = PCI_VENDOR_ID_SERVERWORKS, + .device = PCI_DEVICE_ID_SERVERWORKS_BCM5785_SB_PCI_MAIN, +}; + diff --git a/src/southbridge/broadcom/bcm5785/bcm5785_smbus.h b/src/southbridge/broadcom/bcm5785/bcm5785_smbus.h new file mode 100644 index 0000000000..5f2f7717a0 --- /dev/null +++ b/src/southbridge/broadcom/bcm5785/bcm5785_smbus.h @@ -0,0 +1,184 @@ +/* + * Copyright 2005 AMD + * by yinghai.lu@amd.com + */ +#include <device/smbus_def.h> + +#define SMBHSTSTAT 0x0 +#define SMBSLVSTAT 0x1 +#define SMBHSTCTRL 0x2 +#define SMBHSTCMD 0x3 +#define SMBHSTADDR 0x4 +#define SMBHSTDAT0 0x5 +#define SMBHSTDAT1 0x6 +#define SMBHSTBLKDAT 0x7 + +#define SMBSLVCTRL 0x8 +#define SMBSLVCMD_SHADOW 0x9 +#define SMBSLVEVT 0xa +#define SMBSLVDAT 0xc + + +/* 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; + val = inb(smbus_io_base + SMBHSTSTAT); + val &= 0x1f; + if (val == 0) { // ready now + return 0; + } + outb(val, smbus_io_base + SMBHSTSTAT); + } while(--loops); + return -2; // time out +} + +static int smbus_wait_until_done(unsigned smbus_io_base) +{ + unsigned long loops; + loops = SMBUS_TIMEOUT; + do { + unsigned char val; + + val = inb(smbus_io_base + SMBHSTSTAT); + val &= 0x1f; // mask off reserved bits + if ( val & 0x1c) { + return -5; // error + } + if ( val == 0x02) { + outb(val, smbus_io_base + SMBHSTSTAT); // clear status + return 0; // + } + } while(--loops); + return -3; // timeout +} + +static int do_smbus_recv_byte(unsigned smbus_io_base, unsigned device) +{ + uint8_t byte; + + if (smbus_wait_until_ready(smbus_io_base) < 0) { + return -2; // not ready + } + + /* set the device I'm talking too */ + outb(((device & 0x7f) << 1)|1 , smbus_io_base + SMBHSTADDR); + + byte = inb(smbus_io_base + SMBHSTCTRL); + byte &= 0xe3; // Clear [4:2] + byte |= (1<<2) | (1<<6); // Byte data read/write command, start the command + outb(byte, smbus_io_base + SMBHSTCTRL); + + /* poll for transaction completion */ + if (smbus_wait_until_done(smbus_io_base) < 0) { + return -3; // timeout or error + } + + /* read results of transaction */ + byte = inb(smbus_io_base + SMBHSTCMD); + + return byte; + +} +static int do_smbus_send_byte(unsigned smbus_io_base, unsigned device, unsigned char val) +{ + uint8_t byte; + + if (smbus_wait_until_ready(smbus_io_base) < 0) { + return -2; // not ready + } + + /* set the command... */ + outb(val, smbus_io_base + SMBHSTCMD); + + /* set the device I'm talking too */ + outb(((device & 0x7f) << 1)|0 , smbus_io_base + SMBHSTADDR); + + byte = inb(smbus_io_base + SMBHSTCTRL); + byte &= 0xe3; // Clear [4:2] + byte |= (1<<2) | (1<<6); // Byte data read/write command, start the command + outb(byte, smbus_io_base + SMBHSTCTRL); + + /* poll for transaction completion */ + if (smbus_wait_until_done(smbus_io_base) < 0) { + return -3; // timeout or error + } + + return 0; + +} + + +static int do_smbus_read_byte(unsigned smbus_io_base, unsigned device, unsigned address) +{ + uint8_t byte; + + if (smbus_wait_until_ready(smbus_io_base) < 0) { + return -2; // not ready + } + + /* set the command/address... */ + outb(address & 0xff, smbus_io_base + SMBHSTCMD); + + /* set the device I'm talking too */ + outb(((device & 0x7f) << 1)|1 , smbus_io_base + SMBHSTADDR); + + byte = inb(smbus_io_base + SMBHSTCTRL); + byte &= 0xe3; // Clear [4:2] + byte |= (1<<3) | (1<<6); // Byte data read/write command, start the command + outb(byte, smbus_io_base + SMBHSTCTRL); + + /* poll for transaction completion */ + if (smbus_wait_until_done(smbus_io_base) < 0) { + return -3; // timeout or error + } + + /* read results of transaction */ + byte = inb(smbus_io_base + SMBHSTDAT0); + + return byte; +} +static int do_smbus_write_byte(unsigned smbus_io_base, unsigned device, unsigned address, unsigned char val) +{ + uint8_t byte; + + if (smbus_wait_until_ready(smbus_io_base) < 0) { + return -2; // not ready + } + + /* set the command/address... */ + outb(address & 0xff, smbus_io_base + SMBHSTCMD); + + /* set the device I'm talking too */ + outb(((device & 0x7f) << 1)|0 , smbus_io_base + SMBHSTADDR); + + /* output value */ + outb(val, smbus_io_base + SMBHSTDAT0); + + byte = inb(smbus_io_base + SMBHSTCTRL); + byte &= 0xe3; // Clear [4:2] + byte |= (1<<3) | (1<<6); // Byte data read/write command, start the command + outb(byte, smbus_io_base + SMBHSTCTRL); + + /* poll for transaction completion */ + if (smbus_wait_until_done(smbus_io_base) < 0) { + return -3; // timeout or error + } + + return 0; + +} + + diff --git a/src/southbridge/broadcom/bcm5785/bcm5785_usb.c b/src/southbridge/broadcom/bcm5785/bcm5785_usb.c new file mode 100644 index 0000000000..d9ce41aa1e --- /dev/null +++ b/src/southbridge/broadcom/bcm5785/bcm5785_usb.c @@ -0,0 +1,49 @@ +/* + * Copyright 2005 AMD + * by yinghai.lu@amd.com + */ + +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include "bcm5785.h" + +static void usb_init(struct device *dev) +{ + uint32_t dword; + + dword = pci_read_config32(dev, 0x04); + dword |= (1<<2)|(1<<1)|(1<<0); + pci_write_config32(dev, 0x04, dword); + + pci_write_config8(dev, 0x41, 0x00); // Serversworks said + +} + +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 = usb_init, +// .enable = bcm5785_enable, + .scan_bus = 0, + .ops_pci = &lops_pci, +}; + +static struct pci_driver usb_driver __pci_driver = { + .ops = &usb_ops, + .vendor = PCI_VENDOR_ID_SERVERWORKS, + .device = PCI_DEVICE_ID_SERVERWORKS_BCM5785_USB, +}; + diff --git a/src/southbridge/broadcom/bcm5785/chip.h b/src/southbridge/broadcom/bcm5785/chip.h new file mode 100644 index 0000000000..4aa2ce3217 --- /dev/null +++ b/src/southbridge/broadcom/bcm5785/chip.h @@ -0,0 +1,14 @@ +#ifndef BCM5785_CHIP_H +#define BCM5785_CHIP_H + +struct southbridge_broadcom_bcm5785_config +{ + unsigned int ide0_enable : 1; + unsigned int ide1_enable : 1; + unsigned int sata0_enable : 1; + unsigned int sata1_enable : 1; +}; +struct chip_operations; +extern struct chip_operations southbridge_broadcom_bcm5785_ops; + +#endif /* BCM5785_CHIP_H */ |