From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1NAKMU-0003hN-2A for qemu-devel@nongnu.org; Tue, 17 Nov 2009 04:28:34 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1NAKMO-0003bv-VR for qemu-devel@nongnu.org; Tue, 17 Nov 2009 04:28:33 -0500 Received: from [199.232.76.173] (port=44727 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NAKMO-0003bk-Oa for qemu-devel@nongnu.org; Tue, 17 Nov 2009 04:28:28 -0500 Received: from mail-fx0-f219.google.com ([209.85.220.219]:49094) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1NAKMN-0005WQ-Jj for qemu-devel@nongnu.org; Tue, 17 Nov 2009 04:28:28 -0500 Received: by fxm19 with SMTP id 19so7355878fxm.17 for ; Tue, 17 Nov 2009 01:28:25 -0800 (PST) MIME-Version: 1.0 In-Reply-To: <20091115204705.GA25577@rain> References: <20091115204705.GA25577@rain> Date: Tue, 17 Nov 2009 10:28:25 +0100 Message-ID: <5b31733c0911170128t13c633c3gf621b10f791e144f@mail.gmail.com> Subject: Re: [Qemu-devel] [PATCH 1/2] [RFC] add emulation of atmel pflash memory From: Filip Navara Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Evgeniy Dushistov Cc: qemu-devel@nongnu.org Interesting, I have been working on AT91SAM7X implementation. Most of the stuff is in the GIT repository at http://repo.or.cz/w/qemu/navara.git Any way to merge the efforts? I'd love to merge both mine and your patches to the mainline (minus the overlapping parts of the system controller). In fact my patches lack the flash emulation which would be a welcome addition. Best regards, Filip Navara On Sun, Nov 15, 2009 at 9:47 PM, Evgeniy Dushistov wrot= e: > This patch series add to qemu ability, > to emulate Atmel ARM AT91SAM9263 CPU, details about this CPU > you can find here: > http://www.atmel.com/dyn/products/product_card.asp?part_id=3D4056 > > I used this emulation to simplify process of porting eCos OS on it. > So this emulation support only part of functionality of at91sam9263 cpu. > > The first patch implement support for at49bv642d nor flash, > the second one contains implementation of at91sam9263. > > Here you can find pflash image: > http://sites.google.com/site/duhistov/Home/pflash.img?attredirects=3D0&d= =3D1 > > with at91bootstrap + u-boot + one of last version of linux kernel + > busybox. > > You can run try it in such way: > ./arm-softmmu/qemu-system-arm =A0-serial tcp::4445,server -M at91sam9263e= k > -pflash path/to/pflash.img =A0-s & > telnet localhost 4445 > > Comments? Is any way to merge this patches to mainline? > > Signed-off-by: Evgeniy Dushistov > --- > =A0Makefile.target =A0 | =A0 =A01 + > =A0hw/flash.h =A0 =A0 =A0 =A0| =A0 11 ++ > =A0hw/pflash_atmel.c | =A0501 +++++++++++++++++++++++++++++++++++++++++++= ++++++++++ > =A03 files changed, 513 insertions(+), 0 deletions(-) > =A0create mode 100644 hw/pflash_atmel.c > > diff --git a/Makefile.target b/Makefile.target > index 7068dc5..7542199 100644 > --- a/Makefile.target > +++ b/Makefile.target > @@ -268,6 +268,7 @@ obj-sparc-y +=3D cs4231.o eccmemctl.o sbi.o sun4c_int= ctl.o > =A0endif > > =A0obj-arm-y =3D integratorcp.o versatilepb.o smc91c111.o arm_pic.o arm_t= imer.o > +obj-arm-y +=3D pflash_atmel.o > =A0obj-arm-y +=3D arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl18= 1.o pl190.o > =A0obj-arm-y +=3D versatile_pci.o > =A0obj-arm-y +=3D realview_gic.o realview.o arm_sysctl.o mpcore.o > diff --git a/hw/flash.h b/hw/flash.h > index 69aef8c..0feaf9d 100644 > --- a/hw/flash.h > +++ b/hw/flash.h > @@ -16,6 +16,17 @@ pflash_t *pflash_cfi02_register(target_phys_addr_t bas= e, ram_addr_t off, > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 uint16_t = id2, uint16_t id3, > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 uint16_t = unlock_addr0, uint16_t unlock_addr1); > > +/* pflash_cfi_atmel.c */ > +pflash_t *pflash_cfi_atmel_register(target_phys_addr_t base, ram_addr_t = off, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 Blo= ckDriverState *bs, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 uin= t32_t boot_sect_len, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 int= nb_boot_blocks, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 uin= t32_t sector_len, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 int= nb_blocs, int width, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 uin= t16_t id0, uint16_t id1, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 uin= t16_t id2, uint16_t id3); > + > + > =A0/* nand.c */ > =A0typedef struct NANDFlashState NANDFlashState; > =A0NANDFlashState *nand_init(int manf_id, int chip_id); > diff --git a/hw/pflash_atmel.c b/hw/pflash_atmel.c > new file mode 100644 > index 0000000..cf3e7d4 > --- /dev/null > +++ b/hw/pflash_atmel.c > @@ -0,0 +1,501 @@ > +/* > + * =A0CFI parallel flash for emulating Atmel NOR flash > + * > + * =A0Copyright (c) 2009 Evgeniy Dushistov > + * =A0Copyright (c) 2006 Thorsten Zitterell > + * =A0Copyright (c) 2005 Jocelyn Mayer > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. =A0See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, see . > + */ > + > +/* > + * For now, this code can emulate flashes of 1, 2 or 4 bytes width. > + * Supported commands/modes are: > + * - flash read > + * - flash write > + * - flash ID read > + * - sector erase > + * > + * It does not support timings > + * It does not support flash interleaving > + * It does not implement software data protection as found in many real = chips > + * It does not implement erase suspend/resume commands > + * It does not implement multiple sectors erase > + * > + * It does not implement much more ... > + */ > + > +#include "hw.h" > +#include "flash.h" > +#include "block.h" > +#include "qemu-timer.h" > + > +#define PFLASH_BUG(fmt, ...) =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0 =A0 =A0 =A0 =A0\ > + =A0 =A0do { =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0\ > + =A0 =A0 =A0 =A0printf("PFLASH: Possible BUG - " fmt, ## __VA_ARGS__); = =A0\ > + =A0 =A0 =A0 =A0exit(1); =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0\ > + =A0 =A0} while(0) > + > +//#define PFLASH_DEBUG > +#ifdef PFLASH_DEBUG > +#define DPRINTF(fmt, ...) =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 \ > + =A0 =A0do { =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0 =A0 =A0 =A0 =A0\ > + =A0 =A0 =A0 =A0printf("PFLASH: " fmt , ## __VA_ARGS__); =A0 =A0\ > + =A0 =A0} while (0) > +#else > +#define DPRINTF(fmt, ...) do { } while (0) > +#endif > + > +struct pflash_t { > + =A0 =A0BlockDriverState *bs; > + =A0 =A0target_phys_addr_t base; > + =A0 =A0target_phys_addr_t sector_len; > + =A0 =A0target_phys_addr_t boot_sect_len; > + =A0 =A0target_phys_addr_t nb_blocks; > + =A0 =A0target_phys_addr_t nb_boot_blocks; > + =A0 =A0target_phys_addr_t total_len; > + =A0 =A0int width; > + =A0 =A0int wcycle; /* if 0, the flash is read normally */ > + =A0 =A0int bypass; > + =A0 =A0int ro; > + =A0 =A0uint8_t cmd; > + =A0 =A0uint8_t status; > + =A0 =A0uint16_t ident[4]; > + =A0 =A0target_phys_addr_t counter; > + =A0 =A0QEMUTimer *timer; > + =A0 =A0ram_addr_t off; > + =A0 =A0int fl_mem; > + =A0 =A0void *storage; > +}; > + > +#define AT49_FLASH_CODE1 =A0 =A0 =A0 =A00xAA > +#define AT49_FLASH_CODE2 =A0 =A0 =A0 =A00x55 > +#define AT49_ID_IN_CODE =A0 =A0 =A0 =A00x90 > +#define AT49_ID_OUT_CODE =A0 =A0 =A0 =A00xF0 > +#define AT49_FLASH_Setup_Erase =A0 =A0 0x80 > +#define AT49_FLASH_Program =A0 =A0 =A0 =A0 0xA0 > +#define AT49_FLASH_Sector_Erase =A0 =A00x30 > +#define AT49_CMD_READ_ARRAY =A0 =A0 =A0 =A00x00F0 > +#define AT49_MEM_FLASH_ADDR1 (0x5555<<1) > +#define AT49_MEM_FLASH_ADDR2 (0x00002AAA<<1) > + > +static void pflash_timer (void *opaque) > +{ > + =A0 =A0pflash_t *pfl =3D opaque; > + > + =A0 =A0DPRINTF("%s: command %02x done\n", __func__, pfl->cmd); > + =A0 =A0/* Reset flash */ > + =A0 =A0pfl->status ^=3D 0x80; > + =A0 =A0if (pfl->bypass) { > + =A0 =A0 =A0 =A0pfl->wcycle =3D 2; > + =A0 =A0} else { > + =A0 =A0 =A0 =A0cpu_register_physical_memory(pfl->base, pfl->total_len, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= pfl->off | IO_MEM_ROMD | pfl->fl_mem); > + =A0 =A0 =A0 =A0pfl->wcycle =3D 0; > + =A0 =A0} > + =A0 =A0pfl->cmd =3D 0; > +} > + > +static uint32_t pflash_read (pflash_t *pfl, target_phys_addr_t offset, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 int width) > +{ > + =A0 =A0target_phys_addr_t boff; > + =A0 =A0uint32_t ret; > + =A0 =A0uint8_t *p; > + > + =A0 =A0ret =3D -1; > + =A0 =A0boff =3D offset & 0xFF; /* why this here ?? */ > + > + =A0 =A0if (pfl->width =3D=3D 2) > + =A0 =A0 =A0 =A0boff =3D boff >> 1; > + =A0 =A0else if (pfl->width =3D=3D 4) > + =A0 =A0 =A0 =A0boff =3D boff >> 2; > + > + =A0 =A0DPRINTF("%s: reading offset " TARGET_FMT_plx " under cmd %02x wi= dth %d\n", > + =A0 =A0 =A0 =A0 =A0 =A0__func__, offset, pfl->cmd, width); > + > + =A0 =A0switch (pfl->cmd) { > + =A0 =A0case 0x00: > + =A0 =A0 =A0 =A0/* Flash area read */ > + =A0 =A0 =A0 =A0p =3D pfl->storage; > + =A0 =A0 =A0 =A0switch (width) { > + =A0 =A0 =A0 =A0case 1: > + =A0 =A0 =A0 =A0 =A0 =A0ret =3D p[offset]; > + =A0 =A0 =A0 =A0 =A0 =A0DPRINTF("%s: data offset " TARGET_FMT_plx " %02x= \n", > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0__func__, offset, ret); > + =A0 =A0 =A0 =A0 =A0 =A0break; > + =A0 =A0 =A0 =A0case 2: > +#if defined(TARGET_WORDS_BIGENDIAN) > + =A0 =A0 =A0 =A0 =A0 =A0ret =3D p[offset] << 8; > + =A0 =A0 =A0 =A0 =A0 =A0ret |=3D p[offset + 1]; > +#else > + =A0 =A0 =A0 =A0 =A0 =A0ret =3D p[offset]; > + =A0 =A0 =A0 =A0 =A0 =A0ret |=3D p[offset + 1] << 8; > +#endif > + =A0 =A0 =A0 =A0 =A0 =A0DPRINTF("%s: data offset " TARGET_FMT_plx " %04x= \n", > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0__func__, offset, ret); > + =A0 =A0 =A0 =A0 =A0 =A0break; > + =A0 =A0 =A0 =A0case 4: > +#if defined(TARGET_WORDS_BIGENDIAN) > + =A0 =A0 =A0 =A0 =A0 =A0ret =3D p[offset] << 24; > + =A0 =A0 =A0 =A0 =A0 =A0ret |=3D p[offset + 1] << 16; > + =A0 =A0 =A0 =A0 =A0 =A0ret |=3D p[offset + 2] << 8; > + =A0 =A0 =A0 =A0 =A0 =A0ret |=3D p[offset + 3]; > +#else > + =A0 =A0 =A0 =A0 =A0 =A0ret =3D p[offset]; > + =A0 =A0 =A0 =A0 =A0 =A0ret |=3D p[offset + 1] << 8; > + =A0 =A0 =A0 =A0 =A0 =A0ret |=3D p[offset + 1] << 8; > + =A0 =A0 =A0 =A0 =A0 =A0ret |=3D p[offset + 2] << 16; > + =A0 =A0 =A0 =A0 =A0 =A0ret |=3D p[offset + 3] << 24; > +#endif > + =A0 =A0 =A0 =A0 =A0 =A0DPRINTF("%s: data offset " TARGET_FMT_plx " %08x= \n", > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0__func__, offset, ret); > + =A0 =A0 =A0 =A0 =A0 =A0break; > + =A0 =A0 =A0 =A0default: > + =A0 =A0 =A0 =A0 =A0 =A0DPRINTF("BUG in %s\n", __func__); > + =A0 =A0 =A0 =A0} > + > + =A0 =A0 =A0 =A0break; > + =A0 =A0case AT49_FLASH_Setup_Erase: /* Block erase */ > + =A0 =A0case AT49_FLASH_Sector_Erase: > + =A0 =A0case AT49_FLASH_Program: /* Write block */ > + =A0 =A0 =A0 =A0/* Status register read */ > + =A0 =A0 =A0 =A0ret =3D pfl->status; > + =A0 =A0 =A0 =A0DPRINTF("%s: status %x\n", __func__, ret); > + =A0 =A0 =A0 =A0break; > + =A0 =A0case AT49_ID_IN_CODE: > + =A0 =A0 =A0 =A0DPRINTF("we read ID, boff %u, %X %X\n", boff, pfl->ident= [0], pfl->ident[1]); > + =A0 =A0 =A0 =A0/* flash ID read */ > + =A0 =A0 =A0 =A0switch (boff) { > + =A0 =A0 =A0 =A0case 0x00: > + =A0 =A0 =A0 =A0case 0x01: > + =A0 =A0 =A0 =A0 =A0 =A0ret =3D pfl->ident[boff & 0x01]; > + =A0 =A0 =A0 =A0 =A0 =A0break; > + =A0 =A0 =A0 =A0case 0x02: > + =A0 =A0 =A0 =A0 =A0 =A0ret =3D 0x00; /* Pretend all sectors are unprote= cted */ > + =A0 =A0 =A0 =A0 =A0 =A0break; > + =A0 =A0 =A0 =A0default: > + =A0 =A0 =A0 =A0 =A0 =A0break; > + =A0 =A0 =A0 =A0} > + =A0 =A0 =A0 =A0break; > + =A0 =A0default: > + =A0 =A0 =A0 =A0/* This should never happen : reset state & treat it as = a read */ > + =A0 =A0 =A0 =A0DPRINTF("%s: unknown command state: %x\n", __func__, pfl= ->cmd); > + =A0 =A0 =A0 =A0pfl->wcycle =3D 0; > + =A0 =A0 =A0 =A0pfl->cmd =3D 0; > + =A0 =A0} > + =A0 =A0DPRINTF("%s: ret %X\n", __func__, ret); > + =A0 =A0return ret; > +} > + > +/* update flash content on disk */ > +static void pflash_update(pflash_t *pfl, int offset, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0int size) > +{ > + =A0 =A0int offset_end; > + =A0 =A0if (pfl->bs) { > + =A0 =A0 =A0 =A0offset_end =3D offset + size; > + =A0 =A0 =A0 =A0/* round to sectors */ > + =A0 =A0 =A0 =A0offset =3D offset >> 9; > + =A0 =A0 =A0 =A0offset_end =3D (offset_end + 511) >> 9; > + =A0 =A0 =A0 =A0bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9)= , > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 offset_end - offset); > + =A0 =A0} > +} > + > +static inline void pflash_data_write(pflash_t *pfl, target_phys_addr_t o= ffset, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= uint32_t value, int width) > +{ > + =A0 =A0uint8_t *p =3D pfl->storage; > + > + =A0 =A0DPRINTF("%s: block write offset " TARGET_FMT_plx > + =A0 =A0 =A0 =A0 =A0 =A0" value %x counter " TARGET_FMT_plx "\n", > + =A0 =A0 =A0 =A0 =A0 =A0__func__, offset, value, pfl->counter); > + =A0 =A0switch (width) { > + =A0 =A0case 1: > + =A0 =A0 =A0 =A0p[offset] =3D value; > + =A0 =A0 =A0 =A0pflash_update(pfl, offset, 1); > + =A0 =A0 =A0 =A0break; > + =A0 =A0case 2: > +#if defined(TARGET_WORDS_BIGENDIAN) > + =A0 =A0 =A0 =A0p[offset] =3D value >> 8; > + =A0 =A0 =A0 =A0p[offset + 1] =3D value; > +#else > + =A0 =A0 =A0 =A0p[offset] =3D value; > + =A0 =A0 =A0 =A0p[offset + 1] =3D value >> 8; > +#endif > + =A0 =A0 =A0 =A0pflash_update(pfl, offset, 2); > + =A0 =A0 =A0 =A0break; > + =A0 =A0case 4: > +#if defined(TARGET_WORDS_BIGENDIAN) > + =A0 =A0 =A0 =A0p[offset] =3D value >> 24; > + =A0 =A0 =A0 =A0p[offset + 1] =3D value >> 16; > + =A0 =A0 =A0 =A0p[offset + 2] =3D value >> 8; > + =A0 =A0 =A0 =A0p[offset + 3] =3D value; > +#else > + =A0 =A0 =A0 =A0p[offset] =3D value; > + =A0 =A0 =A0 =A0p[offset + 1] =3D value >> 8; > + =A0 =A0 =A0 =A0p[offset + 2] =3D value >> 16; > + =A0 =A0 =A0 =A0p[offset + 3] =3D value >> 24; > +#endif > + =A0 =A0 =A0 =A0pflash_update(pfl, offset, 4); > + =A0 =A0 =A0 =A0break; > + =A0 =A0} > + > +} > + > +static void pflash_write(pflash_t *pfl, target_phys_addr_t offset, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 uint32_t value, int wid= th) > +{ > + =A0 =A0target_phys_addr_t boff; > + =A0 =A0uint8_t *p; > + =A0 =A0uint8_t cmd; > + > + =A0 =A0cmd =3D value; > + > + =A0 =A0DPRINTF("%s: writing offset " TARGET_FMT_plx " value %08x width = %d wcycle 0x%x\n", > + =A0 =A0 =A0 =A0 =A0 =A0__func__, offset, value, width, pfl->wcycle); > + > + =A0 =A0/* Set the device in I/O access mode */ > + =A0 =A0cpu_register_physical_memory(pfl->base, pfl->total_len, pfl->fl_= mem); > + =A0 =A0boff =3D offset & (pfl->sector_len - 1); > + > + =A0 =A0if (pfl->width =3D=3D 2) > + =A0 =A0 =A0 =A0boff =3D boff >> 1; > + =A0 =A0else if (pfl->width =3D=3D 4) > + =A0 =A0 =A0 =A0boff =3D boff >> 2; > + > + =A0 =A0switch (pfl->wcycle) { > + =A0 =A0case 0: > + =A0 =A0 =A0 =A0/* read mode */ > + =A0 =A0 =A0 =A0switch (cmd) { > + =A0 =A0 =A0 =A0case AT49_CMD_READ_ARRAY: > + =A0 =A0 =A0 =A0 =A0 =A0if (pfl->cmd =3D=3D AT49_FLASH_Program) { > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0DPRINTF("%s: finish program\n", __func__= ); > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0goto reset_flash; > + =A0 =A0 =A0 =A0 =A0 =A0} > + =A0 =A0 =A0 =A0 =A0 =A0goto error_flash; > + =A0 =A0 =A0 =A0case AT49_FLASH_CODE1: > + =A0 =A0 =A0 =A0 =A0 =A0if (offset =3D=3D AT49_MEM_FLASH_ADDR1) { > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0DPRINTF("flash code 1\n"); > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break; > + =A0 =A0 =A0 =A0 =A0 =A0} > + =A0 =A0 =A0 =A0default: > + =A0 =A0 =A0 =A0 =A0 =A0goto error_flash; > + =A0 =A0 =A0 =A0} > + =A0 =A0 =A0 =A0pfl->wcycle++; > + =A0 =A0 =A0 =A0pfl->cmd =3D cmd; > + =A0 =A0 =A0 =A0return; > + =A0 =A0case 1: > + =A0 =A0 =A0 =A0DPRINTF("offset %X, cmd %X wcyle 1\n", offset, pfl->cmd)= ; > + =A0 =A0 =A0 =A0switch (pfl->cmd) { > + =A0 =A0 =A0 =A0case AT49_FLASH_Program: > + =A0 =A0 =A0 =A0 =A0 =A0DPRINTF("%s: Single Byte Program\n", __func__); > + =A0 =A0 =A0 =A0 =A0 =A0pflash_data_write(pfl, offset, value, width); > + =A0 =A0 =A0 =A0 =A0 =A0pfl->status =3D (value & 0x80); /* Ready! */ > + =A0 =A0 =A0 =A0 =A0 =A0pfl->wcycle =3D 0; > + =A0 =A0 =A0 =A0 =A0 =A0break; > + =A0 =A0 =A0 =A0case AT49_FLASH_CODE1: > + =A0 =A0 =A0 =A0 =A0 =A0if (offset =3D=3D AT49_MEM_FLASH_ADDR2 && value = =3D=3D AT49_FLASH_CODE2) { > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0DPRINTF("flash code 2\n"); > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0pfl->cmd =3D value; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0pfl->wcycle++; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break; > + =A0 =A0 =A0 =A0 =A0 =A0} > + =A0 =A0 =A0 =A0default: > + =A0 =A0 =A0 =A0 =A0 =A0goto error_flash; > + =A0 =A0 =A0 =A0} > + =A0 =A0 =A0 =A0return; > + =A0 =A0case 2: > + =A0 =A0 =A0 =A0DPRINTF("%s: cmd %X\n", __func__, pfl->cmd); > + =A0 =A0 =A0 =A0switch (pfl->cmd) { > + =A0 =A0 =A0 =A0case AT49_FLASH_Sector_Erase: > + =A0 =A0 =A0 =A0 =A0 =A0if (value =3D=3D AT49_CMD_READ_ARRAY) { > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0DPRINTF("%s: sector erase finished\n", _= _func__); > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0goto reset_flash; > + =A0 =A0 =A0 =A0 =A0 =A0} > + =A0 =A0 =A0 =A0 =A0 =A0break; > + =A0 =A0 =A0 =A0case AT49_FLASH_CODE2: > + =A0 =A0 =A0 =A0 =A0 =A0if (offset =3D=3D AT49_MEM_FLASH_ADDR1) { > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0switch (value) { > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0case AT49_ID_IN_CODE: > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0DPRINTF("%s: ident command\n", _= _func__); > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0pfl->wcycle =3D 0; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0case AT49_FLASH_Setup_Erase: > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0DPRINTF("%s: erase command\n", _= _func__); > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0pfl->wcycle =3D 0; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0case AT49_FLASH_Program: > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0DPRINTF("%s: program command\n",= __func__); > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0pfl->wcycle =3D 1; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0case AT49_ID_OUT_CODE: > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0DPRINTF("%s: ident command finis= hed\n", __func__); > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0goto reset_flash; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0default: > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0goto error_flash; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0pfl->cmd =3D value; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break; > + =A0 =A0 =A0 =A0 =A0 =A0} else if (value =3D=3D AT49_FLASH_Sector_Erase)= { > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0target_phys_addr_t sect_len =3D offset <= pfl->boot_sect_len * pfl->nb_boot_blocks ? > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0pfl->boot_sect_len : pfl->sector= _len; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0pfl->cmd =3D AT49_FLASH_Sector_Erase; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0p =3D pfl->storage; > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0DPRINTF("%s: offset " TARGET_FMT_plx "\n= ", __func__, offset); > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0offset &=3D ~(sect_len - 1); > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0DPRINTF("%s: block erase at " TARGET_FMT= _plx " bytes " > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0TARGET_FMT_plx "\n", > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0__func__, offset, sect_l= en); > + > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0memset(p + offset, 0xff, sect_len); > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0pflash_update(pfl, offset, sect_len); > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0pfl->status |=3D 0x80; /* Ready! */ > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break; > + =A0 =A0 =A0 =A0 =A0 =A0} > + =A0 =A0 =A0 =A0default: > + =A0 =A0 =A0 =A0 =A0 =A0goto error_flash; > + =A0 =A0 =A0 =A0} > + =A0 =A0 =A0 =A0return; > + =A0 =A0default: > + =A0 =A0 =A0 =A0/* Should never happen */ > + =A0 =A0 =A0 =A0DPRINTF("%s: invalid write state\n", =A0__func__); > + =A0 =A0 =A0 =A0goto reset_flash; > + =A0 =A0} > + =A0 =A0return; > + > +error_flash: > + =A0 =A0printf("%s: Unimplemented flash cmd sequence " > + =A0 =A0 =A0 =A0 =A0 "(offset " TARGET_FMT_plx ", wcycle 0x%x cmd 0x%x v= alue 0x%x)\n", > + =A0 =A0 =A0 =A0 =A0 __func__, offset, pfl->wcycle, pfl->cmd, value); > + > +reset_flash: > + =A0 =A0cpu_register_physical_memory(pfl->base, pfl->total_len, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pfl->of= f | IO_MEM_ROMD | pfl->fl_mem); > + > + =A0 =A0pfl->bypass =3D 0; > + =A0 =A0pfl->wcycle =3D 0; > + =A0 =A0pfl->cmd =3D 0; > + =A0 =A0return; > +} > + > + > +static uint32_t pflash_readb (void *opaque, target_phys_addr_t addr) > +{ > + =A0 =A0return pflash_read(opaque, addr, 1); > +} > + > +static uint32_t pflash_readw (void *opaque, target_phys_addr_t addr) > +{ > + =A0 =A0pflash_t *pfl =3D opaque; > + > + =A0 =A0return pflash_read(pfl, addr, 2); > +} > + > +static uint32_t pflash_readl (void *opaque, target_phys_addr_t addr) > +{ > + =A0 =A0pflash_t *pfl =3D opaque; > + > + =A0 =A0return pflash_read(pfl, addr, 4); > +} > + > +static void pflash_writeb (void *opaque, target_phys_addr_t addr, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 uint32_t value) > +{ > + =A0 =A0pflash_write(opaque, addr, value, 1); > +} > + > +static void pflash_writew (void *opaque, target_phys_addr_t addr, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 uint32_t value) > +{ > + =A0 =A0pflash_t *pfl =3D opaque; > + > + =A0 =A0pflash_write(pfl, addr, value, 2); > +} > + > +static void pflash_writel (void *opaque, target_phys_addr_t addr, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 uint32_t value) > +{ > + =A0 =A0pflash_t *pfl =3D opaque; > + > + =A0 =A0pflash_write(pfl, addr, value, 4); > +} > + > +static CPUWriteMemoryFunc * const pflash_write_ops[] =3D { > + =A0 =A0&pflash_writeb, > + =A0 =A0&pflash_writew, > + =A0 =A0&pflash_writel, > +}; > + > +static CPUReadMemoryFunc * const pflash_read_ops[] =3D { > + =A0 =A0&pflash_readb, > + =A0 =A0&pflash_readw, > + =A0 =A0&pflash_readl, > +}; > + > +pflash_t *pflash_cfi_atmel_register(target_phys_addr_t base, ram_addr_t = off, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= BlockDriverState *bs, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= uint32_t boot_sect_len, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= int nb_boot_blocks, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= uint32_t sector_len, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= int nb_blocs, int width, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= uint16_t id0, uint16_t id1, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= uint16_t id2, uint16_t id3) > +{ > + =A0 =A0pflash_t *pfl; > + =A0 =A0target_phys_addr_t total_len; > + =A0 =A0int ret; > + > + =A0 =A0total_len =3D boot_sect_len * nb_boot_blocks + sector_len * nb_b= locs; > + > + =A0 =A0pfl =3D qemu_mallocz(sizeof(pflash_t)); > + > + =A0 =A0pfl->storage =3D qemu_get_ram_ptr(off); > + =A0 =A0pfl->fl_mem =3D cpu_register_io_memory( > + =A0 =A0 =A0 =A0pflash_read_ops, pflash_write_ops, pfl); > + =A0 =A0pfl->off =3D off; > + =A0 =A0cpu_register_physical_memory(base, total_len, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 off | p= fl->fl_mem | IO_MEM_ROMD); > + > + =A0 =A0pfl->bs =3D bs; > + =A0 =A0if (pfl->bs) { > + =A0 =A0 =A0 =A0/* read the initial flash content */ > + =A0 =A0 =A0 =A0ret =3D bdrv_read(pfl->bs, 0, pfl->storage, total_len >>= 9); > + =A0 =A0 =A0 =A0if (ret < 0) { > + =A0 =A0 =A0 =A0 =A0 =A0cpu_unregister_io_memory(pfl->fl_mem); > + =A0 =A0 =A0 =A0 =A0 =A0qemu_free(pfl); > + =A0 =A0 =A0 =A0 =A0 =A0return NULL; > + =A0 =A0 =A0 =A0} > + =A0 =A0} > + =A0 =A0pfl->ro =3D 0; > + =A0 =A0pfl->timer =3D qemu_new_timer(vm_clock, pflash_timer, pfl); > + =A0 =A0pfl->base =3D base; > + =A0 =A0pfl->sector_len =3D sector_len; > + =A0 =A0pfl->nb_blocks =3D nb_blocs; > + =A0 =A0pfl->boot_sect_len =3D boot_sect_len; > + =A0 =A0pfl->nb_boot_blocks =3D nb_boot_blocks; > + =A0 =A0pfl->total_len =3D total_len; > + =A0 =A0pfl->width =3D width; > + =A0 =A0pfl->wcycle =3D 0; > + =A0 =A0pfl->cmd =3D 0; > + =A0 =A0pfl->status =3D 0; > + =A0 =A0pfl->ident[0] =3D id0; > + =A0 =A0pfl->ident[1] =3D id1; > + =A0 =A0pfl->ident[2] =3D id2; > + =A0 =A0pfl->ident[3] =3D id3; > + > + > + =A0 =A0return pfl; > +} > -- > 1.6.5.2 > > -- > /Evgeniy > > > >