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/i2c/pm_smbus.h" 23 #include "hw/i2c/smbus.h" 24 25 #define SMBHSTSTS 0x00 26 #define SMBHSTCNT 0x02 27 #define SMBHSTCMD 0x03 28 #define SMBHSTADD 0x04 29 #define SMBHSTDAT0 0x05 30 #define SMBHSTDAT1 0x06 31 #define SMBBLKDAT 0x07 32 #define SMBAUXCTL 0x0d 33 34 #define STS_HOST_BUSY (1 << 0) 35 #define STS_INTR (1 << 1) 36 #define STS_DEV_ERR (1 << 2) 37 #define STS_BUS_ERR (1 << 3) 38 #define STS_FAILED (1 << 4) 39 #define STS_SMBALERT (1 << 5) 40 #define STS_INUSE_STS (1 << 6) 41 #define STS_BYTE_DONE (1 << 7) 42 /* Signs of successfully transaction end : 43 * ByteDoneStatus = 1 (STS_BYTE_DONE) and INTR = 1 (STS_INTR ) 44 */ 45 46 #define CTL_INTREN (1 << 0) 47 #define CTL_KILL (1 << 1) 48 #define CTL_LAST_BYTE (1 << 5) 49 #define CTL_START (1 << 6) 50 #define CTL_PEC_EN (1 << 7) 51 #define CTL_RETURN_MASK 0x1f 52 53 #define PROT_QUICK 0 54 #define PROT_BYTE 1 55 #define PROT_BYTE_DATA 2 56 #define PROT_WORD_DATA 3 57 #define PROT_PROC_CALL 4 58 #define PROT_BLOCK_DATA 5 59 #define PROT_I2C_BLOCK_READ 6 60 61 #define AUX_PEC (1 << 0) 62 #define AUX_BLK (1 << 1) 63 #define AUX_MASK 0x3 64 65 /*#define DEBUG*/ 66 67 #ifdef DEBUG 68 # define SMBUS_DPRINTF(format, ...) printf(format, ## __VA_ARGS__) 69 #else 70 # define SMBUS_DPRINTF(format, ...) do { } while (0) 71 #endif 72 73 74 static void smb_transaction(PMSMBus *s) 75 { 76 uint8_t prot = (s->smb_ctl >> 2) & 0x07; 77 uint8_t read = s->smb_addr & 0x01; 78 uint8_t cmd = s->smb_cmd; 79 uint8_t addr = s->smb_addr >> 1; 80 I2CBus *bus = s->smbus; 81 int ret; 82 83 assert(s->smb_stat & STS_HOST_BUSY); 84 s->smb_stat &= ~STS_HOST_BUSY; 85 86 SMBUS_DPRINTF("SMBus trans addr=0x%02x prot=0x%02x\n", addr, prot); 87 /* Transaction isn't exec if STS_DEV_ERR bit set */ 88 if ((s->smb_stat & STS_DEV_ERR) != 0) { 89 goto error; 90 } 91 92 switch(prot) { 93 case PROT_QUICK: 94 ret = smbus_quick_command(bus, addr, read); 95 goto done; 96 case PROT_BYTE: 97 if (read) { 98 ret = smbus_receive_byte(bus, addr); 99 goto data8; 100 } else { 101 ret = smbus_send_byte(bus, addr, cmd); 102 goto done; 103 } 104 case PROT_BYTE_DATA: 105 if (read) { 106 ret = smbus_read_byte(bus, addr, cmd); 107 goto data8; 108 } else { 109 ret = smbus_write_byte(bus, addr, cmd, s->smb_data0); 110 goto done; 111 } 112 break; 113 case PROT_WORD_DATA: 114 if (read) { 115 ret = smbus_read_word(bus, addr, cmd); 116 goto data16; 117 } else { 118 ret = smbus_write_word(bus, addr, cmd, 119 (s->smb_data1 << 8) | s->smb_data0); 120 goto done; 121 } 122 break; 123 case PROT_I2C_BLOCK_READ: 124 if (read) { 125 int xfersize = s->smb_data0; 126 if (xfersize > sizeof(s->smb_data)) { 127 xfersize = sizeof(s->smb_data); 128 } 129 ret = smbus_read_block(bus, addr, s->smb_data1, s->smb_data, 130 xfersize, false, true); 131 goto data8; 132 } else { 133 /* The manual says the behavior is undefined, just set DEV_ERR. */ 134 goto error; 135 } 136 break; 137 case PROT_BLOCK_DATA: 138 if (read) { 139 ret = smbus_read_block(bus, addr, cmd, s->smb_data, 140 sizeof(s->smb_data), !s->i2c_enable, 141 !s->i2c_enable); 142 if (ret < 0) { 143 goto error; 144 } 145 s->smb_index = 0; 146 s->op_done = false; 147 if (s->smb_auxctl & AUX_BLK) { 148 s->smb_stat |= STS_INTR; 149 } else { 150 s->smb_blkdata = s->smb_data[0]; 151 s->smb_stat |= STS_HOST_BUSY | STS_BYTE_DONE; 152 } 153 s->smb_data0 = ret; 154 goto out; 155 } else { 156 if (s->smb_auxctl & AUX_BLK) { 157 if (s->smb_index != s->smb_data0) { 158 s->smb_index = 0; 159 goto error; 160 } 161 /* Data is already all written to the queue, just do 162 the operation. */ 163 s->smb_index = 0; 164 ret = smbus_write_block(bus, addr, cmd, s->smb_data, 165 s->smb_data0, !s->i2c_enable); 166 if (ret < 0) { 167 goto error; 168 } 169 s->op_done = true; 170 s->smb_stat |= STS_INTR; 171 s->smb_stat &= ~STS_HOST_BUSY; 172 } else { 173 s->op_done = false; 174 s->smb_stat |= STS_HOST_BUSY | STS_BYTE_DONE; 175 s->smb_data[0] = s->smb_blkdata; 176 s->smb_index = 0; 177 ret = 0; 178 } 179 goto out; 180 } 181 break; 182 default: 183 goto error; 184 } 185 abort(); 186 187 data16: 188 if (ret < 0) { 189 goto error; 190 } 191 s->smb_data1 = ret >> 8; 192 data8: 193 if (ret < 0) { 194 goto error; 195 } 196 s->smb_data0 = ret; 197 done: 198 if (ret < 0) { 199 goto error; 200 } 201 s->smb_stat |= STS_INTR; 202 out: 203 return; 204 205 error: 206 s->smb_stat |= STS_DEV_ERR; 207 return; 208 } 209 210 static void smb_transaction_start(PMSMBus *s) 211 { 212 /* Do not execute immediately the command ; it will be 213 * executed when guest will read SMB_STAT register */ 214 s->smb_stat |= STS_HOST_BUSY; 215 } 216 217 static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val, 218 unsigned width) 219 { 220 PMSMBus *s = opaque; 221 222 SMBUS_DPRINTF("SMB writeb port=0x%04" HWADDR_PRIx 223 " val=0x%02" PRIx64 "\n", addr, val); 224 switch(addr) { 225 case SMBHSTSTS: 226 s->smb_stat &= ~(val & ~STS_HOST_BUSY); 227 if (!s->op_done && !(s->smb_auxctl & AUX_BLK)) { 228 uint8_t read = s->smb_addr & 0x01; 229 230 s->smb_index++; 231 if (!read && s->smb_index == s->smb_data0) { 232 uint8_t prot = (s->smb_ctl >> 2) & 0x07; 233 uint8_t cmd = s->smb_cmd; 234 uint8_t addr = s->smb_addr >> 1; 235 int ret; 236 237 if (prot == PROT_I2C_BLOCK_READ) { 238 s->smb_stat |= STS_DEV_ERR; 239 goto out; 240 } 241 242 ret = smbus_write_block(s->smbus, addr, cmd, s->smb_data, 243 s->smb_data0, !s->i2c_enable); 244 if (ret < 0) { 245 s->smb_stat |= STS_DEV_ERR; 246 goto out; 247 } 248 s->op_done = true; 249 s->smb_stat |= STS_INTR; 250 s->smb_stat &= ~STS_HOST_BUSY; 251 } else if (!read) { 252 s->smb_data[s->smb_index] = s->smb_blkdata; 253 s->smb_stat |= STS_BYTE_DONE; 254 } else if (s->smb_ctl & CTL_LAST_BYTE) { 255 s->op_done = true; 256 s->smb_blkdata = s->smb_data[s->smb_index]; 257 s->smb_index = 0; 258 s->smb_stat |= STS_INTR; 259 s->smb_stat &= ~STS_HOST_BUSY; 260 } else { 261 s->smb_blkdata = s->smb_data[s->smb_index]; 262 s->smb_stat |= STS_BYTE_DONE; 263 } 264 } 265 break; 266 case SMBHSTCNT: 267 s->smb_ctl = val & ~CTL_START; /* CTL_START always reads 0 */ 268 if (val & CTL_START) { 269 if (!s->op_done) { 270 s->smb_index = 0; 271 s->op_done = true; 272 } 273 smb_transaction_start(s); 274 } 275 if (s->smb_ctl & CTL_KILL) { 276 s->op_done = true; 277 s->smb_index = 0; 278 s->smb_stat |= STS_FAILED; 279 s->smb_stat &= ~STS_HOST_BUSY; 280 } 281 break; 282 case SMBHSTCMD: 283 s->smb_cmd = val; 284 break; 285 case SMBHSTADD: 286 s->smb_addr = val; 287 break; 288 case SMBHSTDAT0: 289 s->smb_data0 = val; 290 break; 291 case SMBHSTDAT1: 292 s->smb_data1 = val; 293 break; 294 case SMBBLKDAT: 295 if (s->smb_index >= PM_SMBUS_MAX_MSG_SIZE) { 296 s->smb_index = 0; 297 } 298 if (s->smb_auxctl & AUX_BLK) { 299 s->smb_data[s->smb_index++] = val; 300 } else { 301 s->smb_blkdata = val; 302 } 303 break; 304 case SMBAUXCTL: 305 s->smb_auxctl = val & AUX_MASK; 306 break; 307 default: 308 break; 309 } 310 311 out: 312 return; 313 } 314 315 static uint64_t smb_ioport_readb(void *opaque, hwaddr addr, unsigned width) 316 { 317 PMSMBus *s = opaque; 318 uint32_t val; 319 320 switch(addr) { 321 case SMBHSTSTS: 322 val = s->smb_stat; 323 if (s->smb_stat & STS_HOST_BUSY) { 324 /* execute command now */ 325 smb_transaction(s); 326 } 327 break; 328 case SMBHSTCNT: 329 val = s->smb_ctl & CTL_RETURN_MASK; 330 break; 331 case SMBHSTCMD: 332 val = s->smb_cmd; 333 break; 334 case SMBHSTADD: 335 val = s->smb_addr; 336 break; 337 case SMBHSTDAT0: 338 val = s->smb_data0; 339 break; 340 case SMBHSTDAT1: 341 val = s->smb_data1; 342 break; 343 case SMBBLKDAT: 344 if (s->smb_index >= PM_SMBUS_MAX_MSG_SIZE) { 345 s->smb_index = 0; 346 } 347 if (s->smb_auxctl & AUX_BLK) { 348 val = s->smb_data[s->smb_index++]; 349 if (!s->op_done && s->smb_index == s->smb_data0) { 350 s->op_done = true; 351 s->smb_index = 0; 352 s->smb_stat &= ~STS_HOST_BUSY; 353 } 354 } else { 355 val = s->smb_blkdata; 356 } 357 break; 358 case SMBAUXCTL: 359 val = s->smb_auxctl; 360 break; 361 default: 362 val = 0; 363 break; 364 } 365 SMBUS_DPRINTF("SMB readb port=0x%04" HWADDR_PRIx " val=0x%02x\n", 366 addr, val); 367 368 return val; 369 } 370 371 static void pm_smbus_reset(PMSMBus *s) 372 { 373 s->op_done = true; 374 s->smb_index = 0; 375 s->smb_stat = 0; 376 } 377 378 static const MemoryRegionOps pm_smbus_ops = { 379 .read = smb_ioport_readb, 380 .write = smb_ioport_writeb, 381 .valid.min_access_size = 1, 382 .valid.max_access_size = 1, 383 .endianness = DEVICE_LITTLE_ENDIAN, 384 }; 385 386 void pm_smbus_init(DeviceState *parent, PMSMBus *smb) 387 { 388 smb->op_done = true; 389 smb->reset = pm_smbus_reset; 390 smb->smbus = i2c_init_bus(parent, "i2c"); 391 memory_region_init_io(&smb->io, OBJECT(parent), &pm_smbus_ops, smb, 392 "pm-smbus", 64); 393 } 394