[RFC 0/8] powerpc: Add initial arch/powerpc support for Marvell/mv64x60

9 messages, 1 author, 2007-03-28 · open the first message on its own page

[RFC 0/8] powerpc: Add initial arch/powerpc support for Marvell/mv64x60

From: Mark A. Greer <hidden>
Date: 2007-03-28 01:04:44

Hi,

The following set of patches add initial support for the Marvell
hostbridge (mv64x60) to the arch/powerpc code.  I did most of the
bootwrapper code and Dale Farnsworth did most of the kernel code.

Since the bootwrapper is moving so fast, we're sending these out for
comment but not asking for submission because they're already out of date.
They are based on Milton Miller's and Scott Woods patches from about a
week ago.  We'll try to respin on the latest patches every couple weeks
or so.

There will be another set of patches for the prpmc280/2800 which are
based on these patches coming shortly.

Mark
--

[RFC 1/8] powerpc: Add bootwrapper support for Marvell/mv64x60 hostbridge

From: Mark A. Greer <hidden>
Date: 2007-03-28 01:09:03

Signed-off-by: Mark A. Greer <redacted>
---

More will be added in future respins of this patch.

 Makefile  |    2 
 mv64x60.c |  252 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 mv64x60.h |   25 ++++++
 3 files changed, 278 insertions(+), 1 deletion(-)
---
diff --git a/arch/powerpc/boot/mv64x60.c b/arch/powerpc/boot/mv64x60.c
Index: powerpc/arch/powerpc/boot/mv64x60.c
===================================================================
--- /dev/null
+++ powerpc/arch/powerpc/boot/mv64x60.c
@@ -0,0 +1,252 @@
+/*
+ * Marvell hostbridge routines
+ *
+ * Author: Mark A. Greer <source@mvista.com>
+ *
+ * 2004, 2005, 2007 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include "types.h"
+#include "elf.h"
+#include "page.h"
+#include "string.h"
+#include "stdio.h"
+#include "io.h"
+#include "ops.h"
+#include "mv64x60.h"
+
+#define	MV64x60_CPU2MEM_WINDOWS			4
+#define	MV64x60_CPU_BAR_ENABLE			0x0278
+#define	MV64x60_CPU2MEM_0_BASE			0x0008
+#define	MV64x60_CPU2MEM_0_SIZE			0x0010
+#define	MV64x60_CPU2MEM_1_BASE			0x0208
+#define	MV64x60_CPU2MEM_1_SIZE			0x0210
+#define	MV64x60_CPU2MEM_2_BASE			0x0018
+#define	MV64x60_CPU2MEM_2_SIZE			0x0020
+#define	MV64x60_CPU2MEM_3_BASE			0x0218
+#define	MV64x60_CPU2MEM_3_SIZE			0x0220
+
+#define	MV64x60_ENET2MEM_BAR_ENABLE		0x2290
+#define	MV64x60_ENET2MEM_0_BASE			0x2200
+#define	MV64x60_ENET2MEM_0_SIZE			0x2204
+#define	MV64x60_ENET2MEM_1_BASE			0x2208
+#define	MV64x60_ENET2MEM_1_SIZE			0x220c
+#define	MV64x60_ENET2MEM_2_BASE			0x2210
+#define	MV64x60_ENET2MEM_2_SIZE			0x2214
+#define	MV64x60_ENET2MEM_3_BASE			0x2218
+#define	MV64x60_ENET2MEM_3_SIZE			0x221c
+#define	MV64x60_ENET2MEM_4_BASE			0x2220
+#define	MV64x60_ENET2MEM_4_SIZE			0x2224
+#define	MV64x60_ENET2MEM_5_BASE			0x2228
+#define	MV64x60_ENET2MEM_5_SIZE			0x222c
+#define	MV64x60_ENET2MEM_ACC_PROT_0		0x2294
+#define	MV64x60_ENET2MEM_ACC_PROT_1		0x2298
+#define	MV64x60_ENET2MEM_ACC_PROT_2		0x229c
+
+#define	MV64x60_MPSC2MEM_BAR_ENABLE		0xf250
+#define	MV64x60_MPSC2MEM_0_BASE			0xf200
+#define	MV64x60_MPSC2MEM_0_SIZE			0xf204
+#define	MV64x60_MPSC2MEM_1_BASE			0xf208
+#define	MV64x60_MPSC2MEM_1_SIZE			0xf20c
+#define	MV64x60_MPSC2MEM_2_BASE			0xf210
+#define	MV64x60_MPSC2MEM_2_SIZE			0xf214
+#define	MV64x60_MPSC2MEM_3_BASE			0xf218
+#define	MV64x60_MPSC2MEM_3_SIZE			0xf21c
+#define MV64x60_MPSC_0_REMAP			0xf240
+#define MV64x60_MPSC_1_REMAP			0xf244
+#define	MV64x60_MPSC2MEM_ACC_PROT_0		0xf254
+#define	MV64x60_MPSC2MEM_ACC_PROT_1		0xf258
+#define	MV64x60_MPSC2REGS_BASE			0xf25c
+
+#define	MV64x60_IDMA2MEM_BAR_ENABLE		0x0a80
+#define	MV64x60_IDMA2MEM_0_BASE			0x0a00
+#define	MV64x60_IDMA2MEM_0_SIZE			0x0a04
+#define	MV64x60_IDMA2MEM_1_BASE			0x0a08
+#define	MV64x60_IDMA2MEM_1_SIZE			0x0a0c
+#define	MV64x60_IDMA2MEM_2_BASE			0x0a10
+#define	MV64x60_IDMA2MEM_2_SIZE			0x0a14
+#define	MV64x60_IDMA2MEM_3_BASE			0x0a18
+#define	MV64x60_IDMA2MEM_3_SIZE			0x0a1c
+#define	MV64x60_IDMA2MEM_4_BASE			0x0a20
+#define	MV64x60_IDMA2MEM_4_SIZE			0x0a24
+#define	MV64x60_IDMA2MEM_5_BASE			0x0a28
+#define	MV64x60_IDMA2MEM_5_SIZE			0x0a2c
+#define	MV64x60_IDMA2MEM_6_BASE			0x0a30
+#define	MV64x60_IDMA2MEM_6_SIZE			0x0a34
+#define	MV64x60_IDMA2MEM_7_BASE			0x0a38
+#define	MV64x60_IDMA2MEM_7_SIZE			0x0a3c
+#define	MV64x60_IDMA2MEM_ACC_PROT_0		0x0a70
+#define	MV64x60_IDMA2MEM_ACC_PROT_1		0x0a74
+#define	MV64x60_IDMA2MEM_ACC_PROT_2		0x0a78
+#define	MV64x60_IDMA2MEM_ACC_PROT_3		0x0a7c
+
+static u32 cpu_base_reg[MV64x60_CPU2MEM_WINDOWS] = {
+	MV64x60_CPU2MEM_0_BASE, MV64x60_CPU2MEM_1_BASE,
+	MV64x60_CPU2MEM_2_BASE, MV64x60_CPU2MEM_3_BASE
+};
+
+static u32 cpu_size_reg[MV64x60_CPU2MEM_WINDOWS] = {
+	MV64x60_CPU2MEM_0_SIZE, MV64x60_CPU2MEM_1_SIZE,
+	MV64x60_CPU2MEM_2_SIZE, MV64x60_CPU2MEM_3_SIZE
+};
+
+static u32 enet_base_reg[MV64x60_CPU2MEM_WINDOWS] = {
+	MV64x60_ENET2MEM_0_BASE, MV64x60_ENET2MEM_1_BASE,
+	MV64x60_ENET2MEM_2_BASE, MV64x60_ENET2MEM_3_BASE
+};
+
+static u32 enet_size_reg[MV64x60_CPU2MEM_WINDOWS] = {
+	MV64x60_ENET2MEM_0_SIZE, MV64x60_ENET2MEM_1_SIZE,
+	MV64x60_ENET2MEM_2_SIZE, MV64x60_ENET2MEM_3_SIZE
+};
+
+static u32 mpsc_base_reg[MV64x60_CPU2MEM_WINDOWS] = {
+	MV64x60_MPSC2MEM_0_BASE, MV64x60_MPSC2MEM_1_BASE,
+	MV64x60_MPSC2MEM_2_BASE, MV64x60_MPSC2MEM_3_BASE
+};
+
+static u32 mpsc_size_reg[MV64x60_CPU2MEM_WINDOWS] = {
+	MV64x60_MPSC2MEM_0_SIZE, MV64x60_MPSC2MEM_1_SIZE,
+	MV64x60_MPSC2MEM_2_SIZE, MV64x60_MPSC2MEM_3_SIZE
+};
+
+static u32 idma_base_reg[MV64x60_CPU2MEM_WINDOWS] = {
+	MV64x60_IDMA2MEM_0_BASE, MV64x60_IDMA2MEM_1_BASE,
+	MV64x60_IDMA2MEM_2_BASE, MV64x60_IDMA2MEM_3_BASE
+};
+
+static u32 idma_size_reg[MV64x60_CPU2MEM_WINDOWS] = {
+	MV64x60_IDMA2MEM_0_SIZE, MV64x60_IDMA2MEM_1_SIZE,
+	MV64x60_IDMA2MEM_2_SIZE, MV64x60_IDMA2MEM_3_SIZE
+};
+
+static u32 dram_selects[MV64x60_CPU2MEM_WINDOWS] = { 0xe, 0xd, 0xb, 0x7 };
+
+/*
+ * ENET, MPSC, and IDMA ctlrs on the MV64x60 have separate windows that
+ * must be set up so that the respective ctlr can access system memory.
+ * Configure them to be same as cpu->memory windows.
+ */
+void mv64x60_config_ctlr_windows(u8 *bridge_base, u8 *bridge_pbase,
+		u8 cache_coherent)
+{
+	u32 i, base, size, enables, prot = 0, snoop_bits = 0;
+
+	out_le32((u32 *)(bridge_base + MV64x60_ENET2MEM_BAR_ENABLE), 0x3f);
+	out_le32((u32 *)(bridge_base + MV64x60_MPSC2MEM_BAR_ENABLE), 0xf);
+	out_le32((u32 *)(bridge_base + MV64x60_ENET2MEM_BAR_ENABLE), 0xff);
+
+	if (cache_coherent)
+		snoop_bits = 0x2 << 12; /* Writeback */
+
+	enables = in_le32((u32 *)(bridge_base + MV64x60_CPU_BAR_ENABLE)) & 0xf;
+
+	for (i=0; i<MV64x60_CPU2MEM_WINDOWS; i++) {
+		if (enables & (1 << i)) /* Set means disabled */
+			continue;
+
+		base = in_le32((u32 *)(bridge_base + cpu_base_reg[i])) << 16;
+		base |= snoop_bits | (dram_selects[i] << 8);
+		size = in_le32((u32 *)(bridge_base + cpu_size_reg[i])) << 16;
+		prot |= (0x3 << (i << 1)); /* RW access */
+
+		out_le32((u32 *)(bridge_base + enet_base_reg[i]), base);
+		out_le32((u32 *)(bridge_base + enet_size_reg[i]), size);
+		out_le32((u32 *)(bridge_base + mpsc_base_reg[i]), base);
+		out_le32((u32 *)(bridge_base + mpsc_size_reg[i]), size);
+		out_le32((u32 *)(bridge_base + idma_base_reg[i]), base);
+		out_le32((u32 *)(bridge_base + idma_size_reg[i]), size);
+	}
+
+	out_le32((u32 *)(bridge_base + MV64x60_ENET2MEM_ACC_PROT_0), prot);
+	out_le32((u32 *)(bridge_base + MV64x60_ENET2MEM_ACC_PROT_1), prot);
+	out_le32((u32 *)(bridge_base + MV64x60_ENET2MEM_ACC_PROT_2), prot);
+	out_le32((u32 *)(bridge_base + MV64x60_MPSC2MEM_ACC_PROT_0), prot);
+	out_le32((u32 *)(bridge_base + MV64x60_MPSC2MEM_ACC_PROT_1), prot);
+	out_le32((u32 *)(bridge_base + MV64x60_IDMA2MEM_ACC_PROT_0), prot);
+	out_le32((u32 *)(bridge_base + MV64x60_IDMA2MEM_ACC_PROT_1), prot);
+	out_le32((u32 *)(bridge_base + MV64x60_IDMA2MEM_ACC_PROT_2), prot);
+	out_le32((u32 *)(bridge_base + MV64x60_IDMA2MEM_ACC_PROT_3), prot);
+
+	/* Set mpsc->bridge's reg window to the bridge's internal registers. */
+	out_le32((u32 *)(bridge_base + MV64x60_MPSC2REGS_BASE),
+			(u32)bridge_pbase);
+
+	out_le32((u32 *)(bridge_base + MV64x60_ENET2MEM_BAR_ENABLE), enables);
+	out_le32((u32 *)(bridge_base + MV64x60_MPSC2MEM_BAR_ENABLE), enables);
+	out_le32((u32 *)(bridge_base + MV64x60_IDMA2MEM_BAR_ENABLE), enables);
+}
+
+/* Read mem ctlr to get the amount of mem in system */
+u32 mv64x60_get_mem_size(u8 *bridge_base)
+{
+	u32 enables, i, v;
+	u32 mem = 0;
+
+	enables = in_le32((u32 *)(bridge_base + MV64x60_CPU_BAR_ENABLE)) & 0xf;
+
+	for (i=0; i<MV64x60_CPU2MEM_WINDOWS; i++)
+		if (!(enables & (1<<i))) {
+			v = in_le32((u32*)(bridge_base + cpu_size_reg[i]));
+			v = ((v & 0xffff) + 1) << 16;
+			mem += v;
+		}
+
+	return mem;
+}
+
+/* Get physical address of bridge's registers */
+u8 *mv64x60_get_bridge_pbase(void)
+{
+	u32 v[2];
+	void *devp;
+
+	devp = finddevice("/mv64x60");
+	if (devp == NULL)
+		goto err_out;
+	if (getprop(devp, "reg", v, sizeof(v)) != sizeof(v))
+		goto err_out;
+
+	return (u8 *)v[0];
+
+err_out:
+	return 0;
+}
+
+/* Get virtual address of bridge's registers */
+u8 *mv64x60_get_bridge_base(void)
+{
+	u32 v;
+	void *devp;
+
+	devp = finddevice("/mv64x60");
+	if (devp == NULL)
+		goto err_out;
+	if (getprop(devp, "virtual-reg", &v, sizeof(v)) != sizeof(v))
+		goto err_out;
+
+	return (u8 *)v;
+
+err_out:
+	return 0;
+}
+
+u8 mv64x60_is_coherency(void)
+{
+	u32 v;
+	void *devp;
+
+	devp = finddevice("/");
+	if (devp == NULL)
+		return 1; /* Assume coherency on */
+
+	if (getprop(devp, "coherency-off", &v, sizeof(v)) < 0)
+		return 1; /* Coherency on */
+	else
+		return 0;
+}
Index: powerpc/arch/powerpc/boot/mv64x60.h
===================================================================
--- /dev/null
+++ powerpc/arch/powerpc/boot/mv64x60.h
@@ -0,0 +1,25 @@
+/*
+ * Author: Mark A. Greer <source@mvista.com>
+ *
+ * 2007 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#ifndef _PPC_BOOT_MV64x60_H_
+#define _PPC_BOOT_MV64x60_H_
+
+void mv64x60_config_ctlr_windows(u8 *bridge_base, u8 *bridge_pbase,
+		u8 cache_coherent);
+u32 mv64x60_get_mem_size(u8 *bridge_base);
+u8 *mv64x60_get_bridge_pbase(void);
+u8 *mv64x60_get_bridge_base(void);
+u8 mv64x60_is_coherency(void);
+
+int mv64x60_i2c_open(void);
+int mv64x60_i2c_read(u32 devaddr, u8 *buf, u32 offset, u32 offset_size,
+		u32 count);
+void mv64x60_i2c_close(void);
+
+#endif /* _PPC_BOOT_MV64x60_H_ */
Index: powerpc/arch/powerpc/boot/Makefile
===================================================================
--- powerpc.orig/arch/powerpc/boot/Makefile
+++ powerpc/arch/powerpc/boot/Makefile
@@ -42,7 +42,7 @@ $(addprefix $(obj)/,$(zlib) main.o): $(a
 
 src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \
 		ns16550.c serial.c simple_alloc.c div64.S util.S \
-		gunzip_util.c devtree.c elf_util.c $(zlib)
+		gunzip_util.c devtree.c elf_util.c mv64x60.c $(zlib)
 cuboot-plats := 83xx
 src-plat := of.c $(cuboot-plats:%=cuboot-%.c)
 src-boot := $(src-wlib) $(src-plat) empty.c

[RFC 2/8] powerpc: Add bootwrapper support for Marvell MPSC

From: Mark A. Greer <hidden>
Date: 2007-03-28 01:09:43

Signed-off-by: Mark A. Greer <redacted>
---

 Makefile |    2 
 mpsc.c   |  170 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 ops.h    |    1 
 serial.c |    2 
 4 files changed, 174 insertions(+), 1 deletion(-)
---
diff --git a/arch/powerpc/boot/mpsc.c b/arch/powerpc/boot/mpsc.c
Index: powerpc/arch/powerpc/boot/mpsc.c
===================================================================
--- /dev/null
+++ powerpc/arch/powerpc/boot/mpsc.c
@@ -0,0 +1,170 @@
+/*
+ * MPSC/UART driver for the Marvell mv64360, mv64460, ...
+ *
+ * Author: Mark A. Greer <mgreer@mvista.com>
+ *
+ * 2007 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include "types.h"
+#include "string.h"
+#include "stdio.h"
+#include "io.h"
+#include "ops.h"
+
+extern void udelay(long delay);
+
+#define	MPSC_CHR_1		0x000c
+
+#define	MPSC_CHR_2		0x0010
+#define	MPSC_CHR_2_TA		(1<<7)
+#define	MPSC_CHR_2_TCS		(1<<9)
+#define	MPSC_CHR_2_RA		(1<<23)
+#define	MPSC_CHR_2_CRD		(1<<25)
+#define	MPSC_CHR_2_EH		(1<<31)
+
+#define	MPSC_CHR_4		0x0018
+#define	MPSC_CHR_4_Z		(1<<29)
+
+#define	MPSC_CHR_5		0x001c
+#define	MPSC_CHR_5_CTL1_INTR	(1<<12)
+#define	MPSC_CHR_5_CTL1_VALID	(1<<15)
+
+#define	MPSC_CHR_10		0x0030
+
+#define	MPSC_INTR_CAUSE		0x0000
+#define	MPSC_INTR_CAUSE_RCC	(1<<6)
+#define	MPSC_INTR_MASK		0x0080
+
+#define	SDMA_SDCM		0x0008
+#define	SDMA_SDCM_AR		(1<<15)
+#define	SDMA_SDCM_AT		(1<<31)
+
+static volatile char *mpsc_base;
+static volatile char *mpscintr_base;
+static u32 chr1, chr2;
+
+static int mpsc_open(void)
+{
+	chr1 = in_le32((u32 *)(mpsc_base + MPSC_CHR_1)) & 0x00ff0000;
+	chr2 = in_le32((u32 *)(mpsc_base + MPSC_CHR_2)) & ~(MPSC_CHR_2_TA
+			| MPSC_CHR_2_TCS | MPSC_CHR_2_RA | MPSC_CHR_2_CRD
+			| MPSC_CHR_2_EH);
+	out_le32((u32 *)(mpsc_base + MPSC_CHR_4), MPSC_CHR_4_Z);
+	out_le32((u32 *)(mpsc_base + MPSC_CHR_5),
+			MPSC_CHR_5_CTL1_INTR | MPSC_CHR_5_CTL1_VALID);
+	out_le32((u32 *)(mpsc_base + MPSC_CHR_2), chr2 | MPSC_CHR_2_EH);
+	return 0;
+}
+
+static void mpsc_putc(unsigned char c)
+{
+	while (in_le32((u32 *)(mpsc_base + MPSC_CHR_2)) & MPSC_CHR_2_TCS);
+
+	out_le32((u32 *)(mpsc_base + MPSC_CHR_1), chr1 | c);
+	out_le32((u32 *)(mpsc_base + MPSC_CHR_2), chr2 | MPSC_CHR_2_TCS);
+}
+
+static unsigned char mpsc_getc(void)
+{
+	u32 cause = 0;
+	unsigned char c;
+
+	while (!(cause & MPSC_INTR_CAUSE_RCC))
+		cause = in_le32((u32 *)(mpscintr_base + MPSC_INTR_CAUSE));
+
+	c = in_8((u8 *)(mpsc_base + MPSC_CHR_10 + 2));
+	out_8((u8 *)(mpsc_base + MPSC_CHR_10 + 2), c);
+	out_le32((u32 *)(mpscintr_base + MPSC_INTR_CAUSE),
+			cause & ~MPSC_INTR_CAUSE_RCC);
+
+	return c;
+}
+
+static u8 mpsc_tstc(void)
+{
+	return (u8)((in_le32((u32 *)(mpscintr_base + MPSC_INTR_CAUSE))
+				& MPSC_INTR_CAUSE_RCC) != 0);
+}
+
+static void mpsc_stop_dma(volatile char *sdma_base)
+{
+	out_le32((u32 *)(mpsc_base + MPSC_CHR_2),MPSC_CHR_2_TA | MPSC_CHR_2_RA);
+	out_le32((u32 *)(sdma_base + SDMA_SDCM), SDMA_SDCM_AR | SDMA_SDCM_AT);
+
+	while ((in_le32((u32 *)(sdma_base + SDMA_SDCM))
+				& (SDMA_SDCM_AR | SDMA_SDCM_AT)) != 0)
+		udelay(100);
+}
+
+static volatile char *mpsc_get_virtreg_of_phandle(void *devp, char *prop)
+{
+	void *v;
+	int n;
+
+	n = getprop(devp, prop, &v, sizeof(v));
+	if (n != sizeof(v))
+		goto err_out;
+
+	devp = find_node_by_linuxphandle((u32)v);
+	if (devp == NULL)
+		goto err_out;
+
+	n = getprop(devp, "virtual-reg", &v, sizeof(v));
+	if (n == sizeof(v))
+		return v;
+
+err_out:
+	return NULL;
+}
+
+int mpsc_console_init(void *devp, struct serial_console_data *scdp)
+{
+	void *v;
+	int n, reg_set;
+	volatile char *sdma_base;
+
+	n = getprop(devp, "virtual-reg", &v, sizeof(v));
+	if (n != sizeof(v))
+		goto err_out;
+	mpsc_base = v;
+
+	sdma_base = mpsc_get_virtreg_of_phandle(devp, "sdma");
+	if (sdma_base == NULL)
+		goto err_out;
+
+	mpscintr_base = mpsc_get_virtreg_of_phandle(devp, "mpscintr");
+	if (mpscintr_base == NULL)
+		goto err_out;
+
+	n = getprop(devp, "block-index", &v, sizeof(v));
+	if (n != sizeof(v))
+		goto err_out;
+	reg_set = (int)v;
+
+	mpscintr_base += (reg_set == 0) ? 0x4 : 0xc;
+
+	/* Make sure the mpsc ctlrs are shutdown */
+	out_le32((u32 *)(mpscintr_base + MPSC_INTR_CAUSE), 0);
+	out_le32((u32 *)(mpscintr_base + MPSC_INTR_CAUSE), 0);
+	out_le32((u32 *)(mpscintr_base + MPSC_INTR_MASK), 0);
+	out_le32((u32 *)(mpscintr_base + MPSC_INTR_MASK), 0);
+
+	mpsc_stop_dma(sdma_base);
+
+	scdp->open = mpsc_open;
+	scdp->putc = mpsc_putc;
+	scdp->getc = mpsc_getc;
+	scdp->tstc = mpsc_tstc;
+	scdp->close = NULL;
+
+	return 0;
+
+err_out:
+	return -1;
+}
Index: powerpc/arch/powerpc/boot/serial.c
===================================================================
--- powerpc.orig/arch/powerpc/boot/serial.c
+++ powerpc/arch/powerpc/boot/serial.c
@@ -125,6 +125,8 @@ int serial_console_init(void)
 
 	if (!strcmp(compat, "ns16550"))
 		rc = ns16550_console_init(devp, &serial_cd);
+	else if (!strcmp(compat, "mpsc"))
+		rc = mpsc_console_init(devp, &serial_cd);
 
 	/* Add other serial console driver calls here */
 
Index: powerpc/arch/powerpc/boot/Makefile
===================================================================
--- powerpc.orig/arch/powerpc/boot/Makefile
+++ powerpc/arch/powerpc/boot/Makefile
@@ -42,7 +42,7 @@ $(addprefix $(obj)/,$(zlib) main.o): $(a
 
 src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \
 		ns16550.c serial.c simple_alloc.c div64.S util.S \
-		gunzip_util.c devtree.c elf_util.c mv64x60.c $(zlib)
+		gunzip_util.c devtree.c elf_util.c mv64x60.c mpsc.c $(zlib)
 cuboot-plats := 83xx
 src-plat := of.c $(cuboot-plats:%=cuboot-%.c)
 src-boot := $(src-wlib) $(src-plat) empty.c
Index: powerpc/arch/powerpc/boot/ops.h
===================================================================
--- powerpc.orig/arch/powerpc/boot/ops.h
+++ powerpc/arch/powerpc/boot/ops.h
@@ -77,6 +77,7 @@ void start(void *sp);
 int ft_init(void *dt_blob, unsigned int max_size, unsigned int max_find_device);
 int serial_console_init(void);
 int ns16550_console_init(void *devp, struct serial_console_data *scdp);
+int mpsc_console_init(void *devp, struct serial_console_data *scdp);
 void *simple_alloc_init(char *base, u32 heap_size, u32 granularity,
 		u32 max_allocs);
 int xlate_reg(void *node, int res, unsigned long *addr, unsigned long *size);

[RFC 3/8] powerpc: Add bootwrapper support for Marvell/mv64x60 I2C

From: Mark A. Greer <hidden>
Date: 2007-03-28 01:10:19

Signed-off-by: Mark A. Greer <redacted>
---

 Makefile      |    3 
 mv64x60_i2c.c |  206 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 208 insertions(+), 1 deletion(-)
---
diff --git a/arch/powerpc/boot/mv64x60_i2c.c b/arch/powerpc/boot/mv64x60_i2c.c
Index: powerpc/arch/powerpc/boot/mv64x60_i2c.c
===================================================================
--- /dev/null
+++ powerpc/arch/powerpc/boot/mv64x60_i2c.c
@@ -0,0 +1,206 @@
+/*
+ * Bootloader version of the i2c driver for the MV64x60.
+ *
+ * Author: Dale Farnsworth <dfarnsworth@mvista.com>
+ * Maintained by: Mark A. Greer <mgreer@mvista.com>
+ *
+ * 2003, 2007 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program is
+ * licensed "as is" without any warranty of any kind, whether express or
+ * implied.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include "types.h"
+#include "elf.h"
+#include "page.h"
+#include "string.h"
+#include "stdio.h"
+#include "io.h"
+#include "ops.h"
+#include "mv64x60.h"
+
+extern void udelay(long);
+
+/* Register defines */
+#define	MV64x60_I2C_REG_SLAVE_ADDR			0x00
+#define	MV64x60_I2C_REG_DATA				0x04
+#define	MV64x60_I2C_REG_CONTROL				0x08
+#define	MV64x60_I2C_REG_STATUS				0x0c
+#define	MV64x60_I2C_REG_BAUD				0x0c
+#define	MV64x60_I2C_REG_EXT_SLAVE_ADDR			0x10
+#define	MV64x60_I2C_REG_SOFT_RESET			0x1c
+
+#define	MV64x60_I2C_CONTROL_ACK				0x04
+#define	MV64x60_I2C_CONTROL_IFLG			0x08
+#define	MV64x60_I2C_CONTROL_STOP			0x10
+#define	MV64x60_I2C_CONTROL_START			0x20
+#define	MV64x60_I2C_CONTROL_TWSIEN			0x40
+#define	MV64x60_I2C_CONTROL_INTEN			0x80
+
+#define	MV64x60_I2C_STATUS_BUS_ERR			0x00
+#define	MV64x60_I2C_STATUS_MAST_START			0x08
+#define	MV64x60_I2C_STATUS_MAST_REPEAT_START		0x10
+#define	MV64x60_I2C_STATUS_MAST_WR_ADDR_ACK		0x18
+#define	MV64x60_I2C_STATUS_MAST_WR_ADDR_NO_ACK		0x20
+#define	MV64x60_I2C_STATUS_MAST_WR_ACK			0x28
+#define	MV64x60_I2C_STATUS_MAST_WR_NO_ACK		0x30
+#define	MV64x60_I2C_STATUS_MAST_LOST_ARB		0x38
+#define	MV64x60_I2C_STATUS_MAST_RD_ADDR_ACK		0x40
+#define	MV64x60_I2C_STATUS_MAST_RD_ADDR_NO_ACK		0x48
+#define	MV64x60_I2C_STATUS_MAST_RD_DATA_ACK		0x50
+#define	MV64x60_I2C_STATUS_MAST_RD_DATA_NO_ACK		0x58
+#define	MV64x60_I2C_STATUS_MAST_WR_ADDR_2_ACK		0xd0
+#define	MV64x60_I2C_STATUS_MAST_WR_ADDR_2_NO_ACK	0xd8
+#define	MV64x60_I2C_STATUS_MAST_RD_ADDR_2_ACK		0xe0
+#define	MV64x60_I2C_STATUS_MAST_RD_ADDR_2_NO_ACK	0xe8
+#define	MV64x60_I2C_STATUS_NO_STATUS			0xf8
+
+static u8 *ctlr_base;
+
+static int mv64x60_i2c_wait_for_status(int wanted)
+{
+	int i;
+	int status;
+
+	for (i=0; i<1000; i++) {
+		udelay(10);
+		status = in_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_STATUS))
+			& 0xff;
+		if (status == wanted)
+			return status;
+	}
+	return -status;
+}
+
+static int mv64x60_i2c_control(int control, int status)
+{
+	out_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_CONTROL), control & 0xff);
+	return mv64x60_i2c_wait_for_status(status);
+}
+
+static int mv64x60_i2c_read_byte(int control, int status)
+{
+	out_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_CONTROL), control & 0xff);
+	if (mv64x60_i2c_wait_for_status(status) < 0)
+		return -1;
+	return in_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_DATA)) & 0xff;
+}
+
+static int mv64x60_i2c_write_byte(int data, int control, int status)
+{
+	out_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_DATA), data & 0xff);
+	out_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_CONTROL), control & 0xff);
+	return mv64x60_i2c_wait_for_status(status);
+}
+
+int mv64x60_i2c_read(u32 devaddr, u8 *buf, u32 offset, u32 offset_size,
+		 u32 count)
+{
+	int i;
+	int data;
+	int control;
+	int status;
+
+	if (ctlr_base == NULL)
+		return -1;
+
+	/* send reset */
+	out_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_SOFT_RESET), 0);
+	out_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_SLAVE_ADDR), 0);
+	out_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_EXT_SLAVE_ADDR), 0);
+	out_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_BAUD), (4 << 3) | 0x4);
+
+	if (mv64x60_i2c_control(MV64x60_I2C_CONTROL_TWSIEN,
+				MV64x60_I2C_STATUS_NO_STATUS) < 0)
+		return -1;
+
+	/* send start */
+	control = MV64x60_I2C_CONTROL_START | MV64x60_I2C_CONTROL_TWSIEN;
+	status = MV64x60_I2C_STATUS_MAST_START;
+	if (mv64x60_i2c_control(control, status) < 0)
+		return -1;
+
+	/* select device for writing */
+	data = devaddr & ~0x1;
+	control = MV64x60_I2C_CONTROL_TWSIEN;
+	status = MV64x60_I2C_STATUS_MAST_WR_ADDR_ACK;
+	if (mv64x60_i2c_write_byte(data, control, status) < 0)
+		return -1;
+
+	/* send offset of data */
+	control = MV64x60_I2C_CONTROL_TWSIEN;
+	status = MV64x60_I2C_STATUS_MAST_WR_ACK;
+	if (offset_size > 1) {
+		if (mv64x60_i2c_write_byte(offset >> 8, control, status) < 0)
+			return -1;
+	}
+	if (mv64x60_i2c_write_byte(offset, control, status) < 0)
+		return -1;
+
+	/* resend start */
+	control = MV64x60_I2C_CONTROL_START | MV64x60_I2C_CONTROL_TWSIEN;
+	status = MV64x60_I2C_STATUS_MAST_REPEAT_START;
+	if (mv64x60_i2c_control(control, status) < 0)
+		return -1;
+
+	/* select device for reading */
+	data = devaddr | 0x1;
+	control = MV64x60_I2C_CONTROL_TWSIEN;
+	status = MV64x60_I2C_STATUS_MAST_RD_ADDR_ACK;
+	if (mv64x60_i2c_write_byte(data, control, status) < 0)
+		return -1;
+
+	/* read all but last byte of data */
+	control = MV64x60_I2C_CONTROL_ACK | MV64x60_I2C_CONTROL_TWSIEN;
+	status = MV64x60_I2C_STATUS_MAST_RD_DATA_ACK;
+
+	for (i=1; i<count; i++) {
+		data = mv64x60_i2c_read_byte(control, status);
+		if (data < 0) {
+			printf("errors on iteration %d\n", i);
+			return -1;
+		}
+		*buf++ = data;
+	}
+
+	/* read last byte of data */
+	control = MV64x60_I2C_CONTROL_TWSIEN;
+	status = MV64x60_I2C_STATUS_MAST_RD_DATA_NO_ACK;
+	data = mv64x60_i2c_read_byte(control, status);
+	if (data < 0)
+		return -1;
+	*buf++ = data;
+
+	/* send stop */
+	control = MV64x60_I2C_CONTROL_STOP | MV64x60_I2C_CONTROL_TWSIEN;
+	status = MV64x60_I2C_STATUS_NO_STATUS;
+	if (mv64x60_i2c_control(control, status) < 0)
+		return -1;
+
+	return count;
+}
+
+int mv64x60_i2c_open(void)
+{
+	u32 v;
+	void *devp;
+
+	devp = finddevice("/mv64x60/i2c");
+	if (devp == NULL)
+		goto err_out;
+	if (getprop(devp, "virtual-reg", &v, sizeof(v)) != sizeof(v))
+		goto err_out;
+
+	ctlr_base = (u8 *)v;
+	return 0;
+
+err_out:
+	return -1;
+}
+
+void mv64x60_i2c_close(void)
+{
+	ctlr_base = NULL;
+}
Index: powerpc/arch/powerpc/boot/Makefile
===================================================================
--- powerpc.orig/arch/powerpc/boot/Makefile
+++ powerpc/arch/powerpc/boot/Makefile
@@ -42,7 +42,8 @@ $(addprefix $(obj)/,$(zlib) main.o): $(a
 
 src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \
 		ns16550.c serial.c simple_alloc.c div64.S util.S \
-		gunzip_util.c devtree.c elf_util.c mv64x60.c mpsc.c $(zlib)
+		gunzip_util.c devtree.c elf_util.c mv64x60.c mpsc.c \
+		mv64x60_i2c.c $(zlib)
 cuboot-plats := 83xx
 src-plat := of.c $(cuboot-plats:%=cuboot-%.c)
 src-boot := $(src-wlib) $(src-plat) empty.c

[RFC 4/8] powerpc: Add arch/powerpc support for Marvell/mv64x60 hostbridge

From: Mark A. Greer <hidden>
Date: 2007-03-28 01:10:53

From: Dale Farnsworth <redacted>

Signed-off-by: Dale Farnsworth <redacted>
---

 platforms/embedded6xx/Kconfig |   32 ----
 sysdev/Makefile               |    1 
 sysdev/mv64x60.c              |  318 ++++++++++++++++++++++++++++++++++++++++++
 sysdev/mv64x60.h              |    9 +
 4 files changed, 330 insertions(+), 30 deletions(-)
---

Index: linux-2.6-powerpc-df/arch/powerpc/sysdev/Makefile
===================================================================
--- linux-2.6-powerpc-df.orig/arch/powerpc/sysdev/Makefile
+++ linux-2.6-powerpc-df/arch/powerpc/sysdev/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_MMIO_NVRAM)	+= mmio_nvram.o
 obj-$(CONFIG_FSL_SOC)		+= fsl_soc.o
 obj-$(CONFIG_TSI108_BRIDGE)	+= tsi108_pci.o tsi108_dev.o
 obj-$(CONFIG_QUICC_ENGINE)	+= qe_lib/
+obj-$(CONFIG_MV64X60)		+= mv64x60.o
 
 ifeq ($(CONFIG_PPC_MERGE),y)
 obj-$(CONFIG_PPC_I8259)		+= i8259.o
Index: linux-2.6-powerpc-df/arch/powerpc/sysdev/mv64x60.c
===================================================================
--- /dev/null
+++ linux-2.6-powerpc-df/arch/powerpc/sysdev/mv64x60.c
@@ -0,0 +1,318 @@
+/*
+ * Common routines for the Marvell mv64360/mv64460 host bridges (Discovery)
+ *
+ * Author: Dale Farnsworth <dale@farnsworth.org>
+ *
+ * 2007 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ * Note that SMP is not currently supported.
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/irq.h>
+#include <asm/machdep.h>
+
+#include "mv64x60.h"
+
+/* Interrupt Controller Interface Registers */
+#define MV64X60_IC_MAIN_CAUSE_LO	0x0004
+#define MV64X60_IC_MAIN_CAUSE_HI	0x000c
+#define MV64X60_IC_CPU0_INTR_MASK_LO	0x0014
+#define MV64X60_IC_CPU0_INTR_MASK_HI	0x001c
+#define MV64X60_IC_CPU0_SELECT_CAUSE	0x0024
+
+#define MV64X60_HIGH_GPP_GROUPS		0x0f000000
+#define MV64X60_SELECT_CAUSE_HIGH	0x40000000
+
+/* General Purpose Pins Controller Interface Registers */
+#define MV64x60_GPP_INTR_CAUSE		0x0008
+#define MV64x60_GPP_INTR_MASK		0x000c
+
+#define MV64x60_LEVEL1_LOW		0
+#define MV64x60_LEVEL1_HIGH		1
+#define MV64x60_LEVEL1_GPP		2
+
+#define MV64x60_LEVEL1_MASK		0x00000060
+#define MV64x60_LEVEL1_OFFSET		5
+
+#define MV64x60_LEVEL2_MASK		0x0000001f
+
+#define MV64x60_NUM_IRQS		96
+
+static void __iomem *mv64x60_irq_reg_base;
+static void __iomem *mv64x60_gpp_reg_base;
+
+/*
+ * Interrupt Controller Handling
+ *
+ * The interrupt controller handles three groups of interrupts:
+ *   main low:	IRQ0-IRQ31
+ *   main high:	IRQ32-IRQ63
+ *   gpp:	IRQ64-IRQ95
+ *
+ * This code handles interrupts in two levels.  Level 1 selects the
+ * interrupt group, and level 2 selects an IRQ within that group.
+ * Each group has its own irq_chip structure.
+ */
+
+static u32 mv64x60_cached_low_mask  = 0;
+static u32 mv64x60_cached_high_mask = MV64X60_HIGH_GPP_GROUPS;
+static u32 mv64x60_cached_gpp_mask  = 0;
+
+static struct irq_host *mv64x60_irq_host;
+
+/*
+ * mv64x60_chip_low functions
+ */
+
+static void mv64x60_mask_low(unsigned int virq)
+{
+	int level2 = irq_map[virq].hwirq & MV64x60_LEVEL2_MASK;
+
+	mv64x60_cached_low_mask &= ~(1 << level2);
+	out_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_LO,
+		 mv64x60_cached_low_mask);
+	(void)in_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_LO);
+}
+
+static void mv64x60_unmask_low(unsigned int virq)
+{
+	int level2 = irq_map[virq].hwirq & MV64x60_LEVEL2_MASK;
+
+	mv64x60_cached_low_mask |= 1 << level2;
+	out_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_LO,
+		 mv64x60_cached_low_mask);
+	(void)in_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_LO);
+}
+
+static struct irq_chip mv64x60_chip_low = {
+	.name		= "mv64x60_low",
+	.mask		= mv64x60_mask_low,
+	.mask_ack	= mv64x60_mask_low,
+	.unmask		= mv64x60_unmask_low,
+};
+
+/*
+ * mv64x60_chip_high functions
+ */
+
+static void mv64x60_mask_high(unsigned int virq)
+{
+	int level2 = irq_map[virq].hwirq & MV64x60_LEVEL2_MASK;
+
+	mv64x60_cached_high_mask &= ~(1 << level2);
+	out_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_HI,
+		 mv64x60_cached_high_mask);
+	(void)in_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_HI);
+}
+
+static void mv64x60_unmask_high(unsigned int virq)
+{
+	int level2 = irq_map[virq].hwirq & MV64x60_LEVEL2_MASK;
+
+	mv64x60_cached_high_mask |= 1 << level2;
+	out_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_HI,
+		 mv64x60_cached_high_mask);
+	(void)in_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_HI);
+}
+
+static struct irq_chip mv64x60_chip_high = {
+	.name		= "mv64x60_high",
+	.mask		= mv64x60_mask_high,
+	.mask_ack	= mv64x60_mask_high,
+	.unmask		= mv64x60_unmask_high,
+};
+
+/*
+ * mv64x60_chip_gpp functions
+ */
+
+static void mv64x60_mask_gpp(unsigned int virq)
+{
+	int level2 = irq_map[virq].hwirq & MV64x60_LEVEL2_MASK;
+
+	mv64x60_cached_gpp_mask &= ~(1 << level2);
+	out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_MASK,
+		 mv64x60_cached_gpp_mask);
+	(void)in_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_MASK);
+}
+
+static void mv64x60_mask_ack_gpp(unsigned int virq)
+{
+	int level2 = irq_map[virq].hwirq & MV64x60_LEVEL2_MASK;
+
+	mv64x60_cached_gpp_mask &= ~(1 << level2);
+	out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_MASK,
+		 mv64x60_cached_gpp_mask);
+	out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_CAUSE,
+		 ~(1 << level2));
+	(void)in_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_CAUSE);
+}
+
+static void mv64x60_unmask_gpp(unsigned int virq)
+{
+	int level2 = irq_map[virq].hwirq & MV64x60_LEVEL2_MASK;
+
+	mv64x60_cached_gpp_mask |= 1 << level2;
+	out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_MASK,
+		 mv64x60_cached_gpp_mask);
+	(void)in_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_MASK);
+}
+
+static struct irq_chip mv64x60_chip_gpp = {
+	.name		= "mv64x60_gpp",
+	.mask		= mv64x60_mask_gpp,
+	.mask_ack	= mv64x60_mask_ack_gpp,
+	.unmask		= mv64x60_unmask_gpp,
+};
+
+/*
+ * mv64x60_host_ops functions
+ */
+
+static int mv64x60_host_match(struct irq_host *h, struct device_node *np)
+{
+	return mv64x60_irq_host->host_data == np;
+}
+
+static struct irq_chip *mv64x60_chips[] = {
+	[MV64x60_LEVEL1_LOW]  = &mv64x60_chip_low,
+	[MV64x60_LEVEL1_HIGH] = &mv64x60_chip_high,
+	[MV64x60_LEVEL1_GPP]  = &mv64x60_chip_gpp,
+};
+
+static int mv64x60_host_map(struct irq_host *h, unsigned int virq,
+			  irq_hw_number_t hwirq)
+{
+	int level1;
+
+	get_irq_desc(virq)->status |= IRQ_LEVEL;
+
+	level1 = (hwirq & MV64x60_LEVEL1_MASK) >> MV64x60_LEVEL1_OFFSET;
+	BUG_ON(level1 > MV64x60_LEVEL1_GPP);
+	set_irq_chip_and_handler(virq, mv64x60_chips[level1], handle_level_irq);
+
+	return 0;
+}
+
+static struct irq_host_ops mv64x60_host_ops = {
+	.match = mv64x60_host_match,
+	.map   = mv64x60_host_map,
+};
+
+/*
+ * Global functions
+ */
+
+void __init mv64x60_init_irq(void)
+{
+	struct device_node *np;
+	phys_addr_t paddr;
+	unsigned int size;
+	const unsigned int *reg;
+
+	np = of_find_compatible_node(NULL, "mv64x60-gpp", "mv64x60-gpp");
+	reg = get_property(np, "reg", &size);
+	paddr = of_translate_address(np, reg);
+	mv64x60_gpp_reg_base = ioremap(paddr, reg[1]);
+	of_node_put(np);
+
+	np = of_find_compatible_node(NULL, "mv64x60-pic", "mv64x60-pic");
+	reg = get_property(np, "reg", &size);
+	paddr = of_translate_address(np, reg);
+	of_node_put(np);
+	mv64x60_irq_reg_base = ioremap(paddr, reg[1]);
+
+	mv64x60_irq_host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, MV64x60_NUM_IRQS,
+					  &mv64x60_host_ops, MV64x60_NUM_IRQS);
+
+	mv64x60_irq_host->host_data = np;
+
+	out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_MASK,
+		 mv64x60_cached_gpp_mask);
+	out_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_LO,
+		 mv64x60_cached_low_mask);
+	out_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_HI,
+		 mv64x60_cached_high_mask);
+
+	out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_CAUSE, 0);
+	out_le32(mv64x60_irq_reg_base + MV64X60_IC_MAIN_CAUSE_LO, 0);
+	out_le32(mv64x60_irq_reg_base + MV64X60_IC_MAIN_CAUSE_HI, 0);
+}
+
+unsigned int mv64x60_get_irq(void)
+{
+	u32 cause;
+	int level1;
+	irq_hw_number_t hwirq;
+	int virq = NO_IRQ;
+
+	cause = in_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_SELECT_CAUSE);
+	if (cause & MV64X60_SELECT_CAUSE_HIGH) {
+		cause &= mv64x60_cached_high_mask;
+		level1 = MV64x60_LEVEL1_HIGH;
+		if (cause & MV64X60_HIGH_GPP_GROUPS) {
+			cause = in_le32(mv64x60_gpp_reg_base +
+					MV64x60_GPP_INTR_CAUSE);
+			cause &= mv64x60_cached_gpp_mask;
+			level1 = MV64x60_LEVEL1_GPP;
+		}
+	} else {
+		cause &= mv64x60_cached_low_mask;
+		level1 = MV64x60_LEVEL1_LOW;
+	}
+	if (cause) {
+		hwirq = (level1 << MV64x60_LEVEL1_OFFSET) | __ilog2(cause);
+		virq = irq_linear_revmap(mv64x60_irq_host, hwirq);
+	}
+
+	return virq;
+}
+
+/*
+ * The bootwrapper sets the coherency of the DMA windows according to
+ * the setting in the device tree.  For the kernel, coherency is a
+ * compile-time configuration option.  Fail if there is a mismatch.
+ */
+
+#ifdef CONFIG_NOT_COHERENT_CACHE
+#define KERNEL_COHERENCY	0
+#else
+#define KERNEL_COHERENCY	1
+#endif
+
+int __init mv64x60_verify_cache_coherency(void)
+{
+	struct device_node *np;
+	const void *prop;
+	int devtree_coherency;
+
+	np = of_find_node_by_path("/");
+	prop = get_property(np, "coherency-off", NULL);
+	of_node_put(np);
+
+	devtree_coherency = prop ? 0 : 1;
+
+	if (devtree_coherency != KERNEL_COHERENCY) {
+		printk(KERN_ERR
+			"kernel coherency:%s != device tree_coherency:%s\n",
+			KERNEL_COHERENCY ? "on" : "off",
+			devtree_coherency ? "on" : "off");
+		BUG();
+	}
+
+	return 0;
+}
+
+late_initcall(mv64x60_verify_cache_coherency);
Index: linux-2.6-powerpc-df/arch/powerpc/sysdev/mv64x60.h
===================================================================
--- /dev/null
+++ linux-2.6-powerpc-df/arch/powerpc/sysdev/mv64x60.h
@@ -0,0 +1,9 @@
+#ifndef __MV64X60_H__
+#define __MV64X60_H__
+
+#include <linux/init.h>
+
+extern void __init mv64x60_init_irq(void);
+extern unsigned int mv64x60_get_irq(void);
+
+#endif /* __MV64X60_H__ */
Index: linux-2.6-powerpc-df/arch/powerpc/platforms/embedded6xx/Kconfig
===================================================================
--- linux-2.6-powerpc-df.orig/arch/powerpc/platforms/embedded6xx/Kconfig
+++ linux-2.6-powerpc-df/arch/powerpc/platforms/embedded6xx/Kconfig
@@ -208,26 +208,14 @@ config FORCE
 	depends on 6xx && POWERPMC250
 	default y
 
-config GT64260
-	bool
-	depends on EV64260 || CPCI690
-	default y
-
-config MV64360		# Really MV64360 & MV64460
+config TSI108_BRIDGE
 	bool
-	depends on CHESTNUT || KATANA || RADSTONE_PPC7D || HDPU || EV64360
+	depends on MPC7448HPC2
 	default y
 
 config MV64X60
 	bool
-	depends on (GT64260 || MV64360)
 	select PPC_INDIRECT_PCI
-	default y
-
-config TSI108_BRIDGE
-	bool
-	depends on MPC7448HPC2
-	default y
 
 menu "Set bridge options"
 	depends on MV64X60
@@ -240,22 +228,6 @@ config NOT_COHERENT_CACHE
 	  When this option is selected, cache coherency will be turned off.
 	  Note that this can cause other problems (e.g., stale data being
 	  speculatively loaded via a cached mapping).  Use at your own risk.
-
-config MV64X60_BASE
-	hex "Set bridge base used by firmware"
-	default "0xf1000000"
-	help
-	  A firmware can leave the base address of the bridge's registers at
-	  a non-standard location.  If so, set this value to reflect the
-	  address of that non-standard location.
-
-config MV64X60_NEW_BASE
-	hex "Set bridge base used by kernel"
-	default "0xf1000000"
-	help
-	  If the current base address of the bridge's registers is not where
-	  you want it, set this value to the address that you want it moved to.
-
 endmenu
 
 config NONMONARCH_SUPPORT

[RFC 5/8] powerpc: Add arch/powerpc mv64x60 MPSC platform data setup

From: Mark A. Greer <hidden>
Date: 2007-03-28 01:11:50

From: Dale Farnsworth <redacted>

Signed-off-by: Dale Farnsworth <redacted>
---

 mv64x60.c |  171 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 171 insertions(+)
---

Index: linux-2.6-powerpc-df/arch/powerpc/sysdev/mv64x60.c
===================================================================
--- linux-2.6-powerpc-df.orig/arch/powerpc/sysdev/mv64x60.c
+++ linux-2.6-powerpc-df/arch/powerpc/sysdev/mv64x60.c
@@ -16,6 +16,9 @@
 #include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
+#include <linux/string.h>
+#include <linux/mv643xx.h>
+#include <linux/platform_device.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
@@ -316,3 +319,171 @@ int __init mv64x60_verify_cache_coherenc
 }
 
 late_initcall(mv64x60_verify_cache_coherency);
+
+#if defined(CONFIG_SERIAL_MPSC) || defined(CONFIG_SERIAL_MPSC_MODULE)
+static int __init mv64x60_mpsc_register_shared_pdev(struct device_node *np)
+{
+	struct platform_device *pdev;
+	struct resource r[2];
+	struct mpsc_shared_pdata pdata;
+	const phandle *ph;
+	struct device_node *mpscrouting, *mpscintr;
+	int err;
+
+	ph = get_property(np, "mpscrouting", NULL);
+	mpscrouting = of_find_node_by_phandle(*ph);
+	if (!mpscrouting)
+		return -ENODEV;
+
+	err = of_address_to_resource(mpscrouting, 0, &r[0]);
+	of_node_put(mpscrouting);
+	if (err)
+		return err;
+
+	ph = get_property(np, "mpscintr", NULL);
+	mpscintr = of_find_node_by_phandle(*ph);
+	if (!mpscintr)
+		return -ENODEV;
+
+	err = of_address_to_resource(mpscintr, 0, &r[1]);
+	of_node_put(mpscintr);
+	if (err)
+		return err;
+
+	pdev = platform_device_register_simple(MPSC_SHARED_NAME, 0, r, 2);
+	if (IS_ERR(pdev))
+		return PTR_ERR(pdev);
+
+	memset(&pdata, 0, sizeof(pdata));
+
+	err = platform_device_add_data(pdev, &pdata, sizeof(pdata));
+	if (err)
+		platform_device_unregister(pdev);
+
+	return 0;
+}
+
+static int __init mv64x60_mpsc_platform_device_init(void)
+{
+	struct device_node *np = NULL;
+	unsigned int i;
+	struct platform_device *pdev;
+	int err;
+
+	for (i = 0; (np = of_find_compatible_node(np, "serial", "mpsc")); i++) {
+		struct resource r[5];
+		struct mpsc_pdata pdata;
+		const unsigned int *prop;
+		const phandle *ph;
+		struct device_node *sdma, *brg;
+
+		memset(&r, 0, sizeof(r));
+
+		if (i == 0) {
+			err = mv64x60_mpsc_register_shared_pdev(np);
+			if (err)
+				goto ret_node_put;
+		}
+
+		err = of_address_to_resource(np, 0, &r[0]);
+		if (err)
+			goto ret_node_put;
+
+		of_irq_to_resource(np, 0, &r[4]);
+
+		ph = get_property(np, "sdma", NULL);
+		sdma = of_find_node_by_phandle(*ph);
+		if (!sdma) {
+			err = -ENODEV;
+			goto ret_node_put;
+		}
+		of_irq_to_resource(sdma, 0, &r[3]);
+		err = of_address_to_resource(sdma, 0, &r[1]);
+		of_node_put(sdma);
+		if (err)
+			goto ret_node_put;
+
+		ph = get_property(np, "brg", NULL);
+		brg = of_find_node_by_phandle(*ph);
+		if (!brg) {
+			err = -ENODEV;
+			goto ret_node_put;
+		}
+
+		err = of_address_to_resource(brg, 0, &r[2]);
+		of_node_put(brg);
+		if (err) {
+			goto ret_node_put;
+		}
+
+		pdev = platform_device_register_simple(MPSC_CTLR_NAME, i, r, 5);
+		if (IS_ERR(pdev)) {
+			err = PTR_ERR(pdev);
+			goto ret_node_put;
+		}
+
+		memset(&pdata, 0, sizeof(pdata));
+
+		pdata.cache_mgmt = 1; /* All current revs need this set */
+
+		prop = get_property(np, "max_idle", NULL);
+		if (prop)
+			pdata.max_idle = *prop;
+
+		prop = get_property(brg, "current-speed", NULL);
+		if (prop)
+			pdata.default_baud = *prop;
+
+		/* Default is 8 bits, no parity, no flow control */
+		pdata.default_bits = 8;
+		pdata.default_parity = 'n';
+		pdata.default_flow = 'n';
+
+		prop = get_property(np, "chr_1", NULL);
+		if (prop)
+			pdata.chr_1_val = *prop;
+
+		prop = get_property(np, "chr_2", NULL);
+		if (prop)
+			pdata.chr_2_val = *prop;
+
+		prop = get_property(np, "chr_10", NULL);
+		if (prop)
+			pdata.chr_10_val = *prop;
+
+		prop = get_property(np, "mpcr", NULL);
+		if (prop)
+			pdata.mpcr_val = *prop;
+
+		prop = get_property(brg, "bcr", NULL);
+		if (prop)
+			pdata.bcr_val = *prop;
+
+		pdata.brg_can_tune = 1; /* All current revs need this set */
+
+		prop = get_property(brg, "clock-src", NULL);
+		if (prop)
+			pdata.brg_clk_src = *prop;
+
+		prop = get_property(brg, "clock-frequency", NULL);
+		if (prop)
+			pdata.brg_clk_freq = *prop;
+
+		err = platform_device_add_data(pdev, &pdata, sizeof(pdata));
+		if (err)
+			goto ret_unreg;
+		of_node_put(np);
+	}
+
+	return 0;
+
+ret_unreg:
+	platform_device_unregister(pdev);
+ret_node_put:
+	of_node_put(np);
+	return err;
+}
+
+arch_initcall(mv64x60_mpsc_platform_device_init);
+
+#endif /* defined(CONFIG_SERIAL_MPSC) || defined(CONFIG_SERIAL_MPSC_MODULE) */

[RFC 6/8] powerpc: Add arch/powerpc mv64x60_eth platform data setup

From: Mark A. Greer <hidden>
Date: 2007-03-28 01:12:17

From: Dale Farnsworth <redacted>

Signed-off-by: Dale Farnsworth <redacted>
---

 arch/powerpc/sysdev/mv64x60.c |  137 ++++++++++++++++++++++++++++++++++++++++++
 drivers/net/Kconfig           |    2 
 2 files changed, 138 insertions(+), 1 deletion(-)
---

Index: linux-2.6-powerpc-df/drivers/net/Kconfig
===================================================================
--- linux-2.6-powerpc-df.orig/drivers/net/Kconfig
+++ linux-2.6-powerpc-df/drivers/net/Kconfig
@@ -2300,7 +2300,7 @@ config UGETH_HAS_GIGA
 
 config MV643XX_ETH
 	tristate "MV-643XX Ethernet support"
-	depends on MOMENCO_OCELOT_C || MOMENCO_JAGUAR_ATX || MV64360 || MOMENCO_OCELOT_3 || (PPC_MULTIPLATFORM && PPC32)
+	depends on MOMENCO_OCELOT_C || MOMENCO_JAGUAR_ATX || MV64360 || MV64X60 || MOMENCO_OCELOT_3 || (PPC_MULTIPLATFORM && PPC32)
 	select MII
 	help
 	  This driver supports the gigabit Ethernet on the Marvell MV643XX
Index: linux-2.6-powerpc-df/arch/powerpc/sysdev/mv64x60.c
===================================================================
--- linux-2.6-powerpc-df.orig/arch/powerpc/sysdev/mv64x60.c
+++ linux-2.6-powerpc-df/arch/powerpc/sysdev/mv64x60.c
@@ -618,3 +618,140 @@ ret_node_put:
 arch_initcall(mv64x60_mpsc_platform_device_init);
 
 #endif /* defined(CONFIG_SERIAL_MPSC) || defined(CONFIG_SERIAL_MPSC_MODULE) */
+
+#if defined(CONFIG_MV643XX_ETH) || defined(CONFIG_MV643XX_ETH_MODULE)
+static int __init eth_register_shared_pdev(struct device_node *np)
+{
+	struct platform_device *pdev;
+	struct resource res;
+	int err;
+
+	np = of_get_parent(np);
+	if (!np)
+		return -ENODEV;
+
+	err = of_address_to_resource(np, 0, &res);
+	of_node_put(np);
+	if (err)
+		return err;
+
+	pdev = platform_device_register_simple(MV643XX_ETH_SHARED_NAME, 0,
+					       &res, 1);
+	if (IS_ERR(pdev))
+		return PTR_ERR(pdev);
+
+	return 0;
+}
+
+static int __init mv64x60_eth_platform_device_init(void)
+{
+	struct device_node *np = NULL;
+	unsigned int i;
+	struct platform_device *pdev;
+	int err;
+
+	for (i = 0;
+	     (np = of_find_compatible_node(np, "network", "mv64x60-eth"));
+	     i++) {
+		struct device_node *phy;
+		struct mv643xx_eth_platform_data pdata;
+		const u8 *mac_addr;
+		const void *prop;
+		const phandle *ph;
+		struct resource res;
+
+		if (i == 0) {
+			err = eth_register_shared_pdev(np);
+			if (err)
+				goto ret_node_put;
+		}
+
+		memset(&res, 0, sizeof(res));
+		of_irq_to_resource(np, 0, &res);
+
+		pdev = platform_device_register_simple(MV643XX_ETH_NAME,
+						       i, &res, 1);
+		if (IS_ERR(pdev)) {
+			err = PTR_ERR(pdev);
+			goto ret_node_put;
+		}
+
+		memset(&pdata, 0, sizeof(pdata));
+
+		prop = get_property(np, "block-index", NULL);
+		if (prop)
+			pdata.port_number = *(int *)prop;
+		else
+			pdata.port_number = i;
+
+		mac_addr = of_get_mac_address(np);
+		if (mac_addr)
+			memcpy(pdata.mac_addr, mac_addr, 6);
+
+		prop = get_property(np, "speed", NULL);
+		if (prop)
+			pdata.speed = *(int *)prop;
+
+		prop = get_property(np, "tx_queue_size", NULL);
+		if (prop)
+			pdata.tx_queue_size = *(int *)prop;
+
+		prop = get_property(np, "rx_queue_size", NULL);
+		if (prop)
+			pdata.rx_queue_size = *(int *)prop;
+
+		prop = get_property(np, "tx_sram_addr", NULL);
+		if (prop)
+			pdata.tx_sram_addr = *(int *)prop;
+
+		prop = get_property(np, "tx_sram_size", NULL);
+		if (prop)
+			pdata.tx_sram_size = *(int *)prop;
+
+		prop = get_property(np, "rx_sram_addr", NULL);
+		if (prop)
+			pdata.rx_sram_addr = *(int *)prop;
+
+		prop = get_property(np, "rx_sram_size", NULL);
+		if (prop)
+			pdata.rx_sram_size = *(int *)prop;
+
+		ph = get_property(np, "phy", NULL);
+		if (!ph) {
+			err = -ENODEV;
+			goto ret_unreg;
+		}
+
+		phy = of_find_node_by_phandle(*ph);
+		if (phy == NULL) {
+			err = -ENODEV;
+			goto ret_unreg;
+		}
+
+		prop = get_property(phy, "reg", NULL);
+		if (prop) {
+			pdata.force_phy_addr = 1;
+			pdata.phy_addr = *(int *)prop;
+		}
+
+		of_node_put(phy);
+
+		err = platform_device_add_data(pdev, &pdata, sizeof(pdata));
+		if (err)
+			goto ret_unreg;
+
+		of_node_put(np);
+	}
+
+	return 0;
+
+ret_unreg:
+	platform_device_unregister(pdev);
+ret_node_put:
+	of_node_put(np);
+	return err;
+}
+
+arch_initcall(mv64x60_eth_platform_device_init);
+
+#endif /* defined(CONFIG_MV643XX_ETH) || defined(CONFIG_MV643XX_ETH_MODULE) */

[RFC 7/8] powerpc: Add arch/powerpc mv64x60 I2C platform data setup

From: Mark A. Greer <hidden>
Date: 2007-03-28 01:12:48

From: Dale Farnsworth <redacted>

Signed-off-by: Dale Farnsworth <redacted>
---

 mv64x60.c |   75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 75 insertions(+)
---

Index: linux-2.6-powerpc-df/arch/powerpc/sysdev/mv64x60.c
===================================================================
--- linux-2.6-powerpc-df.orig/arch/powerpc/sysdev/mv64x60.c
+++ linux-2.6-powerpc-df/arch/powerpc/sysdev/mv64x60.c
@@ -755,3 +755,78 @@ ret_node_put:
 arch_initcall(mv64x60_eth_platform_device_init);
 
 #endif /* defined(CONFIG_MV643XX_ETH) || defined(CONFIG_MV643XX_ETH_MODULE) */
+
+#if defined(CONFIG_I2C_MV64XXX) || defined(CONFIG_I2C_MV64XXX_MODULE)
+static int __init mv64x60_i2c_platform_device_init(void)
+{
+	struct device_node *np;
+	struct platform_device *pdev;
+	int err;
+
+	np = of_find_compatible_node(NULL, "i2c", "mv64x60-i2c");
+	if (np) {
+		struct resource r[2];
+		struct mv64xxx_i2c_pdata pdata;
+		const unsigned int *prop;
+
+		err = of_address_to_resource(np, 0, &r[0]);
+		if (err)
+			goto ret_node_put;
+
+		memset(&r[1], 0, sizeof(r[1]));
+		of_irq_to_resource(np, 0, &r[1]);
+
+		pdev = platform_device_register_simple(MV64XXX_I2C_CTLR_NAME,
+						       0, r, 2);
+		if (IS_ERR(pdev)) {
+			err = PTR_ERR(pdev);
+			goto ret_node_put;
+		}
+
+		memset(&pdata, 0, sizeof(pdata));
+
+		prop = get_property(np, "freq_m", NULL);
+		if (!prop) {
+			err = -ENODEV;
+			goto ret_unreg;
+		}
+		pdata.freq_m = *prop;
+
+		prop = get_property(np, "freq_n", NULL);
+		if (!prop) {
+			err = -ENODEV;
+			goto ret_unreg;
+		}
+		pdata.freq_n = *prop;
+
+		prop = get_property(np, "timeout", NULL);
+		if (prop)
+			pdata.timeout = *prop;
+		else
+			pdata.timeout = 1000;	/* 1 second */
+
+		prop = get_property(np, "retries", NULL);
+		if (prop)
+			pdata.retries = *prop;
+		else
+			pdata.retries = 1;
+
+		err = platform_device_add_data(pdev, &pdata, sizeof(pdata));
+		if (err)
+			goto ret_unreg;
+
+		of_node_put(np);
+	}
+
+	return 0;
+
+ret_unreg:
+	platform_device_unregister(pdev);
+ret_node_put:
+	of_node_put(np);
+	return err;
+}
+
+arch_initcall(mv64x60_i2c_platform_device_init);
+
+#endif /* defined(CONFIG_I2C_MV64XXX) || defined(CONFIG_I2C_MV64XXX_MODULE) */

[RFC 8/8] powerpc: Add arch/powerpc mv64x60 PCI setup

From: Mark A. Greer <hidden>
Date: 2007-03-28 01:13:11

From: Dale Farnsworth <redacted>

Signed-off-by: Dale Farnsworth <redacted>
---

 mv64x60.c |  180 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 mv64x60.h |    2 
 2 files changed, 182 insertions(+)
---

Index: linux-2.6-powerpc-df/arch/powerpc/sysdev/mv64x60.c
===================================================================
--- linux-2.6-powerpc-df.orig/arch/powerpc/sysdev/mv64x60.c
+++ linux-2.6-powerpc-df/arch/powerpc/sysdev/mv64x60.c
@@ -19,12 +19,14 @@
 #include <linux/string.h>
 #include <linux/mv643xx.h>
 #include <linux/platform_device.h>
+#include <linux/pci.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/irq.h>
 #include <asm/machdep.h>
+#include <asm/pci-bridge.h>
 
 #include "mv64x60.h"
 
@@ -662,3 +664,181 @@ ret_node_put:
 arch_initcall(mv64x60_i2c_platform_device_init);
 
 #endif /* defined(CONFIG_I2C_MV64XXX) || defined(CONFIG_I2C_MV64XXX_MODULE) */
+
+#ifdef CONFIG_PCI
+static int mv64x60_pci_exclude_bridge = 1;
+static struct pci_controller *mv64x60_primary_hose;
+static int mv64x60_pci2_busno;
+
+#ifdef CONFIG_SYSFS
+/* 32-bit hex or dec stringified number + '\n' */
+#define MV64X60_VAL_LEN_MAX		11
+#define MV64X60_PCICFG_CPCI_HOTSWAP	0x68
+
+DECLARE_MUTEX(mv64x60_hs_lock);
+
+static ssize_t mv64x60_hs_reg_read(struct kobject *kobj, char *buf, loff_t off,
+				   size_t count)
+{
+	u32 v;
+	int save_exclude;
+
+	if (off > 0)
+		return 0;
+	if (count < MV64X60_VAL_LEN_MAX)
+		return -EINVAL;
+
+	if (down_interruptible(&mv64x60_hs_lock))
+		return -ERESTARTSYS;
+	save_exclude = mv64x60_pci_exclude_bridge;
+	mv64x60_pci_exclude_bridge = 0;
+	early_read_config_dword(mv64x60_primary_hose, 0, PCI_DEVFN(0, 0),
+				MV64X60_PCICFG_CPCI_HOTSWAP, &v);
+	mv64x60_pci_exclude_bridge = save_exclude;
+	up(&mv64x60_hs_lock);
+
+	return sprintf(buf, "0x%08x\n", v);
+}
+
+static ssize_t mv64x60_hs_reg_write(struct kobject *kobj, char *buf,
+				    loff_t off, size_t count)
+{
+	u32 v;
+	int save_exclude;
+
+	if (off > 0)
+		return 0;
+	if (count <= 0)
+		return -EINVAL;
+
+	if (sscanf(buf, "%i", &v) == 1) {
+		if (down_interruptible(&mv64x60_hs_lock))
+			return -ERESTARTSYS;
+		save_exclude = mv64x60_pci_exclude_bridge;
+		mv64x60_pci_exclude_bridge = 0;
+		early_write_config_dword(mv64x60_primary_hose, 0,
+					 PCI_DEVFN(0, 0),
+					 MV64X60_PCICFG_CPCI_HOTSWAP, v);
+		mv64x60_pci_exclude_bridge = save_exclude;
+		up(&mv64x60_hs_lock);
+	}
+	else
+		count = -EINVAL;
+
+	return count;
+}
+
+static struct bin_attribute mv64x60_hs_reg_attr = { /* Hotswap register */
+	.attr = {
+		.name = "hs_reg",
+		.mode = S_IRUGO | S_IWUSR,
+		.owner = THIS_MODULE,
+	},
+	.size  = MV64X60_VAL_LEN_MAX,
+	.read  = mv64x60_hs_reg_read,
+	.write = mv64x60_hs_reg_write,
+};
+
+static int __init mv64x60_sysfs_init(void)
+{
+	struct device_node *np;
+	struct platform_device *pdev;
+	const unsigned int *prop;
+
+	np = of_find_compatible_node(NULL, NULL, "mv64x60");
+	if (!np)
+		return 0;
+
+	pdev = platform_device_register_simple("mv64x60", 0, NULL, 0);
+	if (IS_ERR(pdev))
+		return PTR_ERR(pdev);
+
+	prop = get_property(np, "hs_reg_valid", NULL);
+	of_node_put(np);
+	if (!prop)
+		return 0;
+
+	return sysfs_create_bin_file(&pdev->dev.kobj, &mv64x60_hs_reg_attr);
+}
+
+subsys_initcall(mv64x60_sysfs_init);
+
+#endif /* CONFIG_SYSFS */
+
+static int mv64x60_exclude_device(u_char bus, u_char devfn)
+{
+	if ((bus == 0 || bus == mv64x60_pci2_busno) &&
+	    PCI_SLOT(devfn) == 0 && mv64x60_pci_exclude_bridge)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int __init mv64x60_add_bridge(struct device_node *dev)
+{
+	int len;
+	struct pci_controller *hose;
+	struct resource rsrc;
+	const int *bus_range;
+	int primary;
+
+	memset(&rsrc, 0, sizeof(rsrc));
+
+	/* Fetch host bridge registers address */
+	if (of_address_to_resource(dev, 0, &rsrc)) {
+		printk(KERN_ERR "No PCI reg property in device tree\n");
+		return -ENODEV;
+	}
+
+	/* Get bus range if any */
+	bus_range = get_property(dev, "bus-range", &len);
+	if (bus_range == NULL || len < 2 * sizeof(int))
+		printk(KERN_WARNING "Can't get bus-range for %s, assume"
+		       " bus 0\n", dev->full_name);
+
+	hose = pcibios_alloc_controller();
+	if (!hose)
+		return -ENOMEM;
+
+	hose->arch_data = dev;
+	hose->set_cfg_type = 1;
+
+	hose->first_busno = bus_range ? bus_range[0] : 0;
+	hose->last_busno = bus_range ? bus_range[1] : 0xff;
+	primary = hose->first_busno == 0;
+
+	setup_indirect_pci(hose, rsrc.start, rsrc.start + 4);
+
+	if (primary)
+		mv64x60_primary_hose = hose;
+	else {
+		hose->bus_offset = hose->first_busno;
+		mv64x60_pci2_busno = hose->first_busno;
+	}
+
+	printk(KERN_INFO "Found MV64x60 PCI host bridge at 0x%016llx. "
+	       "Firmware bus number: %d->%d\n",
+	       (unsigned long long)rsrc.start, hose->first_busno,
+	       hose->last_busno);
+
+	/* Interpret the "ranges" property */
+	/* This also maps the I/O region and sets isa_io/mem_base */
+	pci_process_bridge_OF_ranges(hose, dev, primary);
+
+	return 0;
+}
+
+void __init mv64x60_pci_init(void)
+{
+	struct device_node *np = NULL;
+	int rc;
+
+	ppc_md.pci_exclude_device = mv64x60_exclude_device;
+
+	while ((np = of_find_compatible_node(np, "pci", "mv64x60-pci"))) {
+		rc = mv64x60_add_bridge(np);
+		if (rc < 0)
+			break;
+	}
+}
+#endif /* CONFIG_PCI */
Index: linux-2.6-powerpc-df/arch/powerpc/sysdev/mv64x60.h
===================================================================
--- linux-2.6-powerpc-df.orig/arch/powerpc/sysdev/mv64x60.h
+++ linux-2.6-powerpc-df/arch/powerpc/sysdev/mv64x60.h
@@ -6,4 +6,6 @@
 extern void __init mv64x60_init_irq(void);
 extern unsigned int mv64x60_get_irq(void);
 
+extern void __init mv64x60_pci_init(void);
+
 #endif /* __MV64X60_H__ */
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help