Richard Smith | cb8eab4 | 2006-07-24 04:25:47 +0000 | [diff] [blame] | 1 | #include <device/smbus_def.h> |
Uwe Hermann | 4028ce7 | 2010-12-07 19:16:07 +0000 | [diff] [blame] | 2 | #include "i82371eb.h" |
Richard Smith | cb8eab4 | 2006-07-24 04:25:47 +0000 | [diff] [blame] | 3 | |
Richard Smith | d7088c4 | 2006-07-30 00:23:20 +0000 | [diff] [blame] | 4 | #define SMBHST_STATUS 0x0 |
| 5 | #define SMBHST_CTL 0x2 |
| 6 | #define SMBHST_CMD 0x3 |
| 7 | #define SMBHST_ADDR 0x4 |
| 8 | #define SMBHST_DAT 0x5 |
Richard Smith | cb8eab4 | 2006-07-24 04:25:47 +0000 | [diff] [blame] | 9 | |
| 10 | #define SMBUS_TIMEOUT (100*1000*10) |
| 11 | #define SMBUS_STATUS_MASK 0x1e |
Richard Smith | d7088c4 | 2006-07-30 00:23:20 +0000 | [diff] [blame] | 12 | #define SMBUS_ERROR_FLAG (1<<2) |
Richard Smith | cb8eab4 | 2006-07-24 04:25:47 +0000 | [diff] [blame] | 13 | |
Uwe Hermann | 115c5b9 | 2010-10-09 17:00:18 +0000 | [diff] [blame] | 14 | int do_smbus_read_byte(unsigned smbus_io_base, unsigned device, unsigned address); |
| 15 | |
Richard Smith | cb8eab4 | 2006-07-24 04:25:47 +0000 | [diff] [blame] | 16 | static inline void smbus_delay(void) |
| 17 | { |
| 18 | outb(0x80, 0x80); |
| 19 | outb(0x80, 0x80); |
| 20 | outb(0x80, 0x80); |
| 21 | outb(0x80, 0x80); |
| 22 | outb(0x80, 0x80); |
| 23 | outb(0x80, 0x80); |
| 24 | } |
| 25 | |
| 26 | static int smbus_wait_until_ready(unsigned smbus_io_base) |
| 27 | { |
| 28 | unsigned long loops; |
| 29 | loops = SMBUS_TIMEOUT; |
| 30 | do { |
| 31 | unsigned char val; |
| 32 | smbus_delay(); |
Richard Smith | d7088c4 | 2006-07-30 00:23:20 +0000 | [diff] [blame] | 33 | val = inb(smbus_io_base + SMBHST_STATUS); |
Richard Smith | cb8eab4 | 2006-07-24 04:25:47 +0000 | [diff] [blame] | 34 | if ((val & 0x1) == 0) { |
| 35 | break; |
| 36 | } |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 37 | #if 0 |
Richard Smith | cb8eab4 | 2006-07-24 04:25:47 +0000 | [diff] [blame] | 38 | if(loops == (SMBUS_TIMEOUT / 2)) { |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 39 | outw(inw(smbus_io_base + SMBHST_STATUS), |
Richard Smith | d7088c4 | 2006-07-30 00:23:20 +0000 | [diff] [blame] | 40 | smbus_io_base + SMBHST_STATUS); |
Richard Smith | cb8eab4 | 2006-07-24 04:25:47 +0000 | [diff] [blame] | 41 | } |
Richard Smith | d7088c4 | 2006-07-30 00:23:20 +0000 | [diff] [blame] | 42 | #endif |
Richard Smith | cb8eab4 | 2006-07-24 04:25:47 +0000 | [diff] [blame] | 43 | } while(--loops); |
| 44 | return loops?0:SMBUS_WAIT_UNTIL_READY_TIMEOUT; |
| 45 | } |
| 46 | |
| 47 | static int smbus_wait_until_done(unsigned smbus_io_base) |
| 48 | { |
| 49 | unsigned long loops; |
| 50 | loops = SMBUS_TIMEOUT; |
| 51 | do { |
| 52 | unsigned short val; |
| 53 | smbus_delay(); |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 54 | |
Richard Smith | d7088c4 | 2006-07-30 00:23:20 +0000 | [diff] [blame] | 55 | val = inb(smbus_io_base + SMBHST_STATUS); |
Richard Smith | cb8eab4 | 2006-07-24 04:25:47 +0000 | [diff] [blame] | 56 | // Make sure the command is done |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 57 | if ((val & 0x1) != 0) { |
Richard Smith | cb8eab4 | 2006-07-24 04:25:47 +0000 | [diff] [blame] | 58 | continue; |
| 59 | } |
| 60 | // Don't break out until one of the interrupt |
| 61 | // flags is set. |
| 62 | if (val & 0xfe) { |
| 63 | break; |
| 64 | } |
| 65 | } while(--loops); |
| 66 | return loops?0:SMBUS_WAIT_UNTIL_DONE_TIMEOUT; |
| 67 | } |
| 68 | |
Uwe Hermann | 115c5b9 | 2010-10-09 17:00:18 +0000 | [diff] [blame] | 69 | int do_smbus_read_byte(unsigned smbus_io_base, unsigned device, unsigned address) |
Richard Smith | cb8eab4 | 2006-07-24 04:25:47 +0000 | [diff] [blame] | 70 | { |
Richard Smith | d7088c4 | 2006-07-30 00:23:20 +0000 | [diff] [blame] | 71 | unsigned status_register; |
Richard Smith | cb8eab4 | 2006-07-24 04:25:47 +0000 | [diff] [blame] | 72 | unsigned byte; |
| 73 | |
| 74 | if (smbus_wait_until_ready(smbus_io_base) < 0) { |
| 75 | return SMBUS_WAIT_UNTIL_READY_TIMEOUT; |
| 76 | } |
Stefan Reinauer | 14e2277 | 2010-04-27 06:56:47 +0000 | [diff] [blame] | 77 | |
Richard Smith | cb8eab4 | 2006-07-24 04:25:47 +0000 | [diff] [blame] | 78 | /* setup transaction */ |
| 79 | |
| 80 | /* clear any lingering errors, so the transaction will run */ |
Richard Smith | d7088c4 | 2006-07-30 00:23:20 +0000 | [diff] [blame] | 81 | outb(0x1e, smbus_io_base + SMBHST_STATUS); |
Richard Smith | cb8eab4 | 2006-07-24 04:25:47 +0000 | [diff] [blame] | 82 | |
| 83 | /* set the device I'm talking too */ |
Richard Smith | d7088c4 | 2006-07-30 00:23:20 +0000 | [diff] [blame] | 84 | outb(((device & 0x7f) << 1) | 1, smbus_io_base + SMBHST_ADDR); |
| 85 | |
Richard Smith | cb8eab4 | 2006-07-24 04:25:47 +0000 | [diff] [blame] | 86 | /* set the command/address... */ |
Richard Smith | d7088c4 | 2006-07-30 00:23:20 +0000 | [diff] [blame] | 87 | outb(address & 0xff, smbus_io_base + SMBHST_CMD); |
Richard Smith | cb8eab4 | 2006-07-24 04:25:47 +0000 | [diff] [blame] | 88 | |
| 89 | /* clear the data word...*/ |
Richard Smith | d7088c4 | 2006-07-30 00:23:20 +0000 | [diff] [blame] | 90 | outb(0, smbus_io_base + SMBHST_DAT); |
Richard Smith | cb8eab4 | 2006-07-24 04:25:47 +0000 | [diff] [blame] | 91 | |
| 92 | /* start a byte read with interrupts disabled */ |
Richard Smith | d7088c4 | 2006-07-30 00:23:20 +0000 | [diff] [blame] | 93 | outb( (0x02 << 2)|(1<<6), smbus_io_base + SMBHST_CTL); |
Richard Smith | cb8eab4 | 2006-07-24 04:25:47 +0000 | [diff] [blame] | 94 | |
| 95 | /* poll for transaction completion */ |
| 96 | if (smbus_wait_until_done(smbus_io_base) < 0) { |
| 97 | return SMBUS_WAIT_UNTIL_DONE_TIMEOUT; |
| 98 | } |
| 99 | |
Richard Smith | d7088c4 | 2006-07-30 00:23:20 +0000 | [diff] [blame] | 100 | status_register = inw(smbus_io_base + SMBHST_STATUS); |
Richard Smith | cb8eab4 | 2006-07-24 04:25:47 +0000 | [diff] [blame] | 101 | |
| 102 | /* read results of transaction */ |
Richard Smith | d7088c4 | 2006-07-30 00:23:20 +0000 | [diff] [blame] | 103 | byte = inw(smbus_io_base + SMBHST_DAT) & 0xff; |
Richard Smith | cb8eab4 | 2006-07-24 04:25:47 +0000 | [diff] [blame] | 104 | |
Richard Smith | d7088c4 | 2006-07-30 00:23:20 +0000 | [diff] [blame] | 105 | if (status_register & 0x04) { |
| 106 | #if 0 |
Stefan Reinauer | 5ab52dd | 2015-01-05 13:01:01 -0800 | [diff] [blame] | 107 | printk(BIOS_DEBUG, "Read fail %04x\n", status_register); |
Richard Smith | d7088c4 | 2006-07-30 00:23:20 +0000 | [diff] [blame] | 108 | #endif |
Richard Smith | cb8eab4 | 2006-07-24 04:25:47 +0000 | [diff] [blame] | 109 | return SMBUS_ERROR; |
| 110 | } |
| 111 | return byte; |
| 112 | } |