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