diff options
Diffstat (limited to 'src/mainboard/arima/hdama/mainboard.c')
-rw-r--r-- | src/mainboard/arima/hdama/mainboard.c | 247 |
1 files changed, 246 insertions, 1 deletions
diff --git a/src/mainboard/arima/hdama/mainboard.c b/src/mainboard/arima/hdama/mainboard.c index 82041282f6..bbc6f53716 100644 --- a/src/mainboard/arima/hdama/mainboard.c +++ b/src/mainboard/arima/hdama/mainboard.c @@ -3,23 +3,268 @@ #include <device/pci.h> #include <device/pci_ids.h> #include <device/pci_ops.h> +#include <cpu/p6/msr.h> #include <arch/io.h> #include <device/chip.h> #include "../../../northbridge/amd/amdk8/northbridge.h" #include "chip.h" +#include "pc80/mc146818rtc.h" + + unsigned long initial_apicid[CONFIG_MAX_CPUS] = { 0, 1, }; +#define SMBGSTATUS 0xe0 +#define SMBGCTL 0xe2 +#define SMBHSTADDR 0xe4 +#define SMBHSTDAT 0xe6 +#define SMBHSTCMD 0xe8 +#define SMBHSTFIFO 0xe9 + +#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 short val; + smbus_delay(); + val = inw(smbus_io_base + SMBGSTATUS); + if ((val & 0x800) == 0) { + break; + } + if(loops == (SMBUS_TIMEOUT / 2)) { + outw(inw(smbus_io_base + SMBGSTATUS), + smbus_io_base + SMBGSTATUS); + } + } while(--loops); + return loops?0:-2; +} + +static int smbus_wait_until_done(unsigned smbus_io_base) +{ + unsigned long loops; + loops = SMBUS_TIMEOUT; + do { + unsigned short val; + smbus_delay(); + + val = inw(smbus_io_base + SMBGSTATUS); + if (((val & 0x8) == 0) | ((val & 0x437) != 0)) { + break; + } + } while(--loops); + return loops?0:-3; +} + +static int smbus_send_byte(unsigned smbus_io_base, unsigned device, unsigned value) +{ + unsigned char global_status_register; + + if (smbus_wait_until_ready(smbus_io_base) < 0) { + return -2; + } + + /* setup transaction */ + /* disable interrupts */ + outw(inw(smbus_io_base + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), smbus_io_base + SMBGCTL); + /* set the device I'm talking too */ + outw(((device & 0x7f) << 1) | 0, smbus_io_base + SMBHSTADDR); + /* set the command/address... */ + outb(0, smbus_io_base + SMBHSTCMD); + /* set up for a send byte */ + outw((inw(smbus_io_base + SMBGCTL) & ~7) | (0x1), smbus_io_base + SMBGCTL); + + /* clear any lingering errors, so the transaction will run */ + /* Do I need to write the bits to a 1 to clear an error? */ + outw(inw(smbus_io_base + SMBGSTATUS), smbus_io_base + SMBGSTATUS); + + /* set the data word...*/ + outw(value, smbus_io_base + SMBHSTDAT); + + /* start the command */ + outw((inw(smbus_io_base + SMBGCTL) | (1 << 3)), smbus_io_base + SMBGCTL); + + + /* poll for transaction completion */ + if (smbus_wait_until_done(smbus_io_base) < 0) { + return -3; + } + global_status_register = inw(smbus_io_base + SMBGSTATUS); + + if (global_status_register != (1 << 4)) { + return -1; + } + return 0; +} + +static int smbus_recv_byte(unsigned smbus_io_base, unsigned device) +{ + unsigned char global_status_register; + unsigned char byte; + + if (smbus_wait_until_ready(smbus_io_base) < 0) { + return -2; + } + + /* setup transaction */ + /* disable interrupts */ + outw(inw(smbus_io_base + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), smbus_io_base + SMBGCTL); + /* set the device I'm talking too */ + outw(((device & 0x7f) << 1) | 1, smbus_io_base + SMBHSTADDR); + /* set the command/address... */ + outb(0, smbus_io_base + SMBHSTCMD); + /* set up for a send byte */ + outw((inw(smbus_io_base + SMBGCTL) & ~7) | (0x1), smbus_io_base + SMBGCTL); + + /* clear any lingering errors, so the transaction will run */ + /* Do I need to write the bits to a 1 to clear an error? */ + outw(inw(smbus_io_base + SMBGSTATUS), smbus_io_base + SMBGSTATUS); + + /* set the data word...*/ + outw(0, smbus_io_base + SMBHSTDAT); + + /* start the command */ + outw((inw(smbus_io_base + SMBGCTL) | (1 << 3)), smbus_io_base + SMBGCTL); + + + /* poll for transaction completion */ + if (smbus_wait_until_done(smbus_io_base) < 0) { + return -3; + } + + global_status_register = inw(smbus_io_base + SMBGSTATUS); + + /* read results of transaction */ + byte = inw(smbus_io_base + SMBHSTDAT) & 0xff; + + if (global_status_register != (1 << 4)) { + return -1; + } + return byte; +} + +#if 0 +static int smbus_read_byte(unsigned smbus_io_base, unsigned device, unsigned address) +{ + unsigned char global_status_register; + unsigned char byte; + + if (smbus_wait_until_ready(smbus_io_base) < 0) { + return -2; + } + + /* setup transaction */ + /* disable interrupts */ + outw(inw(smbus_io_base + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), smbus_io_base + SMBGCTL); + /* set the device I'm talking too */ + outw(((device & 0x7f) << 1) | 1, smbus_io_base + SMBHSTADDR); + /* set the command/address... */ + outb(address & 0xFF, smbus_io_base + SMBHSTCMD); + /* set up for a byte data read */ + outw((inw(smbus_io_base + SMBGCTL) & ~7) | (0x2), smbus_io_base + SMBGCTL); + + /* clear any lingering errors, so the transaction will run */ + /* Do I need to write the bits to a 1 to clear an error? */ + outw(inw(smbus_io_base + SMBGSTATUS), smbus_io_base + SMBGSTATUS); + + /* clear the data word...*/ + outw(0, smbus_io_base + SMBHSTDAT); + + /* start the command */ + outw((inw(smbus_io_base + SMBGCTL) | (1 << 3)), smbus_io_base + SMBGCTL); + + + /* poll for transaction completion */ + if (smbus_wait_until_done(smbus_io_base) < 0) { + return -3; + } + + global_status_register = inw(smbus_io_base + SMBGSTATUS); + + /* read results of transaction */ + byte = inw(smbus_io_base + SMBHSTDAT) & 0xff; + + if (global_status_register != (1 << 4)) { + return -1; + } + return byte; +} + +static int smbus_write_byte(unsigned smbus_io_base, unsigned device, unsigned address, unsigned char val) +{ + if (smbus_wait_until_ready(smbus_io_base) < 0) { + return -2; + } + + /* setup transaction */ + /* disable interrupts */ + outw(inw(smbus_io_base + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), + smbus_io_base + SMBGCTL); + /* set the device I'm talking too */ + outw(((device & 0x7f) << 1) | 0, smbus_io_base + SMBHSTADDR); + outb(address & 0xFF, smbus_io_base + SMBHSTCMD); + /* set up for a byte data write */ /* FIXME */ + outw((inw(smbus_io_base + SMBGCTL) & ~7) | (0x1), smbus_io_base + SMBGCTL); + /* clear any lingering errors, so the transaction will run */ + /* Do I need to write the bits to a 1 to clear an error? */ + outw(inw(smbus_io_base + SMBGSTATUS), smbus_io_base + SMBGSTATUS); + + /* clear the data word...*/ + outw(val, smbus_io_base + SMBHSTDAT); + + /* start the command */ + outw((inw(smbus_io_base + SMBGCTL) | (1 << 3)), smbus_io_base + SMBGCTL); + + /* poll for transaction completion */ + if (smbus_wait_until_done(smbus_io_base) < 0) { + return -3; + } + return 0; +} +#endif + +#define SMBUS_MUX 0x70 +static void mainboard_init(device_t dev) +{ + /* Set the mux to see the temperature sensors */ + dev = dev_find_device(0x1022, 0x746b, 0); + if (dev) { + unsigned smbus_io_base; + unsigned device; + int result; + int mux_setting; + device = SMBUS_MUX; + mux_setting = 1; + smbus_io_base = pci_read_config32(dev, 0x58) & ~1;; + result = smbus_send_byte(smbus_io_base, device, mux_setting); + if ((result < 0) || + (smbus_recv_byte(smbus_io_base, device) != mux_setting)) { + printk_err("SMBUS mux would not set to %d\n", mux_setting); + } + + } + else { + printk_err("SMBUS_controller not found\n"); + } +} + static struct device_operations mainboard_operations = { .read_resources = root_dev_read_resources, .set_resources = root_dev_set_resources, .enable_resources = enable_childrens_resources, - .init = 0, + .init = mainboard_init, .scan_bus = amdk8_scan_root_bus, .enable = 0, }; |