On Fri, May 08, 2009 at 03:57:10AM +0200, Carl-Daniel Hailfinger wrote: > > Very cool Carl-Daniel! > > So all we would have to do is add "case FLASHER_PARAFLASHER" and it's > > external r/w to each one of the swithes and we are good to go? > > > > Correct. Additionally, you need a command line parameter which sets the > flasher variable to FLASHER_PARAFLASHER, but that's it. I think Uwe has > a patch to do that.
Yep, will send later, probably needs some adaptions. > No problem. I need to dig up the LPC bus bitbang sources I got from Andy > (LPCflasher developer), then someone can integrate them into flashrom. Find my initial LPC bitbanging code attached, which I tried to use for my USBprog-based LPC flasher prototype. It does _not_ work correctly yet, but I don't know if it's a hardware issue or software issue. However, the lpc.c code should be _mostly_ correct, I guess. Uwe. -- http://www.hermann-uwe.de | http://www.holsham-traders.de http://www.crazy-hacks.org | http://www.unmaintained-free-software.org
Initial code for a bitbanging LPC protocol implementation for external flashers. This is a prototype only, it likely doesn't work yet. Signed-off-by: Uwe Hermann <[email protected]> --- /dev/null 2009-05-06 22:52:01.515646584 +0200 +++ lpc.c 2009-05-08 13:18:52.000000000 +0200 @@ -0,0 +1,168 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2009 Uwe Hermann <[email protected]> + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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 + */ + +#include <unistd.h> +#include "flash.h" + +/* LAD[3:0] values */ +#define LAD_START 0x0 /* 0000 */ +#define LAD_CYCDIR_MEM_READ 0x4 /* 010X, bit 0 reserved */ +#define LAD_CYCDIR_MEM_WRITE 0x6 /* 011X, bit 0 reserved */ +#define LAD_TAR0 0xf /* 1111 */ +#define LAD_TAR1 0xf /* 1111 (then float) */ +#define LAD_SYNC_READY 0x0 /* 0000 */ +#define LAD_SYNC_SHORTWAIT 0x5 /* 0101 */ +#define LAD_SYNC_LONGWAIT 0x6 /* 0110 */ +#define LAD_SYNC_ERROR 0xa /* 1010 */ + +/*--- Lowlevel pin toggling functions ---------------------------------------*/ + +void lpc_lclk_high(void) { usleep(5000); programmer_table[programmer].lpc_lclk_high(); } +void lpc_lclk_low(void) { usleep(5000); programmer_table[programmer].lpc_lclk_low(); } + +void lpc_lframe_high(void) { programmer_table[programmer].lpc_lframe_high(); } +void lpc_lframe_low(void) { programmer_table[programmer].lpc_lframe_low(); } + +void lpc_lrst_high(void) { programmer_table[programmer].lpc_lrst_high(); } +void lpc_lrst_low(void) { programmer_table[programmer].lpc_lrst_low(); } + +uint8_t lpc_get_lad(void) { return programmer_table[programmer].lpc_get_lad(); } +void lpc_set_lad(uint8_t b) { programmer_table[programmer].lpc_set_lad(b); } + +/*--- Generic LPC functions -------------------------------------------------*/ + +/* Return the current LAD[3:0] contents. */ +uint8_t lpc_read_nibble(void) +{ + uint8_t lad; + + lpc_lclk_high(); + lad = lpc_get_lad(); + lpc_lclk_low(); + if (verbose) + printf("lpc_read_nibble = 0x%02x\n", lad); + + return lad; +} + +/* Write the specified nibble into LAD[3:0]. */ +void lpc_write_nibble(uint8_t nibble) +{ + if (verbose) + printf("lpc_write_nibble = 0x%02x\n", nibble); + lpc_set_lad(nibble); + lpc_lclk_high(); + lpc_lclk_low(); +} + +/* Perform an LPC read cycle in order to read one byte. */ +uint8_t lpc_read_byte(uint32_t address) +{ + int i; + uint8_t sync, data; + + lpc_lclk_low(); + + printf("lpc_read_byte: 0x%08x\n", address); + + /* Clock cycle 1: Start an LPC cycle/transaction. */ + lpc_lframe_low(); /* Assert LFRAME#. */ + lpc_write_nibble(LAD_START); + lpc_lframe_high(); /* De-assert LFRAME#. */ + + /* Clock cycle 2: Indicate type of cycle (memory cycle, read). */ + lpc_write_nibble(LAD_CYCDIR_MEM_READ); + + /* Clock cycles 3-10: Send address (MSN first). */ + for (i = 7; i >= 0; i--) + lpc_write_nibble((address >> (i * 4)) & 0x0f); + + /* Clock cycle 11, 12: Transfer control to chip. */ + lpc_write_nibble(LAD_TAR0); + lpc_float_lad(); + + /* Clock cycle 13: SYNC, i.e. wait until ROM chip says it's ready. */ + while ((sync = lpc_read_nibble()) != 0) { + if (sync == LAD_SYNC_SHORTWAIT || sync == LAD_SYNC_LONGWAIT) { + /* Wait for a while. TODO: Do clock cycles? */ + lpc_lclk_high(); + lpc_lclk_low(); + } else { + /* TODO: Error */ + } + } + + /* Clock cycle 11-12: Read one data byte (LSN first). */ + data = lpc_read_nibble() & 0x0f; /* LSN */ + data |= lpc_read_nibble() << 4; /* MSN */ + + /* Clock cycle 16, 17: Take control of the bus again. */ + sync = lpc_read_nibble(); + lpc_unfloat_lad(); + lpc_write_nibble(LAD_TAR1); // FIXME? + + return data; +} + +int lpc_write_byte(uint32_t address, uint8_t data) +{ + int i; + uint8_t sync; + + printf("lpc_write_byte: 0x%08x, 0x%02x\n", address, data); + + /* Clock cycle 1: Start an LPC cycle/transaction. */ + lpc_lframe_low(); /* Assert LFRAME#. */ + lpc_write_nibble(LAD_START); + lpc_lframe_high(); /* De-assert LFRAME#. */ + + /* Clock cycle 2: Indicate type of cycle (memory cycle, write). */ + lpc_write_nibble(LAD_CYCDIR_MEM_WRITE); + + /* Clock cycles 3-10: Send address (MSN first). */ + for (i = 7; i >= 0; i--) + lpc_write_nibble((address >> (i * 4)) & 0x0f); + + /* Clock cycle 11-12: Send one data byte (LSN first). */ + lpc_write_nibble(data & 0x0f); /* LSN */ + lpc_write_nibble(data >> 4); /* MSN */ + + /* Clock cycle 13, 14: Transfer control to chip. */ + lpc_write_nibble(LAD_TAR0); + lpc_float_lad(); + + /* Clock cycle 15: SYNC, i.e. wait until ROM chip says it's ready. */ + while ((sync = lpc_read_nibble()) != 0) { + if (sync == LAD_SYNC_SHORTWAIT || sync == LAD_SYNC_LONGWAIT) { + /* Wait for a while. TODO: Do clock cycles? */ + lpc_lclk_high(); + lpc_lclk_low(); + } else { + /* TODO: Error */ + } + } + + /* Clock cycle 16, 17: Take control of the bus again. */ + lpc_read_nibble(); + lpc_unfloat_lad(); + lpc_write_nibble(LAD_TAR1); // FIXME? + + return 0; +}
-- coreboot mailing list: [email protected] http://www.coreboot.org/mailman/listinfo/coreboot

