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 bool 218 smb_irq_value(PMSMBus *s) 219 { 220 return ((s->smb_stat & ~STS_HOST_BUSY) != 0) && (s->smb_ctl & CTL_INTREN); 221 } 222 223 static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val, 224 unsigned width) 225 { 226 PMSMBus *s = opaque; 227 228 SMBUS_DPRINTF("SMB writeb port=0x%04" HWADDR_PRIx 229 " val=0x%02" PRIx64 "\n", addr, val); 230 switch(addr) { 231 case SMBHSTSTS: 232 s->smb_stat &= ~(val & ~STS_HOST_BUSY); 233 if (!s->op_done && !(s->smb_auxctl & AUX_BLK)) { 234 uint8_t read = s->smb_addr & 0x01; 235 236 s->smb_index++; 237 if (!read && s->smb_index == s->smb_data0) { 238 uint8_t prot = (s->smb_ctl >> 2) & 0x07; 239 uint8_t cmd = s->smb_cmd; 240 uint8_t addr = s->smb_addr >> 1; 241 int ret; 242 243 if (prot == PROT_I2C_BLOCK_READ) { 244 s->smb_stat |= STS_DEV_ERR; 245 goto out; 246 } 247 248 ret = smbus_write_block(s->smbus, addr, cmd, s->smb_data, 249 s->smb_data0, !s->i2c_enable); 250 if (ret < 0) { 251 s->smb_stat |= STS_DEV_ERR; 252 goto out; 253 } 254 s->op_done = true; 255 s->smb_stat |= STS_INTR; 256 s->smb_stat &= ~STS_HOST_BUSY; 257 } else if (!read) { 258 s->smb_data[s->smb_index] = s->smb_blkdata; 259 s->smb_stat |= STS_BYTE_DONE; 260 } else if (s->smb_ctl & CTL_LAST_BYTE) { 261 s->op_done = true; 262 s->smb_blkdata = s->smb_data[s->smb_index]; 263 s->smb_index = 0; 264 s->smb_stat |= STS_INTR; 265 s->smb_stat &= ~STS_HOST_BUSY; 266 } else { 267 s->smb_blkdata = s->smb_data[s->smb_index]; 268 s->smb_stat |= STS_BYTE_DONE; 269 } 270 } 271 break; 272 case SMBHSTCNT: 273 s->smb_ctl = val & ~CTL_START; /* CTL_START always reads 0 */ 274 if (val & CTL_START) { 275 if (!s->op_done) { 276 s->smb_index = 0; 277 s->op_done = true; 278 } 279 smb_transaction_start(s); 280 } 281 if (s->smb_ctl & CTL_KILL) { 282 s->op_done = true; 283 s->smb_index = 0; 284 s->smb_stat |= STS_FAILED; 285 s->smb_stat &= ~STS_HOST_BUSY; 286 } 287 break; 288 case SMBHSTCMD: 289 s->smb_cmd = val; 290 break; 291 case SMBHSTADD: 292 s->smb_addr = val; 293 break; 294 case SMBHSTDAT0: 295 s->smb_data0 = val; 296 break; 297 case SMBHSTDAT1: 298 s->smb_data1 = val; 299 break; 300 case SMBBLKDAT: 301 if (s->smb_index >= PM_SMBUS_MAX_MSG_SIZE) { 302 s->smb_index = 0; 303 } 304 if (s->smb_auxctl & AUX_BLK) { 305 s->smb_data[s->smb_index++] = val; 306 } else { 307 s->smb_blkdata = val; 308 } 309 break; 310 case SMBAUXCTL: 311 s->smb_auxctl = val & AUX_MASK; 312 break; 313 default: 314 break; 315 } 316 317 out: 318 if (s->set_irq) { 319 s->set_irq(s, smb_irq_value(s)); 320 } 321 } 322 323 static uint64_t smb_ioport_readb(void *opaque, hwaddr addr, unsigned width) 324 { 325 PMSMBus *s = opaque; 326 uint32_t val; 327 328 switch(addr) { 329 case SMBHSTSTS: 330 val = s->smb_stat; 331 if (s->smb_stat & STS_HOST_BUSY) { 332 /* execute command now */ 333 smb_transaction(s); 334 } 335 break; 336 case SMBHSTCNT: 337 val = s->smb_ctl & CTL_RETURN_MASK; 338 break; 339 case SMBHSTCMD: 340 val = s->smb_cmd; 341 break; 342 case SMBHSTADD: 343 val = s->smb_addr; 344 break; 345 case SMBHSTDAT0: 346 val = s->smb_data0; 347 break; 348 case SMBHSTDAT1: 349 val = s->smb_data1; 350 break; 351 case SMBBLKDAT: 352 if (s->smb_index >= PM_SMBUS_MAX_MSG_SIZE) { 353 s->smb_index = 0; 354 } 355 if (s->smb_auxctl & AUX_BLK) { 356 val = s->smb_data[s->smb_index++]; 357 if (!s->op_done && s->smb_index == s->smb_data0) { 358 s->op_done = true; 359 s->smb_index = 0; 360 s->smb_stat &= ~STS_HOST_BUSY; 361 } 362 } else { 363 val = s->smb_blkdata; 364 } 365 break; 366 case SMBAUXCTL: 367 val = s->smb_auxctl; 368 break; 369 default: 370 val = 0; 371 break; 372 } 373 SMBUS_DPRINTF("SMB readb port=0x%04" HWADDR_PRIx " val=0x%02x\n", 374 addr, val); 375 376 if (s->set_irq) { 377 s->set_irq(s, smb_irq_value(s)); 378 } 379 380 return val; 381 } 382 383 static void pm_smbus_reset(PMSMBus *s) 384 { 385 s->op_done = true; 386 s->smb_index = 0; 387 s->smb_stat = 0; 388 } 389 390 static const MemoryRegionOps pm_smbus_ops = { 391 .read = smb_ioport_readb, 392 .write = smb_ioport_writeb, 393 .valid.min_access_size = 1, 394 .valid.max_access_size = 1, 395 .endianness = DEVICE_LITTLE_ENDIAN, 396 }; 397 398 void pm_smbus_init(DeviceState *parent, PMSMBus *smb) 399 { 400 smb->op_done = true; 401 smb->reset = pm_smbus_reset; 402 smb->smbus = i2c_init_bus(parent, "i2c"); 403 memory_region_init_io(&smb->io, OBJECT(parent), &pm_smbus_ops, smb, 404 "pm-smbus", 64); 405 } 406