Hi Egils,
thanks for the Ezoflash programmer doc. I have tried to implement init and SPI flash support correctly, but I don't own the hardware, so I can't test. A few places are marked FIXME, and it would be really nice if you could take a look. I basically took the RayeR SPIPGM driver in flashrom and modified and extended it. If your mailer mangles the patch, you can also find it at the top of http://patchwork.coreboot.org/project/flashrom/list/
Add support for the Ezoflash programmer. Hopefully complete init. Only SPI supported for now, and with additional 1 us delay per clock. Missing shutdown.
Compiles, otherwise untested. If you want to test, please apply the patch to latest flashrom, then compile with make CONFIG_EZO=yes To test the code, run ./flashrom -p ezo -V
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Index: flashrom-ezoflash/Makefile =================================================================== --- flashrom-ezoflash/Makefile (Revision 1137) +++ flashrom-ezoflash/Makefile (Arbeitskopie) @@ -114,6 +114,9 @@ # RayeR SPIPGM hardware support CONFIG_RAYER_SPI ?= yes
+# Ezoflash hardware support, disabled by default until it works fine. +CONFIG_EZO ?= no + # Bitbanging SPI infrastructure, default off unless needed. ifeq ($(CONFIG_RAYER_SPI), yes) override CONFIG_BITBANG_SPI = yes @@ -121,9 +124,13 @@ ifeq ($(CONFIG_INTERNAL), yes) override CONFIG_BITBANG_SPI = yes else +ifeq ($(CONFIG_EZO), yes) +override CONFIG_BITBANG_SPI = yes +else CONFIG_BITBANG_SPI ?= no endif endif +endif
# Always enable 3Com NICs for now. CONFIG_NIC3COM ?= yes @@ -184,6 +191,13 @@ NEED_PCI := yes endif
+ifeq ($(CONFIG_EZO), yes) +FEATURE_CFLAGS += -D'CONFIG_EZO=1' +PROGRAMMER_OBJS += ezo.o +# Actually, NEED_PCI is wrong. NEED_IOPORT_ACCESS would be more correct. +NEED_PCI := yes +endif + ifeq ($(CONFIG_BITBANG_SPI), yes) FEATURE_CFLAGS += -D'CONFIG_BITBANG_SPI=1' PROGRAMMER_OBJS += bitbang_spi.o Index: flashrom-ezoflash/ezo.c =================================================================== --- flashrom-ezoflash/ezo.c (Revision 0) +++ flashrom-ezoflash/ezo.c (Revision 0) @@ -0,0 +1,248 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2009,2010 Carl-Daniel Hailfinger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program 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. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* Driver for the Ezoflash hardware by Egils Zomerfelds "Ezo". + * See http:// for schematics and instructions. + */ + +/* This driver uses non-portable direct I/O port accesses which won't work on + * any non-x86 platform, and even on x86 there is a high chance there will be + * collisions with any loaded parallel port drivers. + * The big advantage of direct port I/O is OS independence and speed because + * most OS parport drivers will perform many unnecessary accesses although + * this driver just treats the parallel port as a GPIO set. + */ +#if defined(__i386__) || defined(__x86_64__) + +#include "flash.h" +#include "programmer.h" + +/* We have two sets of pins, out and in. The numbers for both sets are + * independent and are bitshift values, not real pin numbers. + */ +/* Pins for master->slave direction, data port */ +#define SPI_MOSI_PIN 0 +#define SPI_SCK_PIN 1 +/* Pins for slave->master direction, status port */ +#define SPI_MISO_PIN 7 +/* Pins for master->slave direction, command port */ +#define SPI_CS_PIN 3 +#define VCC_PIN 2 +#define VPP_PIN 0 +#define PAR_OE_PIN 1 +#define PAR_WE_PIN 3 + +static int lpt_iobase; + +/* FIXME: All ezo_bitbang_set_* functions could use caching of the value + * stored at port lpt_iobase+n to avoid unnecessary INB. + */ + +static void ezo_bitbang_set_cs(int val) +{ + uint8_t tmp; + + tmp = INB(lpt_iobase + 2); + tmp &= ~(1 << SPI_CS_PIN); + tmp |= (val << SPI_CS_PIN); + OUTB(tmp, lpt_iobase + 2); +} + +static void ezo_bitbang_set_sck(int val) +{ + uint8_t tmp; + + tmp = INB(lpt_iobase); + tmp &= ~(1 << SPI_SCK_PIN); + tmp |= (val << SPI_SCK_PIN); + OUTB(tmp, lpt_iobase); +} + +static void ezo_bitbang_set_mosi(int val) +{ + uint8_t tmp; + + tmp = INB(lpt_iobase); + tmp &= ~(1 << SPI_MOSI_PIN); + tmp |= (val << SPI_MOSI_PIN); + OUTB(tmp, lpt_iobase); +} + +static int ezo_bitbang_get_miso(void) +{ + uint8_t tmp; + + tmp = INB(lpt_iobase + 1); + tmp = (tmp >> SPI_MISO_PIN) & 0x1; + return tmp; +} + +static void ezo_set_vcc(int val) +{ + uint8_t tmp; + + tmp = INB(lpt_iobase + 2); + tmp &= ~(1 << VCC_PIN); + tmp |= (val << VCC_PIN); + OUTB(tmp, lpt_iobase + 2); +} + +static void ezo_set_vpp(int val) +{ + uint8_t tmp; + + tmp = INB(lpt_iobase + 2); + tmp &= ~(1 << VPP_PIN); + tmp |= (val << VPP_PIN); + OUTB(tmp, lpt_iobase + 2); +} + +/* Please note that OE# is active low, but inverted by the flasher hardware. + * ezo_set_par_oe(1) will therefore set OE# to 0. + */ +static void ezo_set_par_oe(int val) +{ + uint8_t tmp; + + tmp = INB(lpt_iobase + 2); + tmp &= ~(1 << PAR_OE_PIN); + tmp |= (val << PAR_OE_PIN); + OUTB(tmp, lpt_iobase + 2); +} + +static void ezo_set_par_we(int val) +{ + uint8_t tmp; + + tmp = INB(lpt_iobase + 2); + tmp &= ~(1 << PAR_WE_PIN); + tmp |= (val << PAR_WE_PIN); + OUTB(tmp, lpt_iobase + 2); +} + +static void ezo_bitbang_set_parallel_data(int val) +{ + OUTB(val & 0xff, lpt_iobase); +} + +static const struct bitbang_spi_master bitbang_spi_master_ezo = { + .type = BITBANG_SPI_MASTER_EZO, + .set_cs = ezo_bitbang_set_cs, + .set_sck = ezo_bitbang_set_sck, + .set_mosi = ezo_bitbang_set_mosi, + .get_miso = ezo_bitbang_get_miso, +}; + +static void ezo_prg_rst(void) +{ + ezo_set_vpp(0); + ezo_set_vcc(0); + /* FIXME: WRITE_ADRESS (0x000000) */ + ezo_set_par_oe(1); + ezo_set_par_we(0); + ezo_bitbang_set_parallel_data(0x00); +} + +int ezo_init(void) +{ + int tmp; + + /* Pick a default value for now. */ + lpt_iobase = 0x378; + + msg_pinfo("Ezoflash Willem compatible programmer driver. Untested.\n"); + msg_pdbg("Using port 0x%x as I/O base for parallel port access.\n", + lpt_iobase); + + get_io_perms(); + + /* FIXME: Check init sequence. */ + + /* VCC_ON, VCC_OFF. */ + /* FIXME: Datasheet contradiction! ON->OFF should be 1->0. */ + ezo_set_vcc(0); + ezo_set_vcc(1); + + /* VPP_ON, VPP_OFF. */ + /* FIXME: Datasheet contradiction! ON->OFF should be 1->0. */ + ezo_set_vpp(0); + ezo_set_vpp(1); + + /* OE_LOW, OE_HIGH. OE# is inverted in the flasher. */ + ezo_set_par_oe(1); + ezo_set_par_oe(0); + + /* WE_LOW, WE_HIGH. */ + ezo_set_par_we(0); + ezo_set_par_we(1); + + /* READ_SERBIT. */ + /* FIXME: Throw away the result or check it? */ + ezo_bitbang_get_miso(); + + /* PRG_RST. */ + ezo_prg_rst(); + + /* HW_CHECK. */ + /* FIXME: Check pulse? */ + /* FIXME: We just sent PRG_RST. Resend? */ + ezo_set_vcc(1); + ezo_set_par_oe(0); + /* Want a bitwise function instead of set_parallel_data? */ + ezo_bitbang_set_parallel_data(0x01); + programmer_delay(2); + tmp = ezo_bitbang_get_miso(); + if (!tmp) { + msg_perr("Hardware error! Aborting.\n"); + /* FIXME: Release I/O permissions. */ + return 1; + } + /* Want a bitwise function instead of set_parallel_data? */ + ezo_bitbang_set_parallel_data(0x00); + programmer_delay(2); + tmp = ezo_bitbang_get_miso(); + if (tmp) { + msg_perr("Hardware error! Aborting.\n"); + /* FIXME: Release I/O permissions. */ + return 1; + } + ezo_prg_rst(); + + /* FIXME: PRG_ID. */ + + /* 1 usec halfperiod delay for now. */ + if (bitbang_spi_init(&bitbang_spi_master_ezo, 1)) + return 1; + + buses_supported = CHIP_BUSTYPE_SPI; + spi_controller = SPI_CONTROLLER_EZO; + + return 0; +} + +int ezo_shutdown(void) +{ + /* FIXME: Add shutdown sequence. */ + /* FIXME: Release I/O perms. */ + return 0; +} + +#else +#error PCI port I/O access is not supported on this architecture yet. +#endif Index: flashrom-ezoflash/flashrom.8 =================================================================== --- flashrom-ezoflash/flashrom.8 (Revision 1137) +++ flashrom-ezoflash/flashrom.8 (Arbeitskopie) @@ -190,6 +190,8 @@ .BR "* rayer_spi" " (for SPI flash ROMs attached to a RayeR parport \ based programmer)" .sp +.BR "* ezo" " (for flash ROMs attached to a Ezoflash parport based programmer)" +.sp Some programmers have optional or mandatory parameters which are described in detail in the .B PROGRAMMER SPECIFIC INFO @@ -396,6 +398,10 @@ .BR "rayer_spi " programmer No parameters defined yet. More information about the hardware is available at http://rayer.ic.cz/elektro/spipgm.htm +.TP +.BR "ezo " programmer +No parameters defined yet. More information about the hardware is available at +http:// .SH EXIT STATUS flashrom exits with 0 on success, 1 on most failures but with 2 if /dev/mem (/dev/xsvc on Solaris) can not be opened and with 3 if a call to mmap() fails. @@ -418,8 +424,8 @@ .BR gfxnvidia " and " drkaiser need PCI configuration space access and raw memory access. .sp -.B rayer_spi -needs raw I/O port access. +.BR rayer_spi " and " ezo +need raw I/O port access. .sp .B satasii needs PCI configuration space read access and raw memory access. Index: flashrom-ezoflash/spi.c =================================================================== --- flashrom-ezoflash/spi.c (Revision 1137) +++ flashrom-ezoflash/spi.c (Arbeitskopie) @@ -136,6 +136,15 @@ }, #endif
+#if CONFIG_EZO == 1 + { /* SPI_CONTROLLER_EZO */ + .command = bitbang_spi_send_command, + .multicommand = default_spi_send_multicommand, + .read = bitbang_spi_read, + .write_256 = bitbang_spi_write_256, + }, +#endif + {}, /* This entry corresponds to SPI_CONTROLLER_INVALID. */ };
Index: flashrom-ezoflash/flashrom.c =================================================================== --- flashrom-ezoflash/flashrom.c (Revision 1137) +++ flashrom-ezoflash/flashrom.c (Arbeitskopie) @@ -49,7 +49,7 @@ * if more than one of them is selected. If only one is selected, it is clear * that the user wants that one to become the default. */ -#if CONFIG_NIC3COM+CONFIG_NICREALTEK+CONFIG_NICNATSEMI+CONFIG_GFXNVIDIA+CONFIG_DRKAISER+CONFIG_SATASII+CONFIG_ATAHPT+CONFIG_FT2232_SPI+CONFIG_SERPROG+CONFIG_BUSPIRATE_SPI+CONFIG_DEDIPROG+CONFIG_RAYER_SPI > 1 +#if CONFIG_NIC3COM+CONFIG_NICREALTEK+CONFIG_NICNATSEMI+CONFIG_GFXNVIDIA+CONFIG_DRKAISER+CONFIG_SATASII+CONFIG_ATAHPT+CONFIG_FT2232_SPI+CONFIG_SERPROG+CONFIG_BUSPIRATE_SPI+CONFIG_DEDIPROG+CONFIG_RAYER_SPI+CONFIG_EZO > 1 #error Please enable either CONFIG_DUMMY or CONFIG_INTERNAL or disable support for all programmers except one. #endif enum programmer programmer = @@ -90,6 +90,9 @@ #if CONFIG_RAYER_SPI == 1 PROGRAMMER_RAYER_SPI #endif +#if CONFIG_EZO == 1 + PROGRAMMER_EZO +#endif ; #endif
@@ -414,6 +417,25 @@ }, #endif
+#if CONFIG_EZO == 1 + { + .name = "ezo", + .init = ezo_init, + .shutdown = ezo_shutdown, + .map_flash_region = fallback_map, + .unmap_flash_region = fallback_unmap, + .chip_readb = noop_chip_readb, + .chip_readw = fallback_chip_readw, + .chip_readl = fallback_chip_readl, + .chip_readn = fallback_chip_readn, + .chip_writeb = noop_chip_writeb, + .chip_writew = fallback_chip_writew, + .chip_writel = fallback_chip_writel, + .chip_writen = fallback_chip_writen, + .delay = internal_delay, + }, +#endif + {}, /* This entry corresponds to PROGRAMMER_INVALID. */ };
Index: flashrom-ezoflash/programmer.h =================================================================== --- flashrom-ezoflash/programmer.h (Revision 1137) +++ flashrom-ezoflash/programmer.h (Arbeitskopie) @@ -73,6 +73,9 @@ #if CONFIG_RAYER_SPI == 1 PROGRAMMER_RAYER_SPI, #endif +#if CONFIG_EZO == 1 + PROGRAMMER_EZO, +#endif PROGRAMMER_INVALID /* This must always be the last entry. */ };
@@ -115,6 +118,9 @@ BITBANG_SPI_MASTER_MCP, #endif #endif +#if CONFIG_EZO == 1 + BITBANG_SPI_MASTER_EZO, +#endif };
struct bitbang_spi_master { @@ -425,6 +431,12 @@ #endif #endif
+/* ezo.c */ +#if CONFIG_EZO == 1 +int ezo_init(void); +int ezo_shutdown(void); +#endif + /* bitbang_spi.c */ int bitbang_spi_init(const struct bitbang_spi_master *master, int halfperiod); int bitbang_spi_send_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr); @@ -494,6 +506,9 @@ #if CONFIG_RAYER_SPI == 1 SPI_CONTROLLER_RAYER, #endif +#if CONFIG_EZO == 1 + SPI_CONTROLLER_EZO, +#endif SPI_CONTROLLER_INVALID /* This must always be the last entry. */ }; extern const int spi_programmer_count;