13fffc223Sths /* 23fffc223Sths * QEMU SMBus EEPROM device 33fffc223Sths * 43fffc223Sths * Copyright (c) 2007 Arastra, Inc. 53fffc223Sths * 63fffc223Sths * Permission is hereby granted, free of charge, to any person obtaining a copy 73fffc223Sths * of this software and associated documentation files (the "Software"), to deal 83fffc223Sths * in the Software without restriction, including without limitation the rights 93fffc223Sths * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 103fffc223Sths * copies of the Software, and to permit persons to whom the Software is 113fffc223Sths * furnished to do so, subject to the following conditions: 123fffc223Sths * 133fffc223Sths * The above copyright notice and this permission notice shall be included in 143fffc223Sths * all copies or substantial portions of the Software. 153fffc223Sths * 163fffc223Sths * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 173fffc223Sths * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 183fffc223Sths * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 193fffc223Sths * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 203fffc223Sths * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 213fffc223Sths * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 223fffc223Sths * THE SOFTWARE. 233fffc223Sths */ 243fffc223Sths 250430891cSPeter Maydell #include "qemu/osdep.h" 2683c9f4caSPaolo Bonzini #include "hw/hw.h" 270d09e41aSPaolo Bonzini #include "hw/i2c/i2c.h" 280d09e41aSPaolo Bonzini #include "hw/i2c/smbus.h" 293fffc223Sths 303fffc223Sths //#define DEBUG 313fffc223Sths 323fffc223Sths typedef struct SMBusEEPROMDevice { 331ea96673SPaul Brook SMBusDevice smbusdev; 34bf2782d7SGerd Hoffmann void *data; 353fffc223Sths uint8_t offset; 363fffc223Sths } SMBusEEPROMDevice; 373fffc223Sths 383fffc223Sths static void eeprom_quick_cmd(SMBusDevice *dev, uint8_t read) 393fffc223Sths { 403fffc223Sths #ifdef DEBUG 41ab7d9131Sbalrog printf("eeprom_quick_cmd: addr=0x%02x read=%d\n", dev->i2c.address, read); 423fffc223Sths #endif 433fffc223Sths } 443fffc223Sths 453fffc223Sths static void eeprom_send_byte(SMBusDevice *dev, uint8_t val) 463fffc223Sths { 473fffc223Sths SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev; 483fffc223Sths #ifdef DEBUG 49ab7d9131Sbalrog printf("eeprom_send_byte: addr=0x%02x val=0x%02x\n", 50ab7d9131Sbalrog dev->i2c.address, val); 513fffc223Sths #endif 523fffc223Sths eeprom->offset = val; 533fffc223Sths } 543fffc223Sths 553fffc223Sths static uint8_t eeprom_receive_byte(SMBusDevice *dev) 563fffc223Sths { 573fffc223Sths SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev; 58bf2782d7SGerd Hoffmann uint8_t *data = eeprom->data; 59bf2782d7SGerd Hoffmann uint8_t val = data[eeprom->offset++]; 603fffc223Sths #ifdef DEBUG 61ab7d9131Sbalrog printf("eeprom_receive_byte: addr=0x%02x val=0x%02x\n", 62ab7d9131Sbalrog dev->i2c.address, val); 633fffc223Sths #endif 643fffc223Sths return val; 653fffc223Sths } 663fffc223Sths 670ff596d0Spbrook static void eeprom_write_data(SMBusDevice *dev, uint8_t cmd, uint8_t *buf, int len) 683fffc223Sths { 693fffc223Sths SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev; 700ff596d0Spbrook int n; 713fffc223Sths #ifdef DEBUG 72ab7d9131Sbalrog printf("eeprom_write_byte: addr=0x%02x cmd=0x%02x val=0x%02x\n", 73ab7d9131Sbalrog dev->i2c.address, cmd, buf[0]); 743fffc223Sths #endif 75b36dc67bSStefan Weil /* A page write operation is not a valid SMBus command. 760ff596d0Spbrook It is a block write without a length byte. Fortunately we 770ff596d0Spbrook get the full block anyway. */ 780ff596d0Spbrook /* TODO: Should this set the current location? */ 790ff596d0Spbrook if (cmd + len > 256) 800ff596d0Spbrook n = 256 - cmd; 810ff596d0Spbrook else 820ff596d0Spbrook n = len; 830ff596d0Spbrook memcpy(eeprom->data + cmd, buf, n); 840ff596d0Spbrook len -= n; 850ff596d0Spbrook if (len) 860ff596d0Spbrook memcpy(eeprom->data, buf + n, len); 873fffc223Sths } 883fffc223Sths 890ff596d0Spbrook static uint8_t eeprom_read_data(SMBusDevice *dev, uint8_t cmd, int n) 903fffc223Sths { 913fffc223Sths SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev; 920ff596d0Spbrook /* If this is the first byte then set the current position. */ 930ff596d0Spbrook if (n == 0) 940ff596d0Spbrook eeprom->offset = cmd; 950ff596d0Spbrook /* As with writes, we implement block reads without the 960ff596d0Spbrook SMBus length byte. */ 970ff596d0Spbrook return eeprom_receive_byte(dev); 983fffc223Sths } 993fffc223Sths 10019473e51SPhilippe Mathieu-Daudé static void smbus_eeprom_realize(DeviceState *dev, Error **errp) 1013fffc223Sths { 1021ea96673SPaul Brook SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *)dev; 1030ff596d0Spbrook 1043fffc223Sths eeprom->offset = 0; 1053fffc223Sths } 1061ea96673SPaul Brook 10739bffca2SAnthony Liguori static Property smbus_eeprom_properties[] = { 10839bffca2SAnthony Liguori DEFINE_PROP_PTR("data", SMBusEEPROMDevice, data), 10939bffca2SAnthony Liguori DEFINE_PROP_END_OF_LIST(), 11039bffca2SAnthony Liguori }; 11139bffca2SAnthony Liguori 112b5ea9327SAnthony Liguori static void smbus_eeprom_class_initfn(ObjectClass *klass, void *data) 113b5ea9327SAnthony Liguori { 11439bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 115b5ea9327SAnthony Liguori SMBusDeviceClass *sc = SMBUS_DEVICE_CLASS(klass); 116b5ea9327SAnthony Liguori 11719473e51SPhilippe Mathieu-Daudé dc->realize = smbus_eeprom_realize; 118b5ea9327SAnthony Liguori sc->quick_cmd = eeprom_quick_cmd; 119b5ea9327SAnthony Liguori sc->send_byte = eeprom_send_byte; 120b5ea9327SAnthony Liguori sc->receive_byte = eeprom_receive_byte; 121b5ea9327SAnthony Liguori sc->write_data = eeprom_write_data; 122b5ea9327SAnthony Liguori sc->read_data = eeprom_read_data; 12339bffca2SAnthony Liguori dc->props = smbus_eeprom_properties; 1241b111dc1SMarkus Armbruster /* Reason: pointer property "data" */ 125e90f2a8cSEduardo Habkost dc->user_creatable = false; 126b5ea9327SAnthony Liguori } 127b5ea9327SAnthony Liguori 1288c43a6f0SAndreas Färber static const TypeInfo smbus_eeprom_info = { 129b5ea9327SAnthony Liguori .name = "smbus-eeprom", 13039bffca2SAnthony Liguori .parent = TYPE_SMBUS_DEVICE, 13139bffca2SAnthony Liguori .instance_size = sizeof(SMBusEEPROMDevice), 132b5ea9327SAnthony Liguori .class_init = smbus_eeprom_class_initfn, 1331ea96673SPaul Brook }; 1341ea96673SPaul Brook 13583f7d43aSAndreas Färber static void smbus_eeprom_register_types(void) 1361ea96673SPaul Brook { 13739bffca2SAnthony Liguori type_register_static(&smbus_eeprom_info); 1381ea96673SPaul Brook } 1391ea96673SPaul Brook 14083f7d43aSAndreas Färber type_init(smbus_eeprom_register_types) 141a88df0b9SIsaku Yamahata 142*e2224214SCédric Le Goater void smbus_eeprom_init_one(I2CBus *smbus, uint8_t address, uint8_t *eeprom_buf) 143*e2224214SCédric Le Goater { 144*e2224214SCédric Le Goater DeviceState *dev; 145*e2224214SCédric Le Goater 146*e2224214SCédric Le Goater dev = qdev_create((BusState *) smbus, "smbus-eeprom"); 147*e2224214SCédric Le Goater qdev_prop_set_uint8(dev, "address", address); 148*e2224214SCédric Le Goater qdev_prop_set_ptr(dev, "data", eeprom_buf); 149*e2224214SCédric Le Goater qdev_init_nofail(dev); 150*e2224214SCédric Le Goater } 151*e2224214SCédric Le Goater 152a5c82852SAndreas Färber void smbus_eeprom_init(I2CBus *smbus, int nb_eeprom, 153a88df0b9SIsaku Yamahata const uint8_t *eeprom_spd, int eeprom_spd_size) 154a88df0b9SIsaku Yamahata { 155a88df0b9SIsaku Yamahata int i; 1567267c094SAnthony Liguori uint8_t *eeprom_buf = g_malloc0(8 * 256); /* XXX: make this persistent */ 157a88df0b9SIsaku Yamahata if (eeprom_spd_size > 0) { 158a88df0b9SIsaku Yamahata memcpy(eeprom_buf, eeprom_spd, eeprom_spd_size); 159a88df0b9SIsaku Yamahata } 160a88df0b9SIsaku Yamahata 161a88df0b9SIsaku Yamahata for (i = 0; i < nb_eeprom; i++) { 162*e2224214SCédric Le Goater smbus_eeprom_init_one(smbus, 0x50 + i, eeprom_buf + (i * 256)); 163a88df0b9SIsaku Yamahata } 164a88df0b9SIsaku Yamahata } 165