diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/southbridge/amd/cs5535/cs5535_early_smbus.c | 57 | ||||
-rw-r--r-- | src/southbridge/amd/cs5535/cs5535_smbus.h | 145 |
2 files changed, 202 insertions, 0 deletions
diff --git a/src/southbridge/amd/cs5535/cs5535_early_smbus.c b/src/southbridge/amd/cs5535/cs5535_early_smbus.c new file mode 100644 index 0000000000..4a57dd7438 --- /dev/null +++ b/src/southbridge/amd/cs5535/cs5535_early_smbus.c @@ -0,0 +1,57 @@ +#include "cs5535_smbus.h" + +#define SMBUS_IO_BASE 0x6000 + +/* initialization for SMBus Controller */ +static int enable_smbus(void) +{ + unsigned char val; + + /* FixME: move to early_iobase.c */ + /* setup LBAR for SMBus controller */ + __builtin_wrmsr(0x5140000B, 0x00006000, 0x0000f001); + /* setup LBAR for GPIO at 0x6100 */ + __builtin_wrmsr(0x5140000C, 0x00006100, 0x0000f001); + + + /* setup GPIO pins for SDA/SCL */ + + /* 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); + + /* Set SCL freq and enable SMB controller */ + outb(0x00, SMBUS_IO_BASE + SMB_CTRL2); + val = inb(SMBUS_IO_BASE + SMB_CTRL2); + val |= (0x7F < 1) | SMB_CTRL2_ENABLE; + outb(val, SMBUS_IO_BASE + SMB_CTRL2); + + /* Is SDA pulled high ? */ + val = inb(SMBUS_IO_BASE + SMB_CTRL_STS); + if (val & SMB_CSTS_TSDA) + return SMBUS_ERROR; + +} + +#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_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); +} +#endif diff --git a/src/southbridge/amd/cs5535/cs5535_smbus.h b/src/southbridge/amd/cs5535/cs5535_smbus.h new file mode 100644 index 0000000000..3a2e4928bf --- /dev/null +++ b/src/southbridge/amd/cs5535/cs5535_smbus.h @@ -0,0 +1,145 @@ +//#include <device/smbus_def.h> +#define SMBUS_ERROR -1 +#define SMBUS_WAIT_UNTIL_READY_TIMEOUT -2 +#define SMBUS_WAIT_UNTIL_DONE_TIMEOUT -3 + +enum smb_native_registers { + SMB_SDA = 0x00, SMB_STS = 0x01, SMB_CTRL_STS = 0x02, + SMB_CTRL1 = 0x03, SMB_ADD = 0x04, SMB_CTRL2 = 0x05, + SMB_CTRL3 = 0x06 +}; + +enum smb_sts_bits { + SMB_STS_SLVSTP = (0x01 << 7), SMB_STS_SDAST = (0x01 << 6), + SMB_STS_BER = (0x01 << 5), SMB_STS_NEGACK = (0x01 << 4), + SMB_STS_STASTR = (0x01 << 3), SMB_STS_NMATCH = (0x01 << 2), + SMB_STS_MASTER = (0x01 << 1), SMB_STS_XMIT = (0x01 << 0) +}; + +enum smb_ctrl_sts_bits { + SMB_CSTS_TGSCL = (0x01 << 5), SMB_CSTS_TSDA = (0x01 << 4), + SMB_CSTS_GCMTCH = (0x01 << 3), SMB_CSTS_MATCH = (0x01 << 2), + SMB_CSTS_BB = (0x01 << 1), SMB_CSTS_BUSY = (0x01 << 0) +}; + +enum smb_ctrl1_bits { + SMB_CTRL1_STASTRE = (0x01 << 7), SMB_CTRL1_NMINTE = (0x01 << 6), + SMB_CTRL1_GCMEN = (0x01 << 5), SMB_CTRL1_ACK = (0x01 << 4), + SMB_CTRL1_RSVD = (0x01 << 3), SMB_CTRL1_INTEN = (0x01 << 2), + SMB_CTRL1_STOP = (0x01 << 1), SMB_CTRL1_START = (0x01 << 0) +}; + +enum smb_add_bits { + SMB_ADD_SAEN = (0x01 << 7) +}; + +enum smb_ctrl2_bits { + SMB_CTRL2_ENABLE = 0x01, +}; + +#define SMBUS_TIMEOUT (100*1000*10) +#define SMBUS_STATUS_MASK 0xfbff + +static inline 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_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 int do_smbus_read_byte(unsigned smbus_io_base, unsigned char device, unsigned char address) +{ + unsigned char val; + + 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); + + val = inb(smbus_io_base + SMB_CTRL1); + outb(val | SMB_CTRL1_ACK, smbus_io_base + SMB_CTRL1); + + return inb(smbus_io_base + SMB_SDA); +} |