From 4d6810c60cda5a47b13813b590c57d39b719c013 Mon Sep 17 00:00:00 2001 From: "Ronald G. Minnich" Date: Mon, 18 Sep 2006 22:52:24 +0000 Subject: add the _lx flavor of the 5536. This will later be merged into the cs5536, but I don't want to mess up the OLPC, and we really need the lx support NOW. git-svn-id: svn://svn.coreboot.org/coreboot/trunk@2421 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1 --- src/southbridge/amd/cs5536_lx/Config.lb | 5 + src/southbridge/amd/cs5536_lx/chip.h | 53 ++++ src/southbridge/amd/cs5536_lx/cs5536.c | 331 ++++++++++++++++++++ src/southbridge/amd/cs5536_lx/cs5536.h | 6 + src/southbridge/amd/cs5536_lx/cs5536_early_setup.c | 336 +++++++++++++++++++++ src/southbridge/amd/cs5536_lx/cs5536_early_smbus.c | 45 +++ src/southbridge/amd/cs5536_lx/cs5536_ide.c | 30 ++ src/southbridge/amd/cs5536_lx/cs5536_smbus.h | 180 +++++++++++ src/southbridge/amd/cs5536_lx/cs5536_smbus2.h | 299 ++++++++++++++++++ 9 files changed, 1285 insertions(+) create mode 100644 src/southbridge/amd/cs5536_lx/Config.lb create mode 100644 src/southbridge/amd/cs5536_lx/chip.h create mode 100644 src/southbridge/amd/cs5536_lx/cs5536.c create mode 100644 src/southbridge/amd/cs5536_lx/cs5536.h create mode 100644 src/southbridge/amd/cs5536_lx/cs5536_early_setup.c create mode 100644 src/southbridge/amd/cs5536_lx/cs5536_early_smbus.c create mode 100644 src/southbridge/amd/cs5536_lx/cs5536_ide.c create mode 100644 src/southbridge/amd/cs5536_lx/cs5536_smbus.h create mode 100644 src/southbridge/amd/cs5536_lx/cs5536_smbus2.h diff --git a/src/southbridge/amd/cs5536_lx/Config.lb b/src/southbridge/amd/cs5536_lx/Config.lb new file mode 100644 index 0000000000..3abdf5d4fa --- /dev/null +++ b/src/southbridge/amd/cs5536_lx/Config.lb @@ -0,0 +1,5 @@ +config chip.h +driver cs5536.o +driver cs5536_usb.o +#driver cs5536_pci.o +#driver cs5536_ide.o diff --git a/src/southbridge/amd/cs5536_lx/chip.h b/src/southbridge/amd/cs5536_lx/chip.h new file mode 100644 index 0000000000..146e1d2621 --- /dev/null +++ b/src/southbridge/amd/cs5536_lx/chip.h @@ -0,0 +1,53 @@ +#ifndef _SOUTHBRIDGE_AMD_CS5536 +#define _SOUTHBRIDGE_AMD_CS5536 + +#define MAX_UNWANTED_VPCI 10 /* increase if needed */ + +extern struct chip_operations southbridge_amd_cs5536_ops; + +struct southbridge_amd_cs5536_config { + /* interrupt enable for LPC bus */ + int lpc_serirq_enable; /* how to enable, e.g. 0x80 */ + int lpc_irq; /* what to enable, e.g. 0x18 */ + int enable_ide_nand_flash; /* if you are using nand flash instead of IDE drive */ + + /* following are IRQ numbers for various southbridge resources. + * these are configured and PCI headers are set */ + + int isa_irq; // f.0, 1022:2090 + int flash_irq; // f.1, 1022:2091 + + // ide irq is tied to IRQ14, this can only be enabled or disabled + int enable_ide_irq; // f.2, 1022:2092 + + int audio_irq; // f.3, 1022:2093 + + int usb_irq; // f.4,5,6,7, 1022:2094 + // only one irq source for all usb devices + + // internal UART IRQs + int uart0_irq; + int uart1_irq; + + /* GPIO to IRQ mapping, intended to use for PCI IRQ's. + * This only does physical mapping, no PCI headers are configured + * PCI configuration is mainboard-specific and should be done in mainboard.c + */ + // pci IRQs A-D. Set this to 0 to disable. + int pci_int[4]; + // and their GPIO pins + int pci_int_pin[4]; + + + // Enable KEL keyboard IRQ2 + int enable_kel_keyb_irq; + // Enable KEL mouse IRQ12 + int enable_kel_mouse_irq; + // Configure KEL Emulation IRQ (input Y13) + int kel_emul_irq; + + /* the following allow you to disable unwanted virtualized PCI devices */ + unsigned long unwanted_vpci[MAX_UNWANTED_VPCI]; +}; + +#endif /* _SOUTHBRIDGE_AMD_CS5536 */ diff --git a/src/southbridge/amd/cs5536_lx/cs5536.c b/src/southbridge/amd/cs5536_lx/cs5536.c new file mode 100644 index 0000000000..803a5fbb6b --- /dev/null +++ b/src/southbridge/amd/cs5536_lx/cs5536.c @@ -0,0 +1,331 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "chip.h" + +// prototypes here, avoid warnings +void setup_i8259(void); +void pci_assign_irqs(unsigned bus, unsigned slot, const unsigned char pIntAtoD[4]); +void print_conf(void); + +#define PIN_OPT_IDE (1ULL<<0) /* 0 for flash, 1 for IDE */ + +/* Intended value for LBAR_FLSH0: 4KiB, enabled, MMIO, NAND, @0x20000000 */ +/* NOTE: no longer used, prune at some point */ +/* OOPS: steve's changes don't work, so we have to keep this */ +msr_t flsh1 = { .hi=0xFFFFF007, .lo=0x20000000}; + +// ide is ENABLED by default (in early init), this disables it if neccesary +// and enables flash +static void enable_ide_nand_flash() +{ + msr_t msr; + printk_debug("cs5536: %s\n", __FUNCTION__); +#if 1 + printk_err("WARNING: using deprecated flash enable mechanism\n"); + /* steve took this one out ... not sure if needed or not */ + msr = rdmsr(MDD_LBAR_FLSH1); + + if ( ((msr.hi) & 7) != 7) { + printk_debug("MDD_LBAR_FLSH1 was 0x%08x%08x\n", msr.hi,msr.lo); + wrmsr(MDD_LBAR_FLSH1, flsh1); + } + msr = rdmsr(MDD_LBAR_FLSH1); + printk_debug("MDD_LBAR_FLSH1 is 0x%08x%08x\n", msr.hi,msr.lo); +#endif + msr = rdmsr(MDD_PIN_OPT); + if (msr.lo & PIN_OPT_IDE) { + printk_debug("MDD_PIN_OPT was 0x%08x%08x\n", msr.hi,msr.lo); + msr.lo &= ~PIN_OPT_IDE; + wrmsr(MDD_PIN_OPT, msr); + } + msr = rdmsr(MDD_PIN_OPT); + printk_debug("MDD_PIN_OPT is 0x%08x%08x\n", msr.hi,msr.lo); + + msr = rdmsr(MDD_NANDF_DATA); + if (msr.lo != 0x00100010) { + printk_debug("MDD_NANDF_DATA was 0x%08x%08x\n", msr.hi,msr.lo); + msr.lo = 0x00100010; + wrmsr(MDD_NANDF_DATA, msr); + } + msr = rdmsr(MDD_NANDF_DATA); + printk_debug("MDD_NANDF_DATA is 0x%08x%08x\n", msr.hi,msr.lo); + + msr = rdmsr(MDD_NADF_CNTL); + if (msr.lo != 0x0010) { + printk_debug("MDD_NADF_CNTL was 0x%08x%08x\n", msr.hi,msr.lo); + msr.lo = 0x0010; + wrmsr(MDD_NADF_CNTL, msr); + } + msr = rdmsr(MDD_NADF_CNTL); + printk_debug("MDD_NADF_CNTL is 0x%08x%08x\n", msr.hi,msr.lo); + printk_debug("cs5536: EXIT %s\n", __FUNCTION__); +} + +/* note: this is a candidate for inclusion in src/devices/pci_device.c */ +// set pci headers to indicate correct IRQ number of the device +void setup_irq(unsigned irq, unsigned level, unsigned bus, unsigned device, unsigned fn) +{ + if (irq) + { + unsigned devfn = PCI_DEVFN(device,fn); + device_t dev = dev_find_slot(bus, devfn); + if (dev) + { + printk_debug("%s: assigning IRQ %d to %x.%x (0x%x)\n", + __FUNCTION__, irq, device, fn, devfn); + + pci_write_config8(dev, PCI_INTERRUPT_LINE, irq); + if (level) pci_level_irq(irq); + } + else + printk_err("%s: Can't find PCI device function 0x%x\n", __FUNCTION__, devfn); + } +} + +// map an Y or Z irq source in programmable irq controller +// dev 0..15 Y, 16...31 Z +void map_pic_irq(unsigned int dev, unsigned int irq){ + msr_t msr; + unsigned long mask; + unsigned long val; + + + mask = ~(0xF<<((dev&7)<<2)); + val = irq<<((dev&7)<<2); + + printk_debug("%s: mapping %d to src %d: mask %x val %x\n", + __FUNCTION__, irq, dev,mask,val); + + switch (dev & 0x18){ + case 0: + msr=rdmsr(MDD_IRQM_YLOW); + msr.lo = (msr.lo & mask) | val; + wrmsr(MDD_IRQM_YLOW,msr); + break; + case 8: + msr=rdmsr(MDD_IRQM_YHIGH); + msr.lo = (msr.lo & mask) | val; + wrmsr(MDD_IRQM_YHIGH,msr); + break; + case 16: + msr=rdmsr(MDD_IRQM_ZLOW); + msr.lo = (msr.lo & mask) | val; + wrmsr(MDD_IRQM_ZLOW,msr); + break; + case 24: + msr=rdmsr(MDD_IRQM_ZHIGH); + msr.lo = (msr.lo & mask) | val; + wrmsr(MDD_IRQM_ZHIGH,msr); + } +} + +// map an GPIO pin to PIC Z source and that to an IRQ. +void map_gpio_irq(unsigned int pin, unsigned int gpioirq, unsigned int irq, unsigned int invert){ + + unsigned long temp; + unsigned long mask; + unsigned long val; + + mask = ~(0xF<<((pin&7)<<2)); + val = gpioirq<<((pin&7)<<2); + + // configure GPIO pin as INT source + outl(1<<(pin&0x0F), (pin<16)?GPIOL_INPUT_ENABLE:GPIOH_INPUT_ENABLE); + outl(1<<(pin&0x0F), (pin<16)?GPIOL_EVENTS_ENABLE:GPIOH_EVENTS_ENABLE); + + if (invert) outl(1<<(pin&0x0F), (pin<16)?GPIOL_INPUT_INVERT_ENABLE:GPIOH_INPUT_INVERT_ENABLE); + + // map current GPIO pin to PIC unrestricted Z GPIO irq source gpioirq + temp = inl((pin<16)? + ((pin<8)?GPIO_MAPPER_X:GPIO_MAPPER_Y): + ((pin<24)?GPIO_MAPPER_Z:GPIO_MAPPER_W)); + + outl((temp & mask)|val, + (pin<16)? + ((pin<8)?GPIO_MAPPER_X:GPIO_MAPPER_Y): + ((pin<24)?GPIO_MAPPER_Z:GPIO_MAPPER_W)); + + // map PIC unrestricted Z GPIO source i to IRQ needed + map_pic_irq(gpioirq+24,irq); +} + +static void southbridge_init(struct device *dev) +{ + struct southbridge_amd_cs5536_config *sb = (struct southbridge_amd_cs5536_config *)dev->chip_info; + msr_t msr; + int i; + + printk_spew(">> Entering cs5536.c: %s\n", __FUNCTION__); + + /* + * struct device *gpiodev; + * unsigned short gpiobase = MDD_GPIO; + */ + + setup_i8259(); + + // at first, disable all primary IRQ inputs except timer, RTC and FPU + msr.lo=0x2101; + msr.hi=0; + wrmsr(MDD_IRQM_PRIM, msr); + + // LPC bus IRQs are enabled here + if (sb->lpc_serirq_enable) { + msr.lo = sb->lpc_serirq_enable; + msr.hi = 0; + wrmsr(MDD_LPC_SIRQ, msr); + } + if (sb->lpc_irq) { + msr.lo = sb->lpc_irq; + msr.hi = 0; + wrmsr(MDD_IRQM_LPC, msr); + } + + // GPIO to IRQ mapping (meant for PCI IRQs) + // here, only physical mapping is done. + // pci headers should be configured for all pci slots available in mainboard.c + // so that operating system can read correct irq number from there + for (i=0; i<3; i++){ + if (sb->pci_int[i]){ + printk_debug("cs5536: %s: Configuring PCI INT%c from GPIO %d to INT %d.\n", + __FUNCTION__, 'A'+i, sb->pci_int_pin[i], sb->pci_int[i]); + map_gpio_irq(sb->pci_int_pin[i], i, sb->pci_int[i], 1); + } + } +/* +// PCI IRQ mapping should work like this through vsa, but it doesn't + outl(0xAC1C, 0xFC53); //magic word to enable hidden register + outl(0xAC1C, 0x0009); //command: PCI_INT_AB + outl(0xAC1E, + (sb->pci_int[0]>0)?(sb->pci_int_pin[0]):0x21 | + (sb->pci_int[1]>0)?(sb->pci_int_pin[1]<<8):(0x21<<8) + ); + + outl(0x785C, sb->pci_int[0]|(sb->pci_int[1]<<8)); +*/ + + printk_debug("cs5536: %s: enable_ide_nand_flash is %d\n", __FUNCTION__, sb->enable_ide_nand_flash); + if (sb->enable_ide_nand_flash) { + enable_ide_nand_flash(); + } + + /* irq handling */ + // setup_irq sets irq in pci headers only, no configuration is done. + // pci headers must be set, operating system reads IRQ numbers there. + // to disable, set IRQ=0 + + if (sb->isa_irq){ + setup_irq(sb->isa_irq, 1, 0, 0xf, 0); + } + + if (sb->flash_irq){ + setup_irq(sb->flash_irq, 1, 0, 0xf, 1); + map_pic_irq(6,sb->flash_irq); + map_pic_irq(7,sb->flash_irq); + } + + // IDE IRQ 14 (GPIO pin 2) can only be enabled or disabled + if (sb->enable_ide_irq){ + setup_irq(14, 1, 0, 0xf, 2); + + // set up IDE GPIO IRQ pin + outl(1<<2, GPIOL_INPUT_ENABLE); + outl(1<<2, GPIOL_IN_AUX1_SELECT); + + // enable IDE IRQ in primary IRQ mask + msr=rdmsr(MDD_IRQM_PRIM); + msr.lo |= 0x4000; + wrmsr(MDD_IRQM_PRIM, msr); + } + + if (sb->audio_irq){ + map_pic_irq(4,sb->audio_irq); + setup_irq(sb->audio_irq, 1, 0, 0xf, 3); + } + + if (sb->uart0_irq){ + map_pic_irq(14,sb->uart0_irq); + } + if (sb->uart1_irq){ + map_pic_irq(15,sb->uart1_irq); + } + + if (sb->usb_irq){ + setup_irq(sb->usb_irq, 1, 0, 0xf, 4); + setup_irq(sb->usb_irq, 1, 0, 0xf, 5); + setup_irq(sb->usb_irq, 1, 0, 0xf, 6); + setup_irq(sb->usb_irq, 1, 0, 0xf, 7); + map_pic_irq(2,sb->usb_irq); + } + + // KEL (Keyboard Emulation Logic) IRQs + if (sb->enable_kel_keyb_irq){ + msr=rdmsr(MDD_IRQM_PRIM); + msr.lo |= 0x0002; + wrmsr(MDD_IRQM_PRIM, msr); + } + + if (sb->enable_kel_mouse_irq){ + msr=rdmsr(MDD_IRQM_PRIM); + msr.lo |= 0x1000; + wrmsr(MDD_IRQM_PRIM, msr); + } + + if (sb->kel_emul_irq){ + map_pic_irq(13,sb->kel_emul_irq); + } + + + + + /* disable unwanted virtual PCI devices */ + for (i = 0; (i < MAX_UNWANTED_VPCI) && (0 != sb->unwanted_vpci[i]); i++) { + printk_debug("Disabling VPCI device: 0x%08X\n", sb->unwanted_vpci[i]); + outl(sb->unwanted_vpci[i] + 0x7C, 0xCF8); + outl(0xDEADBEEF, 0xCFC); + } + + /* What do we have there? */ + printk_debug("\nChipset config after southbridge_init():\n"); + print_conf(); +} + +void southbridge_enable(struct device *dev) +{ +} + +static void cs5536_pci_dev_enable_resources(device_t dev) +{ + printk_spew(">> Entering cs5536.c: %s\n", __FUNCTION__); + pci_dev_enable_resources(dev); + enable_childrens_resources(dev); +} + +static struct device_operations southbridge_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = cs5536_pci_dev_enable_resources, + .init = southbridge_init, + .scan_bus = scan_static_bus, +}; + +static struct pci_driver cs5536_pci_driver __pci_driver = { + .ops = &southbridge_ops, + .vendor = PCI_VENDOR_ID_AMD, + .device = PCI_DEVICE_ID_AMD_CS5536_ISA +}; + +struct chip_operations southbridge_amd_cs5536_ops = { + CHIP_NAME("AMD cs5536") + /* This only called when this device is listed in the + * static device tree. + */ + .enable_dev = southbridge_enable, +}; diff --git a/src/southbridge/amd/cs5536_lx/cs5536.h b/src/southbridge/amd/cs5536_lx/cs5536.h new file mode 100644 index 0000000000..8a7453f82e --- /dev/null +++ b/src/southbridge/amd/cs5536_lx/cs5536.h @@ -0,0 +1,6 @@ +#ifndef _CS5536_H +#define _CS5536_H + +extern void southbridge_enable(device_t dev); + +#endif diff --git a/src/southbridge/amd/cs5536_lx/cs5536_early_setup.c b/src/southbridge/amd/cs5536_lx/cs5536_early_setup.c new file mode 100644 index 0000000000..e799db6763 --- /dev/null +++ b/src/southbridge/amd/cs5536_lx/cs5536_early_setup.c @@ -0,0 +1,336 @@ + +/* + * + * cs5536_early_setup.c: Early chipset initialization for CS5536 companion device + * + * + * This file implements the initialization sequence documented in section 4.2 of + * AMD Geode GX Processor CS5536 Companion Device GoedeROM Porting Guide. + * + */ + +#define CS5536_GLINK_PORT_NUM 0x02 /* the geode link port number to the CS5536 */ +#define CS5536_DEV_NUM 0x0F /* default PCI device number for CS5536 */ + + +/** + * By default, on cs5536 IDE is disabled and flash is enabled + * This function disables flash and enables IDE + */ + +static void cs5536_enable_ide(void){ + msr_t msr; + msr = __builtin_rdmsr(0x51400015); + msr.lo |= 0x00000001; + __builtin_wrmsr(0x51400015, msr.lo, msr.hi); +} + +/** + * @brief Setup PCI IDSEL for CS5536 + * + * + */ + +static void cs5536_setup_extmsr(void) +{ + msr_t msr; + + /* forward MSR access to CS5536_GLINK_PORT_NUM to CS5536_DEV_NUM */ + msr.hi = 0x00000000; + msr.lo = 0x00000000; + if (CS5536_GLINK_PORT_NUM <= 4) { + msr.lo = CS5536_DEV_NUM << ((CS5536_GLINK_PORT_NUM - 1) * 8); + } else { + msr.hi = CS5536_DEV_NUM << ((CS5536_GLINK_PORT_NUM - 5) * 8); + } + wrmsr(0x5000201e, msr); +} + +static void cs5536_setup_idsel(void) +{ + /* write IDSEL to the write once register at address 0x0000 */ + outl(0x1 << (CS5536_DEV_NUM + 10), 0); +} + +static void cs5536_usb_swapsif(void) +{ + msr_t msr; + + msr = rdmsr(0x51600005); + //USB Serial short detect bit. + if (msr.hi & 0x10) { + /* We need to preserve bits 32,33,35 and not clear any BIST error, but clear the + * SERSHRT error bit */ + msr.hi &= 0xFFFFFFFB; + wrmsr(0x51600005, msr); + } +} + +static int cs5536_setup_iobase(void) +{ + msr_t msr; + + /* setup LBAR for SMBus controller */ + __builtin_wrmsr(0x5140000b, 0x00006000, 0x0000f001); + /* setup LBAR for GPIO */ + __builtin_wrmsr(0x5140000c, 0x00006100, 0x0000f001); + /* setup LBAR for MFGPT */ + __builtin_wrmsr(0x5140000d, 0x00006200, 0x0000f001); + /* setup LBAR for ACPI */ + __builtin_wrmsr(0x5140000e, 0x00009c00, 0x0000f001); + /* setup LBAR for PM Support */ + __builtin_wrmsr(0x5140000f, 0x00009d00, 0x0000f001); +} + +static void cs5536_setup_power_bottun(void) +{ + /* not implemented yet */ +#if 0 + pwrBtn_setup: + ; + ; Power Button Setup + ; + ;mov eax, 0C0020000h ; 4 seconds + lock + mov eax, 040020000h ; 4 seconds no lock + mov dx, PMLogic_BASE + 40h + out dx, eax + + ; setup GPIO24, it is the external signal for 5536 vsb_work_aux + ; which controls all voltage rails except Vstandby & Vmem. + ; We need to enable, OUT_AUX1 and OUTPUT_ENABLE in this order. + ; If GPIO24 is not enabled then soft-off will not work. + mov dx, GPIOH_OUT_AUX1_SELECT + mov eax, GPIOH_24_SET + out dx, eax + mov dx, GPIOH_OUTPUT_ENABLE + out dx, eax + +#endif +} + +static void cs5536_setup_gpio(void) +{ + uint32_t val; + + /* setup GPIO pins 14/15 for SDA/SCL */ + val = (1<<14 | 1<<15); + /* Output Enable */ + outl(0x3fffc000, 0x6100 + 0x04); + //outl(val, 0x6100 + 0x04); + /* Output AUX1 */ + outl(0x3fffc000, 0x6100 + 0x10); + //outl(val, 0x6100 + 0x10); + /* Input Enable */ + //outl(0x0f5af0a5, 0x6100 + 0x20); + outl(0x3fffc000, 0x6100 + 0x20); + //outl(val, 0x6100 + 0x20); + /* Input AUX1 */ + //outl(0x3ffbc004, 0x6100 + 0x34); + outl(0x3fffc000, 0x6100 + 0x34); + //outl(val, 0x6100 + 0x34); + + /* GX3: Enable GPIO pins for UART2 */ + outl(0x00000010, GPIOL_OUT_AUX1_SELECT); + outl(0x00000010, GPIOL_OUTPUT_ENABLE); + outl(0x00000008, GPIOL_IN_AUX1_SELECT); + outl(0x00000008, GPIOL_INPUT_ENABLE); + +#if 0 + /* changes proposed by Ollie; we will test this later. */ + /* setup GPIO pins 14/15 for SDA/SCL */ + val = GPIOL_15_SET | GPIOL_14_SET; + /* Output Enable */ + //outl(0x3fffc000, 0x6100 + 0x04); + outl(val, 0x6100 + 0x04); + /* Output AUX1 */ + //outl(0x3fffc000, 0x6100 + 0x10); + outl(val, 0x6100 + 0x10); + /* Input Enable */ + //outl(0x3fffc000, 0x6100 + 0x20); + outl(val, 0x6100 + 0x20); + /* Input AUX1 */ + //outl(0x3fffc000, 0x6100 + 0x34); + outl(val, 0x6100 + 0x34); +#endif +} + +static void cs5536_disable_internal_uart(void) +{ + /* not implemented yet */ +#if 0 + ; The UARTs default to enabled. + ; Disable and reset them and configure them later. (SIO init) + mov ecx, MDD_UART1_CONF + RDMSR + mov eax, 1h ; reset + WRMSR + mov eax, 0h ; disabled + WRMSR + + mov ecx, MDD_UART2_CONF + RDMSR + mov eax, 1h ; reset + WRMSR + mov eax, 0h ; disabled + WRMSR + +#endif +} + +static void cs5536_setup_cis_mode(void) +{ + msr_t msr; + + /* setup CPU interface serial to mode C on both sides */ + msr = __builtin_rdmsr(0x51000010); + msr.lo &= ~0x18; + msr.lo |= 0x10; + __builtin_wrmsr(0x51000010, msr.lo, msr.hi); + //Only do this if we are building for 5536 + __builtin_wrmsr(0x54002010, 0x00000002, 0x00000000); +} + +static void dummy(void) +{ +} + +/* see page 412 of the cs5536 companion book */ +static int cs5536_setup_onchipuart(void) +{ + unsigned long m; + + unsigned char n; + + /* + * 1. Eanble GPIO 8 to OUT_AUX1, 9 to IN_AUX1 + * GPIO LBAR + 0x04, LBAR + 0x10, LBAR + 0x20, LBAR + 34 + * 2. Enable UART IO space in MDD + * MSR 0x51400014 bit 18:16 + * 3. Enable UART controller + * MSR 0x5140003A bit 0, 1 + * 4. IRQ routing on IRQ Mapper + * MSR 0x51400021 bit [27:24] + */ + msr_t msr; + + /* Bit 1 = DEVEN (device enable) + * Bit 4 = EN_BANKS (allow access to the upper banks) + */ + + msr.lo = (1 << 4) | (1 << 1); + msr.hi = 0; + /* enable COM1 */ + //wrmsr(0x5140003a, msr); + /* GPIO8 - UART1_TX */ + /* Set: Output Enable (0x4) */ + m = inl(GPIOL_OUTPUT_ENABLE); + m |= GPIOL_8_SET; + m &= ~GPIOL_8_CLEAR; + //outl(m,GPIOL_OUTPUT_ENABLE); + /* Set: OUTAUX1 Select (0x10) */ + m = inl(GPIOL_OUT_AUX1_SELECT); + m |= GPIOL_8_SET; + m &= ~GPIOL_8_CLEAR; + //outl(m,GPIOL_OUT_AUX1_SELECT); + /* Set: Pull Up (0x18) */ + m = inl(GPIOL_PULLUP_ENABLE); + m |= GPIOL_8_SET; + m &= ~GPIOL_8_CLEAR; + /* GPIO9 - UART1_RX */ + /* Set: Pull Up (0x18) */ + m |= GPIOL_9_SET; + m &= ~GPIOL_9_CLEAR; + //outl(m,GPIOL_PULLUP_ENABLE); + /* Set: Input Enable (0x20) */ + m = inl(GPIOL_INPUT_ENABLE); + m |= GPIOL_9_SET; + m &= ~GPIOL_9_CLEAR; + //outl(m,GPIOL_INPUT_ENABLE); + /* Set: INAUX1 Select (0x34) */ + m = inl(GPIOL_IN_AUX1_SELECT); + m |= GPIOL_9_SET; + m &= ~GPIOL_9_CLEAR; + //outl(m,GPIOL_IN_AUX1_SELECT); + + msr = rdmsr(MDD_LEG_IO); + msr.lo |= 0x7 << 16; + //wrmsr(MDD_LEG_IO,msr); + + // GX3: my board has UART2 wired up ;) + + + // enable UART2 as COM1 + msr = rdmsr(MDD_LEG_IO); + msr.lo |= 0x700000; + wrmsr(MDD_LEG_IO, msr); + + // reset UART2 + msr = rdmsr(MDD_UART2_CONF); + msr.lo = 1; + wrmsr(MDD_UART2_CONF, msr); + + // clear reset UART2 + msr.lo = 0; + wrmsr(MDD_UART2_CONF, msr); + + // enable UART2 + msr.lo = 2; + wrmsr(MDD_UART2_CONF, msr); + + + // Set DLAB + n = 0x80; + outb(n, TTYS0_BASE + 3); + + // Baud rate divisor + n = 0x01; + outb(n, TTYS0_BASE); + + // Line mode (8N1) + n = 0x03; + outb(n, TTYS0_BASE + 3); + + // Clear DTR & RTS + n = 0x00; + outb(n, TTYS0_BASE + 4); + +} + +/* note: you can't do prints in here in most cases, + * and we don't want to hang on serial, so they are + * commented out + */ +static int cs5536_early_setup(void) +{ + msr_t msr; + + cs5536_setup_extmsr(); + +/* msr = rdmsr(GLCP_SYS_RSTPLL); + if (msr.lo & (0x3f << 26)) { + // PLL is already set and we are reboot from PLL reset + //print_debug("reboot from BIOS reset\n\r"); + return; + }*/ + + //print_debug("Setup idsel\r\n"); + cs5536_setup_idsel(); + //print_debug("Setup iobase\r\n"); + cs5536_usb_swapsif(); + cs5536_setup_iobase(); + //print_debug("Setup gpio\r\n"); + cs5536_setup_gpio(); + //print_debug("Setup cis_mode\r\n"); + cs5536_setup_cis_mode(); + //print_debug("Setup smbus\r\n"); + cs5536_enable_smbus(); + + // ide/flash bit goes to default on reset + // this value depends on boot straps + // lets set it to known enabled value + // later, cs5536_enable_ide_nand_flash changes it if needed. + //cs5536_enable_ide(); + + + dummy(); +} diff --git a/src/southbridge/amd/cs5536_lx/cs5536_early_smbus.c b/src/southbridge/amd/cs5536_lx/cs5536_early_smbus.c new file mode 100644 index 0000000000..0605d0cb82 --- /dev/null +++ b/src/southbridge/amd/cs5536_lx/cs5536_early_smbus.c @@ -0,0 +1,45 @@ +#include "cs5536_smbus.h" + +#define SMBUS_IO_BASE 0x6000 + +/* initialization for SMBus Controller */ +static int cs5536_enable_smbus(void) +{ + unsigned char val; + + /* reset SMBUS controller */ + outb(0, SMBUS_IO_BASE + SMB_CTRL2); + + /* Set SCL freq and enable SMB controller */ + val = inb(SMBUS_IO_BASE + SMB_CTRL2); + val |= ((0x20 << 1) | SMB_CTRL2_ENABLE); + outb(val, SMBUS_IO_BASE + SMB_CTRL2); + + /* Setup SMBus host controller address to 0xEF */ + val = inb(SMBUS_IO_BASE + SMB_ADD); + val |= (0xEF | SMB_ADD_SAEN); + outb(val, SMBUS_IO_BASE + SMB_ADD); +} + +static int smbus_read_byte(unsigned device, unsigned address) +{ + return do_smbus_read_byte(SMBUS_IO_BASE, device, address-1); +} + +#if 0 +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_write_byte(unsigned device, unsigned address, unsigned char val) +{ + return do_smbus_write_byte(SMBUS_IO_BASE, device, address, val); +} +#endif diff --git a/src/southbridge/amd/cs5536_lx/cs5536_ide.c b/src/southbridge/amd/cs5536_lx/cs5536_ide.c new file mode 100644 index 0000000000..284b5037d8 --- /dev/null +++ b/src/southbridge/amd/cs5536_lx/cs5536_ide.c @@ -0,0 +1,30 @@ +#include +#include +#include +#include +#include +#include "cs5536.h" + +static void ide_init(struct device *dev) +{ + printk_spew("cs5536_ide: %s\n", __FUNCTION__); +} + +static void ide_enable(struct device *dev) +{ + printk_spew("cs5536_ide: %s\n", __FUNCTION__); +} + +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, + .enable = ide_enable, +}; + +static struct pci_driver ide_driver __pci_driver = { + .ops = &ide_ops, + .vendor = PCI_VENDOR_ID_AMD, + .device = PCI_DEVICE_ID_AMD_CS5536_IDE, +}; diff --git a/src/southbridge/amd/cs5536_lx/cs5536_smbus.h b/src/southbridge/amd/cs5536_lx/cs5536_smbus.h new file mode 100644 index 0000000000..9cf55ba29c --- /dev/null +++ b/src/southbridge/amd/cs5536_lx/cs5536_smbus.h @@ -0,0 +1,180 @@ +//#include +#define SMBUS_ERROR -1 +#define SMBUS_WAIT_UNTIL_READY_TIMEOUT -2 +#define SMBUS_WAIT_UNTIL_DONE_TIMEOUT -3 + +#define SMB_SDA 0x00 +#define SMB_STS 0x01 +#define SMB_CTRL_STS 0x02 +#define SMB_CTRL1 0x03 +#define SMB_ADD 0x04 +#define SMB_CTRL2 0x05 +#define SMB_CTRL3 0x06 + +#define SMB_STS_SLVSTP (0x01 << 7) +#define SMB_STS_SDAST (0x01 << 6) +#define SMB_STS_BER (0x01 << 5) +#define SMB_STS_NEGACK (0x01 << 4) +#define SMB_STS_STASTR (0x01 << 3) +#define SMB_STS_NMATCH (0x01 << 2) +#define SMB_STS_MASTER (0x01 << 1) +#define SMB_STS_XMIT (0x01 << 0) + +#define SMB_CSTS_TGSCL (0x01 << 5) +#define SMB_CSTS_TSDA (0x01 << 4) +#define SMB_CSTS_GCMTCH (0x01 << 3) +#define SMB_CSTS_MATCH (0x01 << 2) +#define SMB_CSTS_BB (0x01 << 1) +#define SMB_CSTS_BUSY (0x01 << 0) + +#define SMB_CTRL1_STASTRE (0x01 << 7) +#define SMB_CTRL1_NMINTE (0x01 << 6) +#define SMB_CTRL1_GCMEN (0x01 << 5) +#define SMB_CTRL1_ACK (0x01 << 4) +#define SMB_CTRL1_RSVD (0x01 << 3) +#define SMB_CTRL1_INTEN (0x01 << 2) +#define SMB_CTRL1_STOP (0x01 << 1) +#define SMB_CTRL1_START (0x01 << 0) + +#define SMB_ADD_SAEN (0x01 << 7) + +#define SMB_CTRL2_ENABLE 0x01 + +#define SMBUS_TIMEOUT (100*1000*10) +#define SMBUS_STATUS_MASK 0xfbff + +#define SMBUS_IO_BASE 0x6000 + +static void smbus_delay(void) +{ + outb(0x80, 0x80); +} + +/* generate a smbus start condition */ +static int smbus_start_condition(unsigned smbus_io_base) +{ + unsigned char val; + unsigned long loops; + loops = SMBUS_TIMEOUT; + + /* issue a START condition */ + val = inb(smbus_io_base + SMB_CTRL1); + outb(val | SMB_CTRL1_START, smbus_io_base + SMB_CTRL1); + + /* check for bus conflict */ + val = inb(smbus_io_base + SMB_STS); + if ((val & SMB_STS_BER) != 0) + return SMBUS_ERROR; + + /* check for SDA status */ + do { + smbus_delay(); + val = inw(smbus_io_base + SMB_STS); + if ((val & SMB_STS_SDAST) != 0) { + break; + } + } while(--loops); + return loops?0:SMBUS_WAIT_UNTIL_READY_TIMEOUT; +} + +static int smbus_check_stop_condition(unsigned smbus_io_base) +{ + unsigned char val; + unsigned long loops; + loops = SMBUS_TIMEOUT; + /* check for SDA status */ + do { + smbus_delay(); + val = inw(smbus_io_base + SMB_CTRL1); + if ((val & SMB_CTRL1_STOP) == 0) { + break; + } + } while(--loops); + return loops?0:SMBUS_WAIT_UNTIL_READY_TIMEOUT; +} + +static int smbus_stop_condition(unsigned smbus_io_base) +{ + unsigned char val; + val = inb(smbus_io_base + SMB_CTRL1); + outb(SMB_CTRL1_STOP, smbus_io_base + SMB_CTRL1); +} + +static int smbus_send_slave_address(unsigned smbus_io_base, unsigned char device) +{ + unsigned char val; + unsigned long loops; + loops = SMBUS_TIMEOUT; + + /* send the slave address */ + outb(device, smbus_io_base + SMB_SDA); + + /* check for bus conflict and NACK */ + val = inb(smbus_io_base + SMB_STS); + if (((val & SMB_STS_BER) != 0) || + ((val & SMB_STS_NEGACK) != 0)) + return SMBUS_ERROR; + + /* check for SDA status */ + do { + smbus_delay(); + val = inw(smbus_io_base + SMB_STS); + if ((val & SMB_STS_SDAST) != 0) { + break; + } + } while(--loops); + return loops?0:SMBUS_WAIT_UNTIL_READY_TIMEOUT; +} + +static int smbus_send_command(unsigned smbus_io_base, unsigned char command) +{ + unsigned char val; + unsigned long loops; + loops = SMBUS_TIMEOUT; + + /* send the command */ + outb(command, smbus_io_base + SMB_SDA); + + /* check for bus conflict and NACK */ + val = inb(smbus_io_base + SMB_STS); + if (((val & SMB_STS_BER) != 0) || + ((val & SMB_STS_NEGACK) != 0)) + return SMBUS_ERROR; + + /* check for SDA status */ + do { + smbus_delay(); + val = inw(smbus_io_base + SMB_STS); + if ((val & SMB_STS_SDAST) != 0) { + break; + } + } while(--loops); + return loops?0:SMBUS_WAIT_UNTIL_READY_TIMEOUT; +} + +static unsigned char do_smbus_read_byte(unsigned smbus_io_base, unsigned char device, unsigned char address) +{ + unsigned char val, val1; + + smbus_check_stop_condition(smbus_io_base); + + smbus_start_condition(smbus_io_base); + + smbus_send_slave_address(smbus_io_base, device); + + smbus_send_command(smbus_io_base, address); + + smbus_start_condition(smbus_io_base); + + smbus_send_slave_address(smbus_io_base, device | 0x01); + + /* send NACK to slave */ + val = inb(smbus_io_base + SMB_CTRL1); + outb(val | SMB_CTRL1_ACK, smbus_io_base + SMB_CTRL1); + + val = inb(smbus_io_base + SMB_SDA); + + //smbus_stop_condition(smbus_io_base); + + return val; +} diff --git a/src/southbridge/amd/cs5536_lx/cs5536_smbus2.h b/src/southbridge/amd/cs5536_lx/cs5536_smbus2.h new file mode 100644 index 0000000000..3f5dad002e --- /dev/null +++ b/src/southbridge/amd/cs5536_lx/cs5536_smbus2.h @@ -0,0 +1,299 @@ +//#include +#define SMBUS_ERROR -1 +#define SMBUS_WAIT_UNTIL_READY_TIMEOUT -2 +#define SMBUS_WAIT_UNTIL_DONE_TIMEOUT -3 + +#define SMB_SDA 0x00 +#define SMB_STS 0x01 +#define SMB_CTRL_STS 0x02 +#define SMB_CTRL1 0x03 +#define SMB_ADD 0x04 +#define SMB_CTRL2 0x05 +#define SMB_CTRL3 0x06 + +#define SMB_STS_SLVSTP (0x01 << 7) +#define SMB_STS_SDAST (0x01 << 6) +#define SMB_STS_BER (0x01 << 5) +#define SMB_STS_NEGACK (0x01 << 4) +#define SMB_STS_STASTR (0x01 << 3) +#define SMB_STS_NMATCH (0x01 << 2) +#define SMB_STS_MASTER (0x01 << 1) +#define SMB_STS_XMIT (0x01 << 0) + +#define SMB_CSTS_TGSCL (0x01 << 5) +#define SMB_CSTS_TSDA (0x01 << 4) +#define SMB_CSTS_GCMTCH (0x01 << 3) +#define SMB_CSTS_MATCH (0x01 << 2) +#define SMB_CSTS_BB (0x01 << 1) +#define SMB_CSTS_BUSY (0x01 << 0) + +#define SMB_CTRL1_STASTRE (0x01 << 7) +#define SMB_CTRL1_NMINTE (0x01 << 6) +#define SMB_CTRL1_GCMEN (0x01 << 5) +#define SMB_CTRL1_ACK (0x01 << 4) +#define SMB_CTRL1_RSVD (0x01 << 3) +#define SMB_CTRL1_INTEN (0x01 << 2) +#define SMB_CTRL1_STOP (0x01 << 1) +#define SMB_CTRL1_START (0x01 << 0) + +#define SMB_ADD_SAEN (0x01 << 7) + +#define SMB_CTRL2_ENABLE 0x01 + +#define SMBUS_TIMEOUT (100*1000*10) +#define SMBUS_STATUS_MASK 0xfbff + +#define SMBUS_IO_BASE 0x6000 + +static void smbus_delay(void) +{ + outb(0x80, 0x80); +} + +static int smbus_wait(unsigned smbus_io_base) { + unsigned long loops = SMBUS_TIMEOUT; + unsigned char val; + + do { + smbus_delay(); + val = inb(smbus_io_base + SMB_STS); + if ((val & SMB_STS_SDAST) != 0) + break; + if (val & (SMB_STS_BER | SMB_STS_NEGACK)) { + printk_debug("SMBUS WAIT ERROR %x\n", val); + return SMBUS_ERROR; + } + } while(--loops); + + outb(0, smbus_io_base + SMB_STS); + return loops ? 0 : SMBUS_WAIT_UNTIL_READY_TIMEOUT; +} + +static int smbus_write(unsigned smbus_io_base, unsigned char byte) { + + outb(byte, smbus_io_base + SMB_SDA); + return smbus_wait(smbus_io_base); +} + +/* generate a smbus start condition */ +static int smbus_start_condition(unsigned smbus_io_base) +{ + unsigned char val; + + /* issue a START condition */ + val = inb(smbus_io_base + SMB_CTRL1); + outb(val | SMB_CTRL1_START, smbus_io_base + SMB_CTRL1); + + /* check for bus conflict */ + val = inb(smbus_io_base + SMB_STS); + if ((val & SMB_STS_BER) != 0) + return SMBUS_ERROR; + + return smbus_wait(smbus_io_base); +} + +static int smbus_check_stop_condition(unsigned smbus_io_base) +{ + unsigned char val; + unsigned long loops; + loops = SMBUS_TIMEOUT; + /* check for SDA status */ + do { + smbus_delay(); + val = inb(smbus_io_base + SMB_CTRL1); + if ((val & SMB_CTRL1_STOP) == 0) { + break; + } + } while(--loops); + return loops?0:SMBUS_WAIT_UNTIL_READY_TIMEOUT; + + /* Make sure everything is cleared and ready to go */ + + val = inb(smbus_io_base + SMB_CTRL1); + outb(val & ~(SMB_CTRL1_STASTRE | SMB_CTRL1_NMINTE), + smbus_io_base + SMB_CTRL1); + + outb(SMB_STS_BER | SMB_STS_NEGACK | SMB_STS_STASTR, + smbus_io_base + SMB_STS); + + val = inb(smbus_io_base + SMB_CTRL_STS); + outb(val | SMB_CSTS_BB, smbus_io_base + SMB_CTRL_STS); +} + +static int smbus_stop_condition(unsigned smbus_io_base) +{ + unsigned char val; + val = inb(smbus_io_base + SMB_CTRL1); + outb(SMB_CTRL1_STOP, smbus_io_base + SMB_CTRL1); + + return 0; +} + +static int smbus_ack(unsigned smbus_io_base, int state) +{ + unsigned char val = inb(smbus_io_base + SMB_CTRL1); + + if (state) + outb(val | SMB_CTRL1_ACK, smbus_io_base + SMB_CTRL1); + else + outb(val & ~SMB_CTRL1_ACK, smbus_io_base + SMB_CTRL1); + + return 0; +} + +static int smbus_send_slave_address(unsigned smbus_io_base, unsigned char device) +{ + unsigned char val; + + /* send the slave address */ + outb(device, smbus_io_base + SMB_SDA); + + /* check for bus conflict and NACK */ + val = inb(smbus_io_base + SMB_STS); + if (((val & SMB_STS_BER) != 0) || + ((val & SMB_STS_NEGACK) != 0)) { + printk_debug("SEND SLAVE ERROR (%x)\n", val); + return SMBUS_ERROR; + } + return smbus_wait(smbus_io_base); +} + +static int smbus_send_command(unsigned smbus_io_base, unsigned char command) +{ + unsigned char val; + + /* send the command */ + outb(command, smbus_io_base + SMB_SDA); + + /* check for bus conflict and NACK */ + val = inb(smbus_io_base + SMB_STS); + if (((val & SMB_STS_BER) != 0) || + ((val & SMB_STS_NEGACK) != 0)) + return SMBUS_ERROR; + + return smbus_wait(smbus_io_base); +} + +static void _doread(unsigned smbus_io_base, unsigned char device, + unsigned char address, unsigned char *data, int count) +{ + int ret; + int index = 0; + unsigned char val; + + if ((ret = smbus_check_stop_condition(smbus_io_base))) + goto err; + + index++; + + if ((ret = smbus_start_condition(smbus_io_base))) + goto err; + + index++; /* 2 */ + if ((ret = smbus_send_slave_address(smbus_io_base, device))) + goto err; + + index++; + if ((ret = smbus_send_command(smbus_io_base, address))) + goto err; + + index++; + if ((ret = smbus_start_condition(smbus_io_base))) + goto err; + + /* Clear the ack for multiple byte reads */ + smbus_ack(smbus_io_base, (count == 1) ? 1 : 0); + + index++; + if ((ret = smbus_send_slave_address(smbus_io_base, device | 0x01))) + goto err; + + while(count) { + /* Set the ACK if this is the next to last byte */ + smbus_ack(smbus_io_base, (count == 2) ? 1 : 0); + + /* Set the stop bit if this is the last byte to read */ + + if (count == 1) + smbus_stop_condition(smbus_io_base); + + val = inb(smbus_io_base + SMB_SDA); + *data++ = val; + + if (count > 1) { + int ret = smbus_wait(smbus_io_base); + if (ret) + return ret; + } + + count--; + } + + return; + + err: + printk_debug("SMBUS READ ERROR (%d): %d\n", index, ret); +} + +static unsigned char do_smbus_read_byte(unsigned smbus_io_base, + unsigned char device, + unsigned char address) +{ + unsigned char val = 0; + _doread(smbus_io_base, device, address, &val, sizeof(val)); + return val; +} + +static unsigned short do_smbus_read_word(unsigned smbus_io_base, + unsigned char device, unsigned char address) +{ + unsigned short val = 0; + _doread(smbus_io_base, device, address, (unsigned char *) &val, + sizeof(val)); + return val; +} + +static int _dowrite(unsigned smbus_io_base, unsigned char device, + unsigned char address, unsigned char *data, int count) { + + int ret; + + if ((ret = smbus_check_stop_condition(smbus_io_base))) + goto err; + + if ((ret = smbus_start_condition(smbus_io_base))) + goto err; + + if ((ret = smbus_send_slave_address(smbus_io_base, device))) + goto err; + + if ((ret = smbus_send_command(smbus_io_base, address))) + goto err; + + while(count) { + if ((ret = smbus_write(smbus_io_base, *data++))) + goto err; + count--; + } + + smbus_stop_condition(smbus_io_base); + return 0; + + err: + printk_debug("SMBUS WRITE ERROR: %d\n", ret); + return -1; +} + + +static int do_smbus_write_byte(unsigned smbus_io_base, unsigned char device, + unsigned char address, unsigned char data) +{ + return _dowrite(smbus_io_base, device, address, + (unsigned char *) &data, 1); +} + +static int do_smbus_write_word(unsigned smbus_io_base, unsigned char device, unsigned char address, + unsigned short data) +{ + return _dowrite(smbus_io_base, device ,address, (unsigned char *) &data, 2); +} -- cgit v1.2.3