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

Reply via email to