From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([208.118.235.92]:53839) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UcV5B-0008MQ-LK for Qemu-devel@nongnu.org; Wed, 15 May 2013 02:21:06 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1UcV56-0002PN-Rv for Qemu-devel@nongnu.org; Wed, 15 May 2013 02:21:01 -0400 Received: from [222.73.24.84] (port=40228 helo=song.cn.fujitsu.com) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UcV54-0002OZ-Rf for Qemu-devel@nongnu.org; Wed, 15 May 2013 02:20:56 -0400 Message-ID: <51932943.7020408@cn.fujitsu.com> Date: Wed, 15 May 2013 14:20:51 +0800 From: Weng Fan MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=UTF-8; format=flowed Subject: [Qemu-devel] Fwd: Re: [PATCH v4 2/2] Add AT24Cxx I2C EEPROM device model List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: jan.kiszka@siemens.com, Qemu-devel@nongnu.org Hi. I want to use this patch for qemu-system-arm. But an error occurred during initialization of the i2c device. The error message is : qemu-system-arm: drive property not set qemu-system-arm: Initialization of device at24 failed The command is: qemu-system-arm -M versatilepb -nographic -kernel zImage -initrd initrd.img -append "root=linuxrc console=ttyAMA0,115200" below under patch code : *************************************************************** if (params->size == 0) { error_setg(errp, "invalid EEPROM size, must be 2^(10..17)"); return; } } else if (image_size < size) { error_setg(errp, "image file smaller than EEPROM size"); return; } *************************************************************** I think i need a image file or a block device to save date for eeprom device. What should i do to use the at24 eeprom devcice. I hope you can help me ,thanks. > This implements I2C EEPROMs of the AT24Cxx series. Sizes from 1Kbit to > 1024Kbit are supported. Each EEPROM is backed by a block device. Its > size can be explicitly specified by selecting the exact device type > (required for sizes < 512, the blockdev sector size) or implicitly by > providing a block device image of the corresponding size. Device > addresses are built from the device number property. Write protection > can be configured by declaring the block device read-only. > > Signed-off-by: Jan Kiszka > --- > hw/nvram/Makefile.objs | 2 +- > hw/nvram/at24.c | 391 ++++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 392 insertions(+), 1 deletions(-) > create mode 100644 hw/nvram/at24.c > > diff --git a/hw/nvram/Makefile.objs b/hw/nvram/Makefile.objs > index e9a6694..8271cd6 100644 > --- a/hw/nvram/Makefile.objs > +++ b/hw/nvram/Makefile.objs > @@ -1,5 +1,5 @@ > common-obj-$(CONFIG_DS1225Y) += ds1225y.o > -common-obj-y += eeprom93xx.o > +common-obj-y += eeprom93xx.o at24.o > common-obj-y += fw_cfg.o > common-obj-$(CONFIG_MAC_NVRAM) += mac_nvram.o > obj-$(CONFIG_PSERIES) += spapr_nvram.o > diff --git a/hw/nvram/at24.c b/hw/nvram/at24.c > new file mode 100644 > index 0000000..654a4e2 > --- /dev/null > +++ b/hw/nvram/at24.c > @@ -0,0 +1,391 @@ > +/* > + * AT24Cxx EEPROM emulation > + * > + * Copyright (c) Siemens AG, 2012, 2013 > + * Author: Jan Kiszka > + * > + * Permission is hereby granted, free of charge, to any person > obtaining a copy > + * of this software and associated documentation files (the > "Software"), to > deal > + * in the Software without restriction, including without limitation > the rights > + * to use, copy, modify, merge, publish, distribute, sublicense, and/or > sell > + * copies of the Software, and to permit persons to whom the Software is > + * furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice shall be > included in > + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, > EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF > MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR > OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING > FROM, > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER > DEALINGS IN > + * THE SOFTWARE. > + */ > + > +#include "hw/hw.h" > +#include "hw/i2c/i2c.h" > +#include "hw/block/block.h" > +#include "sysemu/blockdev.h" > + > +#define TYPE_AT24 "at24" > +#define AT24(obj) OBJECT_CHECK(AT24State, (obj), TYPE_AT24) > + > +#define AT24_BASE_ADDRESS 0x50 > +#define AT24_MAX_PAGE_LEN 256 > + > +typedef struct AT24Parameters { > + const char *desc; > + unsigned int size; > + unsigned int page_size; > + unsigned int device_bits; > + unsigned int hi_addr_bits; > + bool addr16; > +} AT24Parameters; > + > +typedef enum AT24TransferState { > + AT24_IDLE, > + AT24_RD_ADDR, > + AT24_WR_ADDR_HI, > + AT24_WR_ADDR_LO, > + AT24_RW_DATA0, > + AT24_RD_DATA, > + AT24_WR_DATA, > +} AT24TransferState; > + > +typedef struct AT24State { > + I2CSlave parent_obj; > + > + BlockConf block_conf; > + BlockDriverState *bs; > + bool wp; > + unsigned int addr_mask; > + unsigned int page_mask; > + bool addr16; > + unsigned int hi_addr_mask; > + uint8_t device; > + AT24TransferState transfer_state; > + uint8_t sector_buffer[BDRV_SECTOR_SIZE]; > + int cached_sector; > + bool cache_dirty; > + uint32_t transfer_addr; > +} AT24State; > + > +static void at24_flush_transfer_buffer(AT24State *s) > +{ > + if (s->cached_sector < 0 || !s->cache_dirty) { > + return; > + } > + bdrv_write(s->bs, s->cached_sector, s->sector_buffer, 1); > + s->cache_dirty = false; > +} > + > +static void at24_event(I2CSlave *i2c, enum i2c_event event, uint8_t param) > +{ > + AT24State *s = AT24(i2c); > + > + switch (event) { > + case I2C_START_SEND: > + switch (s->transfer_state) { > + case AT24_IDLE: > + if (s->addr16) { > + s->transfer_addr = (param & s->hi_addr_mask) << 16; > + s->transfer_state = AT24_WR_ADDR_HI; > + } else { > + s->transfer_addr = (param & s->hi_addr_mask) << 8; > + s->transfer_state = AT24_WR_ADDR_LO; > + } > + break; > + default: > + s->transfer_state = AT24_IDLE; > + break; > + } > + break; > + case I2C_START_RECV: > + switch (s->transfer_state) { > + case AT24_IDLE: > + s->transfer_state = AT24_RD_ADDR; > + break; > + case AT24_RW_DATA0: > + s->transfer_state = AT24_RD_DATA; > + break; > + default: > + s->transfer_state = AT24_IDLE; > + break; > + } > + break; > + case I2C_FINISH: > + switch (s->transfer_state) { > + case AT24_WR_DATA: > + at24_flush_transfer_buffer(s); > + /* fall through */ > + default: > + s->transfer_state = AT24_IDLE; > + break; > + } > + break; > + default: > + s->transfer_state = AT24_IDLE; > + break; > + } > +} > + > +static int at24_cache_sector(AT24State *s, int sector) > +{ > + int ret; > + > + if (s->cached_sector == sector) { > + return 0; > + } > + ret = bdrv_read(s->bs, sector, s->sector_buffer, 1); > + if (ret < 0) { > + s->cached_sector = -1; > + return ret; > + } > + s->cached_sector = sector; > + s->cache_dirty = false; > + return 0; > +} > + > +static int at24_tx(I2CSlave *i2c, uint8_t data) > +{ > + AT24State *s = AT24(i2c); > + > + switch (s->transfer_state) { > + case AT24_WR_ADDR_HI: > + s->transfer_addr |= (data << 8) & s->addr_mask; > + s->transfer_state = AT24_WR_ADDR_LO; > + break; > + case AT24_WR_ADDR_LO: > + s->transfer_addr |= data & s->addr_mask; > + s->transfer_state = AT24_RW_DATA0; > + break; > + case AT24_RW_DATA0: > + s->transfer_state = AT24_WR_DATA; > + if (at24_cache_sector(s, s->transfer_addr >> BDRV_SECTOR_BITS) < 0) { > + s->transfer_state = AT24_IDLE; > + return -1; > + } > + /* fall through */ > + case AT24_WR_DATA: > + if (!s->wp) { > + s->sector_buffer[s->transfer_addr & ~BDRV_SECTOR_MASK] = data; > + s->cache_dirty = true; > + } > + s->transfer_addr = (s->transfer_addr & s->page_mask) | > + ((s->transfer_addr + 1) & ~s->page_mask); > + break; > + default: > + s->transfer_state = AT24_IDLE; > + return -1; > + } > + return 0; > +} > + > +static int at24_rx(I2CSlave *i2c) > +{ > + AT24State *s = AT24(i2c); > + unsigned int sector, offset; > + int result; > + > + switch (s->transfer_state) { > + case AT24_RD_ADDR: > + s->transfer_state = AT24_IDLE; > + result = s->transfer_addr; > + break; > + case AT24_RD_DATA: > + sector = s->transfer_addr >> BDRV_SECTOR_BITS; > + offset = s->transfer_addr & ~BDRV_SECTOR_MASK; > + s->transfer_addr = (s->transfer_addr + 1) & s->addr_mask; > + if (at24_cache_sector(s, sector) < 0) { > + result = 0; > + break; > + } > + result = s->sector_buffer[offset]; > + break; > + default: > + s->transfer_state = AT24_IDLE; > + result = 0; > + break; > + } > + return result; > +} > + > +static void at24_reset(DeviceState *d) > +{ > + AT24State *s = AT24(d); > + > + s->transfer_state = AT24_IDLE; > + s->cached_sector = -1; > +} > + > +static const AT24Parameters at24_parameters[] = { > + { "AT24C1 EEPROM", 1*1024, 8, 3, 0, false }, > + { "AT24C2 EEPROM", 2*1024, 8, 3, 0, false }, > + { "AT24C4 EEPROM", 4*1024, 16, 2, 1, false }, > + { "AT24C8 EEPROM", 8*1024, 16, 1, 2, false }, > + { "AT24C16 EEPROM", 16*1024, 16, 0, 3, false }, > + { "AT24C32 EEPROM", 32*1024, 32, 3, 0, true }, > + { "AT24C62 EEPROM", 64*1024, 32, 3, 0, true }, > + { "AT24C128 EEPROM", 128*1024, 64, 2, 0, true }, > + { "AT24C256 EEPROM", 256*1024, 64, 2, 0, true }, > + { "AT24C512 EEPROM", 512*1024, 128, 2, 0, true }, > + { "AT24C1024 EEPROM", 1024*1024, 256, 1, 1, true }, > + { }, > +}; > + > +static void at24_realize(DeviceState *d, Error **errp) > +{ > + DeviceClass *dc = DEVICE_GET_CLASS(d); > + I2CSlave *i2c = I2C_SLAVE(d); > + AT24State *s = AT24(d); > + const AT24Parameters *params; > + int64_t image_size; > + uint32_t size; > + int dev_no; > + > + s->bs = s->block_conf.bs; > + if (!s->bs) { > + error_setg(errp, "drive property not set"); > + return; > + } > + > + s->wp = bdrv_is_read_only(s->bs); > + > + image_size = bdrv_getlength(s->bs); > + > + for (params = at24_parameters; params->size != 0; params++) { > + if (params->desc == dc->desc) { > + break; > + } > + } > + size = params->size / 8; > + > + if (size == 0) { > + size = image_size; > + > + for (params = at24_parameters; params->size != 0; params++) { > + if (size * 8 == params->size) { > + break; > + } > + } > + if (params->size == 0) { > + error_setg(errp, "invalid EEPROM size, must be 2^(10..17)"); > + return; > + } > + } else if (image_size < size) { > + error_setg(errp, "image file smaller than EEPROM size"); > + return; > + } > + > + s->addr_mask = size - 1; > + s->page_mask = ~(params->page_size - 1); > + s->hi_addr_mask = (1 << params->hi_addr_bits) - 1; > + s->addr16 = params->addr16; > + > + dev_no = (s->device & ((1 << params->device_bits) - 1)) << > + params->hi_addr_bits; > + i2c_set_slave_address(i2c, AT24_BASE_ADDRESS | dev_no); > + i2c_set_slave_address_mask(i2c, 0x7f & ~s->hi_addr_mask); > +} > + > +static void at24_pre_save(void *opaque) > +{ > + AT24State *s = opaque; > + > + at24_flush_transfer_buffer(s); > +} > + > +static int at24_post_load(void *opaque, int version_id) > +{ > + AT24State *s = opaque; > + > + s->cached_sector = -1; > + return 0; > +} > + > +static const VMStateDescription vmstate_at24 = { > + .name = "at24", > + .version_id = 1, > + .minimum_version_id = 1, > + .minimum_version_id_old = 1, > + .pre_save = at24_pre_save, > + .post_load = at24_post_load, > + .fields = (VMStateField[]) { > + VMSTATE_UINT32(transfer_state, AT24State), > + VMSTATE_UINT32(transfer_addr, AT24State), > + VMSTATE_END_OF_LIST() > + } > +}; > + > +static Property at24_properties[] = { > + DEFINE_BLOCK_PROPERTIES(AT24State, block_conf), > + DEFINE_PROP_UINT8("device", AT24State, device, 0), > + DEFINE_PROP_END_OF_LIST(), > +}; > + > +static void at24_base_class_init(ObjectClass *klass, void *data) > +{ > + DeviceClass *dc = DEVICE_CLASS(klass); > + I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass); > + > + sc->event = at24_event; > + sc->recv = at24_rx; > + sc->send = at24_tx; > + dc->desc = "AT24Cxx EEPROM (defined by image size)"; > + dc->reset = at24_reset; > + dc->realize = at24_realize; > + dc->vmsd = &vmstate_at24; > + dc->props = at24_properties; > +} > + > +static void at24cxx_class_init(ObjectClass *klass, void *data) > +{ > + DeviceClass *dc = DEVICE_CLASS(klass); > + const AT24Parameters *params = data; > + > + dc->desc = params->desc; > +} > + > +#define AT24CXX_TYPE_INFO(type_name, param_no) \ > + { \ > + .name = (type_name), \ > + .parent = TYPE_AT24, \ > + .instance_size = sizeof(AT24State), \ > + .class_init = at24cxx_class_init, \ > + .class_data = (void *)&at24_parameters[(param_no)], \ > + } > + > +static const TypeInfo at24_info[] = { > + { > + .name = "at24", > + .parent = TYPE_I2C_SLAVE, > + .instance_size = sizeof(AT24State), > + .class_init = at24_base_class_init, > + }, > + AT24CXX_TYPE_INFO("at24c1", 0), > + AT24CXX_TYPE_INFO("at24c2", 1), > + AT24CXX_TYPE_INFO("at24c4", 2), > + AT24CXX_TYPE_INFO("at24c8", 3), > + AT24CXX_TYPE_INFO("at24c16", 4), > + AT24CXX_TYPE_INFO("at24c32", 5), > + AT24CXX_TYPE_INFO("at24c64", 6), > + AT24CXX_TYPE_INFO("at24c128", 7), > + AT24CXX_TYPE_INFO("at24c256", 8), > + AT24CXX_TYPE_INFO("at24c512", 9), > + AT24CXX_TYPE_INFO("at24c1024", 10), > +}; > + > +static void at24_register_types(void) > +{ > + unsigned int n; > + > + /* buffering is based on this, enforce it early */ > + assert(AT24_MAX_PAGE_LEN <= BDRV_SECTOR_SIZE); > + > + for (n = 0; n < ARRAY_SIZE(at24_info); n++) { > + type_register_static(&at24_info[n]); > + } > +} > + > +type_init(at24_register_types)