summaryrefslogtreecommitdiff
path: root/src/southbridge
diff options
context:
space:
mode:
Diffstat (limited to 'src/southbridge')
-rw-r--r--src/southbridge/broadcom/bcm5780/Config.lb3
-rw-r--r--src/southbridge/broadcom/bcm5780/bcm5780_nic.c49
-rw-r--r--src/southbridge/broadcom/bcm5780/bcm5780_pcie.c46
-rw-r--r--src/southbridge/broadcom/bcm5780/bcm5780_pcix.c37
-rw-r--r--src/southbridge/broadcom/bcm5785/Config.lb8
-rw-r--r--src/southbridge/broadcom/bcm5785/bcm5785.c80
-rw-r--r--src/southbridge/broadcom/bcm5785/bcm5785.h8
-rw-r--r--src/southbridge/broadcom/bcm5785/bcm5785_early_setup.c193
-rw-r--r--src/southbridge/broadcom/bcm5785/bcm5785_early_smbus.c45
-rw-r--r--src/southbridge/broadcom/bcm5785/bcm5785_ide.c58
-rw-r--r--src/southbridge/broadcom/bcm5785/bcm5785_lpc.c137
-rw-r--r--src/southbridge/broadcom/bcm5785/bcm5785_reset.c41
-rw-r--r--src/southbridge/broadcom/bcm5785/bcm5785_sata.c78
-rw-r--r--src/southbridge/broadcom/bcm5785/bcm5785_sb_pci_main.c153
-rw-r--r--src/southbridge/broadcom/bcm5785/bcm5785_smbus.h184
-rw-r--r--src/southbridge/broadcom/bcm5785/bcm5785_usb.c49
-rw-r--r--src/southbridge/broadcom/bcm5785/chip.h14
17 files changed, 1183 insertions, 0 deletions
diff --git a/src/southbridge/broadcom/bcm5780/Config.lb b/src/southbridge/broadcom/bcm5780/Config.lb
new file mode 100644
index 0000000000..69153ef75d
--- /dev/null
+++ b/src/southbridge/broadcom/bcm5780/Config.lb
@@ -0,0 +1,3 @@
+driver bcm5780_nic.o
+driver bcm5780_pcix.o
+driver bcm5780_pcie.o
diff --git a/src/southbridge/broadcom/bcm5780/bcm5780_nic.c b/src/southbridge/broadcom/bcm5780/bcm5780_nic.c
new file mode 100644
index 0000000000..8033f4d5c4
--- /dev/null
+++ b/src/southbridge/broadcom/bcm5780/bcm5780_nic.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>
+
+
+static void nic_init(struct device *dev)
+{
+
+#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,
+ .ops_pci = &lops_pci,
+};
+static struct pci_driver nic_driver __pci_driver = {
+ .ops = &nic_ops,
+ .vendor = PCI_VENDOR_ID_BROADCOM,
+ .device = PCI_DEVICE_ID_BROADCOM_BCM5780_NIC,
+};
+static struct pci_driver nic1_driver __pci_driver = {
+ .ops = &nic_ops,
+ .vendor = PCI_VENDOR_ID_BROADCOM,
+ .device = PCI_DEVICE_ID_BROADCOM_BCM5780_NIC1,
+};
diff --git a/src/southbridge/broadcom/bcm5780/bcm5780_pcie.c b/src/southbridge/broadcom/bcm5780/bcm5780_pcie.c
new file mode 100644
index 0000000000..24691775de
--- /dev/null
+++ b/src/southbridge/broadcom/bcm5780/bcm5780_pcie.c
@@ -0,0 +1,46 @@
+/*
+ * 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>
+
+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,
+ .reset_bus = pci_bus_reset,
+ .ops_pci = &lops_pci,
+
+};
+
+static struct pci_driver pcie_driver __pci_driver = {
+ .ops = &pcie_ops,
+ .vendor = PCI_VENDOR_ID_SERVERWORKS,
+ .device = PCI_DEVICE_ID_SERVERWORKS_BCM5780_PCIE,
+};
+
diff --git a/src/southbridge/broadcom/bcm5780/bcm5780_pcix.c b/src/southbridge/broadcom/bcm5780/bcm5780_pcix.c
new file mode 100644
index 0000000000..d8f1c246ce
--- /dev/null
+++ b/src/southbridge/broadcom/bcm5780/bcm5780_pcix.c
@@ -0,0 +1,37 @@
+/*
+ * 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>
+
+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_bus_read_resources,
+ .set_resources = pci_dev_set_resources,
+ .enable_resources = pci_bus_enable_resources,
+ .init = 0 ,
+ .scan_bus = pci_scan_bridge,
+ .reset_bus = pci_bus_reset,
+ .ops_pci = &lops_pci,
+
+};
+
+static struct pci_driver ht_driver __pci_driver = {
+ .ops = &ht_ops,
+ .vendor = PCI_VENDOR_ID_SERVERWORKS,
+ .device = PCI_DEVICE_ID_SERVERWORKS_BCM5780_PXB,
+};
+
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 */