From: Weng Fan <wengfan-fnst@cn.fujitsu.com>
To: jan.kiszka@siemens.com, Qemu-devel@nongnu.org
Subject: [Qemu-devel] Fwd: Re: [PATCH v4 2/2] Add AT24Cxx I2C EEPROM device model
Date: Wed, 15 May 2013 14:20:51 +0800 [thread overview]
Message-ID: <51932943.7020408@cn.fujitsu.com> (raw)
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 <address@hidden>
> ---
> 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)
next reply other threads:[~2013-05-15 6:21 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-05-15 6:20 Weng Fan [this message]
2013-05-15 16:10 ` [Qemu-devel] Fwd: Re: [PATCH v4 2/2] Add AT24Cxx I2C EEPROM device model Jan Kiszka
2013-05-18 3:01 ` Weng Fan
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=51932943.7020408@cn.fujitsu.com \
--to=wengfan-fnst@cn.fujitsu.com \
--cc=Qemu-devel@nongnu.org \
--cc=jan.kiszka@siemens.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.