1 /* 2 * PC SMBus implementation 3 * splitted from acpi.c 4 * 5 * Copyright (c) 2006 Fabrice Bellard 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License version 2 as published by the Free Software Foundation. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, see 18 * <http://www.gnu.org/licenses/>. 19 */ 20 #include "qemu/osdep.h" 21 #include "hw/hw.h" 22 #include "hw/i386/pc.h" 23 #include "hw/i2c/pm_smbus.h" 24 #include "hw/i2c/smbus.h" 25 26 /* no save/load? */ 27 28 #define SMBHSTSTS 0x00 29 #define SMBHSTCNT 0x02 30 #define SMBHSTCMD 0x03 31 #define SMBHSTADD 0x04 32 #define SMBHSTDAT0 0x05 33 #define SMBHSTDAT1 0x06 34 #define SMBBLKDAT 0x07 35 36 #define STS_HOST_BUSY (1) 37 #define STS_INTR (1<<1) 38 #define STS_DEV_ERR (1<<2) 39 #define STS_BUS_ERR (1<<3) 40 #define STS_FAILED (1<<4) 41 #define STS_SMBALERT (1<<5) 42 #define STS_INUSE_STS (1<<6) 43 #define STS_BYTE_DONE (1<<7) 44 /* Signs of successfully transaction end : 45 * ByteDoneStatus = 1 (STS_BYTE_DONE) and INTR = 1 (STS_INTR ) 46 */ 47 48 //#define DEBUG 49 50 #ifdef DEBUG 51 # define SMBUS_DPRINTF(format, ...) printf(format, ## __VA_ARGS__) 52 #else 53 # define SMBUS_DPRINTF(format, ...) do { } while (0) 54 #endif 55 56 57 static void smb_transaction(PMSMBus *s) 58 { 59 uint8_t prot = (s->smb_ctl >> 2) & 0x07; 60 uint8_t read = s->smb_addr & 0x01; 61 uint8_t cmd = s->smb_cmd; 62 uint8_t addr = s->smb_addr >> 1; 63 I2CBus *bus = s->smbus; 64 int ret; 65 66 assert(s->smb_stat & STS_HOST_BUSY); 67 s->smb_stat &= ~STS_HOST_BUSY; 68 69 SMBUS_DPRINTF("SMBus trans addr=0x%02x prot=0x%02x\n", addr, prot); 70 /* Transaction isn't exec if STS_DEV_ERR bit set */ 71 if ((s->smb_stat & STS_DEV_ERR) != 0) { 72 goto error; 73 } 74 switch(prot) { 75 case 0x0: 76 ret = smbus_quick_command(bus, addr, read); 77 goto done; 78 case 0x1: 79 if (read) { 80 ret = smbus_receive_byte(bus, addr); 81 goto data8; 82 } else { 83 ret = smbus_send_byte(bus, addr, cmd); 84 goto done; 85 } 86 case 0x2: 87 if (read) { 88 ret = smbus_read_byte(bus, addr, cmd); 89 goto data8; 90 } else { 91 ret = smbus_write_byte(bus, addr, cmd, s->smb_data0); 92 goto done; 93 } 94 break; 95 case 0x3: 96 if (read) { 97 ret = smbus_read_word(bus, addr, cmd); 98 goto data16; 99 } else { 100 ret = smbus_write_word(bus, addr, cmd, (s->smb_data1 << 8) | s->smb_data0); 101 goto done; 102 } 103 break; 104 case 0x5: 105 if (read) { 106 ret = smbus_read_block(bus, addr, cmd, s->smb_data); 107 goto data8; 108 } else { 109 ret = smbus_write_block(bus, addr, cmd, s->smb_data, s->smb_data0); 110 goto done; 111 } 112 break; 113 default: 114 goto error; 115 } 116 abort(); 117 118 data16: 119 if (ret < 0) { 120 goto error; 121 } 122 s->smb_data1 = ret >> 8; 123 data8: 124 if (ret < 0) { 125 goto error; 126 } 127 s->smb_data0 = ret; 128 done: 129 if (ret < 0) { 130 goto error; 131 } 132 s->smb_stat |= STS_BYTE_DONE | STS_INTR; 133 return; 134 135 error: 136 s->smb_stat |= STS_DEV_ERR; 137 return; 138 139 } 140 141 static void smb_transaction_start(PMSMBus *s) 142 { 143 /* Do not execute immediately the command ; it will be 144 * executed when guest will read SMB_STAT register */ 145 s->smb_stat |= STS_HOST_BUSY; 146 } 147 148 static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val, 149 unsigned width) 150 { 151 PMSMBus *s = opaque; 152 153 SMBUS_DPRINTF("SMB writeb port=0x%04" HWADDR_PRIx 154 " val=0x%02" PRIx64 "\n", addr, val); 155 switch(addr) { 156 case SMBHSTSTS: 157 s->smb_stat = (~(val & 0xff)) & s->smb_stat; 158 s->smb_index = 0; 159 break; 160 case SMBHSTCNT: 161 s->smb_ctl = val; 162 if (val & 0x40) 163 smb_transaction_start(s); 164 break; 165 case SMBHSTCMD: 166 s->smb_cmd = val; 167 break; 168 case SMBHSTADD: 169 s->smb_addr = val; 170 break; 171 case SMBHSTDAT0: 172 s->smb_data0 = val; 173 break; 174 case SMBHSTDAT1: 175 s->smb_data1 = val; 176 break; 177 case SMBBLKDAT: 178 s->smb_data[s->smb_index++] = val; 179 if (s->smb_index > 31) 180 s->smb_index = 0; 181 break; 182 default: 183 break; 184 } 185 } 186 187 static uint64_t smb_ioport_readb(void *opaque, hwaddr addr, unsigned width) 188 { 189 PMSMBus *s = opaque; 190 uint32_t val; 191 192 switch(addr) { 193 case SMBHSTSTS: 194 val = s->smb_stat; 195 if (s->smb_stat & STS_HOST_BUSY) { 196 /* execute command now */ 197 smb_transaction(s); 198 } 199 break; 200 case SMBHSTCNT: 201 s->smb_index = 0; 202 val = s->smb_ctl & 0x1f; 203 break; 204 case SMBHSTCMD: 205 val = s->smb_cmd; 206 break; 207 case SMBHSTADD: 208 val = s->smb_addr; 209 break; 210 case SMBHSTDAT0: 211 val = s->smb_data0; 212 break; 213 case SMBHSTDAT1: 214 val = s->smb_data1; 215 break; 216 case SMBBLKDAT: 217 val = s->smb_data[s->smb_index++]; 218 if (s->smb_index > 31) 219 s->smb_index = 0; 220 break; 221 default: 222 val = 0; 223 break; 224 } 225 SMBUS_DPRINTF("SMB readb port=0x%04" HWADDR_PRIx " val=0x%02x\n", addr, val); 226 return val; 227 } 228 229 static const MemoryRegionOps pm_smbus_ops = { 230 .read = smb_ioport_readb, 231 .write = smb_ioport_writeb, 232 .valid.min_access_size = 1, 233 .valid.max_access_size = 1, 234 .endianness = DEVICE_LITTLE_ENDIAN, 235 }; 236 237 void pm_smbus_init(DeviceState *parent, PMSMBus *smb) 238 { 239 smb->smbus = i2c_init_bus(parent, "i2c"); 240 memory_region_init_io(&smb->io, OBJECT(parent), &pm_smbus_ops, smb, 241 "pm-smbus", 64); 242 } 243