* Add support for log buffer which can be passed to Linux kernel's
  syslog mechanism; used especially for POST results.

* Patch by Klaus Heydeck, 31 Oct 2002:
  Add initial support for kup4k board
diff --git a/common/Makefile b/common/Makefile
index f2c90c7..3f4ff01 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -33,7 +33,7 @@
 	  cmd_dcr.o cmd_diag.o cmd_doc.o cmd_dtt.o \
 	  cmd_eeprom.o cmd_elf.o cmd_fdc.o cmd_flash.o \
 	  cmd_fpga.o cmd_i2c.o cmd_ide.o cmd_immap.o \
-	  cmd_jffs2.o cmd_mem.o cmd_mii.o cmd_misc.o \
+	  cmd_jffs2.o cmd_log.o cmd_mem.o cmd_mii.o cmd_misc.o \
 	  cmd_net.o cmd_nvedit.o env_common.o \
 	  env_flash.o env_eeprom.o env_nvram.o env_nowhere.o \
 	  cmd_pci.o cmd_pcmcia.o \
diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c
index e8ce40d..70ca999 100644
--- a/common/cmd_bootm.c
+++ b/common/cmd_bootm.c
@@ -325,6 +325,17 @@
 		initrd_high = ~0;
 	}
 
+#ifdef CONFIG_LOGBUFFER
+	kbd=gd->bd;
+	if ((s = getenv ("logstart")) != NULL) {
+		kbd->bi_sramstart = simple_strtoul(s, NULL, 16);
+		/* Prevent initrd from overwriting logbuffer */
+		if (initrd_high < kbd->bi_sramstart)
+			initrd_high = kbd->bi_sramstart-1024;
+	}
+	debug ("## Logbuffer at 0x%08lX ", kbd->bi_sramstart);
+#endif
+
 	/*
 	 * Booting a (Linux) kernel image
 	 *
@@ -337,17 +348,15 @@
 
 	asm( "mr %0,1": "=r"(sp) : );
 
-#ifdef	DEBUG
-	printf ("## Current stack ends at 0x%08lX ", sp);
-#endif
+	debug ("## Current stack ends at 0x%08lX ", sp);
+
 	sp -= 2048;		/* just to be sure */
 	if (sp > CFG_BOOTMAPSZ)
 		sp = CFG_BOOTMAPSZ;
 	sp &= ~0xF;
 
-#ifdef	DEBUG
-	printf ("=> set upper limit to 0x%08lX\n", sp);
-#endif
+	debug ("=> set upper limit to 0x%08lX\n", sp);
+
 	cmdline = (char *)((sp - CFG_BARGSIZE) & ~0xF);
 	kbd = (bd_t *)(((ulong)cmdline - sizeof(bd_t)) & ~0xF);
 
@@ -492,11 +501,9 @@
 		len = data = 0;
 	}
 
-#ifdef	DEBUG
 	if (!data) {
-		printf ("No initrd\n");
+		debug ("No initrd\n");
 	}
-#endif
 
 	if (data) {
 		initrd_start  = (ulong)kbd - len;
@@ -527,10 +534,10 @@
 		}
 
 		SHOW_BOOT_PROGRESS (12);
-#ifdef	DEBUG
-		printf ("## initrd at 0x%08lX ... 0x%08lX (len=%ld=0x%lX)\n",
+
+		debug ("## initrd at 0x%08lX ... 0x%08lX (len=%ld=0x%lX)\n",
 			data, data + len - 1, len, len);
-#endif
+
 		initrd_end    = initrd_start + len;
 		printf ("   Loading Ramdisk to %08lx, end %08lx ... ",
 			initrd_start, initrd_end);
@@ -558,10 +565,10 @@
 		initrd_end = 0;
 	}
 
-#ifdef DEBUG
-	printf ("## Transferring control to Linux (at address %08lx) ...\n",
+
+	debug ("## Transferring control to Linux (at address %08lx) ...\n",
 		(ulong)kernel);
-#endif
+
 	SHOW_BOOT_PROGRESS (15);
 
 #ifdef CFG_INIT_RAM_LOCK
diff --git a/common/cmd_log.c b/common/cmd_log.c
new file mode 100644
index 0000000..2e42f10
--- /dev/null
+++ b/common/cmd_log.c
@@ -0,0 +1,223 @@
+/*
+ * (C) Copyright 2002
+ * Detlev Zundel, DENX Software Engineering, dzu@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Logbuffer handling routines
+ */
+
+#include <common.h>
+#include <command.h>
+#include <devices.h>
+#include <logbuff.h>
+
+#if defined(CONFIG_LOGBUFFER)
+
+#define LOG_BUF_LEN	(16384)
+#define LOG_BUF_MASK	(LOG_BUF_LEN-1)
+
+/* Local prototypes */
+static void logbuff_putc (const char c);
+static void logbuff_puts (const char *s);
+static int logbuff_printk(const char *line);
+
+static char buf[1024];
+
+static unsigned console_loglevel = 3;
+static unsigned default_message_loglevel = 4;
+static unsigned long log_size;
+static unsigned char *log_buf=NULL;
+static unsigned long *ext_log_start, *ext_logged_chars;
+#define log_start (*ext_log_start)
+#define logged_chars (*ext_logged_chars)
+
+/* Forced by code, eh! */
+#define LOGBUFF_MAGIC 0xc0de4ced
+
+int drv_logbuff_init (void)
+{
+	device_t logdev;
+	int rc;
+
+	/* Device initialization */
+	memset (&logdev, 0, sizeof (logdev));
+
+	strcpy (logdev.name, "logbuff");
+	logdev.ext   = 0;			/* No extensions */
+	logdev.flags = DEV_FLAGS_OUTPUT;	/* Output only */
+	logdev.putc  = logbuff_putc;		/* 'putc' function */
+	logdev.puts  = logbuff_puts;		/* 'puts' function */
+
+	rc = device_register (&logdev);
+
+	return (rc == 0) ? 1 : rc;
+}
+
+static void logbuff_putc (const char c)
+{
+	char buf[2];
+	buf[0]=c;
+	buf[1]='\0';
+	logbuff_printk(buf);
+}
+
+static void logbuff_puts (const char *s)
+{
+	char buf[512];
+
+	sprintf(buf, "%s\n", s);
+	logbuff_printk(buf);
+}
+
+void logbuff_log(char *msg)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+
+	if (gd->flags & GD_FLG_RELOC) {
+		logbuff_printk(msg);
+	} else {
+		puts(msg);
+	}
+}
+
+void logbuff_reset (void)
+{
+	char *s;
+	unsigned long *ext_tag;
+
+	if ((s = getenv ("logstart")) != NULL) {
+		log_buf = (unsigned char *)simple_strtoul(s, NULL, 16);
+		ext_tag=(unsigned long *)(log_buf)-3;
+		ext_log_start=(unsigned long *)(log_buf)-2;
+		ext_logged_chars=(unsigned long *)(log_buf)-1;
+//		if (*ext_tag!=LOGBUFF_MAGIC) {
+			logged_chars=log_start=0;
+			*ext_tag=LOGBUFF_MAGIC;
+//		}
+		log_size=logged_chars;
+	}
+}
+
+/*
+ * Subroutine:  do_log
+ *
+ * Description: Handler for 'log' command..
+ *
+ * Inputs:	argv[1] contains the subcommand
+ *
+ * Return:      None
+ *
+ */
+int do_log (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	char *s;
+	unsigned long i;
+
+	if (log_buf==NULL) {
+		printf ("No logbuffer defined!  Set 'logstart' to use this feature.\n");
+		return 1;
+	}
+
+	switch (argc) {
+
+	case 2:
+		if (strcmp(argv[1],"show") == 0) {
+			for (i=0; i<logged_chars; i++) {
+				s=log_buf+((log_start+i)&LOG_BUF_MASK);
+				putc(*s);
+			}
+			return 0;
+		} else if (strcmp(argv[1],"reset") == 0) {
+			log_start=0;
+			logged_chars=0;
+			log_size=0;
+			return 0;
+		}
+		printf ("Usage:\n%s\n", cmdtp->usage);
+		return 1;
+
+	case 3:
+		if (strcmp(argv[1],"append") == 0) {
+			logbuff_puts(argv[2]);
+			return 0;
+
+		}
+		printf ("Usage:\n%s\n", cmdtp->usage);
+		return 1;
+
+	default:
+		printf ("Usage:\n%s\n", cmdtp->usage);
+		return 1;
+	}
+}
+
+static int logbuff_printk(const char *line)
+{
+	int i;
+	char *msg, *p, *buf_end;
+	int line_feed;
+	static signed char msg_level = -1;
+
+	strcpy(buf + 3, line);
+	i = strlen(line);
+	buf_end = buf + 3 + i;
+	for (p = buf + 3; p < buf_end; p++) {
+		msg = p;
+		if (msg_level < 0) {
+			if (
+				p[0] != '<' ||
+				p[1] < '0' ||
+				p[1] > '7' ||
+				p[2] != '>'
+			) {
+				p -= 3;
+				p[0] = '<';
+				p[1] = default_message_loglevel + '0';
+				p[2] = '>';
+			} else
+				msg += 3;
+			msg_level = p[1] - '0';
+		}
+		line_feed = 0;
+		for (; p < buf_end; p++) {
+			log_buf[(log_start+log_size) & LOG_BUF_MASK] = *p;
+			if (log_size < LOG_BUF_LEN)
+				log_size++;
+			else
+				log_start++;
+
+			logged_chars++;
+			if (*p == '\n') {
+				line_feed = 1;
+				break;
+			}
+		}
+		if (msg_level < console_loglevel) {
+			printf("%s", msg);
+		}
+		if (line_feed)
+			msg_level = -1;
+	}
+	return i;
+}
+
+#endif /* (CONFIG_LOGBUFFER) */
diff --git a/common/cmd_pcmcia.c b/common/cmd_pcmcia.c
index ccf21a9..6d01e70 100644
--- a/common/cmd_pcmcia.c
+++ b/common/cmd_pcmcia.c
@@ -1975,6 +1975,224 @@
 
 #endif	/* R360MPI */
 
+/* ---------------------------------------------------------------------------- */
+/* KUP4K Board						*/
+/* ---------------------------------------------------------------------------- */
+#if defined(CONFIG_KUP4K)
+
+#define PCMCIA_BOARD_MSG "KUP4K"
+
+#define KUP4K_PCMCIA_B_3V3 (0x00020000)
+
+static int hardware_enable(int slot)
+{
+	volatile immap_t	*immap;
+	volatile cpm8xx_t	*cp;
+	volatile pcmconf8xx_t	*pcmp;
+	volatile sysconf8xx_t	*sysp;
+	uint reg, mask;
+
+	debug ("hardware_enable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
+
+	udelay(10000);
+
+	immap = (immap_t *)CFG_IMMR;
+	sysp  = (sysconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_siu_conf));
+	pcmp  = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+	cp    = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
+
+	/*
+	 * Configure SIUMCR to enable PCMCIA port B
+	 * (VFLS[0:1] are not used for debugging, we connect FRZ# instead)
+	 */
+	sysp->sc_siumcr &= ~SIUMCR_DBGC11;	/* set DBGC to 00 */
+
+	/* clear interrupt state, and disable interrupts */
+	pcmp->pcmc_pscr =  PCMCIA_MASK(_slot_);
+	pcmp->pcmc_per &= ~PCMCIA_MASK(_slot_);
+
+	/* disable interrupts & DMA */
+	PCMCIA_PGCRX(_slot_) = 0;
+
+	/*
+	 * Disable PCMCIA buffers (isolate the interface)
+	 * and assert RESET signal
+	 */
+	debug ("Disable PCMCIA buffers and assert RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg |=  __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg |=  __MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+	udelay(500);
+
+	/*
+	 * Configure Port B pins for
+	 * 3 Volts enable
+	 */
+	cp->cp_pbdir |=  KUP4K_PCMCIA_B_3V3;
+	cp->cp_pbpar &= ~KUP4K_PCMCIA_B_3V3;
+	/* remove all power */
+	cp->cp_pbdat |=  KUP4K_PCMCIA_B_3V3; /* active low */
+
+	/*
+	 * Make sure there is a card in the slot, then configure the interface.
+	 */
+	udelay(10000);
+	debug ("[%d] %s: PIPR(%p)=0x%x\n",
+		__LINE__,__FUNCTION__,
+		&(pcmp->pcmc_pipr),pcmp->pcmc_pipr);
+	if (pcmp->pcmc_pipr & 0x00001800) {
+		printf ("   No Card found\n");
+		return (1);
+	}
+
+	/*
+	 * Power On.
+	 */
+	mask = PCMCIA_VS1(slot) | PCMCIA_VS2(slot);
+	reg  = pcmp->pcmc_pipr;
+	debug ("PIPR: 0x%x ==> VS1=o%s, VS2=o%s\n",
+		reg,
+		(reg&PCMCIA_VS1(slot))?"n":"ff",
+		(reg&PCMCIA_VS2(slot))?"n":"ff");
+	if ((reg & mask) == mask) {
+		puts (" 5.0V card found: NOT SUPPORTED !!!\n");
+	} else {
+		cp->cp_pbdat &= ~KUP4K_PCMCIA_B_3V3;
+		puts (" 3.3V card found: ");
+	}
+#if 0
+	/*  VCC switch error flag, PCMCIA slot INPACK_ pin */
+	cp->cp_pbdir &= ~(0x0020 | 0x0010);
+	cp->cp_pbpar &= ~(0x0020 | 0x0010);
+	udelay(500000);
+#endif
+	debug ("Enable PCMCIA buffers and stop RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg &= ~__MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg &= ~__MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+
+	udelay(250000);	/* some cards need >150 ms to come up :-( */
+
+	debug ("# hardware_enable done\n");
+
+	return (0);
+}
+
+
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+static int hardware_disable(int slot)
+{
+	volatile immap_t	*immap;
+	volatile cpm8xx_t	*cp;
+	volatile pcmconf8xx_t	*pcmp;
+	u_long reg;
+
+	debug ("hardware_disable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot);
+
+	immap = (immap_t *)CFG_IMMR;
+	pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+	cp    = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
+	
+	/* remove all power */
+	cp->cp_pbdat |= DDC4000_PCMCIA_B_3V3;
+
+	/* Configure PCMCIA General Control Register */
+	PCMCIA_PGCRX(_slot_) = 0;
+
+	debug ("Disable PCMCIA buffers and assert RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg |= __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg |= __MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+
+	udelay(10000);
+
+	return (0);
+}
+#endif	/* CFG_CMD_PCMCIA */
+
+
+
+static int voltage_set(int slot, int vcc, int vpp)
+{
+	volatile immap_t	*immap;
+	volatile cpm8xx_t	*cp;
+	volatile pcmconf8xx_t	*pcmp;
+	u_long reg;
+
+	debug ("voltage_set: "	\
+		PCMCIA_BOARD_MSG	\
+		" Slot %c, Vcc=%d.%d, Vpp=%d.%d\n",
+		'A'+slot, vcc/10, vcc%10, vpp/10, vcc%10);
+
+	immap = (immap_t *)CFG_IMMR;
+	pcmp = (pcmconf8xx_t *)(&(((immap_t *)CFG_IMMR)->im_pcmcia));
+	cp    = (cpm8xx_t *)(&(((immap_t *)CFG_IMMR)->im_cpm));
+
+	/*
+	 * Disable PCMCIA buffers (isolate the interface)
+	 * and assert RESET signal
+	 */
+	debug ("Disable PCMCIA buffers and assert RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg |=  __MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg |=  __MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+	udelay(500);
+
+	debug ("PCMCIA power OFF\n");
+	/*
+	 * Configure Port B pins for
+	 * 3 Volts enable
+	 */
+	cp->cp_pbdir |=  KUP4K_PCMCIA_B_3V3;
+	cp->cp_pbpar &= ~KUP4K_PCMCIA_B_3V3;
+	/* remove all power */
+	cp->cp_pbdat |=  KUP4K_PCMCIA_B_3V3; /* active low */
+
+	switch(vcc) {
+	case  0: 		break;
+	case 33:
+		cp->cp_pbdat &= ~KUP4K_PCMCIA_B_3V3;
+		debug ("PCMCIA powered at 3.3V\n");
+		break;
+	case 50:
+		debug ("PCMCIA: 5Volt vcc not supported\n");
+		break;
+	default:
+		puts("PCMCIA: vcc not supported");
+		break;
+	}
+
+	/* Checking supported voltages */
+
+	debug ("PIPR: 0x%x --> %s\n",
+		pcmp->pcmc_pipr,
+		(pcmp->pcmc_pipr & 0x00008000) 
+			? "only 5 V --> NOT SUPPORTED"
+			: "can do 3.3V");
+
+
+	debug ("Enable PCMCIA buffers and stop RESET\n");
+	reg  =  PCMCIA_PGCRX(_slot_);
+	reg &= ~__MY_PCMCIA_GCRX_CXRESET;	/* active high */
+	reg &= ~__MY_PCMCIA_GCRX_CXOE;		/* active low  */
+	PCMCIA_PGCRX(_slot_) = reg;
+	udelay(500);
+
+	debug ("voltage_set: " PCMCIA_BOARD_MSG " Slot %c, DONE\n",
+		slot+'A');
+	return (0);
+}
+
+#endif	/* KUP4K */
+
+
+
+
 
 /* ---------------------------------------------------------------------------- */
 /* End of Board Specific Stuff							*/
diff --git a/common/command.c b/common/command.c
index 2f50e6d..db39b41 100644
--- a/common/command.c
+++ b/common/command.c
@@ -68,6 +68,7 @@
 #include <cmd_dtt.h>
 
 #include <cmd_vfd.h>		/* load a bitmap to the VFDs on TRAB */
+#include <cmd_log.h>
 
 /*
  * HELP command
@@ -280,6 +281,7 @@
 	CMD_TBL_KGDB
 	CMD_TBL_LOADB
 	CMD_TBL_LOADS
+	CMD_TBL_LOG
 	CMD_TBL_LOOP
 	CMD_TBL_JFFS2_LS
 	CMD_TBL_MCCINFO
diff --git a/common/devices.c b/common/devices.c
index 2d0b046..8207f83 100644
--- a/common/devices.c
+++ b/common/devices.c
@@ -178,6 +178,9 @@
 #ifdef CONFIG_WL_4PPM_KEYBOARD
 	drv_wlkbd_init ();
 #endif
+#ifdef CONFIG_LOGBUFFER
+	drv_logbuff_init ();
+#endif
 	drv_system_init ();
 
 	gd-> flags |= GD_FLG_DEVINIT;	/* device initialization done */