mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* IXP4xx again
@ 2013-03-30 11:19 Krzysztof Halasa
  2013-03-30 11:24 ` [PATCH] ARM: XScale processors don't support "clean+invalidate D entry" operation Krzysztof Halasa
                   ` (2 more replies)
  0 siblings, 3 replies; 24+ messages in thread
From: Krzysztof Halasa @ 2013-03-30 11:19 UTC (permalink / raw)
  To: barebox

Hi,

I'm posting 3 patches:
- the first one fixes a problem with XScale processors. They don't
support "clean + invalidate data cache entry" operation, we must use
separate "clean" and "invalidate".

- the second patch implements "alternate" memory layout, in which
the code+data+bss appears first in memory space, then the malloc space
follows (and then stack). This is required to support large malloc space
(as large as possible) on systems with variable amount of RAM.

- the third patch does IXP4xx (CPU support) + Goramo MultiLink platform.
I can obviously split it if needed but perhaps it can go in in one
piece.

Against "next" branch, tested with regular 2013.03.0.
-- 
Krzysztof Halasa

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH] ARM: XScale processors don't support "clean+invalidate D entry" operation.
  2013-03-30 11:19 IXP4xx again Krzysztof Halasa
@ 2013-03-30 11:24 ` Krzysztof Halasa
  2013-03-30 11:25 ` [PATCH] Implement ALTERNATE memory layout Krzysztof Halasa
  2013-03-30 11:26 ` [PATCH] ARM: Add support for IXP4xx CPU and for Goramo Multilink router platform Krzysztof Halasa
  2 siblings, 0 replies; 24+ messages in thread
From: Krzysztof Halasa @ 2013-03-30 11:24 UTC (permalink / raw)
  To: barebox

Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>

--- a/arch/arm/cpu/cache-armv4.S
+++ b/arch/arm/cpu/cache-armv4.S
@@ -132,11 +132,15 @@ ENTRY(v4_dma_clean_range)
  *
  *	- start	- virtual start address
  *	- end	- virtual end address
+ *
+ *	XScale processors don't support "clean+invalidate D entry"
+ *	(mcr p15, 0, r0, c7, c14, 1).
  */
 .section .text.v4_dma_flush_range
 ENTRY(v4_dma_flush_range)
 	bic	r0, r0, #CACHE_DLINESIZE - 1
-1:	mcr	p15, 0, r0, c7, c14, 1		@ clean+invalidate D entry
+1:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
+	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
 	add	r0, r0, #CACHE_DLINESIZE
 	cmp	r0, r1
 	blo	1b

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH] Implement ALTERNATE memory layout.
  2013-03-30 11:19 IXP4xx again Krzysztof Halasa
  2013-03-30 11:24 ` [PATCH] ARM: XScale processors don't support "clean+invalidate D entry" operation Krzysztof Halasa
@ 2013-03-30 11:25 ` Krzysztof Halasa
  2013-03-30 12:01   ` Alexander Shiyan
                     ` (3 more replies)
  2013-03-30 11:26 ` [PATCH] ARM: Add support for IXP4xx CPU and for Goramo Multilink router platform Krzysztof Halasa
  2 siblings, 4 replies; 24+ messages in thread
From: Krzysztof Halasa @ 2013-03-30 11:25 UTC (permalink / raw)
  To: barebox

Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>

--- a/arch/arm/cpu/start.c
+++ b/arch/arm/cpu/start.c
@@ -58,7 +58,6 @@ static noinline __noreturn void __start(uint32_t membase, uint32_t memsize,
 	endmem -= STACK_SIZE; /* Stack */
 
 	if (IS_ENABLED(CONFIG_MMU_EARLY)) {
-
 		endmem &= ~0x3fff;
 		endmem -= SZ_16K; /* ttb */
 
@@ -66,6 +65,9 @@ static noinline __noreturn void __start(uint32_t membase, uint32_t memsize,
 			mmu_early_enable(membase, memsize, endmem);
 	}
 
+#ifdef CONFIG_MEMORY_LAYOUT_ALTERNATE
+		malloc_end = endmem;
+#else
 	if ((unsigned long)_text > membase + memsize ||
 			(unsigned long)_text < membase)
 		/*
@@ -76,15 +78,21 @@ static noinline __noreturn void __start(uint32_t membase, uint32_t memsize,
 		malloc_end = endmem;
 	else
 		malloc_end = (unsigned long)_text;
+#endif
 
 	/*
 	 * Maximum malloc space is the Kconfig value if given
 	 * or 64MB.
 	 */
 	if (MALLOC_SIZE > 0) {
-		malloc_start = malloc_end - MALLOC_SIZE;
-		if (malloc_start < membase)
+		if (malloc_end > membase + MALLOC_SIZE)
+			malloc_start = malloc_end - MALLOC_SIZE;
+		else
 			malloc_start = membase;
+		if (malloc_start < (unsigned long)_end &&
+		    malloc_end > (unsigned long)_text)
+			/* malloc area follows text */
+			malloc_start = (unsigned long)_end;
 	} else {
 		malloc_start = malloc_end - (malloc_end - membase) / 2;
 		if (malloc_end - malloc_start > SZ_64M)
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -161,7 +161,7 @@ choice
 config MEMORY_LAYOUT_DEFAULT
 	bool "use default memory layout"
 	help
-	  select this option to use bareboxs standard memory layout:
+	  select this option to use barebox's standard memory layout:
 
 	  stack
 	  -----
@@ -169,6 +169,17 @@ config MEMORY_LAYOUT_DEFAULT
 	  -----
 	  TEXT_BASE
 
+config MEMORY_LAYOUT_ALTERNATE
+	bool "use alternate memory layout"
+	help
+	  select this option to use barebox's alternate memory layout:
+
+	  TEXT_BASE
+	  -----
+	  malloc heap
+	  -----
+	  stack
+
 config MEMORY_LAYOUT_FIXED
 	bool "manually assign a memory layout"
 	help

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH] ARM: Add support for IXP4xx CPU and for Goramo Multilink router platform.
  2013-03-30 11:19 IXP4xx again Krzysztof Halasa
  2013-03-30 11:24 ` [PATCH] ARM: XScale processors don't support "clean+invalidate D entry" operation Krzysztof Halasa
  2013-03-30 11:25 ` [PATCH] Implement ALTERNATE memory layout Krzysztof Halasa
@ 2013-03-30 11:26 ` Krzysztof Halasa
  2013-04-02  6:52   ` Sascha Hauer
  2 siblings, 1 reply; 24+ messages in thread
From: Krzysztof Halasa @ 2013-03-30 11:26 UTC (permalink / raw)
  To: barebox

Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>

diff --git a/Documentation/boards.dox b/Documentation/boards.dox
index 41de836..2d248e6 100644
--- a/Documentation/boards.dox
+++ b/Documentation/boards.dox
@@ -21,6 +21,7 @@ ARM type:
 @li @subpage board_loco
 @li @subpage chumbyone
 @li @subpage scb9328
+@li @subpage multilink
 @li @subpage netx
 @li @subpage dev_omap_arch
 @li @subpage a9m2440
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index bb9b47b..2a775d5 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -79,6 +79,12 @@ config ARCH_IMX
 	select WATCHDOG_IMX_RESET_SOURCE
 	select HAS_DEBUG_LL
 
+config ARCH_IXP4XX
+	bool "Intel IXP4xx-based"
+	select CPU_XSCALE
+	select ARCH_SUPPORTS_BIG_ENDIAN
+	select CPU_BIG_ENDIAN
+
 config ARCH_MXS
 	bool "Freescale i.MX23/28 (mxs) based"
 	select GENERIC_GPIO
@@ -153,6 +159,7 @@ source arch/arm/mach-clps711x/Kconfig
 source arch/arm/mach-ep93xx/Kconfig
 source arch/arm/mach-highbank/Kconfig
 source arch/arm/mach-imx/Kconfig
+source arch/arm/mach-ixp4xx/Kconfig
 source arch/arm/mach-mxs/Kconfig
 source arch/arm/mach-netx/Kconfig
 source arch/arm/mach-nomadik/Kconfig
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index d506b12..554072e 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -57,6 +57,7 @@ machine-$(CONFIG_ARCH_CLPS711X)		:= clps711x
 machine-$(CONFIG_ARCH_EP93XX)		:= ep93xx
 machine-$(CONFIG_ARCH_HIGHBANK)		:= highbank
 machine-$(CONFIG_ARCH_IMX)		:= imx
+machine-$(CONFIG_ARCH_IXP4XX)		:= ixp4xx
 machine-$(CONFIG_ARCH_MXS)		:= mxs
 machine-$(CONFIG_ARCH_NOMADIK)		:= nomadik
 machine-$(CONFIG_ARCH_NETX)		:= netx
@@ -101,6 +102,7 @@ board-$(CONFIG_MACH_EUKREA_CPUIMX51SD)		:= eukrea_cpuimx51
 board-$(CONFIG_MACH_FREESCALE_MX25_3STACK)	:= freescale-mx25-3-stack
 board-$(CONFIG_MACH_FREESCALE_MX35_3STACK)	:= freescale-mx35-3-stack
 board-$(CONFIG_MACH_GE863)			:= telit-evk-pro3
+board-$(CONFIG_MACH_GORAMO_MLR)			:= multilink
 board-$(CONFIG_MACH_HIGHBANK)			:= highbank
 board-$(CONFIG_MACH_IMX21ADS)			:= imx21ads
 board-$(CONFIG_MACH_IMX27ADS)			:= imx27ads
diff --git a/arch/arm/boards/multilink/Makefile b/arch/arm/boards/multilink/Makefile
new file mode 100644
index 0000000..d5a8bbc
--- /dev/null
+++ b/arch/arm/boards/multilink/Makefile
@@ -0,0 +1 @@
+obj-y += lowlevel_init.o multilink.o
diff --git a/arch/arm/boards/multilink/config.h b/arch/arm/boards/multilink/config.h
new file mode 100644
index 0000000..e69de29
diff --git a/arch/arm/boards/multilink/lowlevel_init.S b/arch/arm/boards/multilink/lowlevel_init.S
new file mode 100644
index 0000000..a48318c
--- /dev/null
+++ b/arch/arm/boards/multilink/lowlevel_init.S
@@ -0,0 +1,67 @@
+#include <mach/ixp4xx-regs.h>
+#include <mach/ixp4xx-head.h>
+
+	.macro DELAY_FOR cycles, reg0
+	ldr \reg0, =\cycles
+	subs \reg0, \reg0, #1
+	subne pc, pc, #0xc
+	.endm
+
+#define CFG_SDRAM_SIZE    0x50 /* u32 */
+#define CFG_SDRAM_CONF    0x54 /* u32 */
+#define CFG_SDRAM_MODE    0x58 /* u32 */
+#define CFG_SDRAM_REFRESH 0x5C /* u32 */
+
+	.section ".text_bare_init", "ax"
+
+	.globl barebox_arm_reset_vector
+barebox_arm_reset_vector:
+	ixp4xx_cpu_lowlevel_init
+	mov r8, #IXP4XX_EXP_BASE(0)
+	ldr r1, [r8, #CFG_SDRAM_CONF]
+	ldr r2, =IXP4XX_SDRAM_CONFIG
+	str r1, [r2]
+
+	/* disable refresh cycles */
+	mov r1, #0
+	add r2, r2, #4 /* r2 = IXP4XX_SDRAM_REFRESH */
+	str r1, [r2]
+
+	/* send NOP command */
+	mov r1, #3
+	add r3, r2, #4 /* r3 = IXP4XX_SDRAM_IR */
+	str r1, [r3]
+	DELAY_FOR 0x4000, r0
+
+	/* set SDRAM internal refresh */
+	ldr r1, [r8, #CFG_SDRAM_REFRESH]
+	str r1, [r2]
+	DELAY_FOR 0x4000, r0
+
+	/* send precharge-all command to close all open banks */
+	mov r1, #2
+	str r1, [r3]
+	DELAY_FOR 0x4000, r0
+
+	/* provide 8 auto-refresh cycles */
+	mov r1, #4
+	mov r4, #8
+1:	str r1, [r3]
+	DELAY_FOR 0x100, r0
+	subs r4, r4, #1
+	bne 1b
+
+	/* set mode register in SDRAM */
+	ldr r1, [r8, #CFG_SDRAM_MODE]
+	str r1, [r3]
+	DELAY_FOR 0x4000, r0
+
+	/* send normal operation command */
+	mov r1, #6
+	str r1, [r3]
+	DELAY_FOR 0x4000, r0
+
+	mov r0, #0
+	ldr r1, [r8, #CFG_SDRAM_SIZE]
+	mov r2, #0
+	b barebox_arm_entry
diff --git a/arch/arm/boards/multilink/multilink.c b/arch/arm/boards/multilink/multilink.c
new file mode 100644
index 0000000..43a4a08
--- /dev/null
+++ b/arch/arm/boards/multilink/multilink.c
@@ -0,0 +1,109 @@
+//#define DEBUG
+#include <common.h>
+#include <errno.h>
+#include <fs.h>
+#include <init.h>
+#include <linux/types.h>
+#include <asm/armlinux.h>
+#include <asm/io.h>
+#include <generated/mach-types.h>
+#include <mach/ixp4xx-regs.h>
+#include <mach/platform.h>
+
+/* offsets from start of flash ROM = 0x50000000 */
+#define CFG_ETH0_ADDRESS     0x40 /* 6 bytes */
+#define CFG_ETH1_ADDRESS     0x46 /* 6 bytes */
+#define CFG_REV              0x4C /* u32 */
+#define CFG_SDRAM_SIZE       0x50 /* u32 */
+#define CFG_SDRAM_CONF       0x54 /* u32 */
+#define CFG_SDRAM_MODE       0x58 /* u32 */
+#define CFG_SDRAM_REFRESH    0x5C /* u32 */
+
+#define CFG_HW_BITS          0x60 /* u32 */
+#define  CFG_HW_USB_PORTS    0x00000007 /* 0 = no NEC chip, 1-5 = ports # */
+#define  CFG_HW_HAS_PCI_SLOT 0x00000008
+#define  CFG_HW_HAS_ETH0     0x00000010
+#define  CFG_HW_HAS_ETH1     0x00000020
+#define  CFG_HW_HAS_HSS0     0x00000040
+#define  CFG_HW_HAS_HSS1     0x00000080
+#define  CFG_HW_HAS_UART0    0x00000100
+#define  CFG_HW_HAS_UART1    0x00000200
+#define  CFG_HW_HAS_EEPROM   0x00000400
+
+#define ETH_ALEN             6
+
+#define BAREBOX_START        0x00000
+#define BAREBOX_LENGTH       0x3B000
+#define CRAMFS_START         (BAREBOX_START + BAREBOX_LENGTH)
+#define CRAMFS_LENGTH        0x05000
+#define ENV0_START           (CRAMFS_START + CRAMFS_LENGTH)
+#define ENV0_LENGTH          0x20000
+
+static struct eth_plat_info eth_pinfo[2] = {
+	{
+		.regs     = IXP4XX_EthB_BASE,
+		.npe      = 1,
+		.phy      = 0,
+		.rxq      = 20,
+		.txreadyq = 29,
+	}, {
+		.regs     = IXP4XX_EthC_BASE,
+		.npe      = 2,
+		.phy      = 1,
+		.rxq      = 21,
+		.txreadyq = 30,
+	}
+};
+
+static inline u8 __init flash_readb(u32 addr)
+{
+	return __raw_readb(IXP4XX_EXP_BASE(0) + addr);
+}
+
+static int __init gml_mem_init(void)
+{
+	arm_add_mem_device("ram0", 0, __raw_readl(IXP4XX_EXP_BASE(0) + CFG_SDRAM_SIZE));
+	return 0;
+}
+
+mem_initcall(gml_mem_init);
+
+static int __init gml_devices_init(void)
+{
+	u32 hw_bits;
+	int i;
+
+	IXP4XX_EXP_CS0 = IXP4XX_EXP_EN | IXP4XX_EXP_INTEL |
+		IXP4XX_EXP_BITS(24) | IXP4XX_EXP_WR_EN | IXP4XX_EXP_BYTE_RD16;
+	add_cfi_flash_device(0, IXP4XX_EXP_BASE(0), 16 * 1024 * 1024, 0);
+	devfs_add_partition("nor0", BAREBOX_START, BAREBOX_LENGTH,
+			    DEVFS_PARTITION_FIXED | DEVFS_PARTITION_READONLY, "barebox");
+	devfs_add_partition("nor0", CRAMFS_START, CRAMFS_LENGTH,
+			    DEVFS_PARTITION_FIXED | DEVFS_PARTITION_READONLY, "cramfs");
+	devfs_add_partition("nor0", ENV0_START, ENV0_LENGTH,
+			    DEVFS_PARTITION_FIXED, "env0");
+
+	mkdir("/firmware", 0755);
+	mount("/dev/cramfs", "cramfs", "/firmware");
+
+	hw_bits = __raw_readl(IXP4XX_EXP_BASE(0) + CFG_HW_BITS);
+
+	if (hw_bits & CFG_HW_HAS_ETH0) {
+		for (i = 0; i < ETH_ALEN; i++)
+			eth_pinfo[0].hwaddr[i] = flash_readb(CFG_ETH0_ADDRESS + i);
+		add_generic_device("ixp4xx_eth", DEVICE_ID_DYNAMIC, NULL, 0, 0,
+				   IORESOURCE_MEM, &eth_pinfo[0]);
+	}
+
+	if (hw_bits & CFG_HW_HAS_ETH1) {
+		for (i = 0; i < ETH_ALEN; i++)
+			eth_pinfo[1].hwaddr[i] = flash_readb(CFG_ETH1_ADDRESS + i);
+		add_generic_device("ixp4xx_eth", DEVICE_ID_DYNAMIC, NULL, 0, 0,
+				   IORESOURCE_MEM, &eth_pinfo[1]);
+	}
+
+	armlinux_set_bootparams((void *)(0x00000100));
+	armlinux_set_architecture(MACH_TYPE_GORAMO_MLR);
+	return 0;
+}
+device_initcall(gml_devices_init);
diff --git a/arch/arm/boards/multilink/multilink.dox b/arch/arm/boards/multilink/multilink.dox
new file mode 100644
index 0000000..321cbeb
--- /dev/null
+++ b/arch/arm/boards/multilink/multilink.dox
@@ -0,0 +1,34 @@
+/** @page multilink Goramo MultiLink
+
+These boards are based on Intel IXP42x CPU.
+
+Variants:
+
+MicroRouter module: IXP421 or IXP425 266 MHz CPU, 32 MiB SDRAM,
+   1 or 2 Fast Ethernet ports, 2 sync serial ports, 1 RS-232 (console) port.
+
+MultiLink v.1: IXP425 266 or 533 MHz CPU, 64 - 256 MiB SDRAM,
+   2 Fast Ethernet ports, 2 sync serial ports, 1 - 2 RS-232 ports,
+   a mini-PCI slot, 2 optional USB host connectors.
+
+MultiLink v.2: IXP425 266 or 533 MHz CPU, 64 - 256 MiB SDRAM,
+   2 Fast Ethernet ports, 2 sync serial ports, 1 - 2 RS-232 ports,
+   2 additional optional Fast or Gigabit Ethernet ports, a mini-PCI slot,
+   4 optional USB host connectors, optional Real-Time Clock,
+   optional IDE connector.
+
+16 MiB Intel StrataFlash memory is partitioned as follows:
+
+0x00000-0x3B000 : Barebox image
+0x3B000-0x40000 : compressed RAM filesystem (cramfs)
+0x40000-0x60000 : env0
+
+There is a factory configuration region within Barebox image at locations
+0x40 - 0x7F. Details are in file multilink.c
+
+Barebox and cramfs images are combined in first two blocks of flash memory.
+NPE-A microcode contained in cramfs is not used by Barebox (but may be used
+by Linux HSS driver). NPE-B microcode is needed for eth0 and NPE-C for eth1.
+Barebox needs version 2.4 of regular non-VLAN-aware microcode files (with
+or without crypto support).
+*/
diff --git a/arch/arm/lib/barebox.lds.S b/arch/arm/lib/barebox.lds.S
index 10c63bf..b40b24b 100644
--- a/arch/arm/lib/barebox.lds.S
+++ b/arch/arm/lib/barebox.lds.S
@@ -40,6 +40,9 @@ SECTIONS
 		_stext = .;
 		_text = .;
 		*(.text_entry*)
+#ifdef CONFIG_MACH_GORAMO_MLR
+		. = 0x0080; /* config space at 0x40 - 0x7F */
+#endif
 		__bare_init_start = .;
 		*(.text_bare_init*)
 		__bare_init_end = .;
diff --git a/arch/arm/mach-ixp4xx/Kconfig b/arch/arm/mach-ixp4xx/Kconfig
new file mode 100644
index 0000000..db0b768
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/Kconfig
@@ -0,0 +1,26 @@
+if ARCH_IXP4XX
+
+choice
+	prompt "IXP4xx Board Type"
+
+config MACH_GORAMO_MLR
+	bool "Goramo MultiLink"
+	select HAVE_CONFIGURABLE_MEMORY_LAYOUT
+endchoice
+
+config BOARDINFO
+	default "Goramo MultiLink" if MACH_GORAMO_MLR
+
+config IXP4XX_QMGR
+	tristate "IXP4xx Queue Manager support"
+	help
+	  This driver supports IXP4xx built-in hardware queue manager
+	  and is required by the Ethernet driver.
+
+config IXP4XX_NPE
+	tristate "IXP4xx Network Processor Engine support"
+	help
+	  This driver supports IXP4xx built-in network coprocessors
+	  and is required by the Ethernet driver.
+
+endif
diff --git a/arch/arm/mach-ixp4xx/Makefile b/arch/arm/mach-ixp4xx/Makefile
new file mode 100644
index 0000000..7cfc924
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/Makefile
@@ -0,0 +1,3 @@
+obj-y += generic.o
+obj-$(CONFIG_IXP4XX_QMGR) += qmgr.o
+obj-$(CONFIG_IXP4XX_NPE) += npe.o
diff --git a/arch/arm/mach-ixp4xx/generic.c b/arch/arm/mach-ixp4xx/generic.c
new file mode 100644
index 0000000..e81994b
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/generic.c
@@ -0,0 +1,114 @@
+#include <common.h>
+#include <init.h>
+#include <ns16550.h>
+#include <asm/armlinux.h>
+#include <asm/io.h>
+#include <mach/ixp4xx-regs.h>
+
+#define OSTS_FREQUENCY 66666000
+
+void reset_cpu(ulong addr)
+{
+	/* Use on-chip reset capability */
+	/* This may not work on IXP425 rev. A0 */
+
+	IXP4XX_OSWK = IXP4XX_WDT_KEY;
+	IXP4XX_OSWT = 0; /* request immediate reset */
+	IXP4XX_OSWE = IXP4XX_WDT_RESET_ENABLE | IXP4XX_WDT_COUNT_ENABLE;
+	while (1)
+		;
+}
+
+#include <clock.h>
+
+/**
+ * @brief Provide a simple clock read
+ *
+ * Nothing is simpler.. read direct from clock and provide it
+ * to the caller.
+ *
+ * @return clock counter
+ */
+static uint64_t ixp4xx_clocksource_read(void)
+{
+	return IXP4XX_OSTS;
+}
+
+static struct clocksource cs = {
+	.read = ixp4xx_clocksource_read,
+	.mask = 0xffffffff,
+	.shift = 10,
+};
+
+/**
+ * @brief Initialize the Clock
+ *
+ * We use the Time-Stamp Timer
+ *
+ * @return result of @ref init_clock
+ */
+static int ixp4xx_clocksource_init(void)
+{
+	cs.mult = clocksource_hz2mult(OSTS_FREQUENCY, cs.shift);
+
+	return init_clock(&cs);
+}
+
+/* Run me at boot time */
+core_initcall(ixp4xx_clocksource_init);
+
+
+#ifdef CONFIG_DRIVER_SERIAL_NS16550
+
+/**
+ * @brief UART port register read function for IXP4XX
+ *
+ * @param base base address of UART
+ * @param reg_idx register index
+ *
+ * @return character read from register
+ */
+unsigned int ixp4xx_uart_read(unsigned long base, unsigned char reg_idx)
+{
+	return readb(4 * reg_idx + 3 /* big-endian */ + (uint8_t *)base);
+}
+EXPORT_SYMBOL(ixp4xx_uart_read);
+
+/**
+ * @brief UART port register write function for IXP4XX
+ *
+ * @param val value to write
+ * @param base base address of UART
+ * @param reg_idx register index
+ *
+ * @return void
+ */
+void ixp4xx_uart_write(unsigned int val, unsigned long base, unsigned char reg_idx)
+{
+	writeb(val, 4 * reg_idx + 3 /* big-endian */ + (uint8_t *)base);
+}
+EXPORT_SYMBOL(ixp4xx_uart_write);
+
+
+static struct NS16550_plat serial_plat = {
+	.clock = 14745600,
+	.f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR,
+	.reg_read = ixp4xx_uart_read,
+	.reg_write = ixp4xx_uart_write,
+};
+
+/**
+ * @brief UART serial port initialization
+ *
+ * @return result of device registration
+ */
+static int ixp4xx_console_init(void)
+{
+	/* Register the serial port */
+	add_ns16550_device(0, (u32)IXP4XX_UART1_BASE, 1024, IORESOURCE_MEM_8BIT, &serial_plat);
+	return 0;
+}
+
+console_initcall(ixp4xx_console_init);
+
+#endif /* CONFIG_DRIVER_SERIAL_NS16550 */
diff --git a/arch/arm/mach-ixp4xx/include/mach/cpu.h b/arch/arm/mach-ixp4xx/include/mach/cpu.h
new file mode 100644
index 0000000..3de021e
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/include/mach/cpu.h
@@ -0,0 +1,70 @@
+/*
+ * arch/arm/mach-ixp4xx/include/mach/cpu.h
+ *
+ * IXP4XX cpu type detection
+ *
+ * Copyright (C) 2007 MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __ASM_ARCH_CPU_H__
+#define __ASM_ARCH_CPU_H__
+
+#include <linux/types.h>
+
+/* Processor id value in CP15 Register 0 */
+#define IXP42X_PROCESSOR_ID_VALUE 0x690541c0 /* including unused 0x690541Ex */
+#define IXP42X_PROCESSOR_ID_MASK  0xffffffc0
+
+#define IXP43X_PROCESSOR_ID_VALUE 0x69054040
+#define IXP43X_PROCESSOR_ID_MASK  0xfffffff0
+
+#define IXP46X_PROCESSOR_ID_VALUE 0x69054200 /* including IXP455 */
+#define IXP46X_PROCESSOR_ID_MASK  0xfffffff0
+
+#define cpu_is_ixp42x_rev_a0() ((read_cpuid_id() & (IXP42X_PROCESSOR_ID_MASK | 0xF)) == \
+				IXP42X_PROCESSOR_ID_VALUE)
+#define cpu_is_ixp42x() ((read_cpuid_id() & IXP42X_PROCESSOR_ID_MASK) == \
+			 IXP42X_PROCESSOR_ID_VALUE)
+#define cpu_is_ixp43x() ((read_cpuid_id() & IXP43X_PROCESSOR_ID_MASK) == \
+			 IXP43X_PROCESSOR_ID_VALUE)
+#define cpu_is_ixp46x() ((read_cpuid_id() & IXP46X_PROCESSOR_ID_MASK) == \
+			 IXP46X_PROCESSOR_ID_VALUE)
+
+/*
+ * The CPU ID never changes at run time, so we might as well tell the
+ * compiler that it's constant.  Use this function to read the CPU ID
+ * rather than directly reading processor_id or read_cpuid() directly.
+ */
+static inline u32 __attribute_const__ read_cpuid_id(void)
+{
+	u32 val;
+	asm("mrc p15, 0, %0, c0, c0, 0" : "=r" (val) : : "cc");
+
+	return val;
+}
+
+static inline u32 ixp4xx_read_feature_bits(void)
+{
+	u32 val = ~IXP4XX_EXP_CFG2;
+
+	if (cpu_is_ixp42x_rev_a0())
+		return IXP42X_FEATURE_MASK & ~(IXP4XX_FEATURE_RCOMP |
+					       IXP4XX_FEATURE_AES);
+	if (cpu_is_ixp42x())
+		return val & IXP42X_FEATURE_MASK;
+	if (cpu_is_ixp43x())
+		return val & IXP43X_FEATURE_MASK;
+	return val & IXP46X_FEATURE_MASK;
+}
+
+static inline void ixp4xx_write_feature_bits(u32 value)
+{
+	IXP4XX_EXP_CFG2 = ~value;
+}
+
+#endif  /* _ASM_ARCH_CPU_H */
diff --git a/arch/arm/mach-ixp4xx/include/mach/ixp4xx-head.h b/arch/arm/mach-ixp4xx/include/mach/ixp4xx-head.h
new file mode 100644
index 0000000..b3d357f
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/include/mach/ixp4xx-head.h
@@ -0,0 +1,16 @@
+#include <mach/ixp4xx-regs.h>
+#include <asm/barebox-arm-head.h>
+
+.macro	ixp4xx_cpu_lowlevel_init
+
+	arm_cpu_lowlevel_init r0
+
+	add pc, #(0x50000000 - 4) /* jump to ROM area */
+
+	mov r0, #(IXP4XX_EXP_CFG0 & 0xFFFF0000)
+	orr r0, #(IXP4XX_EXP_CFG0 & 0x0000FFFF)
+	ldr r1, [r0]
+	and r1, r1, #~0x80000000 /* unmap EXP bus from 0x0 */
+	str r1, [r0]
+
+.endm
diff --git a/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h b/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h
new file mode 100644
index 0000000..da4dc8a
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h
@@ -0,0 +1,365 @@
+/*
+ * Register definitions for IXP4xx chipset.
+ *
+ * Copyright (C) 2002 Intel Corporation.
+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef _ASM_ARM_IXP4XX_H_
+#define _ASM_ARM_IXP4XX_H_
+
+#ifdef __ASSEMBLER__
+#define IXP4XX_REG(reg)  (reg)
+#else
+#define IXP4XX_REG(reg)  (*(volatile u32 *)(reg))
+#define IXP4XX_BASE(reg) ((u32*)(reg))
+#endif
+
+/* Expansion Bus region */
+
+/* Queue Manager */
+#define IXP4XX_QMGR_BASE              (0x60000000)
+#define IXP4XX_QMGR_REGION_SIZE       (0x00004000)
+
+
+/* PCI Config registers */
+#define IXP4XX_PCI_CFG_BASE           (0xC0000000)
+#define IXP4XX_PCI_CFG_REGION_SIZE    (0x00001000)
+
+/* Peripheral space */
+#define IXP4XX_PERIPHERAL_BASE        (0xC8000000)
+#define IXP4XX_PERIPHERAL_REGION_SIZE (0x00013000)
+
+/*
+ * Debug UART
+ *
+ * This is basically a remap of UART1 into a region that is section
+ * aligned so that it can be used with the low-level debug code.
+ */
+#define IXP4XX_DEBUG_UART_BASE        (0xC8000000)
+#define IXP4XX_DEBUG_UART_REGION_SIZE (0x00001000)
+
+/* Expansion Bus Controller registers. */
+#define IXP4XX_EXP_CS0       IXP4XX_REG(0xC4000000)
+#define IXP4XX_EXP_CS1       IXP4XX_REG(0xC4000004)
+#define IXP4XX_EXP_CS2       IXP4XX_REG(0xC4000008)
+#define IXP4XX_EXP_CS3       IXP4XX_REG(0xC400000C)
+#define IXP4XX_EXP_CS4       IXP4XX_REG(0xC4000010)
+#define IXP4XX_EXP_CS5       IXP4XX_REG(0xC4000014)
+#define IXP4XX_EXP_CS6       IXP4XX_REG(0xC4000018)
+#define IXP4XX_EXP_CS7       IXP4XX_REG(0xC400001C)
+
+#define IXP4XX_EXP_BASE(n)  (0x50000000 + (n) * 1000000)
+
+#define IXP4XX_EXP_EN        0x80000000
+#define IXP4XX_EXP_T1(n)    (0x10000000 * (n)) /* valid: 0 - 3 */
+#define IXP4XX_EXP_T2(n)    (0x04000000 * (n)) /* valid: 0 - 3 */
+#define IXP4XX_EXP_T3(n)    (0x00400000 * (n)) /* valid: 0 - 15 */
+#define IXP4XX_EXP_T4(n)    (0x00100000 * (n)) /* valid: 0 - 3 */
+#define IXP4XX_EXP_T5(n)    (0x00010000 * (n)) /* valid: 0 - 15 */
+#define IXP4XX_EXP_INTEL     0x00000000
+#define IXP4XX_EXP_MOTO      0x00004000
+#define IXP4XX_EXP_HPI       0x00008000
+#define IXP4XX_EXP_BITS(n)  (0x00000400 * ((n) - 9)) /* valid: 9 - 24 */
+#define IXP4XX_EXP_BYTE_RD16 0x00000040
+#define IXP4XX_EXP_HRDY_POL  0x00000020
+#define IXP4XX_EXP_MUX_EN    0x00000010
+#define IXP4XX_EXP_SPLT_EN   0x00000008
+#define IXP4XX_EXP_WR_EN     0x00000002
+#define IXP4XX_EXP_BYTE_EN   0x00000001
+
+#define IXP4XX_EXP_CFG0      IXP4XX_REG(0xC4000020)
+#define IXP4XX_EXP_CFG1      IXP4XX_REG(0xC4000024)
+#define IXP4XX_EXP_CFG2      IXP4XX_REG(0xC4000028)
+#define IXP4XX_EXP_CFG3      IXP4XX_REG(0xC400002C)
+
+
+/* Peripheral Space Register Region Base Addresses */
+#define IXP4XX_UART1_BASE    IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x0000)
+#define IXP4XX_UART2_BASE    IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x1000)
+#define IXP4XX_PMU_BASE      IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x2000)
+#define IXP4XX_INTC_BASE     IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x3000)
+#define IXP4XX_GPIO_BASE     IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x4000)
+#define IXP4XX_NPEA_BASE     IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x6000)
+#define IXP4XX_NPEB_BASE     IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x7000)
+#define IXP4XX_NPEC_BASE     IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x8000)
+#define IXP4XX_EthB_BASE     IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x9000)
+#define IXP4XX_EthC_BASE     IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0xA000)
+#define IXP4XX_USB_BASE      IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0xB000)
+/* IXP46x only */
+#define IXP4XX_EthA_BASE     IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0xC000)
+#define IXP4XX_EthB1_BASE    IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0xD000)
+#define IXP4XX_EthB2_BASE    IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0xE000)
+#define IXP4XX_EthB3_BASE    IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0xF000)
+#define IXP4XX_TIMESYNC_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x10000)
+#define IXP4XX_I2C_BASE      IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x11000)
+#define IXP4XX_SSP_BASE      IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x12000)
+
+/*
+  Constants to make it easy to access Interrupt Controller registers
+ */
+#define IXP4XX_ICPR_OFFSET   0x00 /* Interrupt Status */
+#define IXP4XX_ICMR_OFFSET   0x04 /* Interrupt Enable */
+#define IXP4XX_ICLR_OFFSET   0x08 /* Interrupt IRQ/FIQ Select */
+#define IXP4XX_ICIP_OFFSET   0x0C /* IRQ Status */
+#define IXP4XX_ICFP_OFFSET   0x10 /* FIQ Status */
+#define IXP4XX_ICHR_OFFSET   0x14 /* Interrupt Priority */
+#define IXP4XX_ICIH_OFFSET   0x18 /* IRQ Highest Pri Int */
+#define IXP4XX_ICFH_OFFSET   0x1C /* FIQ Highest Pri Int */
+
+/* IXP465-only */
+#define IXP4XX_ICPR2_OFFSET  0x20 /* Interrupt Status 2 */
+#define IXP4XX_ICMR2_OFFSET  0x24 /* Interrupt Enable 2 */
+#define IXP4XX_ICLR2_OFFSET  0x28 /* Interrupt IRQ/FIQ Select 2 */
+#define IXP4XX_ICIP2_OFFSET  0x2C /* IRQ Status */
+#define IXP4XX_ICFP2_OFFSET  0x30 /* FIQ Status */
+#define IXP4XX_ICEEN_OFFSET  0x34 /* Error High Pri Enable */
+
+
+/* Interrupt Controller Register Definitions. */
+#define IXP4XX_INTC_REG(x)   ((volatile u32 *)(IXP4XX_INTC_BASE + (x)))
+
+#define IXP4XX_ICPR          IXP4XX_INTC_REG(IXP4XX_ICPR_OFFSET)
+#define IXP4XX_ICMR          IXP4XX_INTC_REG(IXP4XX_ICMR_OFFSET)
+#define IXP4XX_ICLR          IXP4XX_INTC_REG(IXP4XX_ICLR_OFFSET)
+#define IXP4XX_ICIP          IXP4XX_INTC_REG(IXP4XX_ICIP_OFFSET)
+#define IXP4XX_ICFP          IXP4XX_INTC_REG(IXP4XX_ICFP_OFFSET)
+#define IXP4XX_ICHR          IXP4XX_INTC_REG(IXP4XX_ICHR_OFFSET)
+#define IXP4XX_ICIH          IXP4XX_INTC_REG(IXP4XX_ICIH_OFFSET)
+#define IXP4XX_ICFH          IXP4XX_INTC_REG(IXP4XX_ICFH_OFFSET)
+#define IXP4XX_ICPR2         IXP4XX_INTC_REG(IXP4XX_ICPR2_OFFSET)
+#define IXP4XX_ICMR2         IXP4XX_INTC_REG(IXP4XX_ICMR2_OFFSET)
+#define IXP4XX_ICLR2         IXP4XX_INTC_REG(IXP4XX_ICLR2_OFFSET)
+#define IXP4XX_ICIP2         IXP4XX_INTC_REG(IXP4XX_ICIP2_OFFSET)
+#define IXP4XX_ICFP2         IXP4XX_INTC_REG(IXP4XX_ICFP2_OFFSET)
+#define IXP4XX_ICEEN         IXP4XX_INTC_REG(IXP4XX_ICEEN_OFFSET)
+
+/* Constants to make it easy to access GPIO registers */
+#define IXP4XX_GPIO_GPOUTR_OFFSET   0x00
+#define IXP4XX_GPIO_GPOER_OFFSET    0x04
+#define IXP4XX_GPIO_GPINR_OFFSET    0x08
+#define IXP4XX_GPIO_GPISR_OFFSET    0x0C
+#define IXP4XX_GPIO_GPIT1R_OFFSET   0x10
+#define IXP4XX_GPIO_GPIT2R_OFFSET   0x14
+#define IXP4XX_GPIO_GPCLKR_OFFSET   0x18
+#define IXP4XX_GPIO_GPDBSELR_OFFSET 0x1C
+
+/* GPIO Register Definitions - perform only 32-bit reads/writes */
+#define IXP4XX_GPIO_REG(x)   ((volatile u32 *)(IXP4XX_GPIO_BASE + (x)))
+
+#define IXP4XX_GPIO_GPOUTR   IXP4XX_GPIO_REG(IXP4XX_GPIO_GPOUTR_OFFSET)
+#define IXP4XX_GPIO_GPOER    IXP4XX_GPIO_REG(IXP4XX_GPIO_GPOER_OFFSET)
+#define IXP4XX_GPIO_GPINR    IXP4XX_GPIO_REG(IXP4XX_GPIO_GPINR_OFFSET)
+#define IXP4XX_GPIO_GPISR    IXP4XX_GPIO_REG(IXP4XX_GPIO_GPISR_OFFSET)
+#define IXP4XX_GPIO_GPIT1R   IXP4XX_GPIO_REG(IXP4XX_GPIO_GPIT1R_OFFSET)
+#define IXP4XX_GPIO_GPIT2R   IXP4XX_GPIO_REG(IXP4XX_GPIO_GPIT2R_OFFSET)
+#define IXP4XX_GPIO_GPCLKR   IXP4XX_GPIO_REG(IXP4XX_GPIO_GPCLKR_OFFSET)
+#define IXP4XX_GPIO_GPDBSELR IXP4XX_GPIO_REG(IXP4XX_GPIO_GPDBSELR_OFFSET)
+
+/* GPIO register bit definitions */
+
+/* Interrupt styles */
+#define IXP4XX_GPIO_STYLE_ACTIVE_HIGH  0x0
+#define IXP4XX_GPIO_STYLE_ACTIVE_LOW   0x1
+#define IXP4XX_GPIO_STYLE_RISING_EDGE  0x2
+#define IXP4XX_GPIO_STYLE_FALLING_EDGE 0x3
+#define IXP4XX_GPIO_STYLE_TRANSITIONAL 0x4
+
+/* Mask used to clear interrupt styles */
+#define IXP4XX_GPIO_STYLE_CLEAR        0x7
+#define IXP4XX_GPIO_STYLE_SIZE         3
+
+/* Operating System Timer Register Definitions. */
+#define IXP4XX_OSTS          IXP4XX_REG(0xC8005000) /* Continious TimeStamp */
+#define IXP4XX_OST1          IXP4XX_REG(0xC8005004) /* Timer 1 Timestamp */
+#define IXP4XX_OSRT1         IXP4XX_REG(0xC8005008) /* Timer 1 Reload */
+#define IXP4XX_OST2          IXP4XX_REG(0xC800500C) /* Timer 2 Timestamp */
+#define IXP4XX_OSRT2         IXP4XX_REG(0xC8005010) /* Timer 2 Reload */
+#define IXP4XX_OSWT          IXP4XX_REG(0xC8005014) /* Watchdog Timer */
+#define IXP4XX_OSWE          IXP4XX_REG(0xC8005018) /* Watchdog Enable */
+#define IXP4XX_OSWK          IXP4XX_REG(0xC800501C) /* Watchdog Key */
+#define IXP4XX_OSST          IXP4XX_REG(0xC8005020) /* Timer Status */
+
+/* Timer register values and bit definitions */
+#define IXP4XX_OST_ENABLE            0x00000001
+#define IXP4XX_OST_ONE_SHOT          0x00000002
+/* Low order bits of reload value ignored */
+#define IXP4XX_OST_RELOAD_MASK       0x00000003
+#define IXP4XX_OST_DISABLED          0x00000000
+#define IXP4XX_OSST_TIMER_1_PEND     0x00000001
+#define IXP4XX_OSST_TIMER_2_PEND     0x00000002
+#define IXP4XX_OSST_TIMER_TS_PEND    0x00000004
+#define IXP4XX_OSST_TIMER_WDOG_PEND  0x00000008
+#define IXP4XX_OSST_TIMER_WARM_RESET 0x00000010
+
+#define IXP4XX_WDT_KEY               0x0000482E
+
+#define IXP4XX_WDT_RESET_ENABLE      0x00000001
+#define IXP4XX_WDT_IRQ_ENABLE        0x00000002
+#define IXP4XX_WDT_COUNT_ENABLE      0x00000004
+
+
+/* Constants to make it easy to access PCI Control/Status registers */
+#define PCI_NP_AD_OFFSET           0x00
+#define PCI_NP_CBE_OFFSET          0x04
+#define PCI_NP_WDATA_OFFSET        0x08
+#define PCI_NP_RDATA_OFFSET        0x0c
+#define PCI_CRP_AD_CBE_OFFSET      0x10
+#define PCI_CRP_WDATA_OFFSET       0x14
+#define PCI_CRP_RDATA_OFFSET       0x18
+#define PCI_CSR_OFFSET             0x1c
+#define PCI_ISR_OFFSET             0x20
+#define PCI_INTEN_OFFSET           0x24
+#define PCI_DMACTRL_OFFSET         0x28
+#define PCI_AHBMEMBASE_OFFSET      0x2c
+#define PCI_AHBIOBASE_OFFSET       0x30
+#define PCI_PCIMEMBASE_OFFSET      0x34
+#define PCI_AHBDOORBELL_OFFSET     0x38
+#define PCI_PCIDOORBELL_OFFSET     0x3C
+#define PCI_ATPDMA0_AHBADDR_OFFSET 0x40
+#define PCI_ATPDMA0_PCIADDR_OFFSET 0x44
+#define PCI_ATPDMA0_LENADDR_OFFSET 0x48
+#define PCI_ATPDMA1_AHBADDR_OFFSET 0x4C
+#define PCI_ATPDMA1_PCIADDR_OFFSET 0x50
+#define PCI_ATPDMA1_LENADDR_OFFSET 0x54
+
+/* PCI Control/Status Registers */
+#define IXP4XX_PCI_CSR(x) ((volatile u32 *)(IXP4XX_PCI_CFG_BASE + (x)))
+
+#define PCI_NP_AD            IXP4XX_PCI_CSR(PCI_NP_AD_OFFSET)
+#define PCI_NP_CBE           IXP4XX_PCI_CSR(PCI_NP_CBE_OFFSET)
+#define PCI_NP_WDATA         IXP4XX_PCI_CSR(PCI_NP_WDATA_OFFSET)
+#define PCI_NP_RDATA         IXP4XX_PCI_CSR(PCI_NP_RDATA_OFFSET)
+#define PCI_CRP_AD_CBE       IXP4XX_PCI_CSR(PCI_CRP_AD_CBE_OFFSET)
+#define PCI_CRP_WDATA        IXP4XX_PCI_CSR(PCI_CRP_WDATA_OFFSET)
+#define PCI_CRP_RDATA        IXP4XX_PCI_CSR(PCI_CRP_RDATA_OFFSET)
+#define PCI_CSR              IXP4XX_PCI_CSR(PCI_CSR_OFFSET)
+#define PCI_ISR              IXP4XX_PCI_CSR(PCI_ISR_OFFSET)
+#define PCI_INTEN            IXP4XX_PCI_CSR(PCI_INTEN_OFFSET)
+#define PCI_DMACTRL          IXP4XX_PCI_CSR(PCI_DMACTRL_OFFSET)
+#define PCI_AHBMEMBASE       IXP4XX_PCI_CSR(PCI_AHBMEMBASE_OFFSET)
+#define PCI_AHBIOBASE        IXP4XX_PCI_CSR(PCI_AHBIOBASE_OFFSET)
+#define PCI_PCIMEMBASE       IXP4XX_PCI_CSR(PCI_PCIMEMBASE_OFFSET)
+#define PCI_AHBDOORBELL      IXP4XX_PCI_CSR(PCI_AHBDOORBELL_OFFSET)
+#define PCI_PCIDOORBELL      IXP4XX_PCI_CSR(PCI_PCIDOORBELL_OFFSET)
+#define PCI_ATPDMA0_AHBADDR  IXP4XX_PCI_CSR(PCI_ATPDMA0_AHBADDR_OFFSET)
+#define PCI_ATPDMA0_PCIADDR  IXP4XX_PCI_CSR(PCI_ATPDMA0_PCIADDR_OFFSET)
+#define PCI_ATPDMA0_LENADDR  IXP4XX_PCI_CSR(PCI_ATPDMA0_LENADDR_OFFSET)
+#define PCI_ATPDMA1_AHBADDR  IXP4XX_PCI_CSR(PCI_ATPDMA1_AHBADDR_OFFSET)
+#define PCI_ATPDMA1_PCIADDR  IXP4XX_PCI_CSR(PCI_ATPDMA1_PCIADDR_OFFSET)
+#define PCI_ATPDMA1_LENADDR  IXP4XX_PCI_CSR(PCI_ATPDMA1_LENADDR_OFFSET)
+
+/* PCI register values and bit definitions */
+
+/* CSR bit definitions */
+#define PCI_CSR_HOST         0x00000001
+#define PCI_CSR_ARBEN        0x00000002
+#define PCI_CSR_ADS          0x00000004
+#define PCI_CSR_PDS          0x00000008
+#define PCI_CSR_ABE          0x00000010
+#define PCI_CSR_DBT          0x00000020
+#define PCI_CSR_ASE          0x00000100
+#define PCI_CSR_IC           0x00008000
+
+/* ISR (Interrupt status) Register bit definitions */
+#define PCI_ISR_PSE          0x00000001
+#define PCI_ISR_PFE          0x00000002
+#define PCI_ISR_PPE          0x00000004
+#define PCI_ISR_AHBE         0x00000008
+#define PCI_ISR_APDC         0x00000010
+#define PCI_ISR_PADC         0x00000020
+#define PCI_ISR_ADB          0x00000040
+#define PCI_ISR_PDB          0x00000080
+
+/* INTEN (Interrupt Enable) Register bit definitions */
+#define PCI_INTEN_PSE        0x00000001
+#define PCI_INTEN_PFE        0x00000002
+#define PCI_INTEN_PPE        0x00000004
+#define PCI_INTEN_AHBE       0x00000008
+#define PCI_INTEN_APDC       0x00000010
+#define PCI_INTEN_PADC       0x00000020
+#define PCI_INTEN_ADB        0x00000040
+#define PCI_INTEN_PDB        0x00000080
+
+/* Shift value for byte enable on NP cmd/byte enable register */
+#define IXP4XX_PCI_NP_CBE_BESL 4
+
+/* PCI commands supported by NP access unit */
+#define NP_CMD_IOREAD        0x2
+#define NP_CMD_IOWRITE       0x3
+#define NP_CMD_CONFIGREAD    0xA
+#define NP_CMD_CONFIGWRITE   0xB
+#define NP_CMD_MEMREAD       0x6
+#define NP_CMD_MEMWRITE      0x7
+
+/* Constants for CRP access into local config space */
+#define CRP_AD_CBE_BESL      20
+#define CRP_AD_CBE_WRITE     0x00010000
+
+/* USB Device Controller */
+# define IXP4XX_USB_REG(x)   (*((volatile u32 *)(x)))
+
+/* SDRAM Controller registers. */
+#define IXP4XX_SDRAM_CONFIG  IXP4XX_REG(0xCC000000)
+#define IXP4XX_SDRAM_REFRESH IXP4XX_REG(0xCC000004)
+#define IXP4XX_SDRAM_IR      IXP4XX_REG(0xCC000008)
+
+/* "fuse" bits of IXP_EXP_CFG2 */
+/* All IXP4xx CPUs */
+#define IXP4XX_FEATURE_RCOMP            (1 << 0)
+#define IXP4XX_FEATURE_USB_DEVICE       (1 << 1)
+#define IXP4XX_FEATURE_HASH             (1 << 2)
+#define IXP4XX_FEATURE_AES              (1 << 3)
+#define IXP4XX_FEATURE_DES              (1 << 4)
+#define IXP4XX_FEATURE_HDLC             (1 << 5)
+#define IXP4XX_FEATURE_AAL              (1 << 6)
+#define IXP4XX_FEATURE_HSS              (1 << 7)
+#define IXP4XX_FEATURE_UTOPIA           (1 << 8)
+#define IXP4XX_FEATURE_NPEB_ETH0        (1 << 9)
+#define IXP4XX_FEATURE_NPEC_ETH         (1 << 10)
+#define IXP4XX_FEATURE_RESET_NPEA       (1 << 11)
+#define IXP4XX_FEATURE_RESET_NPEB       (1 << 12)
+#define IXP4XX_FEATURE_RESET_NPEC       (1 << 13)
+#define IXP4XX_FEATURE_PCI              (1 << 14)
+#define IXP4XX_FEATURE_UTOPIA_PHY_LIMIT (3 << 16)
+#define IXP4XX_FEATURE_XSCALE_MAX_FREQ  (3 << 22)
+#define IXP42X_FEATURE_MASK (IXP4XX_FEATURE_RCOMP            | \
+			     IXP4XX_FEATURE_USB_DEVICE       | \
+			     IXP4XX_FEATURE_HASH             | \
+			     IXP4XX_FEATURE_AES              | \
+			     IXP4XX_FEATURE_DES              | \
+			     IXP4XX_FEATURE_HDLC             | \
+			     IXP4XX_FEATURE_AAL              | \
+			     IXP4XX_FEATURE_HSS              | \
+			     IXP4XX_FEATURE_UTOPIA           | \
+			     IXP4XX_FEATURE_NPEB_ETH0        | \
+			     IXP4XX_FEATURE_NPEC_ETH         | \
+			     IXP4XX_FEATURE_RESET_NPEA       | \
+			     IXP4XX_FEATURE_RESET_NPEB       | \
+			     IXP4XX_FEATURE_RESET_NPEC       | \
+			     IXP4XX_FEATURE_PCI              | \
+			     IXP4XX_FEATURE_UTOPIA_PHY_LIMIT | \
+			     IXP4XX_FEATURE_XSCALE_MAX_FREQ)
+
+/* IXP43x/46x CPUs */
+#define IXP4XX_FEATURE_ECC_TIMESYNC     (1 << 15)
+#define IXP4XX_FEATURE_USB_HOST         (1 << 18)
+#define IXP4XX_FEATURE_NPEA_ETH         (1 << 19)
+#define IXP43X_FEATURE_MASK (IXP42X_FEATURE_MASK             | \
+			     IXP4XX_FEATURE_ECC_TIMESYNC     | \
+			     IXP4XX_FEATURE_USB_HOST         | \
+			     IXP4XX_FEATURE_NPEA_ETH)
+
+/* IXP46x CPU (including IXP455) only */
+#define IXP4XX_FEATURE_NPEB_ETH_1_TO_3  (1 << 20)
+#define IXP4XX_FEATURE_RSA              (1 << 21)
+#define IXP46X_FEATURE_MASK (IXP43X_FEATURE_MASK             | \
+			     IXP4XX_FEATURE_NPEB_ETH_1_TO_3  | \
+			     IXP4XX_FEATURE_RSA)
+
+#endif
diff --git a/arch/arm/mach-ixp4xx/include/mach/npe.h b/arch/arm/mach-ixp4xx/include/mach/npe.h
new file mode 100644
index 0000000..18bd01b
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/include/mach/npe.h
@@ -0,0 +1,30 @@
+#ifndef __IXP4XX_NPE_H
+#define __IXP4XX_NPE_H
+
+#include <common.h>
+
+#define NPE_NAME_LENGTH 5
+
+struct npe_regs {
+	u32 exec_addr, exec_data, exec_status_cmd, exec_count;
+	u32 action_points[4];
+	u32 watchpoint_fifo, watch_count;
+	u32 profile_count;
+	u32 messaging_status, messaging_control;
+	u32 mailbox_status, /*messaging_*/ in_out_fifo;
+};
+
+struct npe {
+	struct npe_regs *regs;
+	int id, valid;
+	const char name[NPE_NAME_LENGTH + 1];
+};
+
+int npe_running(struct npe *npe);
+int npe_send_message(struct npe *npe, const void *msg, const char *what);
+int npe_recv_message(struct npe *npe, void *msg, const char *what);
+int npe_send_recv_message(struct npe *npe, void *msg, const char *what);
+int npe_load_firmware(struct npe *npe);
+struct npe *npe_request(int id);
+
+#endif /* __IXP4XX_NPE_H */
diff --git a/arch/arm/mach-ixp4xx/include/mach/platform.h b/arch/arm/mach-ixp4xx/include/mach/platform.h
new file mode 100644
index 0000000..1df4aa4
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/include/mach/platform.h
@@ -0,0 +1,15 @@
+#include <asm/types.h>
+
+#define IXP4XX_ETH_NPEA 0x00
+#define IXP4XX_ETH_NPEB 0x10
+#define IXP4XX_ETH_NPEC 0x20
+
+/* Information about built-in Ethernet MAC interfaces */
+struct eth_plat_info {
+	void *regs;
+	u8 npe;
+	u8 phy; /* MII PHY ID, 0 - 31 */
+	u8 rxq; /* configurable, currently 0 - 31 only */
+	u8 txreadyq;
+	u8 hwaddr[6];
+};
diff --git a/arch/arm/mach-ixp4xx/include/mach/qmgr.h b/arch/arm/mach-ixp4xx/include/mach/qmgr.h
new file mode 100644
index 0000000..4e9b8d4
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/include/mach/qmgr.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#ifndef IXP4XX_QMGR_H
+#define IXP4XX_QMGR_H
+
+#include <common.h>
+#include <mach/ixp4xx-regs.h>
+#include <asm/io.h>
+
+#define DEBUG_QMGR       0
+
+#define HALF_QUEUES     32
+#define QUEUES          64
+#define MAX_QUEUE_LENGTH 4 /* in dwords */
+
+#define QUEUE_STAT1_EMPTY               1 /* queue status bits */
+#define QUEUE_STAT1_NEARLY_EMPTY        2
+#define QUEUE_STAT1_NEARLY_FULL         4
+#define QUEUE_STAT1_FULL                8
+#define QUEUE_STAT2_UNDERFLOW           1
+#define QUEUE_STAT2_OVERFLOW            2
+
+#define QUEUE_WATERMARK_0_ENTRIES       0
+#define QUEUE_WATERMARK_1_ENTRY         1
+#define QUEUE_WATERMARK_2_ENTRIES       2
+#define QUEUE_WATERMARK_4_ENTRIES       3
+#define QUEUE_WATERMARK_8_ENTRIES       4
+#define QUEUE_WATERMARK_16_ENTRIES      5
+#define QUEUE_WATERMARK_32_ENTRIES      6
+#define QUEUE_WATERMARK_64_ENTRIES      7
+
+/* queue interrupt request conditions */
+#define QUEUE_IRQ_SRC_EMPTY             0
+#define QUEUE_IRQ_SRC_NEARLY_EMPTY      1
+#define QUEUE_IRQ_SRC_NEARLY_FULL       2
+#define QUEUE_IRQ_SRC_FULL              3
+#define QUEUE_IRQ_SRC_NOT_EMPTY         4
+#define QUEUE_IRQ_SRC_NOT_NEARLY_EMPTY  5
+#define QUEUE_IRQ_SRC_NOT_NEARLY_FULL   6
+#define QUEUE_IRQ_SRC_NOT_FULL          7
+
+struct qmgr_regs {
+	u32 acc[QUEUES][MAX_QUEUE_LENGTH]; /* 0x000 - 0x3FF */
+	u32 stat1[4];         /* 0x400 - 0x40F */
+	u32 stat2[2];         /* 0x410 - 0x417 */
+	u32 statne_h;         /* 0x418 - queue nearly empty */
+	u32 statf_h;          /* 0x41C - queue full */
+	u32 irqsrc[4];        /* 0x420 - 0x42F IRC source */
+	u32 irqen[2];         /* 0x430 - 0x437 IRQ enabled */
+	u32 irqstat[2];       /* 0x438 - 0x43F - IRQ access only */
+	u32 reserved[1776];
+	u32 sram[2048];       /* 0x2000 - 0x3FFF - config and buffer */
+};
+
+static const struct qmgr_regs *qmgr_regs = (struct qmgr_regs *)IXP4XX_QMGR_BASE;
+
+void qmgr_set_irq(unsigned int queue, int src,
+		  void (*handler)(void *pdev), void *pdev);
+void qmgr_enable_irq(unsigned int queue);
+void qmgr_disable_irq(unsigned int queue);
+
+/* request_ and release_queue() must be called from non-IRQ context */
+
+#if DEBUG_QMGR
+extern char qmgr_queue_descs[HALF_QUEUES][32];
+
+void qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
+			unsigned int nearly_empty_watermark,
+			unsigned int nearly_full_watermark,
+			const char *desc_format, const char* name);
+#else
+void __qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
+			  unsigned int nearly_empty_watermark,
+			  unsigned int nearly_full_watermark);
+#define qmgr_request_queue(queue, len, nearly_empty_watermark,       \
+			   nearly_full_watermark, desc_format, name) \
+	__qmgr_request_queue(queue, len, nearly_empty_watermark,     \
+			     nearly_full_watermark)
+#endif
+
+void qmgr_release_queue(unsigned int queue);
+
+
+static inline void qmgr_put_entry(unsigned int queue, u32 val)
+{
+#if DEBUG_QMGR
+	BUG_ON(!qmgr_queue_descs[queue]); /* not yet requested */
+
+	fprintf(stderr, "Queue %s(%i) put %X\n",
+		qmgr_queue_descs[queue], queue, val);
+#endif
+	__raw_writel(val, &qmgr_regs->acc[queue][0]);
+}
+
+static inline u32 qmgr_get_entry(unsigned int queue)
+{
+	u32 val;
+	val = __raw_readl(&qmgr_regs->acc[queue][0]);
+#if DEBUG_QMGR
+	BUG_ON(!qmgr_queue_descs[queue]); /* not yet requested */
+
+	fprintf(stderr, "Queue %s(%i) get %X\n",
+		qmgr_queue_descs[queue], queue, val);
+#endif
+	return val;
+}
+
+static inline int __qmgr_get_stat1(unsigned int queue)
+{
+	return (__raw_readl(&qmgr_regs->stat1[queue >> 3])
+		>> ((queue & 7) << 2)) & 0xF;
+}
+
+/**
+ * qmgr_stat_empty() - checks if a hardware queue is empty
+ * @queue: queue number
+ *
+ * Returns non-zero value if the queue is empty.
+ */
+static inline int qmgr_stat_empty(unsigned int queue)
+{
+	return __qmgr_get_stat1(queue) & QUEUE_STAT1_EMPTY;
+}
+
+/**
+ * qmgr_stat_below_low_watermark() - checks if a queue is below low watermark
+ * @queue: queue number
+ *
+ * Returns non-zero value if the queue is below low watermark.
+ */
+static inline int qmgr_stat_below_low_watermark(unsigned int queue)
+{
+	return __qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_EMPTY;
+}
+
+/**
+ * qmgr_stat_above_high_watermark() - checks if a queue is above high watermark
+ * @queue: queue number
+ *
+ * Returns non-zero value if the queue is above high watermark
+ */
+static inline int qmgr_stat_above_high_watermark(unsigned int queue)
+{
+	return __qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_FULL;
+}
+
+/**
+ * qmgr_stat_full() - checks if a hardware queue is full
+ * @queue: queue number
+ *
+ * Returns non-zero value if the queue is full.
+ */
+static inline int qmgr_stat_full(unsigned int queue)
+{
+	return __qmgr_get_stat1(queue) & QUEUE_STAT1_FULL;
+}
+
+#endif
diff --git a/arch/arm/mach-ixp4xx/npe.c b/arch/arm/mach-ixp4xx/npe.c
new file mode 100644
index 0000000..2811a03
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/npe.c
@@ -0,0 +1,668 @@
+/*
+ * Intel IXP4xx Network Processor Engine driver for Linux
+ *
+ * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <fs.h>
+#include <init.h>
+#include <malloc.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <mach/ixp4xx-regs.h>
+#include <mach/cpu.h>
+#include <mach/npe.h>
+
+#define DEBUG_MSG                      0
+#define DEBUG_FW                       0
+
+#define NPE_COUNT                      3
+#define MAX_RETRIES                    1000  /* microseconds */
+#define NPE_42X_DATA_SIZE              0x800 /* in dwords */
+#define NPE_46X_DATA_SIZE              0x1000
+#define NPE_A_42X_INSTR_SIZE           0x1000
+#define NPE_B_AND_C_42X_INSTR_SIZE     0x800
+#define NPE_46X_INSTR_SIZE             0x1000
+#define REGS_SIZE                      0x1000
+
+#define NPE_PHYS_REG                   32
+
+#define FW_MAGIC                       0xFEEDF00D
+#define FW_BLOCK_TYPE_INSTR            0x0
+#define FW_BLOCK_TYPE_DATA             0x1
+#define FW_BLOCK_TYPE_EOF              0xF
+
+/* NPE exec status (read) and command (write) */
+#define CMD_NPE_STEP                   0x01
+#define CMD_NPE_START                  0x02
+#define CMD_NPE_STOP                   0x03
+#define CMD_NPE_CLR_PIPE               0x04
+#define CMD_CLR_PROFILE_CNT            0x0C
+#define CMD_RD_INS_MEM                 0x10 /* instruction memory */
+#define CMD_WR_INS_MEM                 0x11
+#define CMD_RD_DATA_MEM                0x12 /* data memory */
+#define CMD_WR_DATA_MEM                0x13
+#define CMD_RD_ECS_REG                 0x14 /* exec access register */
+#define CMD_WR_ECS_REG                 0x15
+
+#define STAT_RUN                       0x80000000
+#define STAT_STOP                      0x40000000
+#define STAT_CLEAR                     0x20000000
+#define STAT_ECS_K                     0x00800000 /* pipeline clean */
+
+#define NPE_STEVT                      0x1B
+#define NPE_STARTPC                    0x1C
+#define NPE_REGMAP                     0x1E
+#define NPE_CINDEX                     0x1F
+
+#define INSTR_WR_REG_SHORT             0x0000C000
+#define INSTR_WR_REG_BYTE              0x00004000
+#define INSTR_RD_FIFO                  0x0F888220
+#define INSTR_RESET_MBOX               0x0FAC8210
+
+#define ECS_BG_CTXT_REG_0              0x00 /* Background Executing Context */
+#define ECS_BG_CTXT_REG_1              0x01 /* Stack level */
+#define ECS_BG_CTXT_REG_2              0x02
+#define ECS_PRI_1_CTXT_REG_0           0x04 /* Priority 1 Executing Context */
+#define ECS_PRI_1_CTXT_REG_1           0x05 /* Stack level */
+#define ECS_PRI_1_CTXT_REG_2           0x06
+#define ECS_PRI_2_CTXT_REG_0           0x08 /* Priority 2 Executing Context */
+#define ECS_PRI_2_CTXT_REG_1           0x09 /* Stack level */
+#define ECS_PRI_2_CTXT_REG_2           0x0A
+#define ECS_DBG_CTXT_REG_0             0x0C /* Debug Executing Context */
+#define ECS_DBG_CTXT_REG_1             0x0D /* Stack level */
+#define ECS_DBG_CTXT_REG_2             0x0E
+#define ECS_INSTRUCT_REG               0x11 /* NPE Instruction Register */
+
+#define ECS_REG_0_ACTIVE               0x80000000 /* all levels */
+#define ECS_REG_0_NEXTPC_MASK          0x1FFF0000 /* BG/PRI1/PRI2 levels */
+#define ECS_REG_0_LDUR_BITS            8
+#define ECS_REG_0_LDUR_MASK            0x00000700 /* all levels */
+#define ECS_REG_1_CCTXT_BITS           16
+#define ECS_REG_1_CCTXT_MASK           0x000F0000 /* all levels */
+#define ECS_REG_1_SELCTXT_BITS         0
+#define ECS_REG_1_SELCTXT_MASK         0x0000000F /* all levels */
+#define ECS_DBG_REG_2_IF               0x00100000 /* debug level */
+#define ECS_DBG_REG_2_IE               0x00080000 /* debug level */
+
+/* NPE watchpoint_fifo register bit */
+#define WFIFO_VALID                    0x80000000
+
+/* NPE messaging_status register bit definitions */
+#define MSGSTAT_OFNE  0x00010000 /* OutFifoNotEmpty */
+#define MSGSTAT_IFNF  0x00020000 /* InFifoNotFull */
+#define MSGSTAT_OFNF  0x00040000 /* OutFifoNotFull */
+#define MSGSTAT_IFNE  0x00080000 /* InFifoNotEmpty */
+#define MSGSTAT_MBINT 0x00100000 /* Mailbox interrupt */
+#define MSGSTAT_IFINT 0x00200000 /* InFifo interrupt */
+#define MSGSTAT_OFINT 0x00400000 /* OutFifo interrupt */
+#define MSGSTAT_WFINT 0x00800000 /* WatchFifo interrupt */
+
+/* NPE messaging_control register bit definitions */
+#define MSGCTL_OUT_FIFO       0x00010000 /* enable output FIFO */
+#define MSGCTL_IN_FIFO        0x00020000 /* enable input FIFO */
+#define MSGCTL_OUT_FIFO_WRITE 0x01000000 /* enable FIFO + WRITE */
+#define MSGCTL_IN_FIFO_WRITE  0x02000000
+
+/* NPE mailbox_status value for reset */
+#define RESET_MBOX_STAT          0x0000F0F0
+
+#define print_npe(npe, fmt, ...) fprintf(stderr, "%s: " fmt, npe->name, ## __VA_ARGS__)
+
+#if DEBUG_MSG
+#define debug_msg(npe, fmt, ...) print_npe(npe, fmt, ## __VA_ARGS__)
+#else
+#define debug_msg(npe, fmt, ...)
+#endif
+
+static struct {
+	u32 reg, val;
+} ecs_reset[] = {
+	{ECS_BG_CTXT_REG_0,    0xA0000000},
+	{ECS_BG_CTXT_REG_1,    0x01000000},
+	{ECS_BG_CTXT_REG_2,    0x00008000},
+	{ECS_PRI_1_CTXT_REG_0, 0x20000080},
+	{ECS_PRI_1_CTXT_REG_1, 0x01000000},
+	{ECS_PRI_1_CTXT_REG_2, 0x00008000},
+	{ECS_PRI_2_CTXT_REG_0, 0x20000080},
+	{ECS_PRI_2_CTXT_REG_1, 0x01000000},
+	{ECS_PRI_2_CTXT_REG_2, 0x00008000},
+	{ECS_DBG_CTXT_REG_0,   0x20000000},
+	{ECS_DBG_CTXT_REG_1,   0x00000000},
+	{ECS_DBG_CTXT_REG_2,   0x001E0000},
+	{ECS_INSTRUCT_REG,     0x1003C00F},
+};
+
+static struct npe npe_tab[NPE_COUNT] = {
+	{
+		.regs = (struct npe_regs *)IXP4XX_NPEA_BASE,
+		.id = 0,
+		.name = "NPE-A",
+	}, {
+		.regs = (struct npe_regs *)IXP4XX_NPEB_BASE,
+		.id = 1,
+		.name = "NPE-B",
+	}, {
+		.regs = (struct npe_regs *)IXP4XX_NPEC_BASE,
+		.id = 2,
+		.name = "NPE-C",
+	}
+};
+
+int npe_running(struct npe *npe)
+{
+	return (__raw_readl(&npe->regs->exec_status_cmd) & STAT_RUN) != 0;
+}
+
+static void npe_cmd_write(struct npe *npe, u32 addr, int cmd, u32 data)
+{
+	__raw_writel(data, &npe->regs->exec_data);
+	__raw_writel(addr, &npe->regs->exec_addr);
+	__raw_writel(cmd, &npe->regs->exec_status_cmd);
+}
+
+static u32 npe_cmd_read(struct npe *npe, u32 addr, int cmd)
+{
+	__raw_writel(addr, &npe->regs->exec_addr);
+	__raw_writel(cmd, &npe->regs->exec_status_cmd);
+	/* Iintroduce extra read cycles after issuing read command to NPE
+	   so that we read the register after the NPE has updated it.
+	   This is to overcome race condition between XScale and NPE */
+	__raw_readl(&npe->regs->exec_data);
+	__raw_readl(&npe->regs->exec_data);
+	return __raw_readl(&npe->regs->exec_data);
+}
+
+static void npe_clear_active(struct npe *npe, u32 reg)
+{
+	u32 val = npe_cmd_read(npe, reg, CMD_RD_ECS_REG);
+	npe_cmd_write(npe, reg, CMD_WR_ECS_REG, val & ~ECS_REG_0_ACTIVE);
+}
+
+static void npe_start(struct npe *npe)
+{
+	/* ensure only Background Context Stack Level is active */
+	npe_clear_active(npe, ECS_PRI_1_CTXT_REG_0);
+	npe_clear_active(npe, ECS_PRI_2_CTXT_REG_0);
+	npe_clear_active(npe, ECS_DBG_CTXT_REG_0);
+
+	__raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);
+	__raw_writel(CMD_NPE_START, &npe->regs->exec_status_cmd);
+}
+
+static void npe_stop(struct npe *npe)
+{
+	__raw_writel(CMD_NPE_STOP, &npe->regs->exec_status_cmd);
+	__raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd); /*FIXME?*/
+}
+
+static int npe_debug_instr(struct npe *npe, u32 instr, u32 ctx, u32 ldur)
+{
+	u32 wc;
+	int i;
+
+	/* set the Active bit, and the LDUR, in the debug level */
+	npe_cmd_write(npe, ECS_DBG_CTXT_REG_0, CMD_WR_ECS_REG,
+		      ECS_REG_0_ACTIVE | (ldur << ECS_REG_0_LDUR_BITS));
+
+	/* set CCTXT at ECS DEBUG L3 to specify in which context to execute
+	   the instruction, and set SELCTXT at ECS DEBUG Level to specify
+	   which context store to access.
+	   Debug ECS Level Reg 1 has form 0x000n000n, where n = context number
+	*/
+	npe_cmd_write(npe, ECS_DBG_CTXT_REG_1, CMD_WR_ECS_REG,
+		      (ctx << ECS_REG_1_CCTXT_BITS) |
+		      (ctx << ECS_REG_1_SELCTXT_BITS));
+
+	/* clear the pipeline */
+	__raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);
+
+	/* load NPE instruction into the instruction register */
+	npe_cmd_write(npe, ECS_INSTRUCT_REG, CMD_WR_ECS_REG, instr);
+
+	/* we need this value later to wait for completion of NPE execution
+	   step */
+	wc = __raw_readl(&npe->regs->watch_count);
+
+	/* issue a Step One command via the Execution Control register */
+	__raw_writel(CMD_NPE_STEP, &npe->regs->exec_status_cmd);
+
+	/* Watch Count register increments when NPE completes an instruction */
+	for (i = 0; i < MAX_RETRIES; i++) {
+		if (wc != __raw_readl(&npe->regs->watch_count))
+			return 0;
+		udelay(1);
+	}
+
+	print_npe(npe, "reset: npe_debug_instr(): timeout\n");
+	return -ETIMEDOUT;
+}
+
+static int npe_logical_reg_write8(struct npe *npe, u32 addr, u8 val, u32 ctx)
+{
+	/* here we build the NPE assembler instruction: mov8 d0, #0 */
+	u32 instr = INSTR_WR_REG_BYTE | /* OpCode */
+		addr << 9 |             /* base Operand */
+		(val & 0x1F) << 4 |     /* lower 5 bits to immediate data */
+		(val & ~0x1F) << (18 - 5);/* higher 3 bits to CoProc instr. */
+	return npe_debug_instr(npe, instr, ctx, 1); /* execute it */
+}
+
+static int npe_logical_reg_write16(struct npe *npe, u32 addr, u16 val, u32 ctx)
+{
+	/* here we build the NPE assembler instruction: mov16 d0, #0 */
+	u32 instr = INSTR_WR_REG_SHORT | /* OpCode */
+		addr << 9 |             /* base Operand */
+		(val & 0x1F) << 4 |     /* lower 5 bits to immediate data */
+		(val & ~0x1F) << (18 - 5);/* higher 11 bits to CoProc instr. */
+	return npe_debug_instr(npe, instr, ctx, 1); /* execute it */
+}
+
+static int npe_logical_reg_write32(struct npe *npe, u32 addr, u32 val, u32 ctx)
+{
+	/* write in 16 bit steps first the high and then the low value */
+	if (npe_logical_reg_write16(npe, addr, val >> 16, ctx))
+		return -ETIMEDOUT;
+	return npe_logical_reg_write16(npe, addr + 2, val & 0xFFFF, ctx);
+}
+
+static int npe_reset(struct npe *npe)
+{
+	u32 val, ctl, exec_count, ctx_reg2;
+	int i;
+
+	ctl = (__raw_readl(&npe->regs->messaging_control) | 0x3F000000) &
+		0x3F3FFFFF;
+
+	/* disable parity interrupt */
+	__raw_writel(ctl & 0x3F00FFFF, &npe->regs->messaging_control);
+
+	/* pre exec - debug instruction */
+	/* turn off the halt bit by clearing Execution Count register. */
+	exec_count = __raw_readl(&npe->regs->exec_count);
+	__raw_writel(0, &npe->regs->exec_count);
+	/* ensure that IF and IE are on (temporarily), so that we don't end up
+	   stepping forever */
+	ctx_reg2 = npe_cmd_read(npe, ECS_DBG_CTXT_REG_2, CMD_RD_ECS_REG);
+	npe_cmd_write(npe, ECS_DBG_CTXT_REG_2, CMD_WR_ECS_REG, ctx_reg2 |
+		      ECS_DBG_REG_2_IF | ECS_DBG_REG_2_IE);
+
+	/* clear the FIFOs */
+	while (__raw_readl(&npe->regs->watchpoint_fifo) & WFIFO_VALID)
+		;
+	while (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_OFNE)
+		/* read from the outFIFO until empty */
+		print_npe(npe, "npe_reset: read FIFO = 0x%X\n",
+			  __raw_readl(&npe->regs->in_out_fifo));
+
+	while (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE)
+		/* step execution of the NPE intruction to read inFIFO using
+		   the Debug Executing Context stack */
+		if (npe_debug_instr(npe, INSTR_RD_FIFO, 0, 0))
+			return -ETIMEDOUT;
+
+	/* reset the mailbox reg from the XScale side */
+	__raw_writel(RESET_MBOX_STAT, &npe->regs->mailbox_status);
+	/* from NPE side */
+	if (npe_debug_instr(npe, INSTR_RESET_MBOX, 0, 0))
+		return -ETIMEDOUT;
+
+	/* Reset the physical registers in the NPE register file */
+	for (val = 0; val < NPE_PHYS_REG; val++) {
+		if (npe_logical_reg_write16(npe, NPE_REGMAP, val >> 1, 0))
+			return -ETIMEDOUT;
+		/* address is either 0 or 4 */
+		if (npe_logical_reg_write32(npe, (val & 1) * 4, 0, 0))
+			return -ETIMEDOUT;
+	}
+
+	/* Reset the context store = each context's Context Store registers */
+
+	/* Context 0 has no STARTPC. Instead, this value is used to set NextPC
+	   for Background ECS, to set where NPE starts executing code */
+	val = npe_cmd_read(npe, ECS_BG_CTXT_REG_0, CMD_RD_ECS_REG);
+	val &= ~ECS_REG_0_NEXTPC_MASK;
+	val |= (0 /* NextPC */ << 16) & ECS_REG_0_NEXTPC_MASK;
+	npe_cmd_write(npe, ECS_BG_CTXT_REG_0, CMD_WR_ECS_REG, val);
+
+	for (i = 0; i < 16; i++) {
+		if (i) { /* Context 0 has no STEVT nor STARTPC */
+			/* STEVT = off, 0x80 */
+			if (npe_logical_reg_write8(npe, NPE_STEVT, 0x80, i))
+				return -ETIMEDOUT;
+			if (npe_logical_reg_write16(npe, NPE_STARTPC, 0, i))
+				return -ETIMEDOUT;
+		}
+		/* REGMAP = d0->p0, d8->p2, d16->p4 */
+		if (npe_logical_reg_write16(npe, NPE_REGMAP, 0x820, i))
+			return -ETIMEDOUT;
+		if (npe_logical_reg_write8(npe, NPE_CINDEX, 0, i))
+			return -ETIMEDOUT;
+	}
+
+	/* post exec */
+	/* clear active bit in debug level */
+	npe_cmd_write(npe, ECS_DBG_CTXT_REG_0, CMD_WR_ECS_REG, 0);
+	/* clear the pipeline */
+	__raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);
+	/* restore previous values */
+	__raw_writel(exec_count, &npe->regs->exec_count);
+	npe_cmd_write(npe, ECS_DBG_CTXT_REG_2, CMD_WR_ECS_REG, ctx_reg2);
+
+	/* write reset values to Execution Context Stack registers */
+	for (val = 0; val < ARRAY_SIZE(ecs_reset); val++)
+		npe_cmd_write(npe, ecs_reset[val].reg, CMD_WR_ECS_REG,
+			      ecs_reset[val].val);
+
+	/* clear the profile counter */
+	__raw_writel(CMD_CLR_PROFILE_CNT, &npe->regs->exec_status_cmd);
+
+	__raw_writel(0, &npe->regs->exec_count);
+	__raw_writel(0, &npe->regs->action_points[0]);
+	__raw_writel(0, &npe->regs->action_points[1]);
+	__raw_writel(0, &npe->regs->action_points[2]);
+	__raw_writel(0, &npe->regs->action_points[3]);
+	__raw_writel(0, &npe->regs->watch_count);
+
+	val = ixp4xx_read_feature_bits();
+	/* reset the NPE */
+	ixp4xx_write_feature_bits(val &
+				  ~(IXP4XX_FEATURE_RESET_NPEA << npe->id));
+	/* deassert reset */
+	ixp4xx_write_feature_bits(val |
+				  (IXP4XX_FEATURE_RESET_NPEA << npe->id));
+	for (i = 0; i < MAX_RETRIES; i++) {
+		if (ixp4xx_read_feature_bits() &
+		    (IXP4XX_FEATURE_RESET_NPEA << npe->id))
+			break; /* NPE is back alive */
+		udelay(1);
+	}
+	if (i == MAX_RETRIES)
+		return -ETIMEDOUT;
+
+	npe_stop(npe);
+
+	/* restore NPE configuration bus Control Register - parity settings */
+	__raw_writel(ctl, &npe->regs->messaging_control);
+	return 0;
+}
+
+
+int npe_send_message(struct npe *npe, const void *msg, const char *what)
+{
+	const u32 *send = msg;
+	int cycles = 0;
+
+	debug_msg(npe, "Trying to send message %s [%08X:%08X]\n",
+		  what, send[0], send[1]);
+
+	if (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE) {
+		debug_msg(npe, "NPE input FIFO not empty\n");
+		return -EIO;
+	}
+
+	__raw_writel(send[0], &npe->regs->in_out_fifo);
+
+	if (!(__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNF)) {
+		debug_msg(npe, "NPE input FIFO full\n");
+		return -EIO;
+	}
+
+	__raw_writel(send[1], &npe->regs->in_out_fifo);
+
+	while ((cycles < MAX_RETRIES) &&
+	       (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE)) {
+		udelay(1);
+		cycles++;
+	}
+
+	if (cycles == MAX_RETRIES) {
+		debug_msg(npe, "Timeout sending message\n");
+		return -ETIMEDOUT;
+	}
+
+#if DEBUG_MSG > 1
+	debug_msg(npe, "Sending a message took %i cycles\n", cycles);
+#endif
+	return 0;
+}
+
+int npe_recv_message(struct npe *npe, void *msg, const char *what)
+{
+	u32 *recv = msg;
+	int cycles = 0, cnt = 0;
+
+	debug_msg(npe, "Trying to receive message %s\n", what);
+
+	while (cycles < MAX_RETRIES) {
+		if (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_OFNE) {
+			recv[cnt++] = __raw_readl(&npe->regs->in_out_fifo);
+			if (cnt == 2)
+				break;
+		} else {
+			udelay(1);
+			cycles++;
+		}
+	}
+
+	switch(cnt) {
+	case 1:
+		debug_msg(npe, "Received [%08X]\n", recv[0]);
+		break;
+	case 2:
+		debug_msg(npe, "Received [%08X:%08X]\n", recv[0], recv[1]);
+		break;
+	}
+
+	if (cycles == MAX_RETRIES) {
+		debug_msg(npe, "Timeout waiting for message\n");
+		return -ETIMEDOUT;
+	}
+
+#if DEBUG_MSG > 1
+	debug_msg(npe, "Receiving a message took %i cycles\n", cycles);
+#endif
+	return 0;
+}
+
+int npe_send_recv_message(struct npe *npe, void *msg, const char *what)
+{
+	int result;
+	u32 *send = msg, recv[2];
+
+	if ((result = npe_send_message(npe, msg, what)) != 0)
+		return result;
+	if ((result = npe_recv_message(npe, recv, what)) != 0)
+		return result;
+
+	if ((recv[0] != send[0]) || (recv[1] != send[1])) {
+		debug_msg(npe, "Message %s: unexpected message received\n",
+			  what);
+		return -EIO;
+	}
+	return 0;
+}
+
+
+int npe_load_firmware(struct npe *npe)
+{
+	struct dl_block {
+		u32 type;
+		u32 offset;
+	} *blk;
+
+	struct dl_image {
+		u32 magic;
+		u32 id;
+		u32 size;
+		union {
+			u32 data[0];
+			struct dl_block blocks[0];
+		};
+	} *image;
+
+	struct dl_codeblock {
+		u32 npe_addr;
+		u32 size;
+		u32 data[0];
+	} *cb;
+
+	int i, j, err, data_size, instr_size, blocks, table_end;
+	u32 cmd;
+	char name[10 /* "/firmware/" */ + NPE_NAME_LENGTH + 1 /* NUL */];
+	size_t image_size;
+
+	sprintf(name, "/firmware/%s", npe->name);
+	if (!(image = read_file(name, &image_size))) {
+		print_npe(npe, "bad or missing microcode file %s\n", name);
+		return -EIO;
+	}
+
+	err = -EINVAL;
+	if (image_size < sizeof(struct dl_image)) {
+		print_npe(npe, "incomplete microcode file %s\n", name);
+		goto err;
+	}
+
+#if DEBUG_FW
+	print_npe(npe, "microcode: %08X %08X %08X (0x%X bytes)\n",
+		  image->magic, image->id, image->size, image->size * 4);
+#endif
+
+	if (image->magic == swab32(FW_MAGIC)) { /* swapped file */
+		image->id = swab32(image->id);
+		image->size = swab32(image->size);
+	} else if (image->magic != FW_MAGIC) {
+		print_npe(npe, "bad microcode file %s magic: 0x%X\n", name, image->magic);
+		goto err;
+	}
+	if ((image->size * 4 + sizeof(struct dl_image)) > image_size) {
+		print_npe(npe, "incomplete microcode file %s\n", name);
+		goto err;
+	}
+	if (((image->id >> 24) & 0xF /* NPE ID */) != npe->id) {
+		print_npe(npe, "NPE ID mismatch in microcode file %s\n", name);
+		goto err;
+	}
+	if (image->magic == swab32(FW_MAGIC))
+		for (i = 0; i < image->size; i++)
+			image->data[i] = swab32(image->data[i]);
+
+	if (cpu_is_ixp42x() && ((image->id >> 28) & 0xF /* device ID */)) {
+		print_npe(npe, "IXP43x/IXP46x microcode ignored on IXP42x\n");
+		goto err;
+	}
+
+	if (npe_running(npe)) {
+		print_npe(npe, "unable to load microcode file %s, NPE is already running\n", name);
+		err = -EBUSY;
+		goto err;
+	}
+
+	if (cpu_is_ixp42x()) {
+		if (!npe->id)
+			instr_size = NPE_A_42X_INSTR_SIZE;
+		else
+			instr_size = NPE_B_AND_C_42X_INSTR_SIZE;
+		data_size = NPE_42X_DATA_SIZE;
+	} else {
+		instr_size = NPE_46X_INSTR_SIZE;
+		data_size = NPE_46X_DATA_SIZE;
+	}
+
+	for (blocks = 0; blocks * sizeof(struct dl_block) / 4 < image->size;
+	     blocks++)
+		if (image->blocks[blocks].type == FW_BLOCK_TYPE_EOF)
+			break;
+	if (blocks * sizeof(struct dl_block) / 4 >= image->size) {
+		print_npe(npe, "microcode EOF block marker not found\n");
+		goto err;
+	}
+
+#if DEBUG_FW
+	print_npe(npe, "%i microcode blocks found\n", blocks);
+#endif
+
+	table_end = blocks * sizeof(struct dl_block) / 4 + 1 /* EOF marker */;
+	for (i = 0, blk = image->blocks; i < blocks; i++, blk++) {
+		if (blk->offset > image->size - sizeof(struct dl_codeblock) / 4
+		    || blk->offset < table_end) {
+			print_npe(npe, "invalid offset 0x%X of "
+				  "microcode block #%i\n", blk->offset, i);
+			goto err;
+		}
+
+		cb = (struct dl_codeblock*)&image->data[blk->offset];
+		if (blk->type == FW_BLOCK_TYPE_INSTR) {
+			if (cb->npe_addr + cb->size > instr_size)
+				goto too_big;
+			cmd = CMD_WR_INS_MEM;
+		} else if (blk->type == FW_BLOCK_TYPE_DATA) {
+			if (cb->npe_addr + cb->size > data_size)
+				goto too_big;
+			cmd = CMD_WR_DATA_MEM;
+		} else {
+			print_npe(npe, "invalid microcode block #%i type 0x%X\n",
+				  i, blk->type);
+			goto err;
+		}
+		if (blk->offset + sizeof(*cb) / 4 + cb->size > image->size) {
+			print_npe(npe, "microcode block #%i doesn't "
+				  "fit in microcode image: type %c, start 0x%X,"
+				  " length 0x%X\n", i,
+				  blk->type == FW_BLOCK_TYPE_INSTR ? 'I' : 'D',
+				  cb->npe_addr, cb->size);
+			goto err;
+		}
+
+		for (j = 0; j < cb->size; j++)
+			npe_cmd_write(npe, cb->npe_addr + j, cmd, cb->data[j]);
+	}
+
+	npe_start(npe);
+	if (!npe_running(npe))
+		print_npe(npe, "unable to start\n");
+	free(image);
+	return 0;
+
+too_big:
+	print_npe(npe, "microcode block #%i doesn't fit in NPE "
+		  "memory: type %c, start 0x%X, length 0x%X\n", i,
+		  blk->type == FW_BLOCK_TYPE_INSTR ? 'I' : 'D',
+		  cb->npe_addr, cb->size);
+err:
+	free(image);
+	return err;
+}
+
+
+struct npe *npe_request(int id)
+{
+	if (id < NPE_COUNT)
+		if (npe_tab[id].valid)
+			return &npe_tab[id];
+	return NULL;
+}
+
+static int __init npe_init(void)
+{
+	int i;
+
+	for (i = 0; i < NPE_COUNT; i++) {
+		struct npe *npe = &npe_tab[i];
+		if (!(ixp4xx_read_feature_bits() & (IXP4XX_FEATURE_RESET_NPEA << i)))
+			continue; /* NPE already disabled or not present */
+		if (npe_reset(npe))
+			continue;
+		npe->valid = 1;
+	}
+	return 0;
+}
+
+coredevice_initcall(npe_init);
diff --git a/arch/arm/mach-ixp4xx/qmgr.c b/arch/arm/mach-ixp4xx/qmgr.c
new file mode 100644
index 0000000..81b6522
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/qmgr.c
@@ -0,0 +1,259 @@
+/*
+ * Intel IXP4xx Queue Manager driver for Linux
+ *
+ * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#include <init.h>
+#include <errno.h>
+#include <mach/qmgr.h>
+
+static u32 used_sram_bitmap[4]; /* 128 16-dword pages */
+
+#if DEBUG_QMGR
+char qmgr_queue_descs[HALF_QUEUES][32];
+#endif
+
+#ifdef CONFIG_USE_IRQ
+
+static void (*irq_handlers[HALF_QUEUES])(void *pdev);
+static void *irq_pdevs[HALF_QUEUES];
+
+void qmgr_set_irq(unsigned int queue, int src,
+		  void (*handler)(void *pdev), void *pdev)
+{
+	const u32 *reg;
+	int bit;
+	BUG_ON(src > QUEUE_IRQ_SRC_NOT_FULL);
+	reg = &qmgr_regs->irqsrc[queue >> 3]; /* 8 queues per u32 */
+	bit = (queue % 8) * 4; /* 3 bits + 1 reserved bit per queue */
+	__raw_writel((__raw_readl(reg) & ~(7 << bit)) | (src << bit), reg);
+
+	irq_handlers[queue] = handler;
+	irq_pdevs[queue] = pdev;
+}
+
+
+static void qmgr_irq1_a0(void *data)
+{
+	int i;
+	u32 en_bitmap, src, stat;
+
+	/* ACK - it may clear any bits so don't rely on it */
+	__raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[0]);
+
+	en_bitmap = qmgr_regs->irqen[0];
+	while (en_bitmap) {
+		i = fls(en_bitmap) - 1; /* number of the last "low" queue */
+		en_bitmap &= ~BIT(i);
+		src = qmgr_regs->irqsrc[i >> 3];
+		stat = qmgr_regs->stat1[i >> 3];
+		if (src & 4) /* the IRQ condition is inverted */
+			stat = ~stat;
+		if (stat & BIT(src & 3))
+			irq_handlers[i](irq_pdevs[i]);
+	}
+}
+
+
+static void qmgr_irq1(void *data)
+{
+	int i;
+	u32 req_bitmap = __raw_readl(&qmgr_regs->irqstat[0]);
+
+	if (!req_bitmap)
+		return;
+	__raw_writel(req_bitmap, &qmgr_regs->irqstat[0]); /* ACK */
+
+	while (req_bitmap) {
+		i = fls(req_bitmap) - 1; /* number of the last queue */
+		req_bitmap &= ~BIT(i);
+		irq_handlers[i](irq_pdevs[i]);
+	}
+}
+
+
+void qmgr_enable_irq(unsigned int queue)
+{
+	u32 mask = 1 << queue;
+
+	__raw_writel(__raw_readl(&qmgr_regs->irqen[0]) | mask,
+		     &qmgr_regs->irqen[0]);
+}
+
+void qmgr_disable_irq(unsigned int queue)
+{
+	u32 mask = 1 << queue;
+
+	__raw_writel(__raw_readl(&qmgr_regs->irqen[0]) & ~mask,
+		     &qmgr_regs->irqen[0]);
+	__raw_writel(mask, &qmgr_regs->irqstat[0]); /* clear */
+}
+
+#endif /* CONFIG_USE_IRQ */
+
+static inline void shift_mask(u32 *mask)
+{
+	mask[3] = mask[3] << 1 | mask[2] >> 31;
+	mask[2] = mask[2] << 1 | mask[1] >> 31;
+	mask[1] = mask[1] << 1 | mask[0] >> 31;
+	mask[0] <<= 1;
+}
+
+#if DEBUG_QMGR
+void qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
+			unsigned int nearly_empty_watermark,
+			unsigned int nearly_full_watermark,
+			const char *desc_format, const char* name)
+#else
+void __qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
+			  unsigned int nearly_empty_watermark,
+			  unsigned int nearly_full_watermark)
+#endif
+{
+	u32 cfg, addr = 0, mask[4]; /* in 16-dwords */
+
+	BUG_ON(queue >= HALF_QUEUES);
+	BUG_ON((nearly_empty_watermark | nearly_full_watermark) & ~7);
+
+	switch (len) {
+	case  16:
+		cfg = 0 << 24;
+		mask[0] = 0x1;
+		break;
+	case  32:
+		cfg = 1 << 24;
+		mask[0] = 0x3;
+		break;
+	case  64:
+		cfg = 2 << 24;
+		mask[0] = 0xF;
+		break;
+	case 128:
+		cfg = 3 << 24;
+		mask[0] = 0xFF;
+		break;
+	default:
+		BUG();
+	}
+
+	cfg |= nearly_empty_watermark << 26;
+	cfg |= nearly_full_watermark << 29;
+	len /= 16; /* in 16-dwords: 1, 2, 4 or 8 */
+	mask[1] = mask[2] = mask[3] = 0;
+
+	BUG_ON(__raw_readl(&qmgr_regs->sram[queue]));
+
+	while (1) {
+		if (!(used_sram_bitmap[0] & mask[0]) &&
+		    !(used_sram_bitmap[1] & mask[1]) &&
+		    !(used_sram_bitmap[2] & mask[2]) &&
+		    !(used_sram_bitmap[3] & mask[3]))
+			break; /* found free space */
+
+		addr++;
+		shift_mask(mask);
+		if (addr + len > ARRAY_SIZE(qmgr_regs->sram)) {
+			fprintf(stderr, "qmgr: no free SRAM space for"
+				" queue %i\n", queue);
+			BUG();
+		}
+	}
+
+	used_sram_bitmap[0] |= mask[0];
+	used_sram_bitmap[1] |= mask[1];
+	used_sram_bitmap[2] |= mask[2];
+	used_sram_bitmap[3] |= mask[3];
+	__raw_writel(cfg | (addr << 14), &qmgr_regs->sram[queue]);
+#if DEBUG_QMGR
+	/* no snprintf() */
+	sprintf(qmgr_queue_descs[queue], desc_format, name);
+	fprintf(stderr, "qmgr: requested queue %s(%i) addr = 0x%02X\n",
+		qmgr_queue_descs[queue], queue, addr);
+#endif
+}
+
+void qmgr_release_queue(unsigned int queue)
+{
+	u32 cfg, addr, mask[4];
+
+	BUG_ON(queue >= HALF_QUEUES); /* not in valid range */
+
+	cfg = __raw_readl(&qmgr_regs->sram[queue]);
+	addr = (cfg >> 14) & 0xFF;
+
+	BUG_ON(!addr); /* not requested */
+
+	switch ((cfg >> 24) & 3) {
+	case 0: mask[0] = 0x1; break;
+	case 1: mask[0] = 0x3; break;
+	case 2: mask[0] = 0xF; break;
+	case 3: mask[0] = 0xFF; break;
+	}
+
+	mask[1] = mask[2] = mask[3] = 0;
+
+	while (addr--)
+		shift_mask(mask);
+
+#if DEBUG_QMGR
+	fprintf(stderr, "qmgr: releasing queue %s(%i)\n",
+		qmgr_queue_descs[queue], queue);
+	qmgr_queue_descs[queue][0] = '\x0';
+#endif
+	__raw_writel(0, &qmgr_regs->sram[queue]);
+
+	used_sram_bitmap[0] &= ~mask[0];
+	used_sram_bitmap[1] &= ~mask[1];
+	used_sram_bitmap[2] &= ~mask[2];
+	used_sram_bitmap[3] &= ~mask[3];
+#ifdef CONFIG_USE_IRQ
+	irq_handlers[queue] = NULL; /* catch IRQ bugs */
+#endif
+
+	while ((addr = qmgr_get_entry(queue)))
+		fprintf(stderr, "qmgr: released queue %i not empty: 0x%08X\n",
+			queue, addr);
+}
+
+static int __init qmgr_init(void)
+{
+	int i;
+#ifdef CONFIG_USE_IRQ
+	interrupt_handler_t *handler;
+#endif
+
+	/* reset qmgr registers */
+	for (i = 0; i < 4; i++) {
+		__raw_writel(0x33333333, &qmgr_regs->stat1[i]);
+		__raw_writel(0, &qmgr_regs->irqsrc[i]);
+	}
+	for (i = 0; i < 2; i++) {
+		__raw_writel(0, &qmgr_regs->stat2[i]);
+		__raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[i]); /* clear */
+		__raw_writel(0, &qmgr_regs->irqen[i]);
+	}
+
+	__raw_writel(0xFFFFFFFF, &qmgr_regs->statne_h);
+	__raw_writel(0, &qmgr_regs->statf_h);
+
+	for (i = 0; i < QUEUES; i++)
+		__raw_writel(0, &qmgr_regs->sram[i]);
+
+#ifdef CONFIG_USE_IRQ
+	if (cpu_is_ixp42x_rev_a0())
+		handler = qmgr_irq1_a0;
+	else
+		handler = qmgr_irq1;
+
+	irq_install_handler(IXP425_QM1_IRQ, handler, NULL);
+#endif
+	used_sram_bitmap[0] = 0xF; /* 4 first pages reserved for config */
+	return 0;
+}
+
+coredevice_initcall(qmgr_init);
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 2736094..d6164ea 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -93,6 +93,14 @@ config DRIVER_NET_MACB
 	depends on HAS_MACB
 	select PHYLIB
 
+config DRIVER_NET_IXP4XX_ETH
+	tristate "Intel IXP4xx Ethernet support"
+	depends on ARCH_IXP4XX && IXP4XX_NPE && IXP4XX_QMGR
+	select PHYLIB
+	help
+	  Say Y here if you want to use built-in Ethernet ports
+	  on IXP4xx processor.
+
 config DRIVER_NET_TAP
 	bool "tap Ethernet driver"
 	depends on LINUX
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 42136f8..4a2ced9 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_DRIVER_NET_MACB)		+= macb.o
 obj-$(CONFIG_DRIVER_NET_TAP)		+= tap.o
 obj-$(CONFIG_PHYLIB)			+= phy/
 obj-$(CONFIG_NET_USB)			+= usb/
+obj-$(CONFIG_DRIVER_NET_IXP4XX_ETH)	+= ixp4xx_eth.o
 obj-$(CONFIG_DRIVER_NET_TSE)		+= altera_tse.o
 obj-$(CONFIG_DRIVER_NET_KS8851_MLL)	+= ks8851_mll.o
 obj-$(CONFIG_DRIVER_NET_DESIGNWARE)	+= designware.o
diff --git a/drivers/net/ixp4xx_eth.c b/drivers/net/ixp4xx_eth.c
new file mode 100644
index 0000000..1ae37f1
--- /dev/null
+++ b/drivers/net/ixp4xx_eth.c
@@ -0,0 +1,741 @@
+/*
+ * Intel IXP4xx Ethernet driver for Linux
+ *
+ * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * Ethernet port config (0x00 is not present on IXP42X):
+ *
+ * logical port		0x00		0x10		0x20
+ * NPE			0 (NPE-A)	1 (NPE-B)	2 (NPE-C)
+ * physical port	2		0		1
+ * RX queue (variable)	20		21		22
+ * TX queue		23		24		25
+ * RX-free queue	26		27		28
+ * TX-done queue is always 31, per-port RX queue is configurable
+ *
+ *
+ * Queue entries:
+ * bits 0 -> 1  - NPE ID (RX and TX-done)
+ * bits 0 -> 2  - priority (TX, per 802.1D)
+ * bits 3 -> 4  - port ID (user-set?)
+ * bits 5 -> 31 - physical descriptor address
+ */
+
+#include <common.h>
+#include <init.h>
+#include <malloc.h>
+#include <net.h>
+#include <errno.h>
+#include <asm/mmu.h>
+#include <linux/mii.h>
+#include <mach/ixp4xx-regs.h>
+#include <mach/platform.h>
+#include <mach/cpu.h>
+#include <mach/npe.h>
+#include <mach/qmgr.h>
+
+#define DEBUG_DESC		0
+#define DEBUG_RX		0
+#define DEBUG_TX		0
+#define DEBUG_PKT_BYTES		0
+#define DEBUG_MDIO		0
+#define DEBUG_OPEN		0
+#define DEBUG_CLOSE		0
+
+#define RX_DESCS		16 /* also length of all RX queues */
+#define TX_DESCS		16 /* also length of all TX queues */
+#define TXDONE_QUEUE_LEN	16 /* dwords */
+
+#define MAX_MRU			1536 /* 0x600 */
+#define RX_BUFF_SIZE		MAX_MRU
+
+#define MAX_MDIO_RETRIES	100 /* microseconds, typically 30 cycles */
+#define MAX_CLOSE_WAIT		1000 /* microseconds, typically 2-3 cycles */
+#define ETH_ALEN		6
+
+#define PHYSICAL_ID(port)	(((port)->npe->id + 2) % 3)
+#define LOGICAL_ID(port)	((port)->npe->id << 4)
+#define RX_QUEUE(port)		((port)->npe->id + 20) /* can be changed */
+#define TX_QUEUE(port)		((port)->npe->id + 23)
+#define RXFREE_QUEUE(port)	((port)->npe->id + 26)
+#define TXDONE_QUEUE		31
+
+/* TX Control Registers */
+#define TX_CNTRL0_TX_EN		0x01
+#define TX_CNTRL0_HALFDUPLEX	0x02
+#define TX_CNTRL0_RETRY		0x04
+#define TX_CNTRL0_PAD_EN	0x08
+#define TX_CNTRL0_APPEND_FCS	0x10
+#define TX_CNTRL0_2DEFER	0x20
+#define TX_CNTRL0_RMII		0x40 /* reduced MII */
+#define TX_CNTRL1_RETRIES	0x0F /* 4 bits */
+
+/* RX Control Registers */
+#define RX_CNTRL0_RX_EN		0x01
+#define RX_CNTRL0_PADSTRIP_EN	0x02
+#define RX_CNTRL0_SEND_FCS	0x04
+#define RX_CNTRL0_PAUSE_EN	0x08
+#define RX_CNTRL0_LOOP_EN	0x10
+#define RX_CNTRL0_ADDR_FLTR_EN	0x20
+#define RX_CNTRL0_RX_RUNT_EN	0x40
+#define RX_CNTRL0_BCAST_DIS	0x80
+#define RX_CNTRL1_DEFER_EN	0x01
+
+/* Core Control Register */
+#define CORE_RESET		0x01
+#define CORE_RX_FIFO_FLUSH	0x02
+#define CORE_TX_FIFO_FLUSH	0x04
+#define CORE_SEND_JAM		0x08
+#define CORE_MDC_EN		0x10 /* MDIO using NPE-B ETH-0 only */
+
+#define DEFAULT_TX_CNTRL0	(TX_CNTRL0_TX_EN | TX_CNTRL0_RETRY |       \
+				 TX_CNTRL0_PAD_EN | TX_CNTRL0_APPEND_FCS | \
+				 TX_CNTRL0_2DEFER)
+#define DEFAULT_RX_CNTRL0	RX_CNTRL0_RX_EN
+#define DEFAULT_CORE_CNTRL	CORE_MDC_EN
+
+
+/* NPE message codes */
+#define NPE_GETSTATUS			 0x00
+#define NPE_EDB_SETPORTADDRESS		 0x01
+#define NPE_EDB_GETMACADDRESSDATABASE	 0x02
+#define NPE_EDB_SETMACADDRESSSDATABASE	 0x03
+#define NPE_GETSTATS			 0x04
+#define NPE_RESETSTATS			 0x05
+#define NPE_SETMAXFRAMELENGTHS		 0x06
+#define NPE_VLAN_SETRXTAGMODE		 0x07
+#define NPE_VLAN_SETDEFAULTRXVID	 0x08
+#define NPE_VLAN_SETPORTVLANTABLEENTRY	 0x09
+#define NPE_VLAN_SETPORTVLANTABLERANGE	 0x0A
+#define NPE_VLAN_SETRXQOSENTRY		 0x0B
+#define NPE_VLAN_SETPORTIDEXTRACTIONMODE 0x0C
+#define NPE_STP_SETBLOCKINGSTATE	 0x0D
+#define NPE_FW_SETFIREWALLMODE		 0x0E
+#define NPE_PC_SETFRAMECONTROLDURATIONID 0x0F
+#define NPE_PC_SETAPMACTABLE		 0x11
+#define NPE_SETLOOPBACK_MODE		 0x12
+#define NPE_PC_SETBSSIDTABLE		 0x13
+#define NPE_ADDRESS_FILTER_CONFIG	 0x14
+#define NPE_APPENDFCSCONFIG		 0x15
+#define NPE_NOTIFY_MAC_RECOVERY_DONE	 0x16
+#define NPE_MAC_RECOVERY_START		 0x17
+
+struct eth_regs {
+	u32 tx_control[2], __res1[2];		 /* 000 */
+	u32 rx_control[2], __res2[2];		 /* 010 */
+	u32 random_seed, __res3[3];		 /* 020 */
+	u32 partial_empty_threshold, __res4;	 /* 030 */
+	u32 partial_full_threshold, __res5;	 /* 038 */
+	u32 tx_start_bytes, __res6[3];		 /* 040 */
+	u32 tx_deferral, rx_deferral, __res7[2]; /* 050 */
+	u32 tx_2part_deferral[2], __res8[2];	 /* 060 */
+	u32 slot_time, __res9[3];		 /* 070 */
+	u32 mdio_command[4];			 /* 080 */
+	u32 mdio_status[4];			 /* 090 */
+	u32 mcast_mask[6], __res10[2];		 /* 0A0 */
+	u32 mcast_addr[6], __res11[2];		 /* 0C0 */
+	u32 int_clock_threshold, __res12[3];	 /* 0E0 */
+	u32 hw_addr[6], __res13[61];		 /* 0F0 */
+	u32 core_control;			 /* 1FC */
+};
+
+/* NPE message structure */
+struct msg {
+	u8 cmd, eth_id, params[6];
+};
+
+/* Ethernet packet descriptor, 32 bytes */
+struct desc {
+	u8 *next;    /* pointer to next buffer, unused */
+
+	u16 buf_len; /* buffer length */
+	u16 pkt_len; /* packet length */
+	u8 *data;    /* pointer to data buffer in RAM */
+	u8 dest_id;
+	u8 src_id;
+	u16 flags;
+	u8 qos;
+	u8 padlen;
+	u16 vlan_tci;
+
+	u8 dst_mac[ETH_ALEN], src_mac[ETH_ALEN];
+};
+
+struct io {
+	struct desc rx_desc_tab[RX_DESCS]; /* alignment: 0x10 */
+	struct desc tx_desc_tab[TX_DESCS];
+	u8 rx_buff_tab[RX_DESCS][MAX_MRU];
+	u8 tx_buff_tab[TX_DESCS][MAX_MRU];
+};
+
+struct port {
+	struct io *io;
+	struct eth_regs *regs;
+	struct npe *npe;
+	u8 firmware[4];
+	struct eth_plat_info *pinfo;
+	struct mii_bus mii_bus;
+	struct eth_device eth;
+};
+
+static struct eth_regs *mdio_regs; /* mdio command and status only */
+
+static int ixp4xx_mdio_cmd(int write, const struct device_d *dev, unsigned char phy_id,
+			   unsigned char location, unsigned short value)
+{
+	int cycles = 0;
+
+	if (__raw_readl(&mdio_regs->mdio_command[3]) & 0x80) {
+		fprintf(stderr, "%s%d: MII not ready to transmit\n", dev->name, dev->id);
+		return -1;
+	}
+
+	if (write) {
+		__raw_writel(value & 0xFF, &mdio_regs->mdio_command[0]);
+		__raw_writel(value >> 8, &mdio_regs->mdio_command[1]);
+	}
+	__raw_writel(((phy_id << 5) | location) & 0xFF,
+		     &mdio_regs->mdio_command[2]);
+	__raw_writel((phy_id >> 3) | (write << 2) | 0x80 /* GO */,
+		     &mdio_regs->mdio_command[3]);
+
+	while ((cycles < MAX_MDIO_RETRIES) &&
+	       (__raw_readl(&mdio_regs->mdio_command[3]) & 0x80)) {
+		udelay(1);
+		cycles++;
+	}
+
+	if (cycles == MAX_MDIO_RETRIES) {
+		fprintf(stderr, "%s%d: MII write failed\n", dev->name, dev->id);
+		return -1;
+	}
+
+#if DEBUG_MDIO
+	fprintf(stderr, "%s%d: mdio_%s() took %i cycles\n", dev->name, dev->id,
+		write ? "write" : "read", cycles);
+#endif
+
+	if (write)
+		return 0;
+
+	if (__raw_readl(&mdio_regs->mdio_status[3]) & 0x80) {
+#if DEBUG_MDIO
+		fprintf(stderr, "%s%d: MII read failed\n", dev->name, dev->id);
+#endif
+		return -1;
+	}
+
+	value = (__raw_readl(&mdio_regs->mdio_status[0]) & 0xFF) |
+		((__raw_readl(&mdio_regs->mdio_status[1]) & 0xFF) << 8);
+#if DEBUG_MDIO
+	fprintf(stderr, "%s%d: MII read [%i] -> 0x%X\n", dev->name, dev->id, location, value);
+#endif
+
+	return value;
+}
+
+static int ixp4xx_mdio_read(struct mii_bus *mii, int phy_id, int location)
+{
+	int ret = ixp4xx_mdio_cmd(0, &mii->dev, phy_id, location, 0);
+	return ret;
+}
+
+static int ixp4xx_mdio_write(struct mii_bus *mii, int phy_id, int location, u16 value)
+{
+	int ret = ixp4xx_mdio_cmd(1, &mii->dev, phy_id, location, value);
+#if DEBUG_MDIO
+	fprintf(stderr, "%s%d: MII write [%i] <- 0x%X, err = %i\n",
+		mii->dev.name, mii->dev.id, location, value, ret);
+#endif
+	return ret;
+}
+
+static void ixp4xx_adjust_link(struct eth_device *dev)
+{
+	struct port *port = dev->priv;
+
+	if (dev->phydev->duplex)
+		__raw_writel(DEFAULT_TX_CNTRL0 & ~TX_CNTRL0_HALFDUPLEX,
+			     &port->regs->tx_control[0]);
+	else
+		__raw_writel(DEFAULT_TX_CNTRL0 | TX_CNTRL0_HALFDUPLEX,
+			     &port->regs->tx_control[0]);
+}
+
+static inline void debug_pkt(struct eth_device *dev, const char *func,
+			     u8 *data, int len)
+{
+#if DEBUG_PKT_BYTES
+	int i;
+
+	fprintf(stderr, "%s%d: %s(%4i) ", dev->dev.name, dev->dev.id, func, len);
+	for (i = 0; i < len; i++) {
+		if (i >= DEBUG_PKT_BYTES)
+			break;
+		fprintf(stderr, "%s%02X",
+			((i == 6) || (i == 12) || (i >= 14)) ? " " : "",
+			data[i]);
+	}
+	fprintf(stderr, "\n");
+#endif
+}
+
+
+static inline void debug_desc(struct desc *desc)
+{
+#if DEBUG_DESC
+	fprintf(stderr, "%07X: %X %3X %3X %07X %2X < %2X %4X %X"
+		" %X %X %02X%02X%02X%02X%02X%02X < %02X%02X%02X%02X%02X%02X\n",
+		(u32)desc, (u32)desc->next, desc->buf_len, desc->pkt_len,
+		(u32)desc->data, desc->dest_id, desc->src_id, desc->flags,
+		desc->qos, desc->padlen, desc->vlan_tci,
+		desc->dst_mac[0], desc->dst_mac[1], desc->dst_mac[2],
+		desc->dst_mac[3], desc->dst_mac[4], desc->dst_mac[5],
+		desc->src_mac[0], desc->src_mac[1], desc->src_mac[2],
+		desc->src_mac[3], desc->src_mac[4], desc->src_mac[5]);
+#endif
+}
+
+static inline int queue_get_desc(unsigned int queue, struct port *port,
+				 int is_tx)
+{
+	u32 addr, n;
+	struct desc *tab;
+
+	if (!(addr = qmgr_get_entry(queue)))
+		return -1;
+
+	addr &= ~0x1F; /* mask out non-address bits */
+	tab = is_tx ? port->io->tx_desc_tab : port->io->rx_desc_tab;
+	n = (addr - (u32)tab) / sizeof(struct desc);
+	BUG_ON(n >= (is_tx ? TX_DESCS : RX_DESCS));
+	debug_desc((struct desc*)addr);
+	BUG_ON(tab[n].next);
+	return n;
+}
+
+static inline void queue_put_desc(unsigned int queue, struct desc *desc)
+{
+	debug_desc(desc);
+	BUG_ON(((u32)desc) & 0x1F);
+	qmgr_put_entry(queue, (u32)desc);
+	/* Don't check for queue overflow here, we've allocated sufficient
+	   length and queues >= 32 don't support this check anyway. */
+}
+
+
+static int ixp4xx_eth_poll(struct eth_device *dev)
+{
+	struct port *port = dev->priv;
+	struct desc *desc;
+	u8 *buff;
+	int n, len;
+
+#if DEBUG_RX
+	fprintf(stderr, "%s%d: eth_poll\n", dev->dev.name, dev->dev.id);
+#endif
+
+	if ((n = queue_get_desc(RX_QUEUE(port), port, 0)) < 0) {
+#if DEBUG_RX
+		fprintf(stderr, "%s%d: eth_poll = no packet received\n", dev->dev.name, dev->dev.id);
+#endif
+		return 0;
+	}
+
+	barrier();
+	desc = &port->io->rx_desc_tab[n];
+	buff = port->io->rx_buff_tab[n];
+	len = desc->pkt_len;
+	/* process received frame */
+	memcpy((void *)NetRxPackets[0], buff, len);
+	debug_pkt(dev, "RX", desc->data, len);
+
+	/* put the new buffer on RX-free queue */
+	desc->buf_len = MAX_MRU;
+	desc->pkt_len = 0;
+	queue_put_desc(RXFREE_QUEUE(port), desc);
+
+	net_receive(NetRxPackets[0], len);
+
+#if DEBUG_RX
+	fprintf(stderr, "%s%d: eth_poll end\n", dev->dev.name, dev->dev.id);
+#endif
+	return 0;
+}
+
+
+static int ixp4xx_eth_xmit(struct eth_device *dev, void *data, int len)
+{
+	struct port *port = dev->priv;
+	int n;
+	struct desc *desc;
+
+#if DEBUG_TX
+	fprintf(stderr, "%s%d: eth_xmit\n", dev->dev.name, dev->dev.id);
+#endif
+
+	if (unlikely(len > 1500))
+		return -1;
+
+	debug_pkt(dev, "TX", data, len);
+
+	if ((n = queue_get_desc(TXDONE_QUEUE, port, 1)) < 0)
+		return -1; /* no free buffers */
+	desc = &port->io->tx_desc_tab[n];
+	desc->data = port->io->tx_buff_tab[n];
+	desc->buf_len = desc->pkt_len = len;
+	memcpy(desc->data, data, len);
+
+	/* NPE firmware pads short frames with zeros internally */
+	// wmb();
+	barrier();
+	queue_put_desc(TX_QUEUE(port), desc);
+
+#if DEBUG_TX
+	fprintf(stderr, "%s%d: eth_xmit end\n", dev->dev.name, dev->dev.id);
+#endif
+	return 0;
+}
+
+static void request_queues(struct port *port, struct eth_device *dev)
+{
+	qmgr_request_queue(RXFREE_QUEUE(port), RX_DESCS, 0, 0, "%s:RX-free", dev->dev.name);
+	qmgr_request_queue(RX_QUEUE(port), RX_DESCS, 0, 0, "%s:RX", dev->dev.name);
+	qmgr_request_queue(TX_QUEUE(port), TX_DESCS, 0, 0, "%s:TX", dev->dev.name);
+
+	/* Common TX-done queue handles buffers sent out by the NPEs */
+	qmgr_request_queue(TXDONE_QUEUE, TXDONE_QUEUE_LEN, 0, 0,
+			   "%s:TX-done", dev->dev.name);
+}
+
+static void release_queues(struct port *port)
+{
+	qmgr_release_queue(RXFREE_QUEUE(port));
+	qmgr_release_queue(RX_QUEUE(port));
+	qmgr_release_queue(TX_QUEUE(port));
+	qmgr_release_queue(TXDONE_QUEUE);
+}
+
+static void init_queues(struct port *port)
+{
+	int i;
+
+	memset(port->io->tx_desc_tab, 0, sizeof(port->io->tx_desc_tab)); /* descs */
+	memset(port->io->rx_desc_tab, 0, sizeof(port->io->rx_desc_tab));
+
+	/* Setup RX buffers */
+	for (i = 0; i < RX_DESCS; i++) {
+		struct desc *desc = &port->io->rx_desc_tab[i];
+		desc->buf_len = MAX_MRU;
+		desc->data = port->io->rx_buff_tab[i];
+	}
+}
+
+static int ixp4xx_eth_open(struct eth_device *dev)
+{
+	struct port *port = dev->priv;
+	struct npe *npe = port->npe;
+	struct msg msg;
+	int i, err;
+
+#if DEBUG_OPEN
+	fprintf(stderr, "%s%d: opening %p\n", dev->dev.name, dev->dev.id, dev);
+#endif
+
+	if (!npe_running(npe)) {
+		err = npe_load_firmware(npe);
+		if (err)
+			return err;
+
+		if (npe_recv_message(npe, &msg, "ETH_GET_STATUS")) {
+			fprintf(stderr, "%s%d: %s not responding\n", dev->dev.name, dev->dev.id, npe->name);
+			return -EIO;
+		}
+		memcpy(port->firmware, msg.params + 2, 4);
+	}
+
+	err = phy_device_connect(dev, &port->mii_bus, port->pinfo->phy,
+				 ixp4xx_adjust_link, 0, PHY_INTERFACE_MODE_MII);
+	if (err)
+		return err;
+
+	port->io = dma_alloc_coherent(sizeof(*port->io));
+
+	memset(&msg, 0, sizeof(msg));
+	msg.cmd = NPE_VLAN_SETRXQOSENTRY;
+	msg.eth_id = LOGICAL_ID(port);
+	msg.params[3] = RX_QUEUE(port) | 0x80;
+	msg.params[4] = RX_QUEUE(port) >> 4; /* MSB of offset */
+	msg.params[5] = RX_QUEUE(port) << 4; /* LSB of offset */
+	for (i = 0; i < 8; i++) {
+		msg.params[1] = i;
+		if (npe_send_recv_message(port->npe, &msg, "ETH_SET_RXQ")) {
+			err = -EIO;
+			goto out;
+		}
+	}
+
+	msg.cmd = NPE_EDB_SETPORTADDRESS;
+	msg.eth_id = PHYSICAL_ID(port);
+	memcpy(msg.params, port->pinfo->hwaddr, ETH_ALEN);
+	if (npe_send_recv_message(port->npe, &msg, "ETH_SET_MAC")) {
+		err = -EIO;
+		goto out;
+	}
+
+	memset(&msg, 0, sizeof(msg));
+	msg.cmd = NPE_FW_SETFIREWALLMODE;
+	msg.eth_id = LOGICAL_ID(port);
+	if (npe_send_recv_message(port->npe, &msg, "ETH_SET_FIREWALL_MODE")) {
+		err = -EIO;
+		goto out;
+	}
+
+	request_queues(port, dev);
+	init_queues(port);
+
+	for (i = 0; i < ETH_ALEN; i++)
+		__raw_writel(port->pinfo->hwaddr[i], &port->regs->hw_addr[i]);
+	__raw_writel(0x08, &port->regs->random_seed);
+	__raw_writel(0x12, &port->regs->partial_empty_threshold);
+	__raw_writel(0x30, &port->regs->partial_full_threshold);
+	__raw_writel(0x08, &port->regs->tx_start_bytes);
+	__raw_writel(0x15, &port->regs->tx_deferral);
+	__raw_writel(0x08, &port->regs->tx_2part_deferral[0]);
+	__raw_writel(0x07, &port->regs->tx_2part_deferral[1]);
+	__raw_writel(0x80, &port->regs->slot_time);
+	__raw_writel(0x01, &port->regs->int_clock_threshold);
+
+	/* Populate queues with buffers, no failure after this point */
+	for (i = 0; i < TX_DESCS; i++)
+		queue_put_desc(TXDONE_QUEUE, &port->io->tx_desc_tab[i]);
+
+	for (i = 0; i < RX_DESCS; i++)
+		queue_put_desc(RXFREE_QUEUE(port), &port->io->rx_desc_tab[i]);
+
+	__raw_writel(TX_CNTRL1_RETRIES, &port->regs->tx_control[1]);
+	__raw_writel(DEFAULT_TX_CNTRL0, &port->regs->tx_control[0]);
+	__raw_writel(0, &port->regs->rx_control[1]);
+	__raw_writel(DEFAULT_RX_CNTRL0, &port->regs->rx_control[0]);
+
+#if 0
+	qmgr_set_irq(RX_QUEUE(port), QUEUE_IRQ_SRC_NOT_EMPTY,
+		     eth_rx_irq, dev);
+	qmgr_set_irq(TXDONE_QUEUE, QUEUE_IRQ_SRC_NOT_EMPTY,
+		     eth_txdone_irq, NULL);
+	qmgr_enable_irq(TXDONE_QUEUE);
+#endif
+	memset(&msg, 0, sizeof(msg));
+#if DEBUG_OPEN
+	fprintf(stderr, "%s%d opened\n", dev->dev.name, dev->dev.id);
+#endif
+	return 0;
+out:
+	dma_free_coherent(port->io, sizeof(*port->io));
+	port->io = NULL;
+#if DEBUG_OPEN
+	fprintf(stderr, "%s%d open failed (%i)\n", dev->dev.name, dev->dev.id, err);
+#endif
+	return err;
+}
+
+static void ixp4xx_eth_close(struct eth_device *dev)
+{
+	struct port *port = dev->priv;
+	struct msg msg;
+	int buffs = RX_DESCS; /* allocated RX buffers */
+	int i;
+
+#if DEBUG_CLOSE
+	fprintf(stderr, "%s%d: closing\n", dev->dev.name, dev->dev.id);
+#endif
+#if 0
+	qmgr_disable_irq(RX_QUEUE(port));
+#endif
+
+	if (!port->io)
+		return; /* already closed */
+
+	while (queue_get_desc(RXFREE_QUEUE(port), port, 0) >= 0)
+		buffs--;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.cmd = NPE_SETLOOPBACK_MODE;
+	msg.eth_id = LOGICAL_ID(port);
+	msg.params[1] = 1;
+	if (npe_send_recv_message(port->npe, &msg, "ETH_ENABLE_LOOPBACK"))
+		fprintf(stderr, "%s%d: unable to enable loopback\n", dev->dev.name, dev->dev.id);
+
+#if DEBUG_CLOSE
+	fprintf(stderr, "%s%d: draining RX queue\n", dev->dev.name, dev->dev.id);
+#endif
+	i = 0;
+	do { /* drain RX buffers */
+		while (queue_get_desc(RX_QUEUE(port), port, 0) >= 0)
+			buffs--;
+		if (!buffs)
+			break;
+		if (qmgr_stat_full(TXDONE_QUEUE) && !(i % 10)) {
+			/* we have to inject some packet */
+			struct desc *desc;
+			int n = queue_get_desc(TXDONE_QUEUE, port, 1);
+			BUG_ON(n < 0);
+			desc = &port->io->tx_desc_tab[n];
+			desc->buf_len = desc->pkt_len = 1;
+			//wmb();
+			barrier();
+			queue_put_desc(TX_QUEUE(port), desc);
+		}
+		udelay(1);
+	} while (++i < MAX_CLOSE_WAIT);
+
+	if (buffs)
+		fprintf(stderr, "%s%d: unable to drain RX queue, %i buffer(s) left in NPE\n",
+			dev->dev.name, dev->dev.id, buffs);
+#if DEBUG_CLOSE
+	if (!buffs)
+		fprintf(stderr, "%s%d: draining RX queue took %i cycles\n", dev->dev.name, dev->dev.id, i);
+#endif
+
+	buffs = TX_DESCS;
+	while (queue_get_desc(TX_QUEUE(port), port, 1) >= 0)
+		buffs--; /* cancel TX */
+
+	i = 0;
+	do {
+		while (queue_get_desc(TXDONE_QUEUE, port, 1) >= 0)
+			buffs--;
+		if (!buffs)
+			break;
+	} while (++i < MAX_CLOSE_WAIT);
+
+	if (buffs)
+		fprintf(stderr, "%s%d: unable to drain TX queue, %i buffer(s) left in NPE\n",
+			dev->dev.name, dev->dev.id, buffs);
+#if DEBUG_CLOSE
+	if (!buffs)
+		fprintf(stderr, "%s%d: draining TX queues took %i cycles\n", dev->dev.name, dev->dev.id, i);
+#endif
+
+	msg.params[1] = 0;
+	if (npe_send_recv_message(port->npe, &msg, "ETH_DISABLE_LOOPBACK"))
+		fprintf(stderr, "%s%d: unable to disable loopback\n", dev->dev.name, dev->dev.id);
+
+#if 0
+	qmgr_disable_irq(TXDONE_QUEUE);
+#endif
+	release_queues(port);
+	dma_free_coherent(port->io, sizeof(*port->io));
+	port->io = NULL;
+#if DEBUG_CLOSE
+	fprintf(stderr, "%s%d: closed\n", dev->dev.name, dev->dev.id);
+#endif
+}
+
+static int ixp4xx_eth_get_hwaddr(struct eth_device *eth, unsigned char *addr)
+{
+	struct port *port = eth->priv;
+	memcpy(addr, port->pinfo->hwaddr, 6);
+	return 0;
+}
+
+static int ixp4xx_eth_set_hwaddr(struct eth_device *eth, unsigned char *addr)
+{
+	struct port *port = eth->priv;
+	memcpy(port->pinfo->hwaddr, addr, 6);
+	return 0;
+}
+
+static int ixp4xx_eth_init(struct eth_device *eth)
+{
+	struct port *port = eth->priv;
+
+	__raw_writel(DEFAULT_CORE_CNTRL | CORE_RESET,
+		     &port->regs->core_control);
+	udelay(50);
+	__raw_writel(DEFAULT_CORE_CNTRL, &port->regs->core_control);
+	udelay(50);
+	return 0;
+}
+
+static int ixp4xx_eth_probe(struct device_d *dev)
+{
+	struct npe *npe;
+	struct port *port;
+	struct eth_plat_info *pinfo = dev->platform_data;
+
+	if (!pinfo) {
+		fprintf(stderr, "ixp4xx_eth: no platform information\n");
+		return -ENODEV;
+	}
+
+	if (!(npe = npe_request(pinfo->npe))) {
+		fprintf(stderr, "ixp4xx_eth: unable to acquire NPE\n");
+		return -ENODEV;
+	}
+
+	port = xmemalign(0x20, sizeof(*port));
+	memset(port, 0, sizeof(*port));
+
+	port->regs = pinfo->regs;
+	port->npe = npe;
+	port->pinfo = pinfo;
+	port->eth.dev.id = -1;
+	port->eth.priv = port;
+	port->eth.init = ixp4xx_eth_init;
+	port->eth.open = ixp4xx_eth_open;
+	port->eth.halt = ixp4xx_eth_close;
+	port->eth.send = ixp4xx_eth_xmit;
+	port->eth.recv = ixp4xx_eth_poll;
+	port->eth.get_ethaddr = ixp4xx_eth_get_hwaddr;
+	port->eth.set_ethaddr = ixp4xx_eth_set_hwaddr;
+
+	port->mii_bus.dev.id = -1;
+	port->mii_bus.read = ixp4xx_mdio_read;
+	port->mii_bus.write = ixp4xx_mdio_write;
+	mdiobus_register(&port->mii_bus);
+	eth_register(&port->eth);
+	dev->priv = port;
+	return 0;
+}
+
+static void ixp4xx_eth_remove(struct device_d *dev)
+{
+	struct port *port = dev->priv;
+	ixp4xx_eth_close(&port->eth);
+	eth_unregister(&port->eth);
+	mdiobus_unregister(&port->mii_bus);
+	free(port);
+}
+
+static struct driver_d ixp4xx_eth_driver = {
+	.name  = "ixp4xx_eth",
+	.probe = ixp4xx_eth_probe,
+	.remove = ixp4xx_eth_remove,
+};
+
+static int __init ixp4xx_eth_module_init(void)
+{
+	if (cpu_is_ixp43x()) {
+		/* IXP43x lacks NPE-B and uses NPE-C for MII PHY access */
+		if (!(ixp4xx_read_feature_bits() & IXP4XX_FEATURE_NPEC_ETH))
+			return -ENOSYS;
+		mdio_regs = (struct eth_regs *)IXP4XX_EthC_BASE;
+	} else {
+		/* All MII PHY accesses use NPE-B Ethernet registers */
+		if (!(ixp4xx_read_feature_bits() & IXP4XX_FEATURE_NPEB_ETH0))
+			return -ENOSYS;
+		mdio_regs = (struct eth_regs *)IXP4XX_EthB_BASE;
+	}
+
+	__raw_writel(DEFAULT_CORE_CNTRL, &mdio_regs->core_control);
+
+	platform_driver_register(&ixp4xx_eth_driver);
+	return 0;
+}
+
+device_initcall(ixp4xx_eth_module_init);
diff --git a/drivers/serial/serial_ns16550.c b/drivers/serial/serial_ns16550.c
index b7913aa..be1b968 100644
--- a/drivers/serial/serial_ns16550.c
+++ b/drivers/serial/serial_ns16550.c
@@ -137,7 +137,11 @@ static void ns16550_serial_init_port(struct console_device *cdev)
 {
 	/* initializing the device for the first time */
 	ns16550_write(cdev, 0x00, lcr); /* select ier reg */
+#ifdef CONFIG_ARCH_IXP4XX
+	ns16550_write(cdev, IER_UUE, ier); /* Enable UART operation */
+#else
 	ns16550_write(cdev, 0x00, ier);
+#endif
 
 #ifdef CONFIG_DRIVER_SERIAL_NS16550_OMAP_EXTENSIONS
 	ns16550_write(cdev, 0x07, mdr1);	/* Disable */
diff --git a/drivers/serial/serial_ns16550.h b/drivers/serial/serial_ns16550.h
index db8fe64..132f46e 100644
--- a/drivers/serial/serial_ns16550.h
+++ b/drivers/serial/serial_ns16550.h
@@ -50,6 +50,8 @@
 #define dll		rbr
 #define dlm		ier
 
+#define IER_UUE		0x40	/* UART Unit Enable (XScale) */
+
 #define FCR_FIFO_EN     0x01	/* Fifo enable */
 #define FCR_RXSR        0x02	/* Receiver soft reset */
 #define FCR_TXSR        0x04	/* Transmitter soft reset */

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] Implement ALTERNATE memory layout.
  2013-03-30 11:25 ` [PATCH] Implement ALTERNATE memory layout Krzysztof Halasa
@ 2013-03-30 12:01   ` Alexander Shiyan
  2013-03-30 13:15     ` Krzysztof Halasa
  2013-03-30 18:45   ` Antony Pavlov
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 24+ messages in thread
From: Alexander Shiyan @ 2013-03-30 12:01 UTC (permalink / raw)
  To: Krzysztof Halasa; +Cc: barebox

...
> --- a/common/Kconfig
> +++ b/common/Kconfig
> @@ -161,7 +161,7 @@ choice
>  config MEMORY_LAYOUT_DEFAULT
>  	bool "use default memory layout"
>  	help
> -	  select this option to use bareboxs standard memory layout:
> +	  select this option to use barebox's standard memory layout:
>  
>  	  stack
>  	  -----
> @@ -169,6 +169,17 @@ config MEMORY_LAYOUT_DEFAULT
>  	  -----
>  	  TEXT_BASE
>  
> +config MEMORY_LAYOUT_ALTERNATE
> +	bool "use alternate memory layout"
> +	help
> +	  select this option to use barebox's alternate memory layout:
> +
> +	  TEXT_BASE
> +	  -----
> +	  malloc heap
> +	  -----
> +	  stack
> +

This should be described better.

---
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] Implement ALTERNATE memory layout.
  2013-03-30 12:01   ` Alexander Shiyan
@ 2013-03-30 13:15     ` Krzysztof Halasa
  2013-03-30 13:23       ` Re[2]: " Alexander Shiyan
  0 siblings, 1 reply; 24+ messages in thread
From: Krzysztof Halasa @ 2013-03-30 13:15 UTC (permalink / raw)
  To: Alexander Shiyan; +Cc: barebox

Alexander Shiyan <shc_work@mail.ru> writes:

>> +config MEMORY_LAYOUT_ALTERNATE
>> +	bool "use alternate memory layout"
>> +	help
>> +	  select this option to use barebox's alternate memory layout:
>> +
>> +	  TEXT_BASE
>> +	  -----
>> +	  malloc heap
>> +	  -----
>> +	  stack
>> +
>
> This should be described better.

Well... I did it after the default layout. What do you propose?
-- 
Krzysztof Halasa

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re[2]: [PATCH] Implement ALTERNATE memory layout.
  2013-03-30 13:15     ` Krzysztof Halasa
@ 2013-03-30 13:23       ` Alexander Shiyan
  2013-03-30 19:57         ` Krzysztof Halasa
  0 siblings, 1 reply; 24+ messages in thread
From: Alexander Shiyan @ 2013-03-30 13:23 UTC (permalink / raw)
  To: Krzysztof Halasa; +Cc: barebox

> Alexander Shiyan <shc_work@mail.ru> writes:
> 
> >> +config MEMORY_LAYOUT_ALTERNATE
> >> +	bool "use alternate memory layout"
> >> +	help
> >> +	  select this option to use barebox's alternate memory layout:
> >> +
> >> +	  TEXT_BASE
> >> +	  -----
> >> +	  malloc heap
> >> +	  -----
> >> +	  stack
> >> +
> >
> > This should be described better.
> 
> Well... I did it after the default layout. What do you propose?

I cannot say more.
Since this option globally for all barebox targets, it is necessary to
describe all aspects of its application.

---
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] Implement ALTERNATE memory layout.
  2013-03-30 11:25 ` [PATCH] Implement ALTERNATE memory layout Krzysztof Halasa
  2013-03-30 12:01   ` Alexander Shiyan
@ 2013-03-30 18:45   ` Antony Pavlov
  2013-04-01 18:04   ` Sascha Hauer
  2013-04-02  7:20   ` Sascha Hauer
  3 siblings, 0 replies; 24+ messages in thread
From: Antony Pavlov @ 2013-03-30 18:45 UTC (permalink / raw)
  To: Krzysztof Halasa; +Cc: barebox


[-- Attachment #1.1: Type: text/plain, Size: 3189 bytes --]

On 30 March 2013 15:25, Krzysztof Halasa <khc@pm.waw.pl> wrote:

> Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>
>
> --- a/arch/arm/cpu/start.c
> +++ b/arch/arm/cpu/start.c
> @@ -58,7 +58,6 @@ static noinline __noreturn void __start(uint32_t
> membase, uint32_t memsize,
>         endmem -= STACK_SIZE; /* Stack */
>
>         if (IS_ENABLED(CONFIG_MMU_EARLY)) {
> -
>                 endmem &= ~0x3fff;
>                 endmem -= SZ_16K; /* ttb */


This is a formatting change not functional change. Please, move it to a
separate patch.


>


> @@ -66,6 +65,9 @@ static noinline __noreturn void __start(uint32_t
> membase, uint32_t memsize,
>                         mmu_early_enable(membase, memsize, endmem);
>         }
>
> +#ifdef CONFIG_MEMORY_LAYOUT_ALTERNATE
> +               malloc_end = endmem;
> +#else
>         if ((unsigned long)_text > membase + memsize ||
>                         (unsigned long)_text < membase)
>                 /*
> @@ -76,15 +78,21 @@ static noinline __noreturn void __start(uint32_t
> membase, uint32_t memsize,
>                 malloc_end = endmem;
>         else
>                 malloc_end = (unsigned long)_text;
> +#endif
>
>         /*
>          * Maximum malloc space is the Kconfig value if given
>          * or 64MB.
>          */
>         if (MALLOC_SIZE > 0) {
> -               malloc_start = malloc_end - MALLOC_SIZE;
> -               if (malloc_start < membase)
> +               if (malloc_end > membase + MALLOC_SIZE)
> +                       malloc_start = malloc_end - MALLOC_SIZE;
> +               else
>                         malloc_start = membase;
> +               if (malloc_start < (unsigned long)_end &&
> +                   malloc_end > (unsigned long)_text)
> +                       /* malloc area follows text */
> +                       malloc_start = (unsigned long)_end;
>         } else {
>                 malloc_start = malloc_end - (malloc_end - membase) / 2;
>                 if (malloc_end - malloc_start > SZ_64M)
> --- a/common/Kconfig
> +++ b/common/Kconfig
> @@ -161,7 +161,7 @@ choice
>  config MEMORY_LAYOUT_DEFAULT
>         bool "use default memory layout"
>         help
> -         select this option to use bareboxs standard memory layout:
> +         select this option to use barebox's standard memory layout:
>
>
This is a "fix typo" change. Please, move it to a separate patch.

          stack
>           -----
> @@ -169,6 +169,17 @@ config MEMORY_LAYOUT_DEFAULT
>           -----
>           TEXT_BASE
>
> +config MEMORY_LAYOUT_ALTERNATE
> +       bool "use alternate memory layout"
> +       help
> +         select this option to use barebox's alternate memory layout:
> +
> +         TEXT_BASE
> +         -----
> +         malloc heap
> +         -----
> +         stack
> +
>  config MEMORY_LAYOUT_FIXED
>         bool "manually assign a memory layout"
>         help
>
> _______________________________________________
> barebox mailing list
> barebox@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox
>



-- 
Best regards,
  Antony Pavlov

[-- Attachment #1.2: Type: text/html, Size: 5077 bytes --]

[-- Attachment #2: Type: text/plain, Size: 149 bytes --]

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] Implement ALTERNATE memory layout.
  2013-03-30 13:23       ` Re[2]: " Alexander Shiyan
@ 2013-03-30 19:57         ` Krzysztof Halasa
  0 siblings, 0 replies; 24+ messages in thread
From: Krzysztof Halasa @ 2013-03-30 19:57 UTC (permalink / raw)
  To: Alexander Shiyan; +Cc: barebox

Alexander Shiyan <shc_work@mail.ru> writes:

>> >> +config MEMORY_LAYOUT_ALTERNATE
>> >> +	bool "use alternate memory layout"
>> >> +	help
>> >> +	  select this option to use barebox's alternate memory layout:
>> >> +
>> >> +	  TEXT_BASE
>> >> +	  -----
>> >> +	  malloc heap
>> >> +	  -----
>> >> +	  stack
>> >> +
>> >
>> > This should be described better.
>> 
>> Well... I did it after the default layout. What do you propose?
>
> I cannot say more.
> Since this option globally for all barebox targets, it is necessary to
> describe all aspects of its application.

But what "aspects" are you thinking about? This simply swaps the order
in which text (+data/bss) and heap appear in memory.

OTOH I think I should probably restrict its use to ARM, since the code
is ARM-only.
-- 
Krzysztof Halasa

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] Implement ALTERNATE memory layout.
  2013-03-30 11:25 ` [PATCH] Implement ALTERNATE memory layout Krzysztof Halasa
  2013-03-30 12:01   ` Alexander Shiyan
  2013-03-30 18:45   ` Antony Pavlov
@ 2013-04-01 18:04   ` Sascha Hauer
  2013-04-02  7:20   ` Sascha Hauer
  3 siblings, 0 replies; 24+ messages in thread
From: Sascha Hauer @ 2013-04-01 18:04 UTC (permalink / raw)
  To: Krzysztof Halasa; +Cc: barebox

On Sat, Mar 30, 2013 at 12:25:35PM +0100, Krzysztof Halasa wrote:
> Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>
> 
> --- a/arch/arm/cpu/start.c
> +++ b/arch/arm/cpu/start.c
> @@ -58,7 +58,6 @@ static noinline __noreturn void __start(uint32_t membase, uint32_t memsize,
>  	endmem -= STACK_SIZE; /* Stack */
>  
>  	if (IS_ENABLED(CONFIG_MMU_EARLY)) {
> -
>  		endmem &= ~0x3fff;
>  		endmem -= SZ_16K; /* ttb */
>  
> @@ -66,6 +65,9 @@ static noinline __noreturn void __start(uint32_t membase, uint32_t memsize,
>  			mmu_early_enable(membase, memsize, endmem);
>  	}
>  
> +#ifdef CONFIG_MEMORY_LAYOUT_ALTERNATE
> +		malloc_end = endmem;
> +#else

We should not need a kconfig option for this. Why not just use the
biggest memory region we find? Whether this is below or above the
barebox binary doesn't need to be known at compile time.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] ARM: Add support for IXP4xx CPU and for Goramo Multilink router platform.
  2013-03-30 11:26 ` [PATCH] ARM: Add support for IXP4xx CPU and for Goramo Multilink router platform Krzysztof Halasa
@ 2013-04-02  6:52   ` Sascha Hauer
  2013-04-07 11:42     ` Krzysztof Halasa
  0 siblings, 1 reply; 24+ messages in thread
From: Sascha Hauer @ 2013-04-02  6:52 UTC (permalink / raw)
  To: Krzysztof Halasa; +Cc: barebox

On Sat, Mar 30, 2013 at 12:26:47PM +0100, Krzysztof Halasa wrote:
> Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>

The npe driver and the network driver should really be a separate patch.
Some more comments inline.

> 
> +static struct eth_plat_info eth_pinfo[2] = {

Why not use dynamically sized arrays?

> diff --git a/arch/arm/lib/barebox.lds.S b/arch/arm/lib/barebox.lds.S
> index 10c63bf..b40b24b 100644
> --- a/arch/arm/lib/barebox.lds.S
> +++ b/arch/arm/lib/barebox.lds.S
> @@ -40,6 +40,9 @@ SECTIONS
>  		_stext = .;
>  		_text = .;
>  		*(.text_entry*)
> +#ifdef CONFIG_MACH_GORAMO_MLR
> +		. = 0x0080; /* config space at 0x40 - 0x7F */
> +#endif

Please use PRE_IMAGE. We do not want to have such stuff in the generic
linker script.

> +#ifdef CONFIG_DRIVER_SERIAL_NS16550
> +
> +/**
> + * @brief UART port register read function for IXP4XX
> + *
> + * @param base base address of UART
> + * @param reg_idx register index
> + *
> + * @return character read from register
> + */
> +unsigned int ixp4xx_uart_read(unsigned long base, unsigned char reg_idx)
> +{
> +	return readb(4 * reg_idx + 3 /* big-endian */ + (uint8_t *)base);
> +}
> +EXPORT_SYMBOL(ixp4xx_uart_read);
> +
> +/**
> + * @brief UART port register write function for IXP4XX
> + *
> + * @param val value to write
> + * @param base base address of UART
> + * @param reg_idx register index
> + *
> + * @return void
> + */
> +void ixp4xx_uart_write(unsigned int val, unsigned long base, unsigned char reg_idx)
> +{
> +	writeb(val, 4 * reg_idx + 3 /* big-endian */ + (uint8_t *)base);
> +}
> +EXPORT_SYMBOL(ixp4xx_uart_write);
> +
> +
> +static struct NS16550_plat serial_plat = {
> +	.clock = 14745600,
> +	.f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR,
> +	.reg_read = ixp4xx_uart_read,
> +	.reg_write = ixp4xx_uart_write,
> +};
> +
> +/**
> + * @brief UART serial port initialization
> + *
> + * @return result of device registration
> + */
> +static int ixp4xx_console_init(void)
> +{
> +	/* Register the serial port */
> +	add_ns16550_device(0, (u32)IXP4XX_UART1_BASE, 1024, IORESOURCE_MEM_8BIT, &serial_plat);
> +	return 0;
> +}
> +
> +console_initcall(ixp4xx_console_init);
> +
> +#endif /* CONFIG_DRIVER_SERIAL_NS16550 */
> diff --git a/arch/arm/mach-ixp4xx/include/mach/cpu.h b/arch/arm/mach-ixp4xx/include/mach/cpu.h
> new file mode 100644
> index 0000000..3de021e
> --- /dev/null
> +++ b/arch/arm/mach-ixp4xx/include/mach/cpu.h
> @@ -0,0 +1,70 @@
> +/*
> + * arch/arm/mach-ixp4xx/include/mach/cpu.h
> + *
> + * IXP4XX cpu type detection
> + *
> + * Copyright (C) 2007 MontaVista Software, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#ifndef __ASM_ARCH_CPU_H__
> +#define __ASM_ARCH_CPU_H__
> +
> +#include <linux/types.h>
> +
> +/* Processor id value in CP15 Register 0 */
> +#define IXP42X_PROCESSOR_ID_VALUE 0x690541c0 /* including unused 0x690541Ex */
> +#define IXP42X_PROCESSOR_ID_MASK  0xffffffc0
> +
> +#define IXP43X_PROCESSOR_ID_VALUE 0x69054040
> +#define IXP43X_PROCESSOR_ID_MASK  0xfffffff0
> +
> +#define IXP46X_PROCESSOR_ID_VALUE 0x69054200 /* including IXP455 */
> +#define IXP46X_PROCESSOR_ID_MASK  0xfffffff0
> +
> +#define cpu_is_ixp42x_rev_a0() ((read_cpuid_id() & (IXP42X_PROCESSOR_ID_MASK | 0xF)) == \
> +				IXP42X_PROCESSOR_ID_VALUE)
> +#define cpu_is_ixp42x() ((read_cpuid_id() & IXP42X_PROCESSOR_ID_MASK) == \
> +			 IXP42X_PROCESSOR_ID_VALUE)
> +#define cpu_is_ixp43x() ((read_cpuid_id() & IXP43X_PROCESSOR_ID_MASK) == \
> +			 IXP43X_PROCESSOR_ID_VALUE)
> +#define cpu_is_ixp46x() ((read_cpuid_id() & IXP46X_PROCESSOR_ID_MASK) == \
> +			 IXP46X_PROCESSOR_ID_VALUE)
> +
> +/*
> + * The CPU ID never changes at run time, so we might as well tell the
> + * compiler that it's constant.  Use this function to read the CPU ID
> + * rather than directly reading processor_id or read_cpuid() directly.
> + */
> +static inline u32 __attribute_const__ read_cpuid_id(void)
> +{
> +	u32 val;
> +	asm("mrc p15, 0, %0, c0, c0, 0" : "=r" (val) : : "cc");
> +
> +	return val;
> +}

We already have this function. Please do not duplicate.

> +
> +static inline u32 ixp4xx_read_feature_bits(void)
> +{
> +	u32 val = ~IXP4XX_EXP_CFG2;
> +
> +	if (cpu_is_ixp42x_rev_a0())
> +		return IXP42X_FEATURE_MASK & ~(IXP4XX_FEATURE_RCOMP |
> +					       IXP4XX_FEATURE_AES);
> +	if (cpu_is_ixp42x())
> +		return val & IXP42X_FEATURE_MASK;
> +	if (cpu_is_ixp43x())
> +		return val & IXP43X_FEATURE_MASK;
> +	return val & IXP46X_FEATURE_MASK;
> +}
> +
> +static inline void ixp4xx_write_feature_bits(u32 value)
> +{
> +	IXP4XX_EXP_CFG2 = ~value;
> +}
> +
> +#endif  /* _ASM_ARCH_CPU_H */
> diff --git a/arch/arm/mach-ixp4xx/include/mach/ixp4xx-head.h b/arch/arm/mach-ixp4xx/include/mach/ixp4xx-head.h
> new file mode 100644
> index 0000000..b3d357f
> --- /dev/null
> +++ b/arch/arm/mach-ixp4xx/include/mach/ixp4xx-head.h
> @@ -0,0 +1,16 @@
> +#include <mach/ixp4xx-regs.h>
> +#include <asm/barebox-arm-head.h>
> +
> +.macro	ixp4xx_cpu_lowlevel_init
> +
> +	arm_cpu_lowlevel_init r0
> +
> +	add pc, #(0x50000000 - 4) /* jump to ROM area */
> +
> +	mov r0, #(IXP4XX_EXP_CFG0 & 0xFFFF0000)
> +	orr r0, #(IXP4XX_EXP_CFG0 & 0x0000FFFF)
> +	ldr r1, [r0]
> +	and r1, r1, #~0x80000000 /* unmap EXP bus from 0x0 */
> +	str r1, [r0]
> +
> +.endm

[...]

> +
> +static struct npe npe_tab[NPE_COUNT] = {
> +	{
> +		.regs = (struct npe_regs *)IXP4XX_NPEA_BASE,
> +		.id = 0,
> +		.name = "NPE-A",
> +	}, {
> +		.regs = (struct npe_regs *)IXP4XX_NPEB_BASE,
> +		.id = 1,
> +		.name = "NPE-B",
> +	}, {
> +		.regs = (struct npe_regs *)IXP4XX_NPEC_BASE,
> +		.id = 2,
> +		.name = "NPE-C",
> +	}
> +};

#define NPE_COUNT ARRAY_SIZE(npe_tab)?

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] Implement ALTERNATE memory layout.
  2013-03-30 11:25 ` [PATCH] Implement ALTERNATE memory layout Krzysztof Halasa
                     ` (2 preceding siblings ...)
  2013-04-01 18:04   ` Sascha Hauer
@ 2013-04-02  7:20   ` Sascha Hauer
  3 siblings, 0 replies; 24+ messages in thread
From: Sascha Hauer @ 2013-04-02  7:20 UTC (permalink / raw)
  To: Krzysztof Halasa; +Cc: barebox

Hi Krzysztof,

The following patch from Jan is probably what you're looking for.

Sascha

8<-----------------------------------------------------------

On AM335x a barebox MLO is placed at the base of the usable SRAM range.
When running without SDRAM, we should be able to pass the SRAM range
to barebox_arm_entry.

First we check if the ends of the memory range lie in the barebox image
and reduce the range in these cases. Then we check if the image splits
the memory range in two and choose to use the larger one.

Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
---
 arch/arm/cpu/start.c |   48 +++++++++++++++++++++++++++++++-----------------
 1 file changed, 31 insertions(+), 17 deletions(-)

diff --git a/arch/arm/cpu/start.c b/arch/arm/cpu/start.c
index cd34d9c..fa148c2 100644
--- a/arch/arm/cpu/start.c
+++ b/arch/arm/cpu/start.c
@@ -34,38 +34,52 @@ unsigned long arm_stack_top;
 static noinline __noreturn void __start(uint32_t membase, uint32_t memsize,
 		uint32_t boarddata)
 {
-	unsigned long endmem = membase + memsize;
+	unsigned long memend;
 	unsigned long malloc_start, malloc_end;
 
 	setup_c();
 
-	arm_stack_top = endmem;
-	endmem -= STACK_SIZE; /* Stack */
+	if ((unsigned long)_text <= membase &&
+	    (unsigned long)_end > membase) { /* membase is in barebox */
+		memsize -= (unsigned long)_end - membase;
+		membase = (unsigned long)_end;
+	}
+
+	if ((unsigned long)_text < membase + memsize &&
+	    (unsigned long)_end >= membase + memsize) { /* membase + memsize is in barebox */
+		memsize = (unsigned long)_text - membase;
+	}
+
+	if ((unsigned long)_text > membase &&
+	    (unsigned long)_end < membase + memsize) { /* barebox splits or memory range */
+		unsigned long lowsize = (unsigned long)_text - membase;
+		unsigned long highsize = membase + memsize - (unsigned long)_end;
+		/* use larger range */
+		if (lowsize > highsize) {
+			memsize = lowsize;
+		} else {
+			membase = (unsigned long)_end;
+			memsize = highsize;
+		}
+	}
+
+	arm_stack_top = membase + memsize;
+	memend = membase + memsize - STACK_SIZE; /* Stack */
 
 	if (IS_ENABLED(CONFIG_MMU_EARLY)) {
 
-		endmem &= ~0x3fff;
-		endmem -= SZ_16K; /* ttb */
+		memend &= ~0x3fff;
+		memend -= SZ_16K; /* ttb */
 
 		if (!IS_ENABLED(CONFIG_PBL_IMAGE))
-			mmu_early_enable(membase, memsize, endmem);
+			mmu_early_enable(membase, memsize, memend);
 	}
 
-	if ((unsigned long)_text > membase + memsize ||
-			(unsigned long)_text < membase)
-		/*
-		 * barebox is either outside SDRAM or in another
-		 * memory bank, so we can use the whole bank for
-		 * malloc.
-		 */
-		malloc_end = endmem;
-	else
-		malloc_end = (unsigned long)_text;
-
 	/*
 	 * Maximum malloc space is the Kconfig value if given
 	 * or 64MB.
 	 */
+	malloc_end = memend;
 	if (MALLOC_SIZE > 0) {
 		malloc_start = malloc_end - MALLOC_SIZE;
 		if (malloc_start < membase)
-- 
1.7.10.4


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] ARM: Add support for IXP4xx CPU and for Goramo Multilink router platform.
  2013-04-02  6:52   ` Sascha Hauer
@ 2013-04-07 11:42     ` Krzysztof Halasa
  2013-04-07 19:54       ` [PATCH] ARM: Support for IXP4xx CPU Krzysztof Halasa
                         ` (4 more replies)
  0 siblings, 5 replies; 24+ messages in thread
From: Krzysztof Halasa @ 2013-04-07 11:42 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: barebox

Sascha Hauer <s.hauer@pengutronix.de> writes:

>> +static struct eth_plat_info eth_pinfo[2] = {
>
> Why not use dynamically sized arrays?

What do you mean?


Everything else: done, will post shortly.
-- 
Krzysztof Halasa

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH] ARM: Support for IXP4xx CPU.
  2013-04-07 11:42     ` Krzysztof Halasa
@ 2013-04-07 19:54       ` Krzysztof Halasa
  2013-04-08  7:27         ` Jean-Christophe PLAGNIOL-VILLARD
  2013-04-07 19:55       ` [PATCH] ARM: Support for IXP4xx hardware Queue Manager Krzysztof Halasa
                         ` (3 subsequent siblings)
  4 siblings, 1 reply; 24+ messages in thread
From: Krzysztof Halasa @ 2013-04-07 19:54 UTC (permalink / raw)
  To: barebox

Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index bb9b47b..2a775d5 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -79,6 +79,12 @@ config ARCH_IMX
 	select WATCHDOG_IMX_RESET_SOURCE
 	select HAS_DEBUG_LL
 
+config ARCH_IXP4XX
+	bool "Intel IXP4xx-based"
+	select CPU_XSCALE
+	select ARCH_SUPPORTS_BIG_ENDIAN
+	select CPU_BIG_ENDIAN
+
 config ARCH_MXS
 	bool "Freescale i.MX23/28 (mxs) based"
 	select GENERIC_GPIO
@@ -153,6 +159,7 @@ source arch/arm/mach-clps711x/Kconfig
 source arch/arm/mach-ep93xx/Kconfig
 source arch/arm/mach-highbank/Kconfig
 source arch/arm/mach-imx/Kconfig
+source arch/arm/mach-ixp4xx/Kconfig
 source arch/arm/mach-mxs/Kconfig
 source arch/arm/mach-netx/Kconfig
 source arch/arm/mach-nomadik/Kconfig
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index d506b12..584d39b 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -57,6 +57,7 @@ machine-$(CONFIG_ARCH_CLPS711X)		:= clps711x
 machine-$(CONFIG_ARCH_EP93XX)		:= ep93xx
 machine-$(CONFIG_ARCH_HIGHBANK)		:= highbank
 machine-$(CONFIG_ARCH_IMX)		:= imx
+machine-$(CONFIG_ARCH_IXP4XX)		:= ixp4xx
 machine-$(CONFIG_ARCH_MXS)		:= mxs
 machine-$(CONFIG_ARCH_NOMADIK)		:= nomadik
 machine-$(CONFIG_ARCH_NETX)		:= netx
diff --git a/arch/arm/mach-ixp4xx/Kconfig b/arch/arm/mach-ixp4xx/Kconfig
new file mode 100644
index 0000000..e69de29
diff --git a/arch/arm/mach-ixp4xx/Makefile b/arch/arm/mach-ixp4xx/Makefile
new file mode 100644
index 0000000..d8a3d7f
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/Makefile
@@ -0,0 +1 @@
+obj-y += generic.o
diff --git a/arch/arm/mach-ixp4xx/generic.c b/arch/arm/mach-ixp4xx/generic.c
new file mode 100644
index 0000000..e81994b
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/generic.c
@@ -0,0 +1,114 @@
+#include <common.h>
+#include <init.h>
+#include <ns16550.h>
+#include <asm/armlinux.h>
+#include <asm/io.h>
+#include <mach/ixp4xx-regs.h>
+
+#define OSTS_FREQUENCY 66666000
+
+void reset_cpu(ulong addr)
+{
+	/* Use on-chip reset capability */
+	/* This may not work on IXP425 rev. A0 */
+
+	IXP4XX_OSWK = IXP4XX_WDT_KEY;
+	IXP4XX_OSWT = 0; /* request immediate reset */
+	IXP4XX_OSWE = IXP4XX_WDT_RESET_ENABLE | IXP4XX_WDT_COUNT_ENABLE;
+	while (1)
+		;
+}
+
+#include <clock.h>
+
+/**
+ * @brief Provide a simple clock read
+ *
+ * Nothing is simpler.. read direct from clock and provide it
+ * to the caller.
+ *
+ * @return clock counter
+ */
+static uint64_t ixp4xx_clocksource_read(void)
+{
+	return IXP4XX_OSTS;
+}
+
+static struct clocksource cs = {
+	.read = ixp4xx_clocksource_read,
+	.mask = 0xffffffff,
+	.shift = 10,
+};
+
+/**
+ * @brief Initialize the Clock
+ *
+ * We use the Time-Stamp Timer
+ *
+ * @return result of @ref init_clock
+ */
+static int ixp4xx_clocksource_init(void)
+{
+	cs.mult = clocksource_hz2mult(OSTS_FREQUENCY, cs.shift);
+
+	return init_clock(&cs);
+}
+
+/* Run me at boot time */
+core_initcall(ixp4xx_clocksource_init);
+
+
+#ifdef CONFIG_DRIVER_SERIAL_NS16550
+
+/**
+ * @brief UART port register read function for IXP4XX
+ *
+ * @param base base address of UART
+ * @param reg_idx register index
+ *
+ * @return character read from register
+ */
+unsigned int ixp4xx_uart_read(unsigned long base, unsigned char reg_idx)
+{
+	return readb(4 * reg_idx + 3 /* big-endian */ + (uint8_t *)base);
+}
+EXPORT_SYMBOL(ixp4xx_uart_read);
+
+/**
+ * @brief UART port register write function for IXP4XX
+ *
+ * @param val value to write
+ * @param base base address of UART
+ * @param reg_idx register index
+ *
+ * @return void
+ */
+void ixp4xx_uart_write(unsigned int val, unsigned long base, unsigned char reg_idx)
+{
+	writeb(val, 4 * reg_idx + 3 /* big-endian */ + (uint8_t *)base);
+}
+EXPORT_SYMBOL(ixp4xx_uart_write);
+
+
+static struct NS16550_plat serial_plat = {
+	.clock = 14745600,
+	.f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR,
+	.reg_read = ixp4xx_uart_read,
+	.reg_write = ixp4xx_uart_write,
+};
+
+/**
+ * @brief UART serial port initialization
+ *
+ * @return result of device registration
+ */
+static int ixp4xx_console_init(void)
+{
+	/* Register the serial port */
+	add_ns16550_device(0, (u32)IXP4XX_UART1_BASE, 1024, IORESOURCE_MEM_8BIT, &serial_plat);
+	return 0;
+}
+
+console_initcall(ixp4xx_console_init);
+
+#endif /* CONFIG_DRIVER_SERIAL_NS16550 */
diff --git a/arch/arm/mach-ixp4xx/include/mach/cpu.h b/arch/arm/mach-ixp4xx/include/mach/cpu.h
new file mode 100644
index 0000000..1aef932
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/include/mach/cpu.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2007, 2009 Krzysztof Halasa
+ * Copyright (C) 2007 MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __MACH_CPU_H__
+#define __MACH_CPU_H__
+
+#include <linux/types.h>
+#include <asm/cputype.h>
+
+/* Processor id value in CP15 Register 0 */
+#define IXP42X_PROCESSOR_ID_VALUE 0x690541c0 /* including unused 0x690541Ex */
+#define IXP42X_PROCESSOR_ID_MASK  0xffffffc0
+
+#define IXP43X_PROCESSOR_ID_VALUE 0x69054040
+#define IXP43X_PROCESSOR_ID_MASK  0xfffffff0
+
+#define IXP46X_PROCESSOR_ID_VALUE 0x69054200 /* including IXP455 */
+#define IXP46X_PROCESSOR_ID_MASK  0xfffffff0
+
+#define cpu_is_ixp42x_rev_a0() ((read_cpuid_id() & (IXP42X_PROCESSOR_ID_MASK | 0xF)) == \
+				IXP42X_PROCESSOR_ID_VALUE)
+#define cpu_is_ixp42x() ((read_cpuid_id() & IXP42X_PROCESSOR_ID_MASK) == \
+			 IXP42X_PROCESSOR_ID_VALUE)
+#define cpu_is_ixp43x() ((read_cpuid_id() & IXP43X_PROCESSOR_ID_MASK) == \
+			 IXP43X_PROCESSOR_ID_VALUE)
+#define cpu_is_ixp46x() ((read_cpuid_id() & IXP46X_PROCESSOR_ID_MASK) == \
+			 IXP46X_PROCESSOR_ID_VALUE)
+
+static inline u32 ixp4xx_read_feature_bits(void)
+{
+	u32 val = ~IXP4XX_EXP_CFG2;
+
+	if (cpu_is_ixp42x_rev_a0())
+		return IXP42X_FEATURE_MASK & ~(IXP4XX_FEATURE_RCOMP |
+					       IXP4XX_FEATURE_AES);
+	if (cpu_is_ixp42x())
+		return val & IXP42X_FEATURE_MASK;
+	if (cpu_is_ixp43x())
+		return val & IXP43X_FEATURE_MASK;
+	return val & IXP46X_FEATURE_MASK;
+}
+
+static inline void ixp4xx_write_feature_bits(u32 value)
+{
+	IXP4XX_EXP_CFG2 = ~value;
+}
+
+#endif /* _MACH_CPU_H */
diff --git a/arch/arm/mach-ixp4xx/include/mach/ixp4xx-head.h b/arch/arm/mach-ixp4xx/include/mach/ixp4xx-head.h
new file mode 100644
index 0000000..b3d357f
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/include/mach/ixp4xx-head.h
@@ -0,0 +1,16 @@
+#include <mach/ixp4xx-regs.h>
+#include <asm/barebox-arm-head.h>
+
+.macro	ixp4xx_cpu_lowlevel_init
+
+	arm_cpu_lowlevel_init r0
+
+	add pc, #(0x50000000 - 4) /* jump to ROM area */
+
+	mov r0, #(IXP4XX_EXP_CFG0 & 0xFFFF0000)
+	orr r0, #(IXP4XX_EXP_CFG0 & 0x0000FFFF)
+	ldr r1, [r0]
+	and r1, r1, #~0x80000000 /* unmap EXP bus from 0x0 */
+	str r1, [r0]
+
+.endm
diff --git a/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h b/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h
new file mode 100644
index 0000000..da4dc8a
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h
@@ -0,0 +1,365 @@
+/*
+ * Register definitions for IXP4xx chipset.
+ *
+ * Copyright (C) 2002 Intel Corporation.
+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef _ASM_ARM_IXP4XX_H_
+#define _ASM_ARM_IXP4XX_H_
+
+#ifdef __ASSEMBLER__
+#define IXP4XX_REG(reg)  (reg)
+#else
+#define IXP4XX_REG(reg)  (*(volatile u32 *)(reg))
+#define IXP4XX_BASE(reg) ((u32*)(reg))
+#endif
+
+/* Expansion Bus region */
+
+/* Queue Manager */
+#define IXP4XX_QMGR_BASE              (0x60000000)
+#define IXP4XX_QMGR_REGION_SIZE       (0x00004000)
+
+
+/* PCI Config registers */
+#define IXP4XX_PCI_CFG_BASE           (0xC0000000)
+#define IXP4XX_PCI_CFG_REGION_SIZE    (0x00001000)
+
+/* Peripheral space */
+#define IXP4XX_PERIPHERAL_BASE        (0xC8000000)
+#define IXP4XX_PERIPHERAL_REGION_SIZE (0x00013000)
+
+/*
+ * Debug UART
+ *
+ * This is basically a remap of UART1 into a region that is section
+ * aligned so that it can be used with the low-level debug code.
+ */
+#define IXP4XX_DEBUG_UART_BASE        (0xC8000000)
+#define IXP4XX_DEBUG_UART_REGION_SIZE (0x00001000)
+
+/* Expansion Bus Controller registers. */
+#define IXP4XX_EXP_CS0       IXP4XX_REG(0xC4000000)
+#define IXP4XX_EXP_CS1       IXP4XX_REG(0xC4000004)
+#define IXP4XX_EXP_CS2       IXP4XX_REG(0xC4000008)
+#define IXP4XX_EXP_CS3       IXP4XX_REG(0xC400000C)
+#define IXP4XX_EXP_CS4       IXP4XX_REG(0xC4000010)
+#define IXP4XX_EXP_CS5       IXP4XX_REG(0xC4000014)
+#define IXP4XX_EXP_CS6       IXP4XX_REG(0xC4000018)
+#define IXP4XX_EXP_CS7       IXP4XX_REG(0xC400001C)
+
+#define IXP4XX_EXP_BASE(n)  (0x50000000 + (n) * 1000000)
+
+#define IXP4XX_EXP_EN        0x80000000
+#define IXP4XX_EXP_T1(n)    (0x10000000 * (n)) /* valid: 0 - 3 */
+#define IXP4XX_EXP_T2(n)    (0x04000000 * (n)) /* valid: 0 - 3 */
+#define IXP4XX_EXP_T3(n)    (0x00400000 * (n)) /* valid: 0 - 15 */
+#define IXP4XX_EXP_T4(n)    (0x00100000 * (n)) /* valid: 0 - 3 */
+#define IXP4XX_EXP_T5(n)    (0x00010000 * (n)) /* valid: 0 - 15 */
+#define IXP4XX_EXP_INTEL     0x00000000
+#define IXP4XX_EXP_MOTO      0x00004000
+#define IXP4XX_EXP_HPI       0x00008000
+#define IXP4XX_EXP_BITS(n)  (0x00000400 * ((n) - 9)) /* valid: 9 - 24 */
+#define IXP4XX_EXP_BYTE_RD16 0x00000040
+#define IXP4XX_EXP_HRDY_POL  0x00000020
+#define IXP4XX_EXP_MUX_EN    0x00000010
+#define IXP4XX_EXP_SPLT_EN   0x00000008
+#define IXP4XX_EXP_WR_EN     0x00000002
+#define IXP4XX_EXP_BYTE_EN   0x00000001
+
+#define IXP4XX_EXP_CFG0      IXP4XX_REG(0xC4000020)
+#define IXP4XX_EXP_CFG1      IXP4XX_REG(0xC4000024)
+#define IXP4XX_EXP_CFG2      IXP4XX_REG(0xC4000028)
+#define IXP4XX_EXP_CFG3      IXP4XX_REG(0xC400002C)
+
+
+/* Peripheral Space Register Region Base Addresses */
+#define IXP4XX_UART1_BASE    IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x0000)
+#define IXP4XX_UART2_BASE    IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x1000)
+#define IXP4XX_PMU_BASE      IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x2000)
+#define IXP4XX_INTC_BASE     IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x3000)
+#define IXP4XX_GPIO_BASE     IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x4000)
+#define IXP4XX_NPEA_BASE     IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x6000)
+#define IXP4XX_NPEB_BASE     IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x7000)
+#define IXP4XX_NPEC_BASE     IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x8000)
+#define IXP4XX_EthB_BASE     IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x9000)
+#define IXP4XX_EthC_BASE     IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0xA000)
+#define IXP4XX_USB_BASE      IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0xB000)
+/* IXP46x only */
+#define IXP4XX_EthA_BASE     IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0xC000)
+#define IXP4XX_EthB1_BASE    IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0xD000)
+#define IXP4XX_EthB2_BASE    IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0xE000)
+#define IXP4XX_EthB3_BASE    IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0xF000)
+#define IXP4XX_TIMESYNC_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x10000)
+#define IXP4XX_I2C_BASE      IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x11000)
+#define IXP4XX_SSP_BASE      IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x12000)
+
+/*
+  Constants to make it easy to access Interrupt Controller registers
+ */
+#define IXP4XX_ICPR_OFFSET   0x00 /* Interrupt Status */
+#define IXP4XX_ICMR_OFFSET   0x04 /* Interrupt Enable */
+#define IXP4XX_ICLR_OFFSET   0x08 /* Interrupt IRQ/FIQ Select */
+#define IXP4XX_ICIP_OFFSET   0x0C /* IRQ Status */
+#define IXP4XX_ICFP_OFFSET   0x10 /* FIQ Status */
+#define IXP4XX_ICHR_OFFSET   0x14 /* Interrupt Priority */
+#define IXP4XX_ICIH_OFFSET   0x18 /* IRQ Highest Pri Int */
+#define IXP4XX_ICFH_OFFSET   0x1C /* FIQ Highest Pri Int */
+
+/* IXP465-only */
+#define IXP4XX_ICPR2_OFFSET  0x20 /* Interrupt Status 2 */
+#define IXP4XX_ICMR2_OFFSET  0x24 /* Interrupt Enable 2 */
+#define IXP4XX_ICLR2_OFFSET  0x28 /* Interrupt IRQ/FIQ Select 2 */
+#define IXP4XX_ICIP2_OFFSET  0x2C /* IRQ Status */
+#define IXP4XX_ICFP2_OFFSET  0x30 /* FIQ Status */
+#define IXP4XX_ICEEN_OFFSET  0x34 /* Error High Pri Enable */
+
+
+/* Interrupt Controller Register Definitions. */
+#define IXP4XX_INTC_REG(x)   ((volatile u32 *)(IXP4XX_INTC_BASE + (x)))
+
+#define IXP4XX_ICPR          IXP4XX_INTC_REG(IXP4XX_ICPR_OFFSET)
+#define IXP4XX_ICMR          IXP4XX_INTC_REG(IXP4XX_ICMR_OFFSET)
+#define IXP4XX_ICLR          IXP4XX_INTC_REG(IXP4XX_ICLR_OFFSET)
+#define IXP4XX_ICIP          IXP4XX_INTC_REG(IXP4XX_ICIP_OFFSET)
+#define IXP4XX_ICFP          IXP4XX_INTC_REG(IXP4XX_ICFP_OFFSET)
+#define IXP4XX_ICHR          IXP4XX_INTC_REG(IXP4XX_ICHR_OFFSET)
+#define IXP4XX_ICIH          IXP4XX_INTC_REG(IXP4XX_ICIH_OFFSET)
+#define IXP4XX_ICFH          IXP4XX_INTC_REG(IXP4XX_ICFH_OFFSET)
+#define IXP4XX_ICPR2         IXP4XX_INTC_REG(IXP4XX_ICPR2_OFFSET)
+#define IXP4XX_ICMR2         IXP4XX_INTC_REG(IXP4XX_ICMR2_OFFSET)
+#define IXP4XX_ICLR2         IXP4XX_INTC_REG(IXP4XX_ICLR2_OFFSET)
+#define IXP4XX_ICIP2         IXP4XX_INTC_REG(IXP4XX_ICIP2_OFFSET)
+#define IXP4XX_ICFP2         IXP4XX_INTC_REG(IXP4XX_ICFP2_OFFSET)
+#define IXP4XX_ICEEN         IXP4XX_INTC_REG(IXP4XX_ICEEN_OFFSET)
+
+/* Constants to make it easy to access GPIO registers */
+#define IXP4XX_GPIO_GPOUTR_OFFSET   0x00
+#define IXP4XX_GPIO_GPOER_OFFSET    0x04
+#define IXP4XX_GPIO_GPINR_OFFSET    0x08
+#define IXP4XX_GPIO_GPISR_OFFSET    0x0C
+#define IXP4XX_GPIO_GPIT1R_OFFSET   0x10
+#define IXP4XX_GPIO_GPIT2R_OFFSET   0x14
+#define IXP4XX_GPIO_GPCLKR_OFFSET   0x18
+#define IXP4XX_GPIO_GPDBSELR_OFFSET 0x1C
+
+/* GPIO Register Definitions - perform only 32-bit reads/writes */
+#define IXP4XX_GPIO_REG(x)   ((volatile u32 *)(IXP4XX_GPIO_BASE + (x)))
+
+#define IXP4XX_GPIO_GPOUTR   IXP4XX_GPIO_REG(IXP4XX_GPIO_GPOUTR_OFFSET)
+#define IXP4XX_GPIO_GPOER    IXP4XX_GPIO_REG(IXP4XX_GPIO_GPOER_OFFSET)
+#define IXP4XX_GPIO_GPINR    IXP4XX_GPIO_REG(IXP4XX_GPIO_GPINR_OFFSET)
+#define IXP4XX_GPIO_GPISR    IXP4XX_GPIO_REG(IXP4XX_GPIO_GPISR_OFFSET)
+#define IXP4XX_GPIO_GPIT1R   IXP4XX_GPIO_REG(IXP4XX_GPIO_GPIT1R_OFFSET)
+#define IXP4XX_GPIO_GPIT2R   IXP4XX_GPIO_REG(IXP4XX_GPIO_GPIT2R_OFFSET)
+#define IXP4XX_GPIO_GPCLKR   IXP4XX_GPIO_REG(IXP4XX_GPIO_GPCLKR_OFFSET)
+#define IXP4XX_GPIO_GPDBSELR IXP4XX_GPIO_REG(IXP4XX_GPIO_GPDBSELR_OFFSET)
+
+/* GPIO register bit definitions */
+
+/* Interrupt styles */
+#define IXP4XX_GPIO_STYLE_ACTIVE_HIGH  0x0
+#define IXP4XX_GPIO_STYLE_ACTIVE_LOW   0x1
+#define IXP4XX_GPIO_STYLE_RISING_EDGE  0x2
+#define IXP4XX_GPIO_STYLE_FALLING_EDGE 0x3
+#define IXP4XX_GPIO_STYLE_TRANSITIONAL 0x4
+
+/* Mask used to clear interrupt styles */
+#define IXP4XX_GPIO_STYLE_CLEAR        0x7
+#define IXP4XX_GPIO_STYLE_SIZE         3
+
+/* Operating System Timer Register Definitions. */
+#define IXP4XX_OSTS          IXP4XX_REG(0xC8005000) /* Continious TimeStamp */
+#define IXP4XX_OST1          IXP4XX_REG(0xC8005004) /* Timer 1 Timestamp */
+#define IXP4XX_OSRT1         IXP4XX_REG(0xC8005008) /* Timer 1 Reload */
+#define IXP4XX_OST2          IXP4XX_REG(0xC800500C) /* Timer 2 Timestamp */
+#define IXP4XX_OSRT2         IXP4XX_REG(0xC8005010) /* Timer 2 Reload */
+#define IXP4XX_OSWT          IXP4XX_REG(0xC8005014) /* Watchdog Timer */
+#define IXP4XX_OSWE          IXP4XX_REG(0xC8005018) /* Watchdog Enable */
+#define IXP4XX_OSWK          IXP4XX_REG(0xC800501C) /* Watchdog Key */
+#define IXP4XX_OSST          IXP4XX_REG(0xC8005020) /* Timer Status */
+
+/* Timer register values and bit definitions */
+#define IXP4XX_OST_ENABLE            0x00000001
+#define IXP4XX_OST_ONE_SHOT          0x00000002
+/* Low order bits of reload value ignored */
+#define IXP4XX_OST_RELOAD_MASK       0x00000003
+#define IXP4XX_OST_DISABLED          0x00000000
+#define IXP4XX_OSST_TIMER_1_PEND     0x00000001
+#define IXP4XX_OSST_TIMER_2_PEND     0x00000002
+#define IXP4XX_OSST_TIMER_TS_PEND    0x00000004
+#define IXP4XX_OSST_TIMER_WDOG_PEND  0x00000008
+#define IXP4XX_OSST_TIMER_WARM_RESET 0x00000010
+
+#define IXP4XX_WDT_KEY               0x0000482E
+
+#define IXP4XX_WDT_RESET_ENABLE      0x00000001
+#define IXP4XX_WDT_IRQ_ENABLE        0x00000002
+#define IXP4XX_WDT_COUNT_ENABLE      0x00000004
+
+
+/* Constants to make it easy to access PCI Control/Status registers */
+#define PCI_NP_AD_OFFSET           0x00
+#define PCI_NP_CBE_OFFSET          0x04
+#define PCI_NP_WDATA_OFFSET        0x08
+#define PCI_NP_RDATA_OFFSET        0x0c
+#define PCI_CRP_AD_CBE_OFFSET      0x10
+#define PCI_CRP_WDATA_OFFSET       0x14
+#define PCI_CRP_RDATA_OFFSET       0x18
+#define PCI_CSR_OFFSET             0x1c
+#define PCI_ISR_OFFSET             0x20
+#define PCI_INTEN_OFFSET           0x24
+#define PCI_DMACTRL_OFFSET         0x28
+#define PCI_AHBMEMBASE_OFFSET      0x2c
+#define PCI_AHBIOBASE_OFFSET       0x30
+#define PCI_PCIMEMBASE_OFFSET      0x34
+#define PCI_AHBDOORBELL_OFFSET     0x38
+#define PCI_PCIDOORBELL_OFFSET     0x3C
+#define PCI_ATPDMA0_AHBADDR_OFFSET 0x40
+#define PCI_ATPDMA0_PCIADDR_OFFSET 0x44
+#define PCI_ATPDMA0_LENADDR_OFFSET 0x48
+#define PCI_ATPDMA1_AHBADDR_OFFSET 0x4C
+#define PCI_ATPDMA1_PCIADDR_OFFSET 0x50
+#define PCI_ATPDMA1_LENADDR_OFFSET 0x54
+
+/* PCI Control/Status Registers */
+#define IXP4XX_PCI_CSR(x) ((volatile u32 *)(IXP4XX_PCI_CFG_BASE + (x)))
+
+#define PCI_NP_AD            IXP4XX_PCI_CSR(PCI_NP_AD_OFFSET)
+#define PCI_NP_CBE           IXP4XX_PCI_CSR(PCI_NP_CBE_OFFSET)
+#define PCI_NP_WDATA         IXP4XX_PCI_CSR(PCI_NP_WDATA_OFFSET)
+#define PCI_NP_RDATA         IXP4XX_PCI_CSR(PCI_NP_RDATA_OFFSET)
+#define PCI_CRP_AD_CBE       IXP4XX_PCI_CSR(PCI_CRP_AD_CBE_OFFSET)
+#define PCI_CRP_WDATA        IXP4XX_PCI_CSR(PCI_CRP_WDATA_OFFSET)
+#define PCI_CRP_RDATA        IXP4XX_PCI_CSR(PCI_CRP_RDATA_OFFSET)
+#define PCI_CSR              IXP4XX_PCI_CSR(PCI_CSR_OFFSET)
+#define PCI_ISR              IXP4XX_PCI_CSR(PCI_ISR_OFFSET)
+#define PCI_INTEN            IXP4XX_PCI_CSR(PCI_INTEN_OFFSET)
+#define PCI_DMACTRL          IXP4XX_PCI_CSR(PCI_DMACTRL_OFFSET)
+#define PCI_AHBMEMBASE       IXP4XX_PCI_CSR(PCI_AHBMEMBASE_OFFSET)
+#define PCI_AHBIOBASE        IXP4XX_PCI_CSR(PCI_AHBIOBASE_OFFSET)
+#define PCI_PCIMEMBASE       IXP4XX_PCI_CSR(PCI_PCIMEMBASE_OFFSET)
+#define PCI_AHBDOORBELL      IXP4XX_PCI_CSR(PCI_AHBDOORBELL_OFFSET)
+#define PCI_PCIDOORBELL      IXP4XX_PCI_CSR(PCI_PCIDOORBELL_OFFSET)
+#define PCI_ATPDMA0_AHBADDR  IXP4XX_PCI_CSR(PCI_ATPDMA0_AHBADDR_OFFSET)
+#define PCI_ATPDMA0_PCIADDR  IXP4XX_PCI_CSR(PCI_ATPDMA0_PCIADDR_OFFSET)
+#define PCI_ATPDMA0_LENADDR  IXP4XX_PCI_CSR(PCI_ATPDMA0_LENADDR_OFFSET)
+#define PCI_ATPDMA1_AHBADDR  IXP4XX_PCI_CSR(PCI_ATPDMA1_AHBADDR_OFFSET)
+#define PCI_ATPDMA1_PCIADDR  IXP4XX_PCI_CSR(PCI_ATPDMA1_PCIADDR_OFFSET)
+#define PCI_ATPDMA1_LENADDR  IXP4XX_PCI_CSR(PCI_ATPDMA1_LENADDR_OFFSET)
+
+/* PCI register values and bit definitions */
+
+/* CSR bit definitions */
+#define PCI_CSR_HOST         0x00000001
+#define PCI_CSR_ARBEN        0x00000002
+#define PCI_CSR_ADS          0x00000004
+#define PCI_CSR_PDS          0x00000008
+#define PCI_CSR_ABE          0x00000010
+#define PCI_CSR_DBT          0x00000020
+#define PCI_CSR_ASE          0x00000100
+#define PCI_CSR_IC           0x00008000
+
+/* ISR (Interrupt status) Register bit definitions */
+#define PCI_ISR_PSE          0x00000001
+#define PCI_ISR_PFE          0x00000002
+#define PCI_ISR_PPE          0x00000004
+#define PCI_ISR_AHBE         0x00000008
+#define PCI_ISR_APDC         0x00000010
+#define PCI_ISR_PADC         0x00000020
+#define PCI_ISR_ADB          0x00000040
+#define PCI_ISR_PDB          0x00000080
+
+/* INTEN (Interrupt Enable) Register bit definitions */
+#define PCI_INTEN_PSE        0x00000001
+#define PCI_INTEN_PFE        0x00000002
+#define PCI_INTEN_PPE        0x00000004
+#define PCI_INTEN_AHBE       0x00000008
+#define PCI_INTEN_APDC       0x00000010
+#define PCI_INTEN_PADC       0x00000020
+#define PCI_INTEN_ADB        0x00000040
+#define PCI_INTEN_PDB        0x00000080
+
+/* Shift value for byte enable on NP cmd/byte enable register */
+#define IXP4XX_PCI_NP_CBE_BESL 4
+
+/* PCI commands supported by NP access unit */
+#define NP_CMD_IOREAD        0x2
+#define NP_CMD_IOWRITE       0x3
+#define NP_CMD_CONFIGREAD    0xA
+#define NP_CMD_CONFIGWRITE   0xB
+#define NP_CMD_MEMREAD       0x6
+#define NP_CMD_MEMWRITE      0x7
+
+/* Constants for CRP access into local config space */
+#define CRP_AD_CBE_BESL      20
+#define CRP_AD_CBE_WRITE     0x00010000
+
+/* USB Device Controller */
+# define IXP4XX_USB_REG(x)   (*((volatile u32 *)(x)))
+
+/* SDRAM Controller registers. */
+#define IXP4XX_SDRAM_CONFIG  IXP4XX_REG(0xCC000000)
+#define IXP4XX_SDRAM_REFRESH IXP4XX_REG(0xCC000004)
+#define IXP4XX_SDRAM_IR      IXP4XX_REG(0xCC000008)
+
+/* "fuse" bits of IXP_EXP_CFG2 */
+/* All IXP4xx CPUs */
+#define IXP4XX_FEATURE_RCOMP            (1 << 0)
+#define IXP4XX_FEATURE_USB_DEVICE       (1 << 1)
+#define IXP4XX_FEATURE_HASH             (1 << 2)
+#define IXP4XX_FEATURE_AES              (1 << 3)
+#define IXP4XX_FEATURE_DES              (1 << 4)
+#define IXP4XX_FEATURE_HDLC             (1 << 5)
+#define IXP4XX_FEATURE_AAL              (1 << 6)
+#define IXP4XX_FEATURE_HSS              (1 << 7)
+#define IXP4XX_FEATURE_UTOPIA           (1 << 8)
+#define IXP4XX_FEATURE_NPEB_ETH0        (1 << 9)
+#define IXP4XX_FEATURE_NPEC_ETH         (1 << 10)
+#define IXP4XX_FEATURE_RESET_NPEA       (1 << 11)
+#define IXP4XX_FEATURE_RESET_NPEB       (1 << 12)
+#define IXP4XX_FEATURE_RESET_NPEC       (1 << 13)
+#define IXP4XX_FEATURE_PCI              (1 << 14)
+#define IXP4XX_FEATURE_UTOPIA_PHY_LIMIT (3 << 16)
+#define IXP4XX_FEATURE_XSCALE_MAX_FREQ  (3 << 22)
+#define IXP42X_FEATURE_MASK (IXP4XX_FEATURE_RCOMP            | \
+			     IXP4XX_FEATURE_USB_DEVICE       | \
+			     IXP4XX_FEATURE_HASH             | \
+			     IXP4XX_FEATURE_AES              | \
+			     IXP4XX_FEATURE_DES              | \
+			     IXP4XX_FEATURE_HDLC             | \
+			     IXP4XX_FEATURE_AAL              | \
+			     IXP4XX_FEATURE_HSS              | \
+			     IXP4XX_FEATURE_UTOPIA           | \
+			     IXP4XX_FEATURE_NPEB_ETH0        | \
+			     IXP4XX_FEATURE_NPEC_ETH         | \
+			     IXP4XX_FEATURE_RESET_NPEA       | \
+			     IXP4XX_FEATURE_RESET_NPEB       | \
+			     IXP4XX_FEATURE_RESET_NPEC       | \
+			     IXP4XX_FEATURE_PCI              | \
+			     IXP4XX_FEATURE_UTOPIA_PHY_LIMIT | \
+			     IXP4XX_FEATURE_XSCALE_MAX_FREQ)
+
+/* IXP43x/46x CPUs */
+#define IXP4XX_FEATURE_ECC_TIMESYNC     (1 << 15)
+#define IXP4XX_FEATURE_USB_HOST         (1 << 18)
+#define IXP4XX_FEATURE_NPEA_ETH         (1 << 19)
+#define IXP43X_FEATURE_MASK (IXP42X_FEATURE_MASK             | \
+			     IXP4XX_FEATURE_ECC_TIMESYNC     | \
+			     IXP4XX_FEATURE_USB_HOST         | \
+			     IXP4XX_FEATURE_NPEA_ETH)
+
+/* IXP46x CPU (including IXP455) only */
+#define IXP4XX_FEATURE_NPEB_ETH_1_TO_3  (1 << 20)
+#define IXP4XX_FEATURE_RSA              (1 << 21)
+#define IXP46X_FEATURE_MASK (IXP43X_FEATURE_MASK             | \
+			     IXP4XX_FEATURE_NPEB_ETH_1_TO_3  | \
+			     IXP4XX_FEATURE_RSA)
+
+#endif
diff --git a/drivers/serial/serial_ns16550.c b/drivers/serial/serial_ns16550.c
index b7913aa..be1b968 100644
--- a/drivers/serial/serial_ns16550.c
+++ b/drivers/serial/serial_ns16550.c
@@ -137,7 +137,11 @@ static void ns16550_serial_init_port(struct console_device *cdev)
 {
 	/* initializing the device for the first time */
 	ns16550_write(cdev, 0x00, lcr); /* select ier reg */
+#ifdef CONFIG_ARCH_IXP4XX
+	ns16550_write(cdev, IER_UUE, ier); /* Enable UART operation */
+#else
 	ns16550_write(cdev, 0x00, ier);
+#endif
 
 #ifdef CONFIG_DRIVER_SERIAL_NS16550_OMAP_EXTENSIONS
 	ns16550_write(cdev, 0x07, mdr1);	/* Disable */
diff --git a/drivers/serial/serial_ns16550.h b/drivers/serial/serial_ns16550.h
index db8fe64..132f46e 100644
--- a/drivers/serial/serial_ns16550.h
+++ b/drivers/serial/serial_ns16550.h
@@ -50,6 +50,8 @@
 #define dll		rbr
 #define dlm		ier
 
+#define IER_UUE		0x40	/* UART Unit Enable (XScale) */
+
 #define FCR_FIFO_EN     0x01	/* Fifo enable */
 #define FCR_RXSR        0x02	/* Receiver soft reset */
 #define FCR_TXSR        0x04	/* Transmitter soft reset */

-- 
Krzysztof Halasa

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH] ARM: Support for IXP4xx hardware Queue Manager.
  2013-04-07 11:42     ` Krzysztof Halasa
  2013-04-07 19:54       ` [PATCH] ARM: Support for IXP4xx CPU Krzysztof Halasa
@ 2013-04-07 19:55       ` Krzysztof Halasa
  2013-04-08  7:31         ` Jean-Christophe PLAGNIOL-VILLARD
  2013-04-07 19:57       ` [PATCH] ARM: Support for IXP4xx Network Processor Engines (NPEs) Krzysztof Halasa
                         ` (2 subsequent siblings)
  4 siblings, 1 reply; 24+ messages in thread
From: Krzysztof Halasa @ 2013-04-07 19:55 UTC (permalink / raw)
  To: barebox

Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>

diff --git a/arch/arm/mach-ixp4xx/Kconfig b/arch/arm/mach-ixp4xx/Kconfig
index e69de29..9244be9 100644
--- a/arch/arm/mach-ixp4xx/Kconfig
+++ b/arch/arm/mach-ixp4xx/Kconfig
@@ -0,0 +1,9 @@
+if ARCH_IXP4XX
+
+config IXP4XX_QMGR
+	tristate "IXP4xx Queue Manager support"
+	help
+	  This driver supports IXP4xx built-in hardware queue manager
+	  and is required by the Ethernet driver.
+
+endif
diff --git a/arch/arm/mach-ixp4xx/Makefile b/arch/arm/mach-ixp4xx/Makefile
index d8a3d7f..09a0d63 100644
--- a/arch/arm/mach-ixp4xx/Makefile
+++ b/arch/arm/mach-ixp4xx/Makefile
@@ -1 +1,2 @@
 obj-y += generic.o
+obj-$(CONFIG_IXP4XX_QMGR) += qmgr.o
diff --git a/arch/arm/mach-ixp4xx/include/mach/qmgr.h b/arch/arm/mach-ixp4xx/include/mach/qmgr.h
new file mode 100644
index 0000000..4e9b8d4
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/include/mach/qmgr.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#ifndef IXP4XX_QMGR_H
+#define IXP4XX_QMGR_H
+
+#include <common.h>
+#include <mach/ixp4xx-regs.h>
+#include <asm/io.h>
+
+#define DEBUG_QMGR       0
+
+#define HALF_QUEUES     32
+#define QUEUES          64
+#define MAX_QUEUE_LENGTH 4 /* in dwords */
+
+#define QUEUE_STAT1_EMPTY               1 /* queue status bits */
+#define QUEUE_STAT1_NEARLY_EMPTY        2
+#define QUEUE_STAT1_NEARLY_FULL         4
+#define QUEUE_STAT1_FULL                8
+#define QUEUE_STAT2_UNDERFLOW           1
+#define QUEUE_STAT2_OVERFLOW            2
+
+#define QUEUE_WATERMARK_0_ENTRIES       0
+#define QUEUE_WATERMARK_1_ENTRY         1
+#define QUEUE_WATERMARK_2_ENTRIES       2
+#define QUEUE_WATERMARK_4_ENTRIES       3
+#define QUEUE_WATERMARK_8_ENTRIES       4
+#define QUEUE_WATERMARK_16_ENTRIES      5
+#define QUEUE_WATERMARK_32_ENTRIES      6
+#define QUEUE_WATERMARK_64_ENTRIES      7
+
+/* queue interrupt request conditions */
+#define QUEUE_IRQ_SRC_EMPTY             0
+#define QUEUE_IRQ_SRC_NEARLY_EMPTY      1
+#define QUEUE_IRQ_SRC_NEARLY_FULL       2
+#define QUEUE_IRQ_SRC_FULL              3
+#define QUEUE_IRQ_SRC_NOT_EMPTY         4
+#define QUEUE_IRQ_SRC_NOT_NEARLY_EMPTY  5
+#define QUEUE_IRQ_SRC_NOT_NEARLY_FULL   6
+#define QUEUE_IRQ_SRC_NOT_FULL          7
+
+struct qmgr_regs {
+	u32 acc[QUEUES][MAX_QUEUE_LENGTH]; /* 0x000 - 0x3FF */
+	u32 stat1[4];         /* 0x400 - 0x40F */
+	u32 stat2[2];         /* 0x410 - 0x417 */
+	u32 statne_h;         /* 0x418 - queue nearly empty */
+	u32 statf_h;          /* 0x41C - queue full */
+	u32 irqsrc[4];        /* 0x420 - 0x42F IRC source */
+	u32 irqen[2];         /* 0x430 - 0x437 IRQ enabled */
+	u32 irqstat[2];       /* 0x438 - 0x43F - IRQ access only */
+	u32 reserved[1776];
+	u32 sram[2048];       /* 0x2000 - 0x3FFF - config and buffer */
+};
+
+static const struct qmgr_regs *qmgr_regs = (struct qmgr_regs *)IXP4XX_QMGR_BASE;
+
+void qmgr_set_irq(unsigned int queue, int src,
+		  void (*handler)(void *pdev), void *pdev);
+void qmgr_enable_irq(unsigned int queue);
+void qmgr_disable_irq(unsigned int queue);
+
+/* request_ and release_queue() must be called from non-IRQ context */
+
+#if DEBUG_QMGR
+extern char qmgr_queue_descs[HALF_QUEUES][32];
+
+void qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
+			unsigned int nearly_empty_watermark,
+			unsigned int nearly_full_watermark,
+			const char *desc_format, const char* name);
+#else
+void __qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
+			  unsigned int nearly_empty_watermark,
+			  unsigned int nearly_full_watermark);
+#define qmgr_request_queue(queue, len, nearly_empty_watermark,       \
+			   nearly_full_watermark, desc_format, name) \
+	__qmgr_request_queue(queue, len, nearly_empty_watermark,     \
+			     nearly_full_watermark)
+#endif
+
+void qmgr_release_queue(unsigned int queue);
+
+
+static inline void qmgr_put_entry(unsigned int queue, u32 val)
+{
+#if DEBUG_QMGR
+	BUG_ON(!qmgr_queue_descs[queue]); /* not yet requested */
+
+	fprintf(stderr, "Queue %s(%i) put %X\n",
+		qmgr_queue_descs[queue], queue, val);
+#endif
+	__raw_writel(val, &qmgr_regs->acc[queue][0]);
+}
+
+static inline u32 qmgr_get_entry(unsigned int queue)
+{
+	u32 val;
+	val = __raw_readl(&qmgr_regs->acc[queue][0]);
+#if DEBUG_QMGR
+	BUG_ON(!qmgr_queue_descs[queue]); /* not yet requested */
+
+	fprintf(stderr, "Queue %s(%i) get %X\n",
+		qmgr_queue_descs[queue], queue, val);
+#endif
+	return val;
+}
+
+static inline int __qmgr_get_stat1(unsigned int queue)
+{
+	return (__raw_readl(&qmgr_regs->stat1[queue >> 3])
+		>> ((queue & 7) << 2)) & 0xF;
+}
+
+/**
+ * qmgr_stat_empty() - checks if a hardware queue is empty
+ * @queue: queue number
+ *
+ * Returns non-zero value if the queue is empty.
+ */
+static inline int qmgr_stat_empty(unsigned int queue)
+{
+	return __qmgr_get_stat1(queue) & QUEUE_STAT1_EMPTY;
+}
+
+/**
+ * qmgr_stat_below_low_watermark() - checks if a queue is below low watermark
+ * @queue: queue number
+ *
+ * Returns non-zero value if the queue is below low watermark.
+ */
+static inline int qmgr_stat_below_low_watermark(unsigned int queue)
+{
+	return __qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_EMPTY;
+}
+
+/**
+ * qmgr_stat_above_high_watermark() - checks if a queue is above high watermark
+ * @queue: queue number
+ *
+ * Returns non-zero value if the queue is above high watermark
+ */
+static inline int qmgr_stat_above_high_watermark(unsigned int queue)
+{
+	return __qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_FULL;
+}
+
+/**
+ * qmgr_stat_full() - checks if a hardware queue is full
+ * @queue: queue number
+ *
+ * Returns non-zero value if the queue is full.
+ */
+static inline int qmgr_stat_full(unsigned int queue)
+{
+	return __qmgr_get_stat1(queue) & QUEUE_STAT1_FULL;
+}
+
+#endif
diff --git a/arch/arm/mach-ixp4xx/qmgr.c b/arch/arm/mach-ixp4xx/qmgr.c
new file mode 100644
index 0000000..81b6522
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/qmgr.c
@@ -0,0 +1,259 @@
+/*
+ * Intel IXP4xx Queue Manager driver for Linux
+ *
+ * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#include <init.h>
+#include <errno.h>
+#include <mach/qmgr.h>
+
+static u32 used_sram_bitmap[4]; /* 128 16-dword pages */
+
+#if DEBUG_QMGR
+char qmgr_queue_descs[HALF_QUEUES][32];
+#endif
+
+#ifdef CONFIG_USE_IRQ
+
+static void (*irq_handlers[HALF_QUEUES])(void *pdev);
+static void *irq_pdevs[HALF_QUEUES];
+
+void qmgr_set_irq(unsigned int queue, int src,
+		  void (*handler)(void *pdev), void *pdev)
+{
+	const u32 *reg;
+	int bit;
+	BUG_ON(src > QUEUE_IRQ_SRC_NOT_FULL);
+	reg = &qmgr_regs->irqsrc[queue >> 3]; /* 8 queues per u32 */
+	bit = (queue % 8) * 4; /* 3 bits + 1 reserved bit per queue */
+	__raw_writel((__raw_readl(reg) & ~(7 << bit)) | (src << bit), reg);
+
+	irq_handlers[queue] = handler;
+	irq_pdevs[queue] = pdev;
+}
+
+
+static void qmgr_irq1_a0(void *data)
+{
+	int i;
+	u32 en_bitmap, src, stat;
+
+	/* ACK - it may clear any bits so don't rely on it */
+	__raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[0]);
+
+	en_bitmap = qmgr_regs->irqen[0];
+	while (en_bitmap) {
+		i = fls(en_bitmap) - 1; /* number of the last "low" queue */
+		en_bitmap &= ~BIT(i);
+		src = qmgr_regs->irqsrc[i >> 3];
+		stat = qmgr_regs->stat1[i >> 3];
+		if (src & 4) /* the IRQ condition is inverted */
+			stat = ~stat;
+		if (stat & BIT(src & 3))
+			irq_handlers[i](irq_pdevs[i]);
+	}
+}
+
+
+static void qmgr_irq1(void *data)
+{
+	int i;
+	u32 req_bitmap = __raw_readl(&qmgr_regs->irqstat[0]);
+
+	if (!req_bitmap)
+		return;
+	__raw_writel(req_bitmap, &qmgr_regs->irqstat[0]); /* ACK */
+
+	while (req_bitmap) {
+		i = fls(req_bitmap) - 1; /* number of the last queue */
+		req_bitmap &= ~BIT(i);
+		irq_handlers[i](irq_pdevs[i]);
+	}
+}
+
+
+void qmgr_enable_irq(unsigned int queue)
+{
+	u32 mask = 1 << queue;
+
+	__raw_writel(__raw_readl(&qmgr_regs->irqen[0]) | mask,
+		     &qmgr_regs->irqen[0]);
+}
+
+void qmgr_disable_irq(unsigned int queue)
+{
+	u32 mask = 1 << queue;
+
+	__raw_writel(__raw_readl(&qmgr_regs->irqen[0]) & ~mask,
+		     &qmgr_regs->irqen[0]);
+	__raw_writel(mask, &qmgr_regs->irqstat[0]); /* clear */
+}
+
+#endif /* CONFIG_USE_IRQ */
+
+static inline void shift_mask(u32 *mask)
+{
+	mask[3] = mask[3] << 1 | mask[2] >> 31;
+	mask[2] = mask[2] << 1 | mask[1] >> 31;
+	mask[1] = mask[1] << 1 | mask[0] >> 31;
+	mask[0] <<= 1;
+}
+
+#if DEBUG_QMGR
+void qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
+			unsigned int nearly_empty_watermark,
+			unsigned int nearly_full_watermark,
+			const char *desc_format, const char* name)
+#else
+void __qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
+			  unsigned int nearly_empty_watermark,
+			  unsigned int nearly_full_watermark)
+#endif
+{
+	u32 cfg, addr = 0, mask[4]; /* in 16-dwords */
+
+	BUG_ON(queue >= HALF_QUEUES);
+	BUG_ON((nearly_empty_watermark | nearly_full_watermark) & ~7);
+
+	switch (len) {
+	case  16:
+		cfg = 0 << 24;
+		mask[0] = 0x1;
+		break;
+	case  32:
+		cfg = 1 << 24;
+		mask[0] = 0x3;
+		break;
+	case  64:
+		cfg = 2 << 24;
+		mask[0] = 0xF;
+		break;
+	case 128:
+		cfg = 3 << 24;
+		mask[0] = 0xFF;
+		break;
+	default:
+		BUG();
+	}
+
+	cfg |= nearly_empty_watermark << 26;
+	cfg |= nearly_full_watermark << 29;
+	len /= 16; /* in 16-dwords: 1, 2, 4 or 8 */
+	mask[1] = mask[2] = mask[3] = 0;
+
+	BUG_ON(__raw_readl(&qmgr_regs->sram[queue]));
+
+	while (1) {
+		if (!(used_sram_bitmap[0] & mask[0]) &&
+		    !(used_sram_bitmap[1] & mask[1]) &&
+		    !(used_sram_bitmap[2] & mask[2]) &&
+		    !(used_sram_bitmap[3] & mask[3]))
+			break; /* found free space */
+
+		addr++;
+		shift_mask(mask);
+		if (addr + len > ARRAY_SIZE(qmgr_regs->sram)) {
+			fprintf(stderr, "qmgr: no free SRAM space for"
+				" queue %i\n", queue);
+			BUG();
+		}
+	}
+
+	used_sram_bitmap[0] |= mask[0];
+	used_sram_bitmap[1] |= mask[1];
+	used_sram_bitmap[2] |= mask[2];
+	used_sram_bitmap[3] |= mask[3];
+	__raw_writel(cfg | (addr << 14), &qmgr_regs->sram[queue]);
+#if DEBUG_QMGR
+	/* no snprintf() */
+	sprintf(qmgr_queue_descs[queue], desc_format, name);
+	fprintf(stderr, "qmgr: requested queue %s(%i) addr = 0x%02X\n",
+		qmgr_queue_descs[queue], queue, addr);
+#endif
+}
+
+void qmgr_release_queue(unsigned int queue)
+{
+	u32 cfg, addr, mask[4];
+
+	BUG_ON(queue >= HALF_QUEUES); /* not in valid range */
+
+	cfg = __raw_readl(&qmgr_regs->sram[queue]);
+	addr = (cfg >> 14) & 0xFF;
+
+	BUG_ON(!addr); /* not requested */
+
+	switch ((cfg >> 24) & 3) {
+	case 0: mask[0] = 0x1; break;
+	case 1: mask[0] = 0x3; break;
+	case 2: mask[0] = 0xF; break;
+	case 3: mask[0] = 0xFF; break;
+	}
+
+	mask[1] = mask[2] = mask[3] = 0;
+
+	while (addr--)
+		shift_mask(mask);
+
+#if DEBUG_QMGR
+	fprintf(stderr, "qmgr: releasing queue %s(%i)\n",
+		qmgr_queue_descs[queue], queue);
+	qmgr_queue_descs[queue][0] = '\x0';
+#endif
+	__raw_writel(0, &qmgr_regs->sram[queue]);
+
+	used_sram_bitmap[0] &= ~mask[0];
+	used_sram_bitmap[1] &= ~mask[1];
+	used_sram_bitmap[2] &= ~mask[2];
+	used_sram_bitmap[3] &= ~mask[3];
+#ifdef CONFIG_USE_IRQ
+	irq_handlers[queue] = NULL; /* catch IRQ bugs */
+#endif
+
+	while ((addr = qmgr_get_entry(queue)))
+		fprintf(stderr, "qmgr: released queue %i not empty: 0x%08X\n",
+			queue, addr);
+}
+
+static int __init qmgr_init(void)
+{
+	int i;
+#ifdef CONFIG_USE_IRQ
+	interrupt_handler_t *handler;
+#endif
+
+	/* reset qmgr registers */
+	for (i = 0; i < 4; i++) {
+		__raw_writel(0x33333333, &qmgr_regs->stat1[i]);
+		__raw_writel(0, &qmgr_regs->irqsrc[i]);
+	}
+	for (i = 0; i < 2; i++) {
+		__raw_writel(0, &qmgr_regs->stat2[i]);
+		__raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[i]); /* clear */
+		__raw_writel(0, &qmgr_regs->irqen[i]);
+	}
+
+	__raw_writel(0xFFFFFFFF, &qmgr_regs->statne_h);
+	__raw_writel(0, &qmgr_regs->statf_h);
+
+	for (i = 0; i < QUEUES; i++)
+		__raw_writel(0, &qmgr_regs->sram[i]);
+
+#ifdef CONFIG_USE_IRQ
+	if (cpu_is_ixp42x_rev_a0())
+		handler = qmgr_irq1_a0;
+	else
+		handler = qmgr_irq1;
+
+	irq_install_handler(IXP425_QM1_IRQ, handler, NULL);
+#endif
+	used_sram_bitmap[0] = 0xF; /* 4 first pages reserved for config */
+	return 0;
+}
+
+coredevice_initcall(qmgr_init);

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH] ARM: Support for IXP4xx Network Processor Engines (NPEs).
  2013-04-07 11:42     ` Krzysztof Halasa
  2013-04-07 19:54       ` [PATCH] ARM: Support for IXP4xx CPU Krzysztof Halasa
  2013-04-07 19:55       ` [PATCH] ARM: Support for IXP4xx hardware Queue Manager Krzysztof Halasa
@ 2013-04-07 19:57       ` Krzysztof Halasa
  2013-04-08  7:30         ` Jean-Christophe PLAGNIOL-VILLARD
  2013-04-07 19:58       ` [PATCH] ARM: Support for IXP4xx built-in Ethernet interfaces Krzysztof Halasa
  2013-04-08  7:56       ` [PATCH] ARM: Add support for IXP4xx CPU and for Goramo Multilink router platform Sascha Hauer
  4 siblings, 1 reply; 24+ messages in thread
From: Krzysztof Halasa @ 2013-04-07 19:57 UTC (permalink / raw)
  To: barebox

Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>

diff --git a/arch/arm/mach-ixp4xx/Kconfig b/arch/arm/mach-ixp4xx/Kconfig
index 9244be9..33e8bb3 100644
--- a/arch/arm/mach-ixp4xx/Kconfig
+++ b/arch/arm/mach-ixp4xx/Kconfig
@@ -6,4 +6,10 @@ config IXP4XX_QMGR
 	  This driver supports IXP4xx built-in hardware queue manager
 	  and is required by the Ethernet driver.
 
+config IXP4XX_NPE
+	tristate "IXP4xx Network Processor Engine support"
+	help
+	  This driver supports IXP4xx built-in network coprocessors
+	  and is required by the Ethernet driver.
+
 endif
diff --git a/arch/arm/mach-ixp4xx/Makefile b/arch/arm/mach-ixp4xx/Makefile
index 09a0d63..7cfc924 100644
--- a/arch/arm/mach-ixp4xx/Makefile
+++ b/arch/arm/mach-ixp4xx/Makefile
@@ -1,2 +1,3 @@
 obj-y += generic.o
 obj-$(CONFIG_IXP4XX_QMGR) += qmgr.o
+obj-$(CONFIG_IXP4XX_NPE) += npe.o
diff --git a/arch/arm/mach-ixp4xx/include/mach/npe.h b/arch/arm/mach-ixp4xx/include/mach/npe.h
new file mode 100644
index 0000000..18bd01b
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/include/mach/npe.h
@@ -0,0 +1,30 @@
+#ifndef __IXP4XX_NPE_H
+#define __IXP4XX_NPE_H
+
+#include <common.h>
+
+#define NPE_NAME_LENGTH 5
+
+struct npe_regs {
+	u32 exec_addr, exec_data, exec_status_cmd, exec_count;
+	u32 action_points[4];
+	u32 watchpoint_fifo, watch_count;
+	u32 profile_count;
+	u32 messaging_status, messaging_control;
+	u32 mailbox_status, /*messaging_*/ in_out_fifo;
+};
+
+struct npe {
+	struct npe_regs *regs;
+	int id, valid;
+	const char name[NPE_NAME_LENGTH + 1];
+};
+
+int npe_running(struct npe *npe);
+int npe_send_message(struct npe *npe, const void *msg, const char *what);
+int npe_recv_message(struct npe *npe, void *msg, const char *what);
+int npe_send_recv_message(struct npe *npe, void *msg, const char *what);
+int npe_load_firmware(struct npe *npe);
+struct npe *npe_request(int id);
+
+#endif /* __IXP4XX_NPE_H */
diff --git a/arch/arm/mach-ixp4xx/npe.c b/arch/arm/mach-ixp4xx/npe.c
new file mode 100644
index 0000000..d403340
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/npe.c
@@ -0,0 +1,667 @@
+/*
+ * Intel IXP4xx Network Processor Engine driver for Linux
+ *
+ * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <fs.h>
+#include <init.h>
+#include <malloc.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <mach/ixp4xx-regs.h>
+#include <mach/cpu.h>
+#include <mach/npe.h>
+
+#define DEBUG_MSG                      0
+#define DEBUG_FW                       0
+
+#define MAX_RETRIES                    1000  /* microseconds */
+#define NPE_42X_DATA_SIZE              0x800 /* in dwords */
+#define NPE_46X_DATA_SIZE              0x1000
+#define NPE_A_42X_INSTR_SIZE           0x1000
+#define NPE_B_AND_C_42X_INSTR_SIZE     0x800
+#define NPE_46X_INSTR_SIZE             0x1000
+#define REGS_SIZE                      0x1000
+
+#define NPE_PHYS_REG                   32
+
+#define FW_MAGIC                       0xFEEDF00D
+#define FW_BLOCK_TYPE_INSTR            0x0
+#define FW_BLOCK_TYPE_DATA             0x1
+#define FW_BLOCK_TYPE_EOF              0xF
+
+/* NPE exec status (read) and command (write) */
+#define CMD_NPE_STEP                   0x01
+#define CMD_NPE_START                  0x02
+#define CMD_NPE_STOP                   0x03
+#define CMD_NPE_CLR_PIPE               0x04
+#define CMD_CLR_PROFILE_CNT            0x0C
+#define CMD_RD_INS_MEM                 0x10 /* instruction memory */
+#define CMD_WR_INS_MEM                 0x11
+#define CMD_RD_DATA_MEM                0x12 /* data memory */
+#define CMD_WR_DATA_MEM                0x13
+#define CMD_RD_ECS_REG                 0x14 /* exec access register */
+#define CMD_WR_ECS_REG                 0x15
+
+#define STAT_RUN                       0x80000000
+#define STAT_STOP                      0x40000000
+#define STAT_CLEAR                     0x20000000
+#define STAT_ECS_K                     0x00800000 /* pipeline clean */
+
+#define NPE_STEVT                      0x1B
+#define NPE_STARTPC                    0x1C
+#define NPE_REGMAP                     0x1E
+#define NPE_CINDEX                     0x1F
+
+#define INSTR_WR_REG_SHORT             0x0000C000
+#define INSTR_WR_REG_BYTE              0x00004000
+#define INSTR_RD_FIFO                  0x0F888220
+#define INSTR_RESET_MBOX               0x0FAC8210
+
+#define ECS_BG_CTXT_REG_0              0x00 /* Background Executing Context */
+#define ECS_BG_CTXT_REG_1              0x01 /* Stack level */
+#define ECS_BG_CTXT_REG_2              0x02
+#define ECS_PRI_1_CTXT_REG_0           0x04 /* Priority 1 Executing Context */
+#define ECS_PRI_1_CTXT_REG_1           0x05 /* Stack level */
+#define ECS_PRI_1_CTXT_REG_2           0x06
+#define ECS_PRI_2_CTXT_REG_0           0x08 /* Priority 2 Executing Context */
+#define ECS_PRI_2_CTXT_REG_1           0x09 /* Stack level */
+#define ECS_PRI_2_CTXT_REG_2           0x0A
+#define ECS_DBG_CTXT_REG_0             0x0C /* Debug Executing Context */
+#define ECS_DBG_CTXT_REG_1             0x0D /* Stack level */
+#define ECS_DBG_CTXT_REG_2             0x0E
+#define ECS_INSTRUCT_REG               0x11 /* NPE Instruction Register */
+
+#define ECS_REG_0_ACTIVE               0x80000000 /* all levels */
+#define ECS_REG_0_NEXTPC_MASK          0x1FFF0000 /* BG/PRI1/PRI2 levels */
+#define ECS_REG_0_LDUR_BITS            8
+#define ECS_REG_0_LDUR_MASK            0x00000700 /* all levels */
+#define ECS_REG_1_CCTXT_BITS           16
+#define ECS_REG_1_CCTXT_MASK           0x000F0000 /* all levels */
+#define ECS_REG_1_SELCTXT_BITS         0
+#define ECS_REG_1_SELCTXT_MASK         0x0000000F /* all levels */
+#define ECS_DBG_REG_2_IF               0x00100000 /* debug level */
+#define ECS_DBG_REG_2_IE               0x00080000 /* debug level */
+
+/* NPE watchpoint_fifo register bit */
+#define WFIFO_VALID                    0x80000000
+
+/* NPE messaging_status register bit definitions */
+#define MSGSTAT_OFNE  0x00010000 /* OutFifoNotEmpty */
+#define MSGSTAT_IFNF  0x00020000 /* InFifoNotFull */
+#define MSGSTAT_OFNF  0x00040000 /* OutFifoNotFull */
+#define MSGSTAT_IFNE  0x00080000 /* InFifoNotEmpty */
+#define MSGSTAT_MBINT 0x00100000 /* Mailbox interrupt */
+#define MSGSTAT_IFINT 0x00200000 /* InFifo interrupt */
+#define MSGSTAT_OFINT 0x00400000 /* OutFifo interrupt */
+#define MSGSTAT_WFINT 0x00800000 /* WatchFifo interrupt */
+
+/* NPE messaging_control register bit definitions */
+#define MSGCTL_OUT_FIFO       0x00010000 /* enable output FIFO */
+#define MSGCTL_IN_FIFO        0x00020000 /* enable input FIFO */
+#define MSGCTL_OUT_FIFO_WRITE 0x01000000 /* enable FIFO + WRITE */
+#define MSGCTL_IN_FIFO_WRITE  0x02000000
+
+/* NPE mailbox_status value for reset */
+#define RESET_MBOX_STAT          0x0000F0F0
+
+#define print_npe(npe, fmt, ...) fprintf(stderr, "%s: " fmt, npe->name, ## __VA_ARGS__)
+
+#if DEBUG_MSG
+#define debug_msg(npe, fmt, ...) print_npe(npe, fmt, ## __VA_ARGS__)
+#else
+#define debug_msg(npe, fmt, ...)
+#endif
+
+static struct {
+	u32 reg, val;
+} ecs_reset[] = {
+	{ECS_BG_CTXT_REG_0,    0xA0000000},
+	{ECS_BG_CTXT_REG_1,    0x01000000},
+	{ECS_BG_CTXT_REG_2,    0x00008000},
+	{ECS_PRI_1_CTXT_REG_0, 0x20000080},
+	{ECS_PRI_1_CTXT_REG_1, 0x01000000},
+	{ECS_PRI_1_CTXT_REG_2, 0x00008000},
+	{ECS_PRI_2_CTXT_REG_0, 0x20000080},
+	{ECS_PRI_2_CTXT_REG_1, 0x01000000},
+	{ECS_PRI_2_CTXT_REG_2, 0x00008000},
+	{ECS_DBG_CTXT_REG_0,   0x20000000},
+	{ECS_DBG_CTXT_REG_1,   0x00000000},
+	{ECS_DBG_CTXT_REG_2,   0x001E0000},
+	{ECS_INSTRUCT_REG,     0x1003C00F},
+};
+
+static struct npe npe_tab[] = {
+	{
+		.regs = (struct npe_regs *)IXP4XX_NPEA_BASE,
+		.id = 0,
+		.name = "NPE-A",
+	}, {
+		.regs = (struct npe_regs *)IXP4XX_NPEB_BASE,
+		.id = 1,
+		.name = "NPE-B",
+	}, {
+		.regs = (struct npe_regs *)IXP4XX_NPEC_BASE,
+		.id = 2,
+		.name = "NPE-C",
+	}
+};
+
+int npe_running(struct npe *npe)
+{
+	return (__raw_readl(&npe->regs->exec_status_cmd) & STAT_RUN) != 0;
+}
+
+static void npe_cmd_write(struct npe *npe, u32 addr, int cmd, u32 data)
+{
+	__raw_writel(data, &npe->regs->exec_data);
+	__raw_writel(addr, &npe->regs->exec_addr);
+	__raw_writel(cmd, &npe->regs->exec_status_cmd);
+}
+
+static u32 npe_cmd_read(struct npe *npe, u32 addr, int cmd)
+{
+	__raw_writel(addr, &npe->regs->exec_addr);
+	__raw_writel(cmd, &npe->regs->exec_status_cmd);
+	/* Iintroduce extra read cycles after issuing read command to NPE
+	   so that we read the register after the NPE has updated it.
+	   This is to overcome race condition between XScale and NPE */
+	__raw_readl(&npe->regs->exec_data);
+	__raw_readl(&npe->regs->exec_data);
+	return __raw_readl(&npe->regs->exec_data);
+}
+
+static void npe_clear_active(struct npe *npe, u32 reg)
+{
+	u32 val = npe_cmd_read(npe, reg, CMD_RD_ECS_REG);
+	npe_cmd_write(npe, reg, CMD_WR_ECS_REG, val & ~ECS_REG_0_ACTIVE);
+}
+
+static void npe_start(struct npe *npe)
+{
+	/* ensure only Background Context Stack Level is active */
+	npe_clear_active(npe, ECS_PRI_1_CTXT_REG_0);
+	npe_clear_active(npe, ECS_PRI_2_CTXT_REG_0);
+	npe_clear_active(npe, ECS_DBG_CTXT_REG_0);
+
+	__raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);
+	__raw_writel(CMD_NPE_START, &npe->regs->exec_status_cmd);
+}
+
+static void npe_stop(struct npe *npe)
+{
+	__raw_writel(CMD_NPE_STOP, &npe->regs->exec_status_cmd);
+	__raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd); /*FIXME?*/
+}
+
+static int npe_debug_instr(struct npe *npe, u32 instr, u32 ctx, u32 ldur)
+{
+	u32 wc;
+	int i;
+
+	/* set the Active bit, and the LDUR, in the debug level */
+	npe_cmd_write(npe, ECS_DBG_CTXT_REG_0, CMD_WR_ECS_REG,
+		      ECS_REG_0_ACTIVE | (ldur << ECS_REG_0_LDUR_BITS));
+
+	/* set CCTXT at ECS DEBUG L3 to specify in which context to execute
+	   the instruction, and set SELCTXT at ECS DEBUG Level to specify
+	   which context store to access.
+	   Debug ECS Level Reg 1 has form 0x000n000n, where n = context number
+	*/
+	npe_cmd_write(npe, ECS_DBG_CTXT_REG_1, CMD_WR_ECS_REG,
+		      (ctx << ECS_REG_1_CCTXT_BITS) |
+		      (ctx << ECS_REG_1_SELCTXT_BITS));
+
+	/* clear the pipeline */
+	__raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);
+
+	/* load NPE instruction into the instruction register */
+	npe_cmd_write(npe, ECS_INSTRUCT_REG, CMD_WR_ECS_REG, instr);
+
+	/* we need this value later to wait for completion of NPE execution
+	   step */
+	wc = __raw_readl(&npe->regs->watch_count);
+
+	/* issue a Step One command via the Execution Control register */
+	__raw_writel(CMD_NPE_STEP, &npe->regs->exec_status_cmd);
+
+	/* Watch Count register increments when NPE completes an instruction */
+	for (i = 0; i < MAX_RETRIES; i++) {
+		if (wc != __raw_readl(&npe->regs->watch_count))
+			return 0;
+		udelay(1);
+	}
+
+	print_npe(npe, "reset: npe_debug_instr(): timeout\n");
+	return -ETIMEDOUT;
+}
+
+static int npe_logical_reg_write8(struct npe *npe, u32 addr, u8 val, u32 ctx)
+{
+	/* here we build the NPE assembler instruction: mov8 d0, #0 */
+	u32 instr = INSTR_WR_REG_BYTE | /* OpCode */
+		addr << 9 |             /* base Operand */
+		(val & 0x1F) << 4 |     /* lower 5 bits to immediate data */
+		(val & ~0x1F) << (18 - 5);/* higher 3 bits to CoProc instr. */
+	return npe_debug_instr(npe, instr, ctx, 1); /* execute it */
+}
+
+static int npe_logical_reg_write16(struct npe *npe, u32 addr, u16 val, u32 ctx)
+{
+	/* here we build the NPE assembler instruction: mov16 d0, #0 */
+	u32 instr = INSTR_WR_REG_SHORT | /* OpCode */
+		addr << 9 |             /* base Operand */
+		(val & 0x1F) << 4 |     /* lower 5 bits to immediate data */
+		(val & ~0x1F) << (18 - 5);/* higher 11 bits to CoProc instr. */
+	return npe_debug_instr(npe, instr, ctx, 1); /* execute it */
+}
+
+static int npe_logical_reg_write32(struct npe *npe, u32 addr, u32 val, u32 ctx)
+{
+	/* write in 16 bit steps first the high and then the low value */
+	if (npe_logical_reg_write16(npe, addr, val >> 16, ctx))
+		return -ETIMEDOUT;
+	return npe_logical_reg_write16(npe, addr + 2, val & 0xFFFF, ctx);
+}
+
+static int npe_reset(struct npe *npe)
+{
+	u32 val, ctl, exec_count, ctx_reg2;
+	int i;
+
+	ctl = (__raw_readl(&npe->regs->messaging_control) | 0x3F000000) &
+		0x3F3FFFFF;
+
+	/* disable parity interrupt */
+	__raw_writel(ctl & 0x3F00FFFF, &npe->regs->messaging_control);
+
+	/* pre exec - debug instruction */
+	/* turn off the halt bit by clearing Execution Count register. */
+	exec_count = __raw_readl(&npe->regs->exec_count);
+	__raw_writel(0, &npe->regs->exec_count);
+	/* ensure that IF and IE are on (temporarily), so that we don't end up
+	   stepping forever */
+	ctx_reg2 = npe_cmd_read(npe, ECS_DBG_CTXT_REG_2, CMD_RD_ECS_REG);
+	npe_cmd_write(npe, ECS_DBG_CTXT_REG_2, CMD_WR_ECS_REG, ctx_reg2 |
+		      ECS_DBG_REG_2_IF | ECS_DBG_REG_2_IE);
+
+	/* clear the FIFOs */
+	while (__raw_readl(&npe->regs->watchpoint_fifo) & WFIFO_VALID)
+		;
+	while (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_OFNE)
+		/* read from the outFIFO until empty */
+		print_npe(npe, "npe_reset: read FIFO = 0x%X\n",
+			  __raw_readl(&npe->regs->in_out_fifo));
+
+	while (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE)
+		/* step execution of the NPE intruction to read inFIFO using
+		   the Debug Executing Context stack */
+		if (npe_debug_instr(npe, INSTR_RD_FIFO, 0, 0))
+			return -ETIMEDOUT;
+
+	/* reset the mailbox reg from the XScale side */
+	__raw_writel(RESET_MBOX_STAT, &npe->regs->mailbox_status);
+	/* from NPE side */
+	if (npe_debug_instr(npe, INSTR_RESET_MBOX, 0, 0))
+		return -ETIMEDOUT;
+
+	/* Reset the physical registers in the NPE register file */
+	for (val = 0; val < NPE_PHYS_REG; val++) {
+		if (npe_logical_reg_write16(npe, NPE_REGMAP, val >> 1, 0))
+			return -ETIMEDOUT;
+		/* address is either 0 or 4 */
+		if (npe_logical_reg_write32(npe, (val & 1) * 4, 0, 0))
+			return -ETIMEDOUT;
+	}
+
+	/* Reset the context store = each context's Context Store registers */
+
+	/* Context 0 has no STARTPC. Instead, this value is used to set NextPC
+	   for Background ECS, to set where NPE starts executing code */
+	val = npe_cmd_read(npe, ECS_BG_CTXT_REG_0, CMD_RD_ECS_REG);
+	val &= ~ECS_REG_0_NEXTPC_MASK;
+	val |= (0 /* NextPC */ << 16) & ECS_REG_0_NEXTPC_MASK;
+	npe_cmd_write(npe, ECS_BG_CTXT_REG_0, CMD_WR_ECS_REG, val);
+
+	for (i = 0; i < 16; i++) {
+		if (i) { /* Context 0 has no STEVT nor STARTPC */
+			/* STEVT = off, 0x80 */
+			if (npe_logical_reg_write8(npe, NPE_STEVT, 0x80, i))
+				return -ETIMEDOUT;
+			if (npe_logical_reg_write16(npe, NPE_STARTPC, 0, i))
+				return -ETIMEDOUT;
+		}
+		/* REGMAP = d0->p0, d8->p2, d16->p4 */
+		if (npe_logical_reg_write16(npe, NPE_REGMAP, 0x820, i))
+			return -ETIMEDOUT;
+		if (npe_logical_reg_write8(npe, NPE_CINDEX, 0, i))
+			return -ETIMEDOUT;
+	}
+
+	/* post exec */
+	/* clear active bit in debug level */
+	npe_cmd_write(npe, ECS_DBG_CTXT_REG_0, CMD_WR_ECS_REG, 0);
+	/* clear the pipeline */
+	__raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);
+	/* restore previous values */
+	__raw_writel(exec_count, &npe->regs->exec_count);
+	npe_cmd_write(npe, ECS_DBG_CTXT_REG_2, CMD_WR_ECS_REG, ctx_reg2);
+
+	/* write reset values to Execution Context Stack registers */
+	for (val = 0; val < ARRAY_SIZE(ecs_reset); val++)
+		npe_cmd_write(npe, ecs_reset[val].reg, CMD_WR_ECS_REG,
+			      ecs_reset[val].val);
+
+	/* clear the profile counter */
+	__raw_writel(CMD_CLR_PROFILE_CNT, &npe->regs->exec_status_cmd);
+
+	__raw_writel(0, &npe->regs->exec_count);
+	__raw_writel(0, &npe->regs->action_points[0]);
+	__raw_writel(0, &npe->regs->action_points[1]);
+	__raw_writel(0, &npe->regs->action_points[2]);
+	__raw_writel(0, &npe->regs->action_points[3]);
+	__raw_writel(0, &npe->regs->watch_count);
+
+	val = ixp4xx_read_feature_bits();
+	/* reset the NPE */
+	ixp4xx_write_feature_bits(val &
+				  ~(IXP4XX_FEATURE_RESET_NPEA << npe->id));
+	/* deassert reset */
+	ixp4xx_write_feature_bits(val |
+				  (IXP4XX_FEATURE_RESET_NPEA << npe->id));
+	for (i = 0; i < MAX_RETRIES; i++) {
+		if (ixp4xx_read_feature_bits() &
+		    (IXP4XX_FEATURE_RESET_NPEA << npe->id))
+			break; /* NPE is back alive */
+		udelay(1);
+	}
+	if (i == MAX_RETRIES)
+		return -ETIMEDOUT;
+
+	npe_stop(npe);
+
+	/* restore NPE configuration bus Control Register - parity settings */
+	__raw_writel(ctl, &npe->regs->messaging_control);
+	return 0;
+}
+
+
+int npe_send_message(struct npe *npe, const void *msg, const char *what)
+{
+	const u32 *send = msg;
+	int cycles = 0;
+
+	debug_msg(npe, "Trying to send message %s [%08X:%08X]\n",
+		  what, send[0], send[1]);
+
+	if (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE) {
+		debug_msg(npe, "NPE input FIFO not empty\n");
+		return -EIO;
+	}
+
+	__raw_writel(send[0], &npe->regs->in_out_fifo);
+
+	if (!(__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNF)) {
+		debug_msg(npe, "NPE input FIFO full\n");
+		return -EIO;
+	}
+
+	__raw_writel(send[1], &npe->regs->in_out_fifo);
+
+	while ((cycles < MAX_RETRIES) &&
+	       (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE)) {
+		udelay(1);
+		cycles++;
+	}
+
+	if (cycles == MAX_RETRIES) {
+		debug_msg(npe, "Timeout sending message\n");
+		return -ETIMEDOUT;
+	}
+
+#if DEBUG_MSG > 1
+	debug_msg(npe, "Sending a message took %i cycles\n", cycles);
+#endif
+	return 0;
+}
+
+int npe_recv_message(struct npe *npe, void *msg, const char *what)
+{
+	u32 *recv = msg;
+	int cycles = 0, cnt = 0;
+
+	debug_msg(npe, "Trying to receive message %s\n", what);
+
+	while (cycles < MAX_RETRIES) {
+		if (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_OFNE) {
+			recv[cnt++] = __raw_readl(&npe->regs->in_out_fifo);
+			if (cnt == 2)
+				break;
+		} else {
+			udelay(1);
+			cycles++;
+		}
+	}
+
+	switch(cnt) {
+	case 1:
+		debug_msg(npe, "Received [%08X]\n", recv[0]);
+		break;
+	case 2:
+		debug_msg(npe, "Received [%08X:%08X]\n", recv[0], recv[1]);
+		break;
+	}
+
+	if (cycles == MAX_RETRIES) {
+		debug_msg(npe, "Timeout waiting for message\n");
+		return -ETIMEDOUT;
+	}
+
+#if DEBUG_MSG > 1
+	debug_msg(npe, "Receiving a message took %i cycles\n", cycles);
+#endif
+	return 0;
+}
+
+int npe_send_recv_message(struct npe *npe, void *msg, const char *what)
+{
+	int result;
+	u32 *send = msg, recv[2];
+
+	if ((result = npe_send_message(npe, msg, what)) != 0)
+		return result;
+	if ((result = npe_recv_message(npe, recv, what)) != 0)
+		return result;
+
+	if ((recv[0] != send[0]) || (recv[1] != send[1])) {
+		debug_msg(npe, "Message %s: unexpected message received\n",
+			  what);
+		return -EIO;
+	}
+	return 0;
+}
+
+
+int npe_load_firmware(struct npe *npe)
+{
+	struct dl_block {
+		u32 type;
+		u32 offset;
+	} *blk;
+
+	struct dl_image {
+		u32 magic;
+		u32 id;
+		u32 size;
+		union {
+			u32 data[0];
+			struct dl_block blocks[0];
+		};
+	} *image;
+
+	struct dl_codeblock {
+		u32 npe_addr;
+		u32 size;
+		u32 data[0];
+	} *cb;
+
+	int i, j, err, data_size, instr_size, blocks, table_end;
+	u32 cmd;
+	char name[10 /* "/firmware/" */ + NPE_NAME_LENGTH + 1 /* NUL */];
+	size_t image_size;
+
+	sprintf(name, "/firmware/%s", npe->name);
+	if (!(image = read_file(name, &image_size))) {
+		print_npe(npe, "bad or missing microcode file %s\n", name);
+		return -EIO;
+	}
+
+	err = -EINVAL;
+	if (image_size < sizeof(struct dl_image)) {
+		print_npe(npe, "incomplete microcode file %s\n", name);
+		goto err;
+	}
+
+#if DEBUG_FW
+	print_npe(npe, "microcode: %08X %08X %08X (0x%X bytes)\n",
+		  image->magic, image->id, image->size, image->size * 4);
+#endif
+
+	if (image->magic == swab32(FW_MAGIC)) { /* swapped file */
+		image->id = swab32(image->id);
+		image->size = swab32(image->size);
+	} else if (image->magic != FW_MAGIC) {
+		print_npe(npe, "bad microcode file %s magic: 0x%X\n", name, image->magic);
+		goto err;
+	}
+	if ((image->size * 4 + sizeof(struct dl_image)) > image_size) {
+		print_npe(npe, "incomplete microcode file %s\n", name);
+		goto err;
+	}
+	if (((image->id >> 24) & 0xF /* NPE ID */) != npe->id) {
+		print_npe(npe, "NPE ID mismatch in microcode file %s\n", name);
+		goto err;
+	}
+	if (image->magic == swab32(FW_MAGIC))
+		for (i = 0; i < image->size; i++)
+			image->data[i] = swab32(image->data[i]);
+
+	if (cpu_is_ixp42x() && ((image->id >> 28) & 0xF /* device ID */)) {
+		print_npe(npe, "IXP43x/IXP46x microcode ignored on IXP42x\n");
+		goto err;
+	}
+
+	if (npe_running(npe)) {
+		print_npe(npe, "unable to load microcode file %s, NPE is already running\n", name);
+		err = -EBUSY;
+		goto err;
+	}
+
+	if (cpu_is_ixp42x()) {
+		if (!npe->id)
+			instr_size = NPE_A_42X_INSTR_SIZE;
+		else
+			instr_size = NPE_B_AND_C_42X_INSTR_SIZE;
+		data_size = NPE_42X_DATA_SIZE;
+	} else {
+		instr_size = NPE_46X_INSTR_SIZE;
+		data_size = NPE_46X_DATA_SIZE;
+	}
+
+	for (blocks = 0; blocks * sizeof(struct dl_block) / 4 < image->size;
+	     blocks++)
+		if (image->blocks[blocks].type == FW_BLOCK_TYPE_EOF)
+			break;
+	if (blocks * sizeof(struct dl_block) / 4 >= image->size) {
+		print_npe(npe, "microcode EOF block marker not found\n");
+		goto err;
+	}
+
+#if DEBUG_FW
+	print_npe(npe, "%i microcode blocks found\n", blocks);
+#endif
+
+	table_end = blocks * sizeof(struct dl_block) / 4 + 1 /* EOF marker */;
+	for (i = 0, blk = image->blocks; i < blocks; i++, blk++) {
+		if (blk->offset > image->size - sizeof(struct dl_codeblock) / 4
+		    || blk->offset < table_end) {
+			print_npe(npe, "invalid offset 0x%X of "
+				  "microcode block #%i\n", blk->offset, i);
+			goto err;
+		}
+
+		cb = (struct dl_codeblock*)&image->data[blk->offset];
+		if (blk->type == FW_BLOCK_TYPE_INSTR) {
+			if (cb->npe_addr + cb->size > instr_size)
+				goto too_big;
+			cmd = CMD_WR_INS_MEM;
+		} else if (blk->type == FW_BLOCK_TYPE_DATA) {
+			if (cb->npe_addr + cb->size > data_size)
+				goto too_big;
+			cmd = CMD_WR_DATA_MEM;
+		} else {
+			print_npe(npe, "invalid microcode block #%i type 0x%X\n",
+				  i, blk->type);
+			goto err;
+		}
+		if (blk->offset + sizeof(*cb) / 4 + cb->size > image->size) {
+			print_npe(npe, "microcode block #%i doesn't "
+				  "fit in microcode image: type %c, start 0x%X,"
+				  " length 0x%X\n", i,
+				  blk->type == FW_BLOCK_TYPE_INSTR ? 'I' : 'D',
+				  cb->npe_addr, cb->size);
+			goto err;
+		}
+
+		for (j = 0; j < cb->size; j++)
+			npe_cmd_write(npe, cb->npe_addr + j, cmd, cb->data[j]);
+	}
+
+	npe_start(npe);
+	if (!npe_running(npe))
+		print_npe(npe, "unable to start\n");
+	free(image);
+	return 0;
+
+too_big:
+	print_npe(npe, "microcode block #%i doesn't fit in NPE "
+		  "memory: type %c, start 0x%X, length 0x%X\n", i,
+		  blk->type == FW_BLOCK_TYPE_INSTR ? 'I' : 'D',
+		  cb->npe_addr, cb->size);
+err:
+	free(image);
+	return err;
+}
+
+
+struct npe *npe_request(int id)
+{
+	if (id < ARRAY_SIZE(npe_tab))
+		if (npe_tab[id].valid)
+			return &npe_tab[id];
+	return NULL;
+}
+
+static int __init npe_init(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(npe_tab); i++) {
+		struct npe *npe = &npe_tab[i];
+		if (!(ixp4xx_read_feature_bits() & (IXP4XX_FEATURE_RESET_NPEA << i)))
+			continue; /* NPE already disabled or not present */
+		if (npe_reset(npe))
+			continue;
+		npe->valid = 1;
+	}
+	return 0;
+}
+
+coredevice_initcall(npe_init);

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH] ARM: Support for IXP4xx built-in Ethernet interfaces.
  2013-04-07 11:42     ` Krzysztof Halasa
                         ` (2 preceding siblings ...)
  2013-04-07 19:57       ` [PATCH] ARM: Support for IXP4xx Network Processor Engines (NPEs) Krzysztof Halasa
@ 2013-04-07 19:58       ` Krzysztof Halasa
  2013-04-08  7:29         ` Jean-Christophe PLAGNIOL-VILLARD
  2013-04-08  7:56       ` [PATCH] ARM: Add support for IXP4xx CPU and for Goramo Multilink router platform Sascha Hauer
  4 siblings, 1 reply; 24+ messages in thread
From: Krzysztof Halasa @ 2013-04-07 19:58 UTC (permalink / raw)
  To: barebox

Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>

diff --git a/arch/arm/mach-ixp4xx/include/mach/platform.h b/arch/arm/mach-ixp4xx/include/mach/platform.h
new file mode 100644
index 0000000..1df4aa4
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/include/mach/platform.h
@@ -0,0 +1,15 @@
+#include <asm/types.h>
+
+#define IXP4XX_ETH_NPEA 0x00
+#define IXP4XX_ETH_NPEB 0x10
+#define IXP4XX_ETH_NPEC 0x20
+
+/* Information about built-in Ethernet MAC interfaces */
+struct eth_plat_info {
+	void *regs;
+	u8 npe;
+	u8 phy; /* MII PHY ID, 0 - 31 */
+	u8 rxq; /* configurable, currently 0 - 31 only */
+	u8 txreadyq;
+	u8 hwaddr[6];
+};
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 2736094..d6164ea 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -93,6 +93,14 @@ config DRIVER_NET_MACB
 	depends on HAS_MACB
 	select PHYLIB
 
+config DRIVER_NET_IXP4XX_ETH
+	tristate "Intel IXP4xx Ethernet support"
+	depends on ARCH_IXP4XX && IXP4XX_NPE && IXP4XX_QMGR
+	select PHYLIB
+	help
+	  Say Y here if you want to use built-in Ethernet ports
+	  on IXP4xx processor.
+
 config DRIVER_NET_TAP
 	bool "tap Ethernet driver"
 	depends on LINUX
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 42136f8..4a2ced9 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_DRIVER_NET_MACB)		+= macb.o
 obj-$(CONFIG_DRIVER_NET_TAP)		+= tap.o
 obj-$(CONFIG_PHYLIB)			+= phy/
 obj-$(CONFIG_NET_USB)			+= usb/
+obj-$(CONFIG_DRIVER_NET_IXP4XX_ETH)	+= ixp4xx_eth.o
 obj-$(CONFIG_DRIVER_NET_TSE)		+= altera_tse.o
 obj-$(CONFIG_DRIVER_NET_KS8851_MLL)	+= ks8851_mll.o
 obj-$(CONFIG_DRIVER_NET_DESIGNWARE)	+= designware.o
diff --git a/drivers/net/ixp4xx_eth.c b/drivers/net/ixp4xx_eth.c
new file mode 100644
index 0000000..1ae37f1
--- /dev/null
+++ b/drivers/net/ixp4xx_eth.c
@@ -0,0 +1,741 @@
+/*
+ * Intel IXP4xx Ethernet driver for Linux
+ *
+ * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * Ethernet port config (0x00 is not present on IXP42X):
+ *
+ * logical port		0x00		0x10		0x20
+ * NPE			0 (NPE-A)	1 (NPE-B)	2 (NPE-C)
+ * physical port	2		0		1
+ * RX queue (variable)	20		21		22
+ * TX queue		23		24		25
+ * RX-free queue	26		27		28
+ * TX-done queue is always 31, per-port RX queue is configurable
+ *
+ *
+ * Queue entries:
+ * bits 0 -> 1  - NPE ID (RX and TX-done)
+ * bits 0 -> 2  - priority (TX, per 802.1D)
+ * bits 3 -> 4  - port ID (user-set?)
+ * bits 5 -> 31 - physical descriptor address
+ */
+
+#include <common.h>
+#include <init.h>
+#include <malloc.h>
+#include <net.h>
+#include <errno.h>
+#include <asm/mmu.h>
+#include <linux/mii.h>
+#include <mach/ixp4xx-regs.h>
+#include <mach/platform.h>
+#include <mach/cpu.h>
+#include <mach/npe.h>
+#include <mach/qmgr.h>
+
+#define DEBUG_DESC		0
+#define DEBUG_RX		0
+#define DEBUG_TX		0
+#define DEBUG_PKT_BYTES		0
+#define DEBUG_MDIO		0
+#define DEBUG_OPEN		0
+#define DEBUG_CLOSE		0
+
+#define RX_DESCS		16 /* also length of all RX queues */
+#define TX_DESCS		16 /* also length of all TX queues */
+#define TXDONE_QUEUE_LEN	16 /* dwords */
+
+#define MAX_MRU			1536 /* 0x600 */
+#define RX_BUFF_SIZE		MAX_MRU
+
+#define MAX_MDIO_RETRIES	100 /* microseconds, typically 30 cycles */
+#define MAX_CLOSE_WAIT		1000 /* microseconds, typically 2-3 cycles */
+#define ETH_ALEN		6
+
+#define PHYSICAL_ID(port)	(((port)->npe->id + 2) % 3)
+#define LOGICAL_ID(port)	((port)->npe->id << 4)
+#define RX_QUEUE(port)		((port)->npe->id + 20) /* can be changed */
+#define TX_QUEUE(port)		((port)->npe->id + 23)
+#define RXFREE_QUEUE(port)	((port)->npe->id + 26)
+#define TXDONE_QUEUE		31
+
+/* TX Control Registers */
+#define TX_CNTRL0_TX_EN		0x01
+#define TX_CNTRL0_HALFDUPLEX	0x02
+#define TX_CNTRL0_RETRY		0x04
+#define TX_CNTRL0_PAD_EN	0x08
+#define TX_CNTRL0_APPEND_FCS	0x10
+#define TX_CNTRL0_2DEFER	0x20
+#define TX_CNTRL0_RMII		0x40 /* reduced MII */
+#define TX_CNTRL1_RETRIES	0x0F /* 4 bits */
+
+/* RX Control Registers */
+#define RX_CNTRL0_RX_EN		0x01
+#define RX_CNTRL0_PADSTRIP_EN	0x02
+#define RX_CNTRL0_SEND_FCS	0x04
+#define RX_CNTRL0_PAUSE_EN	0x08
+#define RX_CNTRL0_LOOP_EN	0x10
+#define RX_CNTRL0_ADDR_FLTR_EN	0x20
+#define RX_CNTRL0_RX_RUNT_EN	0x40
+#define RX_CNTRL0_BCAST_DIS	0x80
+#define RX_CNTRL1_DEFER_EN	0x01
+
+/* Core Control Register */
+#define CORE_RESET		0x01
+#define CORE_RX_FIFO_FLUSH	0x02
+#define CORE_TX_FIFO_FLUSH	0x04
+#define CORE_SEND_JAM		0x08
+#define CORE_MDC_EN		0x10 /* MDIO using NPE-B ETH-0 only */
+
+#define DEFAULT_TX_CNTRL0	(TX_CNTRL0_TX_EN | TX_CNTRL0_RETRY |       \
+				 TX_CNTRL0_PAD_EN | TX_CNTRL0_APPEND_FCS | \
+				 TX_CNTRL0_2DEFER)
+#define DEFAULT_RX_CNTRL0	RX_CNTRL0_RX_EN
+#define DEFAULT_CORE_CNTRL	CORE_MDC_EN
+
+
+/* NPE message codes */
+#define NPE_GETSTATUS			 0x00
+#define NPE_EDB_SETPORTADDRESS		 0x01
+#define NPE_EDB_GETMACADDRESSDATABASE	 0x02
+#define NPE_EDB_SETMACADDRESSSDATABASE	 0x03
+#define NPE_GETSTATS			 0x04
+#define NPE_RESETSTATS			 0x05
+#define NPE_SETMAXFRAMELENGTHS		 0x06
+#define NPE_VLAN_SETRXTAGMODE		 0x07
+#define NPE_VLAN_SETDEFAULTRXVID	 0x08
+#define NPE_VLAN_SETPORTVLANTABLEENTRY	 0x09
+#define NPE_VLAN_SETPORTVLANTABLERANGE	 0x0A
+#define NPE_VLAN_SETRXQOSENTRY		 0x0B
+#define NPE_VLAN_SETPORTIDEXTRACTIONMODE 0x0C
+#define NPE_STP_SETBLOCKINGSTATE	 0x0D
+#define NPE_FW_SETFIREWALLMODE		 0x0E
+#define NPE_PC_SETFRAMECONTROLDURATIONID 0x0F
+#define NPE_PC_SETAPMACTABLE		 0x11
+#define NPE_SETLOOPBACK_MODE		 0x12
+#define NPE_PC_SETBSSIDTABLE		 0x13
+#define NPE_ADDRESS_FILTER_CONFIG	 0x14
+#define NPE_APPENDFCSCONFIG		 0x15
+#define NPE_NOTIFY_MAC_RECOVERY_DONE	 0x16
+#define NPE_MAC_RECOVERY_START		 0x17
+
+struct eth_regs {
+	u32 tx_control[2], __res1[2];		 /* 000 */
+	u32 rx_control[2], __res2[2];		 /* 010 */
+	u32 random_seed, __res3[3];		 /* 020 */
+	u32 partial_empty_threshold, __res4;	 /* 030 */
+	u32 partial_full_threshold, __res5;	 /* 038 */
+	u32 tx_start_bytes, __res6[3];		 /* 040 */
+	u32 tx_deferral, rx_deferral, __res7[2]; /* 050 */
+	u32 tx_2part_deferral[2], __res8[2];	 /* 060 */
+	u32 slot_time, __res9[3];		 /* 070 */
+	u32 mdio_command[4];			 /* 080 */
+	u32 mdio_status[4];			 /* 090 */
+	u32 mcast_mask[6], __res10[2];		 /* 0A0 */
+	u32 mcast_addr[6], __res11[2];		 /* 0C0 */
+	u32 int_clock_threshold, __res12[3];	 /* 0E0 */
+	u32 hw_addr[6], __res13[61];		 /* 0F0 */
+	u32 core_control;			 /* 1FC */
+};
+
+/* NPE message structure */
+struct msg {
+	u8 cmd, eth_id, params[6];
+};
+
+/* Ethernet packet descriptor, 32 bytes */
+struct desc {
+	u8 *next;    /* pointer to next buffer, unused */
+
+	u16 buf_len; /* buffer length */
+	u16 pkt_len; /* packet length */
+	u8 *data;    /* pointer to data buffer in RAM */
+	u8 dest_id;
+	u8 src_id;
+	u16 flags;
+	u8 qos;
+	u8 padlen;
+	u16 vlan_tci;
+
+	u8 dst_mac[ETH_ALEN], src_mac[ETH_ALEN];
+};
+
+struct io {
+	struct desc rx_desc_tab[RX_DESCS]; /* alignment: 0x10 */
+	struct desc tx_desc_tab[TX_DESCS];
+	u8 rx_buff_tab[RX_DESCS][MAX_MRU];
+	u8 tx_buff_tab[TX_DESCS][MAX_MRU];
+};
+
+struct port {
+	struct io *io;
+	struct eth_regs *regs;
+	struct npe *npe;
+	u8 firmware[4];
+	struct eth_plat_info *pinfo;
+	struct mii_bus mii_bus;
+	struct eth_device eth;
+};
+
+static struct eth_regs *mdio_regs; /* mdio command and status only */
+
+static int ixp4xx_mdio_cmd(int write, const struct device_d *dev, unsigned char phy_id,
+			   unsigned char location, unsigned short value)
+{
+	int cycles = 0;
+
+	if (__raw_readl(&mdio_regs->mdio_command[3]) & 0x80) {
+		fprintf(stderr, "%s%d: MII not ready to transmit\n", dev->name, dev->id);
+		return -1;
+	}
+
+	if (write) {
+		__raw_writel(value & 0xFF, &mdio_regs->mdio_command[0]);
+		__raw_writel(value >> 8, &mdio_regs->mdio_command[1]);
+	}
+	__raw_writel(((phy_id << 5) | location) & 0xFF,
+		     &mdio_regs->mdio_command[2]);
+	__raw_writel((phy_id >> 3) | (write << 2) | 0x80 /* GO */,
+		     &mdio_regs->mdio_command[3]);
+
+	while ((cycles < MAX_MDIO_RETRIES) &&
+	       (__raw_readl(&mdio_regs->mdio_command[3]) & 0x80)) {
+		udelay(1);
+		cycles++;
+	}
+
+	if (cycles == MAX_MDIO_RETRIES) {
+		fprintf(stderr, "%s%d: MII write failed\n", dev->name, dev->id);
+		return -1;
+	}
+
+#if DEBUG_MDIO
+	fprintf(stderr, "%s%d: mdio_%s() took %i cycles\n", dev->name, dev->id,
+		write ? "write" : "read", cycles);
+#endif
+
+	if (write)
+		return 0;
+
+	if (__raw_readl(&mdio_regs->mdio_status[3]) & 0x80) {
+#if DEBUG_MDIO
+		fprintf(stderr, "%s%d: MII read failed\n", dev->name, dev->id);
+#endif
+		return -1;
+	}
+
+	value = (__raw_readl(&mdio_regs->mdio_status[0]) & 0xFF) |
+		((__raw_readl(&mdio_regs->mdio_status[1]) & 0xFF) << 8);
+#if DEBUG_MDIO
+	fprintf(stderr, "%s%d: MII read [%i] -> 0x%X\n", dev->name, dev->id, location, value);
+#endif
+
+	return value;
+}
+
+static int ixp4xx_mdio_read(struct mii_bus *mii, int phy_id, int location)
+{
+	int ret = ixp4xx_mdio_cmd(0, &mii->dev, phy_id, location, 0);
+	return ret;
+}
+
+static int ixp4xx_mdio_write(struct mii_bus *mii, int phy_id, int location, u16 value)
+{
+	int ret = ixp4xx_mdio_cmd(1, &mii->dev, phy_id, location, value);
+#if DEBUG_MDIO
+	fprintf(stderr, "%s%d: MII write [%i] <- 0x%X, err = %i\n",
+		mii->dev.name, mii->dev.id, location, value, ret);
+#endif
+	return ret;
+}
+
+static void ixp4xx_adjust_link(struct eth_device *dev)
+{
+	struct port *port = dev->priv;
+
+	if (dev->phydev->duplex)
+		__raw_writel(DEFAULT_TX_CNTRL0 & ~TX_CNTRL0_HALFDUPLEX,
+			     &port->regs->tx_control[0]);
+	else
+		__raw_writel(DEFAULT_TX_CNTRL0 | TX_CNTRL0_HALFDUPLEX,
+			     &port->regs->tx_control[0]);
+}
+
+static inline void debug_pkt(struct eth_device *dev, const char *func,
+			     u8 *data, int len)
+{
+#if DEBUG_PKT_BYTES
+	int i;
+
+	fprintf(stderr, "%s%d: %s(%4i) ", dev->dev.name, dev->dev.id, func, len);
+	for (i = 0; i < len; i++) {
+		if (i >= DEBUG_PKT_BYTES)
+			break;
+		fprintf(stderr, "%s%02X",
+			((i == 6) || (i == 12) || (i >= 14)) ? " " : "",
+			data[i]);
+	}
+	fprintf(stderr, "\n");
+#endif
+}
+
+
+static inline void debug_desc(struct desc *desc)
+{
+#if DEBUG_DESC
+	fprintf(stderr, "%07X: %X %3X %3X %07X %2X < %2X %4X %X"
+		" %X %X %02X%02X%02X%02X%02X%02X < %02X%02X%02X%02X%02X%02X\n",
+		(u32)desc, (u32)desc->next, desc->buf_len, desc->pkt_len,
+		(u32)desc->data, desc->dest_id, desc->src_id, desc->flags,
+		desc->qos, desc->padlen, desc->vlan_tci,
+		desc->dst_mac[0], desc->dst_mac[1], desc->dst_mac[2],
+		desc->dst_mac[3], desc->dst_mac[4], desc->dst_mac[5],
+		desc->src_mac[0], desc->src_mac[1], desc->src_mac[2],
+		desc->src_mac[3], desc->src_mac[4], desc->src_mac[5]);
+#endif
+}
+
+static inline int queue_get_desc(unsigned int queue, struct port *port,
+				 int is_tx)
+{
+	u32 addr, n;
+	struct desc *tab;
+
+	if (!(addr = qmgr_get_entry(queue)))
+		return -1;
+
+	addr &= ~0x1F; /* mask out non-address bits */
+	tab = is_tx ? port->io->tx_desc_tab : port->io->rx_desc_tab;
+	n = (addr - (u32)tab) / sizeof(struct desc);
+	BUG_ON(n >= (is_tx ? TX_DESCS : RX_DESCS));
+	debug_desc((struct desc*)addr);
+	BUG_ON(tab[n].next);
+	return n;
+}
+
+static inline void queue_put_desc(unsigned int queue, struct desc *desc)
+{
+	debug_desc(desc);
+	BUG_ON(((u32)desc) & 0x1F);
+	qmgr_put_entry(queue, (u32)desc);
+	/* Don't check for queue overflow here, we've allocated sufficient
+	   length and queues >= 32 don't support this check anyway. */
+}
+
+
+static int ixp4xx_eth_poll(struct eth_device *dev)
+{
+	struct port *port = dev->priv;
+	struct desc *desc;
+	u8 *buff;
+	int n, len;
+
+#if DEBUG_RX
+	fprintf(stderr, "%s%d: eth_poll\n", dev->dev.name, dev->dev.id);
+#endif
+
+	if ((n = queue_get_desc(RX_QUEUE(port), port, 0)) < 0) {
+#if DEBUG_RX
+		fprintf(stderr, "%s%d: eth_poll = no packet received\n", dev->dev.name, dev->dev.id);
+#endif
+		return 0;
+	}
+
+	barrier();
+	desc = &port->io->rx_desc_tab[n];
+	buff = port->io->rx_buff_tab[n];
+	len = desc->pkt_len;
+	/* process received frame */
+	memcpy((void *)NetRxPackets[0], buff, len);
+	debug_pkt(dev, "RX", desc->data, len);
+
+	/* put the new buffer on RX-free queue */
+	desc->buf_len = MAX_MRU;
+	desc->pkt_len = 0;
+	queue_put_desc(RXFREE_QUEUE(port), desc);
+
+	net_receive(NetRxPackets[0], len);
+
+#if DEBUG_RX
+	fprintf(stderr, "%s%d: eth_poll end\n", dev->dev.name, dev->dev.id);
+#endif
+	return 0;
+}
+
+
+static int ixp4xx_eth_xmit(struct eth_device *dev, void *data, int len)
+{
+	struct port *port = dev->priv;
+	int n;
+	struct desc *desc;
+
+#if DEBUG_TX
+	fprintf(stderr, "%s%d: eth_xmit\n", dev->dev.name, dev->dev.id);
+#endif
+
+	if (unlikely(len > 1500))
+		return -1;
+
+	debug_pkt(dev, "TX", data, len);
+
+	if ((n = queue_get_desc(TXDONE_QUEUE, port, 1)) < 0)
+		return -1; /* no free buffers */
+	desc = &port->io->tx_desc_tab[n];
+	desc->data = port->io->tx_buff_tab[n];
+	desc->buf_len = desc->pkt_len = len;
+	memcpy(desc->data, data, len);
+
+	/* NPE firmware pads short frames with zeros internally */
+	// wmb();
+	barrier();
+	queue_put_desc(TX_QUEUE(port), desc);
+
+#if DEBUG_TX
+	fprintf(stderr, "%s%d: eth_xmit end\n", dev->dev.name, dev->dev.id);
+#endif
+	return 0;
+}
+
+static void request_queues(struct port *port, struct eth_device *dev)
+{
+	qmgr_request_queue(RXFREE_QUEUE(port), RX_DESCS, 0, 0, "%s:RX-free", dev->dev.name);
+	qmgr_request_queue(RX_QUEUE(port), RX_DESCS, 0, 0, "%s:RX", dev->dev.name);
+	qmgr_request_queue(TX_QUEUE(port), TX_DESCS, 0, 0, "%s:TX", dev->dev.name);
+
+	/* Common TX-done queue handles buffers sent out by the NPEs */
+	qmgr_request_queue(TXDONE_QUEUE, TXDONE_QUEUE_LEN, 0, 0,
+			   "%s:TX-done", dev->dev.name);
+}
+
+static void release_queues(struct port *port)
+{
+	qmgr_release_queue(RXFREE_QUEUE(port));
+	qmgr_release_queue(RX_QUEUE(port));
+	qmgr_release_queue(TX_QUEUE(port));
+	qmgr_release_queue(TXDONE_QUEUE);
+}
+
+static void init_queues(struct port *port)
+{
+	int i;
+
+	memset(port->io->tx_desc_tab, 0, sizeof(port->io->tx_desc_tab)); /* descs */
+	memset(port->io->rx_desc_tab, 0, sizeof(port->io->rx_desc_tab));
+
+	/* Setup RX buffers */
+	for (i = 0; i < RX_DESCS; i++) {
+		struct desc *desc = &port->io->rx_desc_tab[i];
+		desc->buf_len = MAX_MRU;
+		desc->data = port->io->rx_buff_tab[i];
+	}
+}
+
+static int ixp4xx_eth_open(struct eth_device *dev)
+{
+	struct port *port = dev->priv;
+	struct npe *npe = port->npe;
+	struct msg msg;
+	int i, err;
+
+#if DEBUG_OPEN
+	fprintf(stderr, "%s%d: opening %p\n", dev->dev.name, dev->dev.id, dev);
+#endif
+
+	if (!npe_running(npe)) {
+		err = npe_load_firmware(npe);
+		if (err)
+			return err;
+
+		if (npe_recv_message(npe, &msg, "ETH_GET_STATUS")) {
+			fprintf(stderr, "%s%d: %s not responding\n", dev->dev.name, dev->dev.id, npe->name);
+			return -EIO;
+		}
+		memcpy(port->firmware, msg.params + 2, 4);
+	}
+
+	err = phy_device_connect(dev, &port->mii_bus, port->pinfo->phy,
+				 ixp4xx_adjust_link, 0, PHY_INTERFACE_MODE_MII);
+	if (err)
+		return err;
+
+	port->io = dma_alloc_coherent(sizeof(*port->io));
+
+	memset(&msg, 0, sizeof(msg));
+	msg.cmd = NPE_VLAN_SETRXQOSENTRY;
+	msg.eth_id = LOGICAL_ID(port);
+	msg.params[3] = RX_QUEUE(port) | 0x80;
+	msg.params[4] = RX_QUEUE(port) >> 4; /* MSB of offset */
+	msg.params[5] = RX_QUEUE(port) << 4; /* LSB of offset */
+	for (i = 0; i < 8; i++) {
+		msg.params[1] = i;
+		if (npe_send_recv_message(port->npe, &msg, "ETH_SET_RXQ")) {
+			err = -EIO;
+			goto out;
+		}
+	}
+
+	msg.cmd = NPE_EDB_SETPORTADDRESS;
+	msg.eth_id = PHYSICAL_ID(port);
+	memcpy(msg.params, port->pinfo->hwaddr, ETH_ALEN);
+	if (npe_send_recv_message(port->npe, &msg, "ETH_SET_MAC")) {
+		err = -EIO;
+		goto out;
+	}
+
+	memset(&msg, 0, sizeof(msg));
+	msg.cmd = NPE_FW_SETFIREWALLMODE;
+	msg.eth_id = LOGICAL_ID(port);
+	if (npe_send_recv_message(port->npe, &msg, "ETH_SET_FIREWALL_MODE")) {
+		err = -EIO;
+		goto out;
+	}
+
+	request_queues(port, dev);
+	init_queues(port);
+
+	for (i = 0; i < ETH_ALEN; i++)
+		__raw_writel(port->pinfo->hwaddr[i], &port->regs->hw_addr[i]);
+	__raw_writel(0x08, &port->regs->random_seed);
+	__raw_writel(0x12, &port->regs->partial_empty_threshold);
+	__raw_writel(0x30, &port->regs->partial_full_threshold);
+	__raw_writel(0x08, &port->regs->tx_start_bytes);
+	__raw_writel(0x15, &port->regs->tx_deferral);
+	__raw_writel(0x08, &port->regs->tx_2part_deferral[0]);
+	__raw_writel(0x07, &port->regs->tx_2part_deferral[1]);
+	__raw_writel(0x80, &port->regs->slot_time);
+	__raw_writel(0x01, &port->regs->int_clock_threshold);
+
+	/* Populate queues with buffers, no failure after this point */
+	for (i = 0; i < TX_DESCS; i++)
+		queue_put_desc(TXDONE_QUEUE, &port->io->tx_desc_tab[i]);
+
+	for (i = 0; i < RX_DESCS; i++)
+		queue_put_desc(RXFREE_QUEUE(port), &port->io->rx_desc_tab[i]);
+
+	__raw_writel(TX_CNTRL1_RETRIES, &port->regs->tx_control[1]);
+	__raw_writel(DEFAULT_TX_CNTRL0, &port->regs->tx_control[0]);
+	__raw_writel(0, &port->regs->rx_control[1]);
+	__raw_writel(DEFAULT_RX_CNTRL0, &port->regs->rx_control[0]);
+
+#if 0
+	qmgr_set_irq(RX_QUEUE(port), QUEUE_IRQ_SRC_NOT_EMPTY,
+		     eth_rx_irq, dev);
+	qmgr_set_irq(TXDONE_QUEUE, QUEUE_IRQ_SRC_NOT_EMPTY,
+		     eth_txdone_irq, NULL);
+	qmgr_enable_irq(TXDONE_QUEUE);
+#endif
+	memset(&msg, 0, sizeof(msg));
+#if DEBUG_OPEN
+	fprintf(stderr, "%s%d opened\n", dev->dev.name, dev->dev.id);
+#endif
+	return 0;
+out:
+	dma_free_coherent(port->io, sizeof(*port->io));
+	port->io = NULL;
+#if DEBUG_OPEN
+	fprintf(stderr, "%s%d open failed (%i)\n", dev->dev.name, dev->dev.id, err);
+#endif
+	return err;
+}
+
+static void ixp4xx_eth_close(struct eth_device *dev)
+{
+	struct port *port = dev->priv;
+	struct msg msg;
+	int buffs = RX_DESCS; /* allocated RX buffers */
+	int i;
+
+#if DEBUG_CLOSE
+	fprintf(stderr, "%s%d: closing\n", dev->dev.name, dev->dev.id);
+#endif
+#if 0
+	qmgr_disable_irq(RX_QUEUE(port));
+#endif
+
+	if (!port->io)
+		return; /* already closed */
+
+	while (queue_get_desc(RXFREE_QUEUE(port), port, 0) >= 0)
+		buffs--;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.cmd = NPE_SETLOOPBACK_MODE;
+	msg.eth_id = LOGICAL_ID(port);
+	msg.params[1] = 1;
+	if (npe_send_recv_message(port->npe, &msg, "ETH_ENABLE_LOOPBACK"))
+		fprintf(stderr, "%s%d: unable to enable loopback\n", dev->dev.name, dev->dev.id);
+
+#if DEBUG_CLOSE
+	fprintf(stderr, "%s%d: draining RX queue\n", dev->dev.name, dev->dev.id);
+#endif
+	i = 0;
+	do { /* drain RX buffers */
+		while (queue_get_desc(RX_QUEUE(port), port, 0) >= 0)
+			buffs--;
+		if (!buffs)
+			break;
+		if (qmgr_stat_full(TXDONE_QUEUE) && !(i % 10)) {
+			/* we have to inject some packet */
+			struct desc *desc;
+			int n = queue_get_desc(TXDONE_QUEUE, port, 1);
+			BUG_ON(n < 0);
+			desc = &port->io->tx_desc_tab[n];
+			desc->buf_len = desc->pkt_len = 1;
+			//wmb();
+			barrier();
+			queue_put_desc(TX_QUEUE(port), desc);
+		}
+		udelay(1);
+	} while (++i < MAX_CLOSE_WAIT);
+
+	if (buffs)
+		fprintf(stderr, "%s%d: unable to drain RX queue, %i buffer(s) left in NPE\n",
+			dev->dev.name, dev->dev.id, buffs);
+#if DEBUG_CLOSE
+	if (!buffs)
+		fprintf(stderr, "%s%d: draining RX queue took %i cycles\n", dev->dev.name, dev->dev.id, i);
+#endif
+
+	buffs = TX_DESCS;
+	while (queue_get_desc(TX_QUEUE(port), port, 1) >= 0)
+		buffs--; /* cancel TX */
+
+	i = 0;
+	do {
+		while (queue_get_desc(TXDONE_QUEUE, port, 1) >= 0)
+			buffs--;
+		if (!buffs)
+			break;
+	} while (++i < MAX_CLOSE_WAIT);
+
+	if (buffs)
+		fprintf(stderr, "%s%d: unable to drain TX queue, %i buffer(s) left in NPE\n",
+			dev->dev.name, dev->dev.id, buffs);
+#if DEBUG_CLOSE
+	if (!buffs)
+		fprintf(stderr, "%s%d: draining TX queues took %i cycles\n", dev->dev.name, dev->dev.id, i);
+#endif
+
+	msg.params[1] = 0;
+	if (npe_send_recv_message(port->npe, &msg, "ETH_DISABLE_LOOPBACK"))
+		fprintf(stderr, "%s%d: unable to disable loopback\n", dev->dev.name, dev->dev.id);
+
+#if 0
+	qmgr_disable_irq(TXDONE_QUEUE);
+#endif
+	release_queues(port);
+	dma_free_coherent(port->io, sizeof(*port->io));
+	port->io = NULL;
+#if DEBUG_CLOSE
+	fprintf(stderr, "%s%d: closed\n", dev->dev.name, dev->dev.id);
+#endif
+}
+
+static int ixp4xx_eth_get_hwaddr(struct eth_device *eth, unsigned char *addr)
+{
+	struct port *port = eth->priv;
+	memcpy(addr, port->pinfo->hwaddr, 6);
+	return 0;
+}
+
+static int ixp4xx_eth_set_hwaddr(struct eth_device *eth, unsigned char *addr)
+{
+	struct port *port = eth->priv;
+	memcpy(port->pinfo->hwaddr, addr, 6);
+	return 0;
+}
+
+static int ixp4xx_eth_init(struct eth_device *eth)
+{
+	struct port *port = eth->priv;
+
+	__raw_writel(DEFAULT_CORE_CNTRL | CORE_RESET,
+		     &port->regs->core_control);
+	udelay(50);
+	__raw_writel(DEFAULT_CORE_CNTRL, &port->regs->core_control);
+	udelay(50);
+	return 0;
+}
+
+static int ixp4xx_eth_probe(struct device_d *dev)
+{
+	struct npe *npe;
+	struct port *port;
+	struct eth_plat_info *pinfo = dev->platform_data;
+
+	if (!pinfo) {
+		fprintf(stderr, "ixp4xx_eth: no platform information\n");
+		return -ENODEV;
+	}
+
+	if (!(npe = npe_request(pinfo->npe))) {
+		fprintf(stderr, "ixp4xx_eth: unable to acquire NPE\n");
+		return -ENODEV;
+	}
+
+	port = xmemalign(0x20, sizeof(*port));
+	memset(port, 0, sizeof(*port));
+
+	port->regs = pinfo->regs;
+	port->npe = npe;
+	port->pinfo = pinfo;
+	port->eth.dev.id = -1;
+	port->eth.priv = port;
+	port->eth.init = ixp4xx_eth_init;
+	port->eth.open = ixp4xx_eth_open;
+	port->eth.halt = ixp4xx_eth_close;
+	port->eth.send = ixp4xx_eth_xmit;
+	port->eth.recv = ixp4xx_eth_poll;
+	port->eth.get_ethaddr = ixp4xx_eth_get_hwaddr;
+	port->eth.set_ethaddr = ixp4xx_eth_set_hwaddr;
+
+	port->mii_bus.dev.id = -1;
+	port->mii_bus.read = ixp4xx_mdio_read;
+	port->mii_bus.write = ixp4xx_mdio_write;
+	mdiobus_register(&port->mii_bus);
+	eth_register(&port->eth);
+	dev->priv = port;
+	return 0;
+}
+
+static void ixp4xx_eth_remove(struct device_d *dev)
+{
+	struct port *port = dev->priv;
+	ixp4xx_eth_close(&port->eth);
+	eth_unregister(&port->eth);
+	mdiobus_unregister(&port->mii_bus);
+	free(port);
+}
+
+static struct driver_d ixp4xx_eth_driver = {
+	.name  = "ixp4xx_eth",
+	.probe = ixp4xx_eth_probe,
+	.remove = ixp4xx_eth_remove,
+};
+
+static int __init ixp4xx_eth_module_init(void)
+{
+	if (cpu_is_ixp43x()) {
+		/* IXP43x lacks NPE-B and uses NPE-C for MII PHY access */
+		if (!(ixp4xx_read_feature_bits() & IXP4XX_FEATURE_NPEC_ETH))
+			return -ENOSYS;
+		mdio_regs = (struct eth_regs *)IXP4XX_EthC_BASE;
+	} else {
+		/* All MII PHY accesses use NPE-B Ethernet registers */
+		if (!(ixp4xx_read_feature_bits() & IXP4XX_FEATURE_NPEB_ETH0))
+			return -ENOSYS;
+		mdio_regs = (struct eth_regs *)IXP4XX_EthB_BASE;
+	}
+
+	__raw_writel(DEFAULT_CORE_CNTRL, &mdio_regs->core_control);
+
+	platform_driver_register(&ixp4xx_eth_driver);
+	return 0;
+}
+
+device_initcall(ixp4xx_eth_module_init);

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] ARM: Support for IXP4xx CPU.
  2013-04-07 19:54       ` [PATCH] ARM: Support for IXP4xx CPU Krzysztof Halasa
@ 2013-04-08  7:27         ` Jean-Christophe PLAGNIOL-VILLARD
  2013-04-14 10:30           ` Krzysztof Halasa
  0 siblings, 1 reply; 24+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2013-04-08  7:27 UTC (permalink / raw)
  To: Krzysztof Halasa; +Cc: barebox

On 21:54 Sun 07 Apr     , Krzysztof Halasa wrote:
> Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>
> 
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index bb9b47b..2a775d5 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -79,6 +79,12 @@ config ARCH_IMX
>  	select WATCHDOG_IMX_RESET_SOURCE
>  	select HAS_DEBUG_LL
>  
> +config ARCH_IXP4XX
> +	bool "Intel IXP4xx-based"
> +	select CPU_XSCALE
> +	select ARCH_SUPPORTS_BIG_ENDIAN
> +	select CPU_BIG_ENDIAN
> +
>  config ARCH_MXS
>  	bool "Freescale i.MX23/28 (mxs) based"
>  	select GENERIC_GPIO
> @@ -153,6 +159,7 @@ source arch/arm/mach-clps711x/Kconfig
>  source arch/arm/mach-ep93xx/Kconfig
>  source arch/arm/mach-highbank/Kconfig
>  source arch/arm/mach-imx/Kconfig
> +source arch/arm/mach-ixp4xx/Kconfig
>  source arch/arm/mach-mxs/Kconfig
>  source arch/arm/mach-netx/Kconfig
>  source arch/arm/mach-nomadik/Kconfig
> diff --git a/arch/arm/Makefile b/arch/arm/Makefile
> index d506b12..584d39b 100644
> --- a/arch/arm/Makefile
> +++ b/arch/arm/Makefile
> @@ -57,6 +57,7 @@ machine-$(CONFIG_ARCH_CLPS711X)		:= clps711x
>  machine-$(CONFIG_ARCH_EP93XX)		:= ep93xx
>  machine-$(CONFIG_ARCH_HIGHBANK)		:= highbank
>  machine-$(CONFIG_ARCH_IMX)		:= imx
> +machine-$(CONFIG_ARCH_IXP4XX)		:= ixp4xx
>  machine-$(CONFIG_ARCH_MXS)		:= mxs
>  machine-$(CONFIG_ARCH_NOMADIK)		:= nomadik
>  machine-$(CONFIG_ARCH_NETX)		:= netx
> diff --git a/arch/arm/mach-ixp4xx/Kconfig b/arch/arm/mach-ixp4xx/Kconfig
> new file mode 100644
> index 0000000..e69de29
> diff --git a/arch/arm/mach-ixp4xx/Makefile b/arch/arm/mach-ixp4xx/Makefile
> new file mode 100644
> index 0000000..d8a3d7f
> --- /dev/null
> +++ b/arch/arm/mach-ixp4xx/Makefile
> @@ -0,0 +1 @@
> +obj-y += generic.o
> diff --git a/arch/arm/mach-ixp4xx/generic.c b/arch/arm/mach-ixp4xx/generic.c
> new file mode 100644
> index 0000000..e81994b
> --- /dev/null
> +++ b/arch/arm/mach-ixp4xx/generic.c
> @@ -0,0 +1,114 @@
> +#include <common.h>
> +#include <init.h>
> +#include <ns16550.h>
> +#include <asm/armlinux.h>
> +#include <asm/io.h>
> +#include <mach/ixp4xx-regs.h>
> +
> +#define OSTS_FREQUENCY 66666000
> +
> +void reset_cpu(ulong addr)
> +{
> +	/* Use on-chip reset capability */
> +	/* This may not work on IXP425 rev. A0 */
> +
> +	IXP4XX_OSWK = IXP4XX_WDT_KEY;
> +	IXP4XX_OSWT = 0; /* request immediate reset */
> +	IXP4XX_OSWE = IXP4XX_WDT_RESET_ENABLE | IXP4XX_WDT_COUNT_ENABLE;
> +	while (1)
> +		;
> +}
> +
> +#include <clock.h>
> +
> +/**
> + * @brief Provide a simple clock read
> + *
> + * Nothing is simpler.. read direct from clock and provide it
> + * to the caller.
> + *
> + * @return clock counter
> + */
> +static uint64_t ixp4xx_clocksource_read(void)
> +{
> +	return IXP4XX_OSTS;
> +}
> +
> +static struct clocksource cs = {
> +	.read = ixp4xx_clocksource_read,
> +	.mask = 0xffffffff,
use CLOCKSOURCE_MASK(32),
> +	.shift = 10,
> +};
> +
> +/**
> + * @brief Initialize the Clock
> + *
> + * We use the Time-Stamp Timer
> + *
> + * @return result of @ref init_clock
> + */
> +static int ixp4xx_clocksource_init(void)
> +{
> +	cs.mult = clocksource_hz2mult(OSTS_FREQUENCY, cs.shift);
> +
> +	return init_clock(&cs);
> +}
> +
> +/* Run me at boot time */
> +core_initcall(ixp4xx_clocksource_init);
> +
> +
> +#ifdef CONFIG_DRIVER_SERIAL_NS16550
> +
> +/**
> + * @brief UART port register read function for IXP4XX
> + *
> + * @param base base address of UART
> + * @param reg_idx register index
> + *
> + * @return character read from register
> + */
> +unsigned int ixp4xx_uart_read(unsigned long base, unsigned char reg_idx)
> +{
> +	return readb(4 * reg_idx + 3 /* big-endian */ + (uint8_t *)base);
drop the 4 and use shift = 2 in pdata
> +}
> +EXPORT_SYMBOL(ixp4xx_uart_read);
> +
> +/**
> + * @brief UART port register write function for IXP4XX
> + *
> + * @param val value to write
> + * @param base base address of UART
> + * @param reg_idx register index
> + *
> + * @return void
> + */
> +void ixp4xx_uart_write(unsigned int val, unsigned long base, unsigned char reg_idx)
> +{
> +	writeb(val, 4 * reg_idx + 3 /* big-endian */ + (uint8_t *)base);
> +}
> +EXPORT_SYMBOL(ixp4xx_uart_write);
> +
> +
> +static struct NS16550_plat serial_plat = {
> +	.clock = 14745600,
> +	.f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR,
> +	.reg_read = ixp4xx_uart_read,
> +	.reg_write = ixp4xx_uart_write,
> +};
> +
> +/**
> + * @brief UART serial port initialization
> + *
> + * @return result of device registration
> + */
> +static int ixp4xx_console_init(void)
> +{
> +	/* Register the serial port */
> +	add_ns16550_device(0, (u32)IXP4XX_UART1_BASE, 1024, IORESOURCE_MEM_8BIT, &serial_plat);
we have multiple uart on ixp do no hard code it
> +	return 0;
> +}
> +
> +console_initcall(ixp4xx_console_init);
> +
> +#endif /* CONFIG_DRIVER_SERIAL_NS16550 */
> diff --git a/arch/arm/mach-ixp4xx/include/mach/cpu.h b/arch/arm/mach-ixp4xx/include/mach/cpu.h
> new file mode 100644
> index 0000000..1aef932
> --- /dev/null
> +++ b/arch/arm/mach-ixp4xx/include/mach/cpu.h
> @@ -0,0 +1,55 @@
> +/*
> + * Copyright (C) 2007, 2009 Krzysztof Halasa
> + * Copyright (C) 2007 MontaVista Software, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#ifndef __MACH_CPU_H__
> +#define __MACH_CPU_H__
> +
> +#include <linux/types.h>
> +#include <asm/cputype.h>
> +
> +/* Processor id value in CP15 Register 0 */
> +#define IXP42X_PROCESSOR_ID_VALUE 0x690541c0 /* including unused 0x690541Ex */
> +#define IXP42X_PROCESSOR_ID_MASK  0xffffffc0
> +
> +#define IXP43X_PROCESSOR_ID_VALUE 0x69054040
> +#define IXP43X_PROCESSOR_ID_MASK  0xfffffff0
> +
> +#define IXP46X_PROCESSOR_ID_VALUE 0x69054200 /* including IXP455 */
> +#define IXP46X_PROCESSOR_ID_MASK  0xfffffff0
> +
> +#define cpu_is_ixp42x_rev_a0() ((read_cpuid_id() & (IXP42X_PROCESSOR_ID_MASK | 0xF)) == \
> +				IXP42X_PROCESSOR_ID_VALUE)
> +#define cpu_is_ixp42x() ((read_cpuid_id() & IXP42X_PROCESSOR_ID_MASK) == \
> +			 IXP42X_PROCESSOR_ID_VALUE)
> +#define cpu_is_ixp43x() ((read_cpuid_id() & IXP43X_PROCESSOR_ID_MASK) == \
> +			 IXP43X_PROCESSOR_ID_VALUE)
> +#define cpu_is_ixp46x() ((read_cpuid_id() & IXP46X_PROCESSOR_ID_MASK) == \
> +			 IXP46X_PROCESSOR_ID_VALUE)
> +
> +static inline u32 ixp4xx_read_feature_bits(void)
> +{
> +	u32 val = ~IXP4XX_EXP_CFG2;
> +
> +	if (cpu_is_ixp42x_rev_a0())
> +		return IXP42X_FEATURE_MASK & ~(IXP4XX_FEATURE_RCOMP |
> +					       IXP4XX_FEATURE_AES);
> +	if (cpu_is_ixp42x())
> +		return val & IXP42X_FEATURE_MASK;
> +	if (cpu_is_ixp43x())
> +		return val & IXP43X_FEATURE_MASK;
> +	return val & IXP46X_FEATURE_MASK;
> +}
> +
> +static inline void ixp4xx_write_feature_bits(u32 value)
> +{
> +	IXP4XX_EXP_CFG2 = ~value;
> +}
> +
> +#endif /* _MACH_CPU_H */
> diff --git a/arch/arm/mach-ixp4xx/include/mach/ixp4xx-head.h b/arch/arm/mach-ixp4xx/include/mach/ixp4xx-head.h
> new file mode 100644
> index 0000000..b3d357f
> --- /dev/null
> +++ b/arch/arm/mach-ixp4xx/include/mach/ixp4xx-head.h
> @@ -0,0 +1,16 @@
> +#include <mach/ixp4xx-regs.h>
> +#include <asm/barebox-arm-head.h>
> +
> +.macro	ixp4xx_cpu_lowlevel_init
> +
> +	arm_cpu_lowlevel_init r0
> +
> +	add pc, #(0x50000000 - 4) /* jump to ROM area */
> +
> +	mov r0, #(IXP4XX_EXP_CFG0 & 0xFFFF0000)
> +	orr r0, #(IXP4XX_EXP_CFG0 & 0x0000FFFF)
> +	ldr r1, [r0]
> +	and r1, r1, #~0x80000000 /* unmap EXP bus from 0x0 */
> +	str r1, [r0]
> +
> +.endm
> diff --git a/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h b/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h
> new file mode 100644
> index 0000000..da4dc8a
> --- /dev/null
> +++ b/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h
> @@ -0,0 +1,365 @@
> +/*
> + * Register definitions for IXP4xx chipset.
> + *
> + * Copyright (C) 2002 Intel Corporation.
> + * Copyright (C) 2003-2004 MontaVista Software, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#ifndef _ASM_ARM_IXP4XX_H_
> +#define _ASM_ARM_IXP4XX_H_
> +
> +#ifdef __ASSEMBLER__
> +#define IXP4XX_REG(reg)  (reg)
> +#else
> +#define IXP4XX_REG(reg)  (*(volatile u32 *)(reg))
> +#define IXP4XX_BASE(reg) ((u32*)(reg))
> +#endif
> +
> +/* Expansion Bus region */
> +
> +/* Queue Manager */
> +#define IXP4XX_QMGR_BASE              (0x60000000)
> +#define IXP4XX_QMGR_REGION_SIZE       (0x00004000)
> +
> +
> +/* PCI Config registers */
> +#define IXP4XX_PCI_CFG_BASE           (0xC0000000)
> +#define IXP4XX_PCI_CFG_REGION_SIZE    (0x00001000)
> +
> +/* Peripheral space */
> +#define IXP4XX_PERIPHERAL_BASE        (0xC8000000)
> +#define IXP4XX_PERIPHERAL_REGION_SIZE (0x00013000)
> +
> +/*
> + * Debug UART
> + *
> + * This is basically a remap of UART1 into a region that is section
> + * aligned so that it can be used with the low-level debug code.
> + */
> +#define IXP4XX_DEBUG_UART_BASE        (0xC8000000)
> +#define IXP4XX_DEBUG_UART_REGION_SIZE (0x00001000)
> +
> +/* Expansion Bus Controller registers. */
> +#define IXP4XX_EXP_CS0       IXP4XX_REG(0xC4000000)
> +#define IXP4XX_EXP_CS1       IXP4XX_REG(0xC4000004)
> +#define IXP4XX_EXP_CS2       IXP4XX_REG(0xC4000008)
> +#define IXP4XX_EXP_CS3       IXP4XX_REG(0xC400000C)
> +#define IXP4XX_EXP_CS4       IXP4XX_REG(0xC4000010)
> +#define IXP4XX_EXP_CS5       IXP4XX_REG(0xC4000014)
> +#define IXP4XX_EXP_CS6       IXP4XX_REG(0xC4000018)
> +#define IXP4XX_EXP_CS7       IXP4XX_REG(0xC400001C)
> +
> +#define IXP4XX_EXP_BASE(n)  (0x50000000 + (n) * 1000000)
> +
> +#define IXP4XX_EXP_EN        0x80000000
> +#define IXP4XX_EXP_T1(n)    (0x10000000 * (n)) /* valid: 0 - 3 */
> +#define IXP4XX_EXP_T2(n)    (0x04000000 * (n)) /* valid: 0 - 3 */
> +#define IXP4XX_EXP_T3(n)    (0x00400000 * (n)) /* valid: 0 - 15 */
> +#define IXP4XX_EXP_T4(n)    (0x00100000 * (n)) /* valid: 0 - 3 */
> +#define IXP4XX_EXP_T5(n)    (0x00010000 * (n)) /* valid: 0 - 15 */
> +#define IXP4XX_EXP_INTEL     0x00000000
> +#define IXP4XX_EXP_MOTO      0x00004000
> +#define IXP4XX_EXP_HPI       0x00008000
> +#define IXP4XX_EXP_BITS(n)  (0x00000400 * ((n) - 9)) /* valid: 9 - 24 */
> +#define IXP4XX_EXP_BYTE_RD16 0x00000040
> +#define IXP4XX_EXP_HRDY_POL  0x00000020
> +#define IXP4XX_EXP_MUX_EN    0x00000010
> +#define IXP4XX_EXP_SPLT_EN   0x00000008
> +#define IXP4XX_EXP_WR_EN     0x00000002
> +#define IXP4XX_EXP_BYTE_EN   0x00000001
> +
> +#define IXP4XX_EXP_CFG0      IXP4XX_REG(0xC4000020)
> +#define IXP4XX_EXP_CFG1      IXP4XX_REG(0xC4000024)
> +#define IXP4XX_EXP_CFG2      IXP4XX_REG(0xC4000028)
> +#define IXP4XX_EXP_CFG3      IXP4XX_REG(0xC400002C)
> +
> +
> +/* Peripheral Space Register Region Base Addresses */
> +#define IXP4XX_UART1_BASE    IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x0000)
> +#define IXP4XX_UART2_BASE    IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x1000)
> +#define IXP4XX_PMU_BASE      IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x2000)
> +#define IXP4XX_INTC_BASE     IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x3000)
> +#define IXP4XX_GPIO_BASE     IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x4000)
> +#define IXP4XX_NPEA_BASE     IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x6000)
> +#define IXP4XX_NPEB_BASE     IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x7000)
> +#define IXP4XX_NPEC_BASE     IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x8000)
> +#define IXP4XX_EthB_BASE     IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x9000)
> +#define IXP4XX_EthC_BASE     IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0xA000)
> +#define IXP4XX_USB_BASE      IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0xB000)
> +/* IXP46x only */
> +#define IXP4XX_EthA_BASE     IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0xC000)
> +#define IXP4XX_EthB1_BASE    IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0xD000)
> +#define IXP4XX_EthB2_BASE    IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0xE000)
> +#define IXP4XX_EthB3_BASE    IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0xF000)
> +#define IXP4XX_TIMESYNC_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x10000)
> +#define IXP4XX_I2C_BASE      IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x11000)
> +#define IXP4XX_SSP_BASE      IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x12000)
> +
> +/*
> +  Constants to make it easy to access Interrupt Controller registers
> + */
> +#define IXP4XX_ICPR_OFFSET   0x00 /* Interrupt Status */
> +#define IXP4XX_ICMR_OFFSET   0x04 /* Interrupt Enable */
> +#define IXP4XX_ICLR_OFFSET   0x08 /* Interrupt IRQ/FIQ Select */
> +#define IXP4XX_ICIP_OFFSET   0x0C /* IRQ Status */
> +#define IXP4XX_ICFP_OFFSET   0x10 /* FIQ Status */
> +#define IXP4XX_ICHR_OFFSET   0x14 /* Interrupt Priority */
> +#define IXP4XX_ICIH_OFFSET   0x18 /* IRQ Highest Pri Int */
> +#define IXP4XX_ICFH_OFFSET   0x1C /* FIQ Highest Pri Int */
> +
> +/* IXP465-only */
> +#define IXP4XX_ICPR2_OFFSET  0x20 /* Interrupt Status 2 */
> +#define IXP4XX_ICMR2_OFFSET  0x24 /* Interrupt Enable 2 */
> +#define IXP4XX_ICLR2_OFFSET  0x28 /* Interrupt IRQ/FIQ Select 2 */
> +#define IXP4XX_ICIP2_OFFSET  0x2C /* IRQ Status */
> +#define IXP4XX_ICFP2_OFFSET  0x30 /* FIQ Status */
> +#define IXP4XX_ICEEN_OFFSET  0x34 /* Error High Pri Enable */
> +
> +
> +/* Interrupt Controller Register Definitions. */
> +#define IXP4XX_INTC_REG(x)   ((volatile u32 *)(IXP4XX_INTC_BASE + (x)))
> +
> +#define IXP4XX_ICPR          IXP4XX_INTC_REG(IXP4XX_ICPR_OFFSET)
> +#define IXP4XX_ICMR          IXP4XX_INTC_REG(IXP4XX_ICMR_OFFSET)
> +#define IXP4XX_ICLR          IXP4XX_INTC_REG(IXP4XX_ICLR_OFFSET)
> +#define IXP4XX_ICIP          IXP4XX_INTC_REG(IXP4XX_ICIP_OFFSET)
> +#define IXP4XX_ICFP          IXP4XX_INTC_REG(IXP4XX_ICFP_OFFSET)
> +#define IXP4XX_ICHR          IXP4XX_INTC_REG(IXP4XX_ICHR_OFFSET)
> +#define IXP4XX_ICIH          IXP4XX_INTC_REG(IXP4XX_ICIH_OFFSET)
> +#define IXP4XX_ICFH          IXP4XX_INTC_REG(IXP4XX_ICFH_OFFSET)
> +#define IXP4XX_ICPR2         IXP4XX_INTC_REG(IXP4XX_ICPR2_OFFSET)
> +#define IXP4XX_ICMR2         IXP4XX_INTC_REG(IXP4XX_ICMR2_OFFSET)
> +#define IXP4XX_ICLR2         IXP4XX_INTC_REG(IXP4XX_ICLR2_OFFSET)
> +#define IXP4XX_ICIP2         IXP4XX_INTC_REG(IXP4XX_ICIP2_OFFSET)
> +#define IXP4XX_ICFP2         IXP4XX_INTC_REG(IXP4XX_ICFP2_OFFSET)
> +#define IXP4XX_ICEEN         IXP4XX_INTC_REG(IXP4XX_ICEEN_OFFSET)
> +
> +/* Constants to make it easy to access GPIO registers */
> +#define IXP4XX_GPIO_GPOUTR_OFFSET   0x00
> +#define IXP4XX_GPIO_GPOER_OFFSET    0x04
> +#define IXP4XX_GPIO_GPINR_OFFSET    0x08
> +#define IXP4XX_GPIO_GPISR_OFFSET    0x0C
> +#define IXP4XX_GPIO_GPIT1R_OFFSET   0x10
> +#define IXP4XX_GPIO_GPIT2R_OFFSET   0x14
> +#define IXP4XX_GPIO_GPCLKR_OFFSET   0x18
> +#define IXP4XX_GPIO_GPDBSELR_OFFSET 0x1C
> +
> +/* GPIO Register Definitions - perform only 32-bit reads/writes */
> +#define IXP4XX_GPIO_REG(x)   ((volatile u32 *)(IXP4XX_GPIO_BASE + (x)))
> +
> +#define IXP4XX_GPIO_GPOUTR   IXP4XX_GPIO_REG(IXP4XX_GPIO_GPOUTR_OFFSET)
> +#define IXP4XX_GPIO_GPOER    IXP4XX_GPIO_REG(IXP4XX_GPIO_GPOER_OFFSET)
> +#define IXP4XX_GPIO_GPINR    IXP4XX_GPIO_REG(IXP4XX_GPIO_GPINR_OFFSET)
> +#define IXP4XX_GPIO_GPISR    IXP4XX_GPIO_REG(IXP4XX_GPIO_GPISR_OFFSET)
> +#define IXP4XX_GPIO_GPIT1R   IXP4XX_GPIO_REG(IXP4XX_GPIO_GPIT1R_OFFSET)
> +#define IXP4XX_GPIO_GPIT2R   IXP4XX_GPIO_REG(IXP4XX_GPIO_GPIT2R_OFFSET)
> +#define IXP4XX_GPIO_GPCLKR   IXP4XX_GPIO_REG(IXP4XX_GPIO_GPCLKR_OFFSET)
> +#define IXP4XX_GPIO_GPDBSELR IXP4XX_GPIO_REG(IXP4XX_GPIO_GPDBSELR_OFFSET)
> +
> +/* GPIO register bit definitions */
> +
> +/* Interrupt styles */
> +#define IXP4XX_GPIO_STYLE_ACTIVE_HIGH  0x0
> +#define IXP4XX_GPIO_STYLE_ACTIVE_LOW   0x1
> +#define IXP4XX_GPIO_STYLE_RISING_EDGE  0x2
> +#define IXP4XX_GPIO_STYLE_FALLING_EDGE 0x3
> +#define IXP4XX_GPIO_STYLE_TRANSITIONAL 0x4
> +
> +/* Mask used to clear interrupt styles */
> +#define IXP4XX_GPIO_STYLE_CLEAR        0x7
> +#define IXP4XX_GPIO_STYLE_SIZE         3
> +
> +/* Operating System Timer Register Definitions. */
> +#define IXP4XX_OSTS          IXP4XX_REG(0xC8005000) /* Continious TimeStamp */
> +#define IXP4XX_OST1          IXP4XX_REG(0xC8005004) /* Timer 1 Timestamp */
> +#define IXP4XX_OSRT1         IXP4XX_REG(0xC8005008) /* Timer 1 Reload */
> +#define IXP4XX_OST2          IXP4XX_REG(0xC800500C) /* Timer 2 Timestamp */
> +#define IXP4XX_OSRT2         IXP4XX_REG(0xC8005010) /* Timer 2 Reload */
> +#define IXP4XX_OSWT          IXP4XX_REG(0xC8005014) /* Watchdog Timer */
> +#define IXP4XX_OSWE          IXP4XX_REG(0xC8005018) /* Watchdog Enable */
> +#define IXP4XX_OSWK          IXP4XX_REG(0xC800501C) /* Watchdog Key */
> +#define IXP4XX_OSST          IXP4XX_REG(0xC8005020) /* Timer Status */
> +
> +/* Timer register values and bit definitions */
> +#define IXP4XX_OST_ENABLE            0x00000001
> +#define IXP4XX_OST_ONE_SHOT          0x00000002
> +/* Low order bits of reload value ignored */
> +#define IXP4XX_OST_RELOAD_MASK       0x00000003
> +#define IXP4XX_OST_DISABLED          0x00000000
> +#define IXP4XX_OSST_TIMER_1_PEND     0x00000001
> +#define IXP4XX_OSST_TIMER_2_PEND     0x00000002
> +#define IXP4XX_OSST_TIMER_TS_PEND    0x00000004
> +#define IXP4XX_OSST_TIMER_WDOG_PEND  0x00000008
> +#define IXP4XX_OSST_TIMER_WARM_RESET 0x00000010
> +
> +#define IXP4XX_WDT_KEY               0x0000482E
> +
> +#define IXP4XX_WDT_RESET_ENABLE      0x00000001
> +#define IXP4XX_WDT_IRQ_ENABLE        0x00000002
> +#define IXP4XX_WDT_COUNT_ENABLE      0x00000004
> +
> +
> +/* Constants to make it easy to access PCI Control/Status registers */
> +#define PCI_NP_AD_OFFSET           0x00
> +#define PCI_NP_CBE_OFFSET          0x04
> +#define PCI_NP_WDATA_OFFSET        0x08
> +#define PCI_NP_RDATA_OFFSET        0x0c
> +#define PCI_CRP_AD_CBE_OFFSET      0x10
> +#define PCI_CRP_WDATA_OFFSET       0x14
> +#define PCI_CRP_RDATA_OFFSET       0x18
> +#define PCI_CSR_OFFSET             0x1c
> +#define PCI_ISR_OFFSET             0x20
> +#define PCI_INTEN_OFFSET           0x24
> +#define PCI_DMACTRL_OFFSET         0x28
> +#define PCI_AHBMEMBASE_OFFSET      0x2c
> +#define PCI_AHBIOBASE_OFFSET       0x30
> +#define PCI_PCIMEMBASE_OFFSET      0x34
> +#define PCI_AHBDOORBELL_OFFSET     0x38
> +#define PCI_PCIDOORBELL_OFFSET     0x3C
> +#define PCI_ATPDMA0_AHBADDR_OFFSET 0x40
> +#define PCI_ATPDMA0_PCIADDR_OFFSET 0x44
> +#define PCI_ATPDMA0_LENADDR_OFFSET 0x48
> +#define PCI_ATPDMA1_AHBADDR_OFFSET 0x4C
> +#define PCI_ATPDMA1_PCIADDR_OFFSET 0x50
> +#define PCI_ATPDMA1_LENADDR_OFFSET 0x54
> +
> +/* PCI Control/Status Registers */
> +#define IXP4XX_PCI_CSR(x) ((volatile u32 *)(IXP4XX_PCI_CFG_BASE + (x)))
> +
> +#define PCI_NP_AD            IXP4XX_PCI_CSR(PCI_NP_AD_OFFSET)
> +#define PCI_NP_CBE           IXP4XX_PCI_CSR(PCI_NP_CBE_OFFSET)
> +#define PCI_NP_WDATA         IXP4XX_PCI_CSR(PCI_NP_WDATA_OFFSET)
> +#define PCI_NP_RDATA         IXP4XX_PCI_CSR(PCI_NP_RDATA_OFFSET)
> +#define PCI_CRP_AD_CBE       IXP4XX_PCI_CSR(PCI_CRP_AD_CBE_OFFSET)
> +#define PCI_CRP_WDATA        IXP4XX_PCI_CSR(PCI_CRP_WDATA_OFFSET)
> +#define PCI_CRP_RDATA        IXP4XX_PCI_CSR(PCI_CRP_RDATA_OFFSET)
> +#define PCI_CSR              IXP4XX_PCI_CSR(PCI_CSR_OFFSET)
> +#define PCI_ISR              IXP4XX_PCI_CSR(PCI_ISR_OFFSET)
> +#define PCI_INTEN            IXP4XX_PCI_CSR(PCI_INTEN_OFFSET)
> +#define PCI_DMACTRL          IXP4XX_PCI_CSR(PCI_DMACTRL_OFFSET)
> +#define PCI_AHBMEMBASE       IXP4XX_PCI_CSR(PCI_AHBMEMBASE_OFFSET)
> +#define PCI_AHBIOBASE        IXP4XX_PCI_CSR(PCI_AHBIOBASE_OFFSET)
> +#define PCI_PCIMEMBASE       IXP4XX_PCI_CSR(PCI_PCIMEMBASE_OFFSET)
> +#define PCI_AHBDOORBELL      IXP4XX_PCI_CSR(PCI_AHBDOORBELL_OFFSET)
> +#define PCI_PCIDOORBELL      IXP4XX_PCI_CSR(PCI_PCIDOORBELL_OFFSET)
> +#define PCI_ATPDMA0_AHBADDR  IXP4XX_PCI_CSR(PCI_ATPDMA0_AHBADDR_OFFSET)
> +#define PCI_ATPDMA0_PCIADDR  IXP4XX_PCI_CSR(PCI_ATPDMA0_PCIADDR_OFFSET)
> +#define PCI_ATPDMA0_LENADDR  IXP4XX_PCI_CSR(PCI_ATPDMA0_LENADDR_OFFSET)
> +#define PCI_ATPDMA1_AHBADDR  IXP4XX_PCI_CSR(PCI_ATPDMA1_AHBADDR_OFFSET)
> +#define PCI_ATPDMA1_PCIADDR  IXP4XX_PCI_CSR(PCI_ATPDMA1_PCIADDR_OFFSET)
> +#define PCI_ATPDMA1_LENADDR  IXP4XX_PCI_CSR(PCI_ATPDMA1_LENADDR_OFFSET)
> +
> +/* PCI register values and bit definitions */
> +
> +/* CSR bit definitions */
> +#define PCI_CSR_HOST         0x00000001
> +#define PCI_CSR_ARBEN        0x00000002
> +#define PCI_CSR_ADS          0x00000004
> +#define PCI_CSR_PDS          0x00000008
> +#define PCI_CSR_ABE          0x00000010
> +#define PCI_CSR_DBT          0x00000020
> +#define PCI_CSR_ASE          0x00000100
> +#define PCI_CSR_IC           0x00008000
> +
> +/* ISR (Interrupt status) Register bit definitions */
> +#define PCI_ISR_PSE          0x00000001
> +#define PCI_ISR_PFE          0x00000002
> +#define PCI_ISR_PPE          0x00000004
> +#define PCI_ISR_AHBE         0x00000008
> +#define PCI_ISR_APDC         0x00000010
> +#define PCI_ISR_PADC         0x00000020
> +#define PCI_ISR_ADB          0x00000040
> +#define PCI_ISR_PDB          0x00000080
> +
> +/* INTEN (Interrupt Enable) Register bit definitions */
> +#define PCI_INTEN_PSE        0x00000001
> +#define PCI_INTEN_PFE        0x00000002
> +#define PCI_INTEN_PPE        0x00000004
> +#define PCI_INTEN_AHBE       0x00000008
> +#define PCI_INTEN_APDC       0x00000010
> +#define PCI_INTEN_PADC       0x00000020
> +#define PCI_INTEN_ADB        0x00000040
> +#define PCI_INTEN_PDB        0x00000080
> +
> +/* Shift value for byte enable on NP cmd/byte enable register */
> +#define IXP4XX_PCI_NP_CBE_BESL 4
> +
> +/* PCI commands supported by NP access unit */
> +#define NP_CMD_IOREAD        0x2
> +#define NP_CMD_IOWRITE       0x3
> +#define NP_CMD_CONFIGREAD    0xA
> +#define NP_CMD_CONFIGWRITE   0xB
> +#define NP_CMD_MEMREAD       0x6
> +#define NP_CMD_MEMWRITE      0x7
> +
> +/* Constants for CRP access into local config space */
> +#define CRP_AD_CBE_BESL      20
> +#define CRP_AD_CBE_WRITE     0x00010000
> +
> +/* USB Device Controller */
> +# define IXP4XX_USB_REG(x)   (*((volatile u32 *)(x)))
> +
> +/* SDRAM Controller registers. */
> +#define IXP4XX_SDRAM_CONFIG  IXP4XX_REG(0xCC000000)
> +#define IXP4XX_SDRAM_REFRESH IXP4XX_REG(0xCC000004)
> +#define IXP4XX_SDRAM_IR      IXP4XX_REG(0xCC000008)
> +
> +/* "fuse" bits of IXP_EXP_CFG2 */
> +/* All IXP4xx CPUs */
> +#define IXP4XX_FEATURE_RCOMP            (1 << 0)
> +#define IXP4XX_FEATURE_USB_DEVICE       (1 << 1)
> +#define IXP4XX_FEATURE_HASH             (1 << 2)
> +#define IXP4XX_FEATURE_AES              (1 << 3)
> +#define IXP4XX_FEATURE_DES              (1 << 4)
> +#define IXP4XX_FEATURE_HDLC             (1 << 5)
> +#define IXP4XX_FEATURE_AAL              (1 << 6)
> +#define IXP4XX_FEATURE_HSS              (1 << 7)
> +#define IXP4XX_FEATURE_UTOPIA           (1 << 8)
> +#define IXP4XX_FEATURE_NPEB_ETH0        (1 << 9)
> +#define IXP4XX_FEATURE_NPEC_ETH         (1 << 10)
> +#define IXP4XX_FEATURE_RESET_NPEA       (1 << 11)
> +#define IXP4XX_FEATURE_RESET_NPEB       (1 << 12)
> +#define IXP4XX_FEATURE_RESET_NPEC       (1 << 13)
> +#define IXP4XX_FEATURE_PCI              (1 << 14)
> +#define IXP4XX_FEATURE_UTOPIA_PHY_LIMIT (3 << 16)
> +#define IXP4XX_FEATURE_XSCALE_MAX_FREQ  (3 << 22)
> +#define IXP42X_FEATURE_MASK (IXP4XX_FEATURE_RCOMP            | \
> +			     IXP4XX_FEATURE_USB_DEVICE       | \
> +			     IXP4XX_FEATURE_HASH             | \
> +			     IXP4XX_FEATURE_AES              | \
> +			     IXP4XX_FEATURE_DES              | \
> +			     IXP4XX_FEATURE_HDLC             | \
> +			     IXP4XX_FEATURE_AAL              | \
> +			     IXP4XX_FEATURE_HSS              | \
> +			     IXP4XX_FEATURE_UTOPIA           | \
> +			     IXP4XX_FEATURE_NPEB_ETH0        | \
> +			     IXP4XX_FEATURE_NPEC_ETH         | \
> +			     IXP4XX_FEATURE_RESET_NPEA       | \
> +			     IXP4XX_FEATURE_RESET_NPEB       | \
> +			     IXP4XX_FEATURE_RESET_NPEC       | \
> +			     IXP4XX_FEATURE_PCI              | \
> +			     IXP4XX_FEATURE_UTOPIA_PHY_LIMIT | \
> +			     IXP4XX_FEATURE_XSCALE_MAX_FREQ)
> +
> +/* IXP43x/46x CPUs */
> +#define IXP4XX_FEATURE_ECC_TIMESYNC     (1 << 15)
> +#define IXP4XX_FEATURE_USB_HOST         (1 << 18)
> +#define IXP4XX_FEATURE_NPEA_ETH         (1 << 19)
> +#define IXP43X_FEATURE_MASK (IXP42X_FEATURE_MASK             | \
> +			     IXP4XX_FEATURE_ECC_TIMESYNC     | \
> +			     IXP4XX_FEATURE_USB_HOST         | \
> +			     IXP4XX_FEATURE_NPEA_ETH)
> +
> +/* IXP46x CPU (including IXP455) only */
> +#define IXP4XX_FEATURE_NPEB_ETH_1_TO_3  (1 << 20)
> +#define IXP4XX_FEATURE_RSA              (1 << 21)
> +#define IXP46X_FEATURE_MASK (IXP43X_FEATURE_MASK             | \
> +			     IXP4XX_FEATURE_NPEB_ETH_1_TO_3  | \
> +			     IXP4XX_FEATURE_RSA)
> +
> +#endif
> diff --git a/drivers/serial/serial_ns16550.c b/drivers/serial/serial_ns16550.c
> index b7913aa..be1b968 100644
> --- a/drivers/serial/serial_ns16550.c
> +++ b/drivers/serial/serial_ns16550.c
please split this in an other patch

and pass this as a pdata
> @@ -137,7 +137,11 @@ static void ns16550_serial_init_port(struct console_device *cdev)
>  {
>  	/* initializing the device for the first time */
>  	ns16550_write(cdev, 0x00, lcr); /* select ier reg */
> +#ifdef CONFIG_ARCH_IXP4XX
> +	ns16550_write(cdev, IER_UUE, ier); /* Enable UART operation */
> +#else
>  	ns16550_write(cdev, 0x00, ier);
> +#endif
>  
>  #ifdef CONFIG_DRIVER_SERIAL_NS16550_OMAP_EXTENSIONS
>  	ns16550_write(cdev, 0x07, mdr1);	/* Disable */
> diff --git a/drivers/serial/serial_ns16550.h b/drivers/serial/serial_ns16550.h
> index db8fe64..132f46e 100644
> --- a/drivers/serial/serial_ns16550.h
> +++ b/drivers/serial/serial_ns16550.h
> @@ -50,6 +50,8 @@
>  #define dll		rbr
>  #define dlm		ier
>  
> +#define IER_UUE		0x40	/* UART Unit Enable (XScale) */
> +
>  #define FCR_FIFO_EN     0x01	/* Fifo enable */
>  #define FCR_RXSR        0x02	/* Receiver soft reset */
>  #define FCR_TXSR        0x04	/* Transmitter soft reset */
> 
> -- 
> Krzysztof Halasa
> 
> _______________________________________________
> barebox mailing list
> barebox@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] ARM: Support for IXP4xx built-in Ethernet interfaces.
  2013-04-07 19:58       ` [PATCH] ARM: Support for IXP4xx built-in Ethernet interfaces Krzysztof Halasa
@ 2013-04-08  7:29         ` Jean-Christophe PLAGNIOL-VILLARD
  0 siblings, 0 replies; 24+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2013-04-08  7:29 UTC (permalink / raw)
  To: Krzysztof Halasa; +Cc: barebox

On 21:58 Sun 07 Apr     , Krzysztof Halasa wrote:
> Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>
> 
> diff --git a/arch/arm/mach-ixp4xx/include/mach/platform.h b/arch/arm/mach-ixp4xx/include/mach/platform.h
> new file mode 100644
> index 0000000..1df4aa4
> --- /dev/null
> +++ b/arch/arm/mach-ixp4xx/include/mach/platform.h
> @@ -0,0 +1,15 @@
> +#include <asm/types.h>
> +
> +#define IXP4XX_ETH_NPEA 0x00
> +#define IXP4XX_ETH_NPEB 0x10
> +#define IXP4XX_ETH_NPEC 0x20
> +
> +/* Information about built-in Ethernet MAC interfaces */
> +struct eth_plat_info {
> +	void *regs;
> +	u8 npe;
> +	u8 phy; /* MII PHY ID, 0 - 31 */
> +	u8 rxq; /* configurable, currently 0 - 31 only */
> +	u8 txreadyq;
> +	u8 hwaddr[6];
> +};
> diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
> index 2736094..d6164ea 100644
> --- a/drivers/net/Kconfig
> +++ b/drivers/net/Kconfig
> @@ -93,6 +93,14 @@ config DRIVER_NET_MACB
>  	depends on HAS_MACB
>  	select PHYLIB
>  
> +config DRIVER_NET_IXP4XX_ETH
> +	tristate "Intel IXP4xx Ethernet support"
> +	depends on ARCH_IXP4XX && IXP4XX_NPE && IXP4XX_QMGR
> +	select PHYLIB
> +	help
> +	  Say Y here if you want to use built-in Ethernet ports
> +	  on IXP4xx processor.
> +
>  config DRIVER_NET_TAP
>  	bool "tap Ethernet driver"
>  	depends on LINUX
> diff --git a/drivers/net/Makefile b/drivers/net/Makefile
> index 42136f8..4a2ced9 100644
> --- a/drivers/net/Makefile
> +++ b/drivers/net/Makefile
> @@ -14,6 +14,7 @@ obj-$(CONFIG_DRIVER_NET_MACB)		+= macb.o
>  obj-$(CONFIG_DRIVER_NET_TAP)		+= tap.o
>  obj-$(CONFIG_PHYLIB)			+= phy/
>  obj-$(CONFIG_NET_USB)			+= usb/
> +obj-$(CONFIG_DRIVER_NET_IXP4XX_ETH)	+= ixp4xx_eth.o
>  obj-$(CONFIG_DRIVER_NET_TSE)		+= altera_tse.o
>  obj-$(CONFIG_DRIVER_NET_KS8851_MLL)	+= ks8851_mll.o
>  obj-$(CONFIG_DRIVER_NET_DESIGNWARE)	+= designware.o
> diff --git a/drivers/net/ixp4xx_eth.c b/drivers/net/ixp4xx_eth.c
> new file mode 100644
> index 0000000..1ae37f1
> --- /dev/null
> +++ b/drivers/net/ixp4xx_eth.c
> @@ -0,0 +1,741 @@
> +/*
> + * Intel IXP4xx Ethernet driver for Linux
> + *
> + * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of version 2 of the GNU General Public License
> + * as published by the Free Software Foundation.
> + *
> + * Ethernet port config (0x00 is not present on IXP42X):
> + *
> + * logical port		0x00		0x10		0x20
> + * NPE			0 (NPE-A)	1 (NPE-B)	2 (NPE-C)
> + * physical port	2		0		1
> + * RX queue (variable)	20		21		22
> + * TX queue		23		24		25
> + * RX-free queue	26		27		28
> + * TX-done queue is always 31, per-port RX queue is configurable
> + *
> + *
> + * Queue entries:
> + * bits 0 -> 1  - NPE ID (RX and TX-done)
> + * bits 0 -> 2  - priority (TX, per 802.1D)
> + * bits 3 -> 4  - port ID (user-set?)
> + * bits 5 -> 31 - physical descriptor address
> + */
> +
> +#include <common.h>
> +#include <init.h>
> +#include <malloc.h>
> +#include <net.h>
> +#include <errno.h>
> +#include <asm/mmu.h>
> +#include <linux/mii.h>
> +#include <mach/ixp4xx-regs.h>
> +#include <mach/platform.h>
> +#include <mach/cpu.h>
> +#include <mach/npe.h>
> +#include <mach/qmgr.h>
> +
> +#define DEBUG_DESC		0
> +#define DEBUG_RX		0
> +#define DEBUG_TX		0
> +#define DEBUG_PKT_BYTES		0
> +#define DEBUG_MDIO		0
> +#define DEBUG_OPEN		0
> +#define DEBUG_CLOSE		0
> +
> +#define RX_DESCS		16 /* also length of all RX queues */
> +#define TX_DESCS		16 /* also length of all TX queues */
> +#define TXDONE_QUEUE_LEN	16 /* dwords */
> +
> +#define MAX_MRU			1536 /* 0x600 */
> +#define RX_BUFF_SIZE		MAX_MRU
> +
> +#define MAX_MDIO_RETRIES	100 /* microseconds, typically 30 cycles */
> +#define MAX_CLOSE_WAIT		1000 /* microseconds, typically 2-3 cycles */
> +#define ETH_ALEN		6
> +
> +#define PHYSICAL_ID(port)	(((port)->npe->id + 2) % 3)
> +#define LOGICAL_ID(port)	((port)->npe->id << 4)
> +#define RX_QUEUE(port)		((port)->npe->id + 20) /* can be changed */
> +#define TX_QUEUE(port)		((port)->npe->id + 23)
> +#define RXFREE_QUEUE(port)	((port)->npe->id + 26)
> +#define TXDONE_QUEUE		31
> +
> +/* TX Control Registers */
> +#define TX_CNTRL0_TX_EN		0x01
> +#define TX_CNTRL0_HALFDUPLEX	0x02
> +#define TX_CNTRL0_RETRY		0x04
> +#define TX_CNTRL0_PAD_EN	0x08
> +#define TX_CNTRL0_APPEND_FCS	0x10
> +#define TX_CNTRL0_2DEFER	0x20
> +#define TX_CNTRL0_RMII		0x40 /* reduced MII */
> +#define TX_CNTRL1_RETRIES	0x0F /* 4 bits */
> +
> +/* RX Control Registers */
> +#define RX_CNTRL0_RX_EN		0x01
> +#define RX_CNTRL0_PADSTRIP_EN	0x02
> +#define RX_CNTRL0_SEND_FCS	0x04
> +#define RX_CNTRL0_PAUSE_EN	0x08
> +#define RX_CNTRL0_LOOP_EN	0x10
> +#define RX_CNTRL0_ADDR_FLTR_EN	0x20
> +#define RX_CNTRL0_RX_RUNT_EN	0x40
> +#define RX_CNTRL0_BCAST_DIS	0x80
> +#define RX_CNTRL1_DEFER_EN	0x01
> +
> +/* Core Control Register */
> +#define CORE_RESET		0x01
> +#define CORE_RX_FIFO_FLUSH	0x02
> +#define CORE_TX_FIFO_FLUSH	0x04
> +#define CORE_SEND_JAM		0x08
> +#define CORE_MDC_EN		0x10 /* MDIO using NPE-B ETH-0 only */
> +
> +#define DEFAULT_TX_CNTRL0	(TX_CNTRL0_TX_EN | TX_CNTRL0_RETRY |       \
> +				 TX_CNTRL0_PAD_EN | TX_CNTRL0_APPEND_FCS | \
> +				 TX_CNTRL0_2DEFER)
> +#define DEFAULT_RX_CNTRL0	RX_CNTRL0_RX_EN
> +#define DEFAULT_CORE_CNTRL	CORE_MDC_EN
> +
> +
> +/* NPE message codes */
> +#define NPE_GETSTATUS			 0x00
> +#define NPE_EDB_SETPORTADDRESS		 0x01
> +#define NPE_EDB_GETMACADDRESSDATABASE	 0x02
> +#define NPE_EDB_SETMACADDRESSSDATABASE	 0x03
> +#define NPE_GETSTATS			 0x04
> +#define NPE_RESETSTATS			 0x05
> +#define NPE_SETMAXFRAMELENGTHS		 0x06
> +#define NPE_VLAN_SETRXTAGMODE		 0x07
> +#define NPE_VLAN_SETDEFAULTRXVID	 0x08
> +#define NPE_VLAN_SETPORTVLANTABLEENTRY	 0x09
> +#define NPE_VLAN_SETPORTVLANTABLERANGE	 0x0A
> +#define NPE_VLAN_SETRXQOSENTRY		 0x0B
> +#define NPE_VLAN_SETPORTIDEXTRACTIONMODE 0x0C
> +#define NPE_STP_SETBLOCKINGSTATE	 0x0D
> +#define NPE_FW_SETFIREWALLMODE		 0x0E
> +#define NPE_PC_SETFRAMECONTROLDURATIONID 0x0F
> +#define NPE_PC_SETAPMACTABLE		 0x11
> +#define NPE_SETLOOPBACK_MODE		 0x12
> +#define NPE_PC_SETBSSIDTABLE		 0x13
> +#define NPE_ADDRESS_FILTER_CONFIG	 0x14
> +#define NPE_APPENDFCSCONFIG		 0x15
> +#define NPE_NOTIFY_MAC_RECOVERY_DONE	 0x16
> +#define NPE_MAC_RECOVERY_START		 0x17
> +
> +struct eth_regs {
> +	u32 tx_control[2], __res1[2];		 /* 000 */
> +	u32 rx_control[2], __res2[2];		 /* 010 */
> +	u32 random_seed, __res3[3];		 /* 020 */
> +	u32 partial_empty_threshold, __res4;	 /* 030 */
> +	u32 partial_full_threshold, __res5;	 /* 038 */
> +	u32 tx_start_bytes, __res6[3];		 /* 040 */
> +	u32 tx_deferral, rx_deferral, __res7[2]; /* 050 */
> +	u32 tx_2part_deferral[2], __res8[2];	 /* 060 */
> +	u32 slot_time, __res9[3];		 /* 070 */
> +	u32 mdio_command[4];			 /* 080 */
> +	u32 mdio_status[4];			 /* 090 */
> +	u32 mcast_mask[6], __res10[2];		 /* 0A0 */
> +	u32 mcast_addr[6], __res11[2];		 /* 0C0 */
> +	u32 int_clock_threshold, __res12[3];	 /* 0E0 */
> +	u32 hw_addr[6], __res13[61];		 /* 0F0 */
> +	u32 core_control;			 /* 1FC */
> +};
> +
> +/* NPE message structure */
> +struct msg {
> +	u8 cmd, eth_id, params[6];
> +};
> +
> +/* Ethernet packet descriptor, 32 bytes */
> +struct desc {
> +	u8 *next;    /* pointer to next buffer, unused */
> +
> +	u16 buf_len; /* buffer length */
> +	u16 pkt_len; /* packet length */
> +	u8 *data;    /* pointer to data buffer in RAM */
> +	u8 dest_id;
> +	u8 src_id;
> +	u16 flags;
> +	u8 qos;
> +	u8 padlen;
> +	u16 vlan_tci;
> +
> +	u8 dst_mac[ETH_ALEN], src_mac[ETH_ALEN];
> +};
> +
> +struct io {
> +	struct desc rx_desc_tab[RX_DESCS]; /* alignment: 0x10 */
> +	struct desc tx_desc_tab[TX_DESCS];
> +	u8 rx_buff_tab[RX_DESCS][MAX_MRU];
> +	u8 tx_buff_tab[TX_DESCS][MAX_MRU];
> +};
> +
> +struct port {
> +	struct io *io;
> +	struct eth_regs *regs;
> +	struct npe *npe;
> +	u8 firmware[4];
> +	struct eth_plat_info *pinfo;
> +	struct mii_bus mii_bus;
> +	struct eth_device eth;
> +};
> +
> +static struct eth_regs *mdio_regs; /* mdio command and status only */
> +
> +static int ixp4xx_mdio_cmd(int write, const struct device_d *dev, unsigned char phy_id,
> +			   unsigned char location, unsigned short value)
> +{
> +	int cycles = 0;
> +
> +	if (__raw_readl(&mdio_regs->mdio_command[3]) & 0x80) {
> +		fprintf(stderr, "%s%d: MII not ready to transmit\n", dev->name, dev->id);
> +		return -1;
> +	}
> +
> +	if (write) {
> +		__raw_writel(value & 0xFF, &mdio_regs->mdio_command[0]);
> +		__raw_writel(value >> 8, &mdio_regs->mdio_command[1]);
> +	}
> +	__raw_writel(((phy_id << 5) | location) & 0xFF,
> +		     &mdio_regs->mdio_command[2]);
> +	__raw_writel((phy_id >> 3) | (write << 2) | 0x80 /* GO */,
> +		     &mdio_regs->mdio_command[3]);
> +
> +	while ((cycles < MAX_MDIO_RETRIES) &&
> +	       (__raw_readl(&mdio_regs->mdio_command[3]) & 0x80)) {
> +		udelay(1);
> +		cycles++;
> +	}
> +
> +	if (cycles == MAX_MDIO_RETRIES) {
> +		fprintf(stderr, "%s%d: MII write failed\n", dev->name, dev->id);
> +		return -1;
> +	}
> +
> +#if DEBUG_MDIO
> +	fprintf(stderr, "%s%d: mdio_%s() took %i cycles\n", dev->name, dev->id,
> +		write ? "write" : "read", cycles);
> +#endif
no printf in driver use dev_dbg
> +
> +	if (write)
> +		return 0;
> +
> +	if (__raw_readl(&mdio_regs->mdio_status[3]) & 0x80) {
> +#if DEBUG_MDIO
> +		fprintf(stderr, "%s%d: MII read failed\n", dev->name, dev->id);
> +#endif
> +		return -1;
> +	}
> +
> +	value = (__raw_readl(&mdio_regs->mdio_status[0]) & 0xFF) |
> +		((__raw_readl(&mdio_regs->mdio_status[1]) & 0xFF) << 8);
> +#if DEBUG_MDIO
> +	fprintf(stderr, "%s%d: MII read [%i] -> 0x%X\n", dev->name, dev->id, location, value);
> +#endif
> +
> +	return value;
> +}
> +
> +static int ixp4xx_mdio_read(struct mii_bus *mii, int phy_id, int location)
> +{
> +	int ret = ixp4xx_mdio_cmd(0, &mii->dev, phy_id, location, 0);
> +	return ret;
> +}
> +
> +static int ixp4xx_mdio_write(struct mii_bus *mii, int phy_id, int location, u16 value)
> +{
> +	int ret = ixp4xx_mdio_cmd(1, &mii->dev, phy_id, location, value);
> +#if DEBUG_MDIO
> +	fprintf(stderr, "%s%d: MII write [%i] <- 0x%X, err = %i\n",
> +		mii->dev.name, mii->dev.id, location, value, ret);
> +#endif
> +	return ret;
> +}
> +
> +static void ixp4xx_adjust_link(struct eth_device *dev)
> +{
> +	struct port *port = dev->priv;
> +
> +	if (dev->phydev->duplex)
> +		__raw_writel(DEFAULT_TX_CNTRL0 & ~TX_CNTRL0_HALFDUPLEX,
> +			     &port->regs->tx_control[0]);
> +	else
> +		__raw_writel(DEFAULT_TX_CNTRL0 | TX_CNTRL0_HALFDUPLEX,
> +			     &port->regs->tx_control[0]);
> +}
> +
> +static inline void debug_pkt(struct eth_device *dev, const char *func,
> +			     u8 *data, int len)
> +{
> +#if DEBUG_PKT_BYTES
> +	int i;
> +
> +	fprintf(stderr, "%s%d: %s(%4i) ", dev->dev.name, dev->dev.id, func, len);
> +	for (i = 0; i < len; i++) {
> +		if (i >= DEBUG_PKT_BYTES)
> +			break;
> +		fprintf(stderr, "%s%02X",
> +			((i == 6) || (i == 12) || (i >= 14)) ? " " : "",
> +			data[i]);
> +	}
> +	fprintf(stderr, "\n");
> +#endif
> +}
> +
> +
> +static inline void debug_desc(struct desc *desc)
> +{
> +#if DEBUG_DESC
> +	fprintf(stderr, "%07X: %X %3X %3X %07X %2X < %2X %4X %X"
> +		" %X %X %02X%02X%02X%02X%02X%02X < %02X%02X%02X%02X%02X%02X\n",
> +		(u32)desc, (u32)desc->next, desc->buf_len, desc->pkt_len,
> +		(u32)desc->data, desc->dest_id, desc->src_id, desc->flags,
> +		desc->qos, desc->padlen, desc->vlan_tci,
> +		desc->dst_mac[0], desc->dst_mac[1], desc->dst_mac[2],
> +		desc->dst_mac[3], desc->dst_mac[4], desc->dst_mac[5],
> +		desc->src_mac[0], desc->src_mac[1], desc->src_mac[2],
> +		desc->src_mac[3], desc->src_mac[4], desc->src_mac[5]);
> +#endif
> +}
> +
> +static inline int queue_get_desc(unsigned int queue, struct port *port,
> +				 int is_tx)
> +{
> +	u32 addr, n;
> +	struct desc *tab;
> +
> +	if (!(addr = qmgr_get_entry(queue)))
> +		return -1;
> +
> +	addr &= ~0x1F; /* mask out non-address bits */
> +	tab = is_tx ? port->io->tx_desc_tab : port->io->rx_desc_tab;
> +	n = (addr - (u32)tab) / sizeof(struct desc);
> +	BUG_ON(n >= (is_tx ? TX_DESCS : RX_DESCS));
> +	debug_desc((struct desc*)addr);
> +	BUG_ON(tab[n].next);
> +	return n;
> +}
> +
> +static inline void queue_put_desc(unsigned int queue, struct desc *desc)
> +{
> +	debug_desc(desc);
> +	BUG_ON(((u32)desc) & 0x1F);
> +	qmgr_put_entry(queue, (u32)desc);
> +	/* Don't check for queue overflow here, we've allocated sufficient
> +	   length and queues >= 32 don't support this check anyway. */
> +}
> +
> +
> +static int ixp4xx_eth_poll(struct eth_device *dev)
> +{
> +	struct port *port = dev->priv;
> +	struct desc *desc;
> +	u8 *buff;
> +	int n, len;
> +
> +#if DEBUG_RX
> +	fprintf(stderr, "%s%d: eth_poll\n", dev->dev.name, dev->dev.id);
> +#endif
> +
> +	if ((n = queue_get_desc(RX_QUEUE(port), port, 0)) < 0) {
> +#if DEBUG_RX
> +		fprintf(stderr, "%s%d: eth_poll = no packet received\n", dev->dev.name, dev->dev.id);
> +#endif
> +		return 0;
> +	}
> +
> +	barrier();
> +	desc = &port->io->rx_desc_tab[n];
> +	buff = port->io->rx_buff_tab[n];
> +	len = desc->pkt_len;
> +	/* process received frame */
> +	memcpy((void *)NetRxPackets[0], buff, len);
> +	debug_pkt(dev, "RX", desc->data, len);
> +
> +	/* put the new buffer on RX-free queue */
> +	desc->buf_len = MAX_MRU;
> +	desc->pkt_len = 0;
> +	queue_put_desc(RXFREE_QUEUE(port), desc);
> +
> +	net_receive(NetRxPackets[0], len);
> +
> +#if DEBUG_RX
> +	fprintf(stderr, "%s%d: eth_poll end\n", dev->dev.name, dev->dev.id);
> +#endif
> +	return 0;
> +}
> +
> +
> +static int ixp4xx_eth_xmit(struct eth_device *dev, void *data, int len)
> +{
> +	struct port *port = dev->priv;
> +	int n;
> +	struct desc *desc;
> +
> +#if DEBUG_TX
> +	fprintf(stderr, "%s%d: eth_xmit\n", dev->dev.name, dev->dev.id);
> +#endif
> +
> +	if (unlikely(len > 1500))
> +		return -1;
> +
> +	debug_pkt(dev, "TX", data, len);
> +
> +	if ((n = queue_get_desc(TXDONE_QUEUE, port, 1)) < 0)
> +		return -1; /* no free buffers */
> +	desc = &port->io->tx_desc_tab[n];
> +	desc->data = port->io->tx_buff_tab[n];
> +	desc->buf_len = desc->pkt_len = len;
> +	memcpy(desc->data, data, len);
> +
> +	/* NPE firmware pads short frames with zeros internally */
> +	// wmb();
> +	barrier();
> +	queue_put_desc(TX_QUEUE(port), desc);
> +
> +#if DEBUG_TX
> +	fprintf(stderr, "%s%d: eth_xmit end\n", dev->dev.name, dev->dev.id);
> +#endif
> +	return 0;
> +}
> +
> +static void request_queues(struct port *port, struct eth_device *dev)
> +{
> +	qmgr_request_queue(RXFREE_QUEUE(port), RX_DESCS, 0, 0, "%s:RX-free", dev->dev.name);
> +	qmgr_request_queue(RX_QUEUE(port), RX_DESCS, 0, 0, "%s:RX", dev->dev.name);
> +	qmgr_request_queue(TX_QUEUE(port), TX_DESCS, 0, 0, "%s:TX", dev->dev.name);
> +
> +	/* Common TX-done queue handles buffers sent out by the NPEs */
> +	qmgr_request_queue(TXDONE_QUEUE, TXDONE_QUEUE_LEN, 0, 0,
> +			   "%s:TX-done", dev->dev.name);
> +}
> +
> +static void release_queues(struct port *port)
> +{
> +	qmgr_release_queue(RXFREE_QUEUE(port));
> +	qmgr_release_queue(RX_QUEUE(port));
> +	qmgr_release_queue(TX_QUEUE(port));
> +	qmgr_release_queue(TXDONE_QUEUE);
> +}
> +
> +static void init_queues(struct port *port)
> +{
> +	int i;
> +
> +	memset(port->io->tx_desc_tab, 0, sizeof(port->io->tx_desc_tab)); /* descs */
> +	memset(port->io->rx_desc_tab, 0, sizeof(port->io->rx_desc_tab));
> +
> +	/* Setup RX buffers */
> +	for (i = 0; i < RX_DESCS; i++) {
> +		struct desc *desc = &port->io->rx_desc_tab[i];
> +		desc->buf_len = MAX_MRU;
> +		desc->data = port->io->rx_buff_tab[i];
> +	}
> +}
> +
> +static int ixp4xx_eth_open(struct eth_device *dev)
> +{
> +	struct port *port = dev->priv;
> +	struct npe *npe = port->npe;
> +	struct msg msg;
> +	int i, err;
> +
> +#if DEBUG_OPEN
> +	fprintf(stderr, "%s%d: opening %p\n", dev->dev.name, dev->dev.id, dev);
> +#endif
> +
> +	if (!npe_running(npe)) {
> +		err = npe_load_firmware(npe);
> +		if (err)
> +			return err;
> +
> +		if (npe_recv_message(npe, &msg, "ETH_GET_STATUS")) {
> +			fprintf(stderr, "%s%d: %s not responding\n", dev->dev.name, dev->dev.id, npe->name);
> +			return -EIO;
> +		}
> +		memcpy(port->firmware, msg.params + 2, 4);
> +	}
> +
> +	err = phy_device_connect(dev, &port->mii_bus, port->pinfo->phy,
> +				 ixp4xx_adjust_link, 0, PHY_INTERFACE_MODE_MII);
> +	if (err)
> +		return err;
> +
> +	port->io = dma_alloc_coherent(sizeof(*port->io));
> +
> +	memset(&msg, 0, sizeof(msg));
> +	msg.cmd = NPE_VLAN_SETRXQOSENTRY;
> +	msg.eth_id = LOGICAL_ID(port);
> +	msg.params[3] = RX_QUEUE(port) | 0x80;
> +	msg.params[4] = RX_QUEUE(port) >> 4; /* MSB of offset */
> +	msg.params[5] = RX_QUEUE(port) << 4; /* LSB of offset */
> +	for (i = 0; i < 8; i++) {
> +		msg.params[1] = i;
> +		if (npe_send_recv_message(port->npe, &msg, "ETH_SET_RXQ")) {
> +			err = -EIO;
> +			goto out;
> +		}
> +	}
> +
> +	msg.cmd = NPE_EDB_SETPORTADDRESS;
> +	msg.eth_id = PHYSICAL_ID(port);
> +	memcpy(msg.params, port->pinfo->hwaddr, ETH_ALEN);
> +	if (npe_send_recv_message(port->npe, &msg, "ETH_SET_MAC")) {
> +		err = -EIO;
> +		goto out;
> +	}
> +
> +	memset(&msg, 0, sizeof(msg));
> +	msg.cmd = NPE_FW_SETFIREWALLMODE;
> +	msg.eth_id = LOGICAL_ID(port);
> +	if (npe_send_recv_message(port->npe, &msg, "ETH_SET_FIREWALL_MODE")) {
> +		err = -EIO;
> +		goto out;
> +	}
> +
> +	request_queues(port, dev);
> +	init_queues(port);
> +
> +	for (i = 0; i < ETH_ALEN; i++)
> +		__raw_writel(port->pinfo->hwaddr[i], &port->regs->hw_addr[i]);
> +	__raw_writel(0x08, &port->regs->random_seed);
> +	__raw_writel(0x12, &port->regs->partial_empty_threshold);
> +	__raw_writel(0x30, &port->regs->partial_full_threshold);
> +	__raw_writel(0x08, &port->regs->tx_start_bytes);
> +	__raw_writel(0x15, &port->regs->tx_deferral);
> +	__raw_writel(0x08, &port->regs->tx_2part_deferral[0]);
> +	__raw_writel(0x07, &port->regs->tx_2part_deferral[1]);
> +	__raw_writel(0x80, &port->regs->slot_time);
> +	__raw_writel(0x01, &port->regs->int_clock_threshold);
> +
> +	/* Populate queues with buffers, no failure after this point */
> +	for (i = 0; i < TX_DESCS; i++)
> +		queue_put_desc(TXDONE_QUEUE, &port->io->tx_desc_tab[i]);
> +
> +	for (i = 0; i < RX_DESCS; i++)
> +		queue_put_desc(RXFREE_QUEUE(port), &port->io->rx_desc_tab[i]);
> +
> +	__raw_writel(TX_CNTRL1_RETRIES, &port->regs->tx_control[1]);
> +	__raw_writel(DEFAULT_TX_CNTRL0, &port->regs->tx_control[0]);
> +	__raw_writel(0, &port->regs->rx_control[1]);
> +	__raw_writel(DEFAULT_RX_CNTRL0, &port->regs->rx_control[0]);
> +
> +#if 0
> +	qmgr_set_irq(RX_QUEUE(port), QUEUE_IRQ_SRC_NOT_EMPTY,
> +		     eth_rx_irq, dev);
> +	qmgr_set_irq(TXDONE_QUEUE, QUEUE_IRQ_SRC_NOT_EMPTY,
> +		     eth_txdone_irq, NULL);
> +	qmgr_enable_irq(TXDONE_QUEUE);
> +#endif
??
> +	memset(&msg, 0, sizeof(msg));
> +#if DEBUG_OPEN
> +	fprintf(stderr, "%s%d opened\n", dev->dev.name, dev->dev.id);
> +#endif
> +	return 0;
> +out:
> +	dma_free_coherent(port->io, sizeof(*port->io));
> +	port->io = NULL;
> +#if DEBUG_OPEN
> +	fprintf(stderr, "%s%d open failed (%i)\n", dev->dev.name, dev->dev.id, err);
> +#endif
> +	return err;
> +}
> +
> +static void ixp4xx_eth_close(struct eth_device *dev)
> +{
> +	struct port *port = dev->priv;
> +	struct msg msg;
> +	int buffs = RX_DESCS; /* allocated RX buffers */
> +	int i;
> +
> +#if DEBUG_CLOSE
> +	fprintf(stderr, "%s%d: closing\n", dev->dev.name, dev->dev.id);
> +#endif
> +#if 0
> +	qmgr_disable_irq(RX_QUEUE(port));
> +#endif
> +
> +	if (!port->io)
> +		return; /* already closed */
> +
> +	while (queue_get_desc(RXFREE_QUEUE(port), port, 0) >= 0)
> +		buffs--;
> +
> +	memset(&msg, 0, sizeof(msg));
> +	msg.cmd = NPE_SETLOOPBACK_MODE;
> +	msg.eth_id = LOGICAL_ID(port);
> +	msg.params[1] = 1;
> +	if (npe_send_recv_message(port->npe, &msg, "ETH_ENABLE_LOOPBACK"))
> +		fprintf(stderr, "%s%d: unable to enable loopback\n", dev->dev.name, dev->dev.id);
> +
> +#if DEBUG_CLOSE
> +	fprintf(stderr, "%s%d: draining RX queue\n", dev->dev.name, dev->dev.id);
> +#endif
> +	i = 0;
> +	do { /* drain RX buffers */
> +		while (queue_get_desc(RX_QUEUE(port), port, 0) >= 0)
> +			buffs--;
> +		if (!buffs)
> +			break;
> +		if (qmgr_stat_full(TXDONE_QUEUE) && !(i % 10)) {
> +			/* we have to inject some packet */
> +			struct desc *desc;
> +			int n = queue_get_desc(TXDONE_QUEUE, port, 1);
> +			BUG_ON(n < 0);
> +			desc = &port->io->tx_desc_tab[n];
> +			desc->buf_len = desc->pkt_len = 1;
> +			//wmb();
> +			barrier();
> +			queue_put_desc(TX_QUEUE(port), desc);
> +		}
> +		udelay(1);
> +	} while (++i < MAX_CLOSE_WAIT);
> +
> +	if (buffs)
> +		fprintf(stderr, "%s%d: unable to drain RX queue, %i buffer(s) left in NPE\n",
> +			dev->dev.name, dev->dev.id, buffs);
> +#if DEBUG_CLOSE
> +	if (!buffs)
> +		fprintf(stderr, "%s%d: draining RX queue took %i cycles\n", dev->dev.name, dev->dev.id, i);
> +#endif
> +
> +	buffs = TX_DESCS;
> +	while (queue_get_desc(TX_QUEUE(port), port, 1) >= 0)
> +		buffs--; /* cancel TX */
> +
> +	i = 0;
> +	do {
> +		while (queue_get_desc(TXDONE_QUEUE, port, 1) >= 0)
> +			buffs--;
> +		if (!buffs)
> +			break;
> +	} while (++i < MAX_CLOSE_WAIT);
> +
> +	if (buffs)
> +		fprintf(stderr, "%s%d: unable to drain TX queue, %i buffer(s) left in NPE\n",
> +			dev->dev.name, dev->dev.id, buffs);
> +#if DEBUG_CLOSE
> +	if (!buffs)
> +		fprintf(stderr, "%s%d: draining TX queues took %i cycles\n", dev->dev.name, dev->dev.id, i);
> +#endif
> +
> +	msg.params[1] = 0;
> +	if (npe_send_recv_message(port->npe, &msg, "ETH_DISABLE_LOOPBACK"))
> +		fprintf(stderr, "%s%d: unable to disable loopback\n", dev->dev.name, dev->dev.id);
> +
> +#if 0
> +	qmgr_disable_irq(TXDONE_QUEUE);
> +#endif
> +	release_queues(port);
> +	dma_free_coherent(port->io, sizeof(*port->io));
> +	port->io = NULL;
> +#if DEBUG_CLOSE
> +	fprintf(stderr, "%s%d: closed\n", dev->dev.name, dev->dev.id);
> +#endif
> +}
> +
> +static int ixp4xx_eth_get_hwaddr(struct eth_device *eth, unsigned char *addr)
> +{
> +	struct port *port = eth->priv;
> +	memcpy(addr, port->pinfo->hwaddr, 6);
> +	return 0;
> +}
> +
> +static int ixp4xx_eth_set_hwaddr(struct eth_device *eth, unsigned char *addr)
> +{
> +	struct port *port = eth->priv;
> +	memcpy(port->pinfo->hwaddr, addr, 6);
> +	return 0;
> +}
> +
> +static int ixp4xx_eth_init(struct eth_device *eth)
> +{
> +	struct port *port = eth->priv;
> +
> +	__raw_writel(DEFAULT_CORE_CNTRL | CORE_RESET,
> +		     &port->regs->core_control);
> +	udelay(50);
> +	__raw_writel(DEFAULT_CORE_CNTRL, &port->regs->core_control);
> +	udelay(50);
> +	return 0;
> +}
> +
> +static int ixp4xx_eth_probe(struct device_d *dev)
> +{
> +	struct npe *npe;
> +	struct port *port;
> +	struct eth_plat_info *pinfo = dev->platform_data;
> +
> +	if (!pinfo) {
> +		fprintf(stderr, "ixp4xx_eth: no platform information\n");
> +		return -ENODEV;
> +	}
> +
> +	if (!(npe = npe_request(pinfo->npe))) {
> +		fprintf(stderr, "ixp4xx_eth: unable to acquire NPE\n");
> +		return -ENODEV;
> +	}
> +
> +	port = xmemalign(0x20, sizeof(*port));
> +	memset(port, 0, sizeof(*port));
> +
> +	port->regs = pinfo->regs;
> +	port->npe = npe;
> +	port->pinfo = pinfo;
> +	port->eth.dev.id = -1;
> +	port->eth.priv = port;
> +	port->eth.init = ixp4xx_eth_init;
> +	port->eth.open = ixp4xx_eth_open;
> +	port->eth.halt = ixp4xx_eth_close;
> +	port->eth.send = ixp4xx_eth_xmit;
> +	port->eth.recv = ixp4xx_eth_poll;
> +	port->eth.get_ethaddr = ixp4xx_eth_get_hwaddr;
> +	port->eth.set_ethaddr = ixp4xx_eth_set_hwaddr;
> +
> +	port->mii_bus.dev.id = -1;
> +	port->mii_bus.read = ixp4xx_mdio_read;
> +	port->mii_bus.write = ixp4xx_mdio_write;
> +	mdiobus_register(&port->mii_bus);
> +	eth_register(&port->eth);
> +	dev->priv = port;
> +	return 0;
> +}
> +
> +static void ixp4xx_eth_remove(struct device_d *dev)
> +{
> +	struct port *port = dev->priv;
> +	ixp4xx_eth_close(&port->eth);
> +	eth_unregister(&port->eth);
> +	mdiobus_unregister(&port->mii_bus);
> +	free(port);
> +}
> +
> +static struct driver_d ixp4xx_eth_driver = {
> +	.name  = "ixp4xx_eth",
> +	.probe = ixp4xx_eth_probe,
> +	.remove = ixp4xx_eth_remove,
> +};
> +
> +static int __init ixp4xx_eth_module_init(void)
> +{
> +	if (cpu_is_ixp43x()) {
> +		/* IXP43x lacks NPE-B and uses NPE-C for MII PHY access */
> +		if (!(ixp4xx_read_feature_bits() & IXP4XX_FEATURE_NPEC_ETH))
> +			return -ENOSYS;
> +		mdio_regs = (struct eth_regs *)IXP4XX_EthC_BASE;
> +	} else {
> +		/* All MII PHY accesses use NPE-B Ethernet registers */
> +		if (!(ixp4xx_read_feature_bits() & IXP4XX_FEATURE_NPEB_ETH0))
> +			return -ENOSYS;
> +		mdio_regs = (struct eth_regs *)IXP4XX_EthB_BASE;
> +	}
> +
> +	__raw_writel(DEFAULT_CORE_CNTRL, &mdio_regs->core_control);
this is no the place of the cpu restrition
when I post the ixp4xx I clenanup this
> +
> +	platform_driver_register(&ixp4xx_eth_driver);
> +	return 0;
> +}
> +
> +device_initcall(ixp4xx_eth_module_init);
> 
> _______________________________________________
> barebox mailing list
> barebox@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] ARM: Support for IXP4xx Network Processor Engines (NPEs).
  2013-04-07 19:57       ` [PATCH] ARM: Support for IXP4xx Network Processor Engines (NPEs) Krzysztof Halasa
@ 2013-04-08  7:30         ` Jean-Christophe PLAGNIOL-VILLARD
  0 siblings, 0 replies; 24+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2013-04-08  7:30 UTC (permalink / raw)
  To: Krzysztof Halasa; +Cc: barebox

On 21:57 Sun 07 Apr     , Krzysztof Halasa wrote:
> Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>
> 
> diff --git a/arch/arm/mach-ixp4xx/Kconfig b/arch/arm/mach-ixp4xx/Kconfig
> index 9244be9..33e8bb3 100644
> --- a/arch/arm/mach-ixp4xx/Kconfig
> +++ b/arch/arm/mach-ixp4xx/Kconfig
> @@ -6,4 +6,10 @@ config IXP4XX_QMGR
>  	  This driver supports IXP4xx built-in hardware queue manager
>  	  and is required by the Ethernet driver.
>  
> +config IXP4XX_NPE
> +	tristate "IXP4xx Network Processor Engine support"
> +	help
> +	  This driver supports IXP4xx built-in network coprocessors
> +	  and is required by the Ethernet driver.
> +
>  endif
> diff --git a/arch/arm/mach-ixp4xx/Makefile b/arch/arm/mach-ixp4xx/Makefile
> index 09a0d63..7cfc924 100644
> --- a/arch/arm/mach-ixp4xx/Makefile
> +++ b/arch/arm/mach-ixp4xx/Makefile
> @@ -1,2 +1,3 @@
>  obj-y += generic.o
>  obj-$(CONFIG_IXP4XX_QMGR) += qmgr.o
> +obj-$(CONFIG_IXP4XX_NPE) += npe.o
> diff --git a/arch/arm/mach-ixp4xx/include/mach/npe.h b/arch/arm/mach-ixp4xx/include/mach/npe.h
> new file mode 100644
> index 0000000..18bd01b
> --- /dev/null
> +++ b/arch/arm/mach-ixp4xx/include/mach/npe.h
> @@ -0,0 +1,30 @@
> +#ifndef __IXP4XX_NPE_H
> +#define __IXP4XX_NPE_H
> +
> +#include <common.h>
> +
> +#define NPE_NAME_LENGTH 5
> +
> +struct npe_regs {
> +	u32 exec_addr, exec_data, exec_status_cmd, exec_count;
> +	u32 action_points[4];
> +	u32 watchpoint_fifo, watch_count;
> +	u32 profile_count;
> +	u32 messaging_status, messaging_control;
> +	u32 mailbox_status, /*messaging_*/ in_out_fifo;
> +};
> +
> +struct npe {
> +	struct npe_regs *regs;
> +	int id, valid;
> +	const char name[NPE_NAME_LENGTH + 1];
> +};
> +
> +int npe_running(struct npe *npe);
> +int npe_send_message(struct npe *npe, const void *msg, const char *what);
> +int npe_recv_message(struct npe *npe, void *msg, const char *what);
> +int npe_send_recv_message(struct npe *npe, void *msg, const char *what);
> +int npe_load_firmware(struct npe *npe);
> +struct npe *npe_request(int id);
> +
> +#endif /* __IXP4XX_NPE_H */
> diff --git a/arch/arm/mach-ixp4xx/npe.c b/arch/arm/mach-ixp4xx/npe.c
> new file mode 100644
> index 0000000..d403340
> --- /dev/null
> +++ b/arch/arm/mach-ixp4xx/npe.c
> @@ -0,0 +1,667 @@
> +/*
> + * Intel IXP4xx Network Processor Engine driver for Linux
> + *
> + * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of version 2 of the GNU General Public License
> + * as published by the Free Software Foundation.
> + */
> +
> +#include <common.h>
> +#include <errno.h>
> +#include <fs.h>
> +#include <init.h>
> +#include <malloc.h>
> +#include <asm/byteorder.h>
> +#include <asm/io.h>
> +#include <mach/ixp4xx-regs.h>
> +#include <mach/cpu.h>
> +#include <mach/npe.h>
> +
> +#define DEBUG_MSG                      0
> +#define DEBUG_FW                       0
> +
> +#define MAX_RETRIES                    1000  /* microseconds */
> +#define NPE_42X_DATA_SIZE              0x800 /* in dwords */
> +#define NPE_46X_DATA_SIZE              0x1000
> +#define NPE_A_42X_INSTR_SIZE           0x1000
> +#define NPE_B_AND_C_42X_INSTR_SIZE     0x800
> +#define NPE_46X_INSTR_SIZE             0x1000
> +#define REGS_SIZE                      0x1000
> +
> +#define NPE_PHYS_REG                   32
> +
> +#define FW_MAGIC                       0xFEEDF00D
> +#define FW_BLOCK_TYPE_INSTR            0x0
> +#define FW_BLOCK_TYPE_DATA             0x1
> +#define FW_BLOCK_TYPE_EOF              0xF
> +
> +/* NPE exec status (read) and command (write) */
> +#define CMD_NPE_STEP                   0x01
> +#define CMD_NPE_START                  0x02
> +#define CMD_NPE_STOP                   0x03
> +#define CMD_NPE_CLR_PIPE               0x04
> +#define CMD_CLR_PROFILE_CNT            0x0C
> +#define CMD_RD_INS_MEM                 0x10 /* instruction memory */
> +#define CMD_WR_INS_MEM                 0x11
> +#define CMD_RD_DATA_MEM                0x12 /* data memory */
> +#define CMD_WR_DATA_MEM                0x13
> +#define CMD_RD_ECS_REG                 0x14 /* exec access register */
> +#define CMD_WR_ECS_REG                 0x15
> +
> +#define STAT_RUN                       0x80000000
> +#define STAT_STOP                      0x40000000
> +#define STAT_CLEAR                     0x20000000
> +#define STAT_ECS_K                     0x00800000 /* pipeline clean */
> +
> +#define NPE_STEVT                      0x1B
> +#define NPE_STARTPC                    0x1C
> +#define NPE_REGMAP                     0x1E
> +#define NPE_CINDEX                     0x1F
> +
> +#define INSTR_WR_REG_SHORT             0x0000C000
> +#define INSTR_WR_REG_BYTE              0x00004000
> +#define INSTR_RD_FIFO                  0x0F888220
> +#define INSTR_RESET_MBOX               0x0FAC8210
> +
> +#define ECS_BG_CTXT_REG_0              0x00 /* Background Executing Context */
> +#define ECS_BG_CTXT_REG_1              0x01 /* Stack level */
> +#define ECS_BG_CTXT_REG_2              0x02
> +#define ECS_PRI_1_CTXT_REG_0           0x04 /* Priority 1 Executing Context */
> +#define ECS_PRI_1_CTXT_REG_1           0x05 /* Stack level */
> +#define ECS_PRI_1_CTXT_REG_2           0x06
> +#define ECS_PRI_2_CTXT_REG_0           0x08 /* Priority 2 Executing Context */
> +#define ECS_PRI_2_CTXT_REG_1           0x09 /* Stack level */
> +#define ECS_PRI_2_CTXT_REG_2           0x0A
> +#define ECS_DBG_CTXT_REG_0             0x0C /* Debug Executing Context */
> +#define ECS_DBG_CTXT_REG_1             0x0D /* Stack level */
> +#define ECS_DBG_CTXT_REG_2             0x0E
> +#define ECS_INSTRUCT_REG               0x11 /* NPE Instruction Register */
> +
> +#define ECS_REG_0_ACTIVE               0x80000000 /* all levels */
> +#define ECS_REG_0_NEXTPC_MASK          0x1FFF0000 /* BG/PRI1/PRI2 levels */
> +#define ECS_REG_0_LDUR_BITS            8
> +#define ECS_REG_0_LDUR_MASK            0x00000700 /* all levels */
> +#define ECS_REG_1_CCTXT_BITS           16
> +#define ECS_REG_1_CCTXT_MASK           0x000F0000 /* all levels */
> +#define ECS_REG_1_SELCTXT_BITS         0
> +#define ECS_REG_1_SELCTXT_MASK         0x0000000F /* all levels */
> +#define ECS_DBG_REG_2_IF               0x00100000 /* debug level */
> +#define ECS_DBG_REG_2_IE               0x00080000 /* debug level */
> +
> +/* NPE watchpoint_fifo register bit */
> +#define WFIFO_VALID                    0x80000000
> +
> +/* NPE messaging_status register bit definitions */
> +#define MSGSTAT_OFNE  0x00010000 /* OutFifoNotEmpty */
> +#define MSGSTAT_IFNF  0x00020000 /* InFifoNotFull */
> +#define MSGSTAT_OFNF  0x00040000 /* OutFifoNotFull */
> +#define MSGSTAT_IFNE  0x00080000 /* InFifoNotEmpty */
> +#define MSGSTAT_MBINT 0x00100000 /* Mailbox interrupt */
> +#define MSGSTAT_IFINT 0x00200000 /* InFifo interrupt */
> +#define MSGSTAT_OFINT 0x00400000 /* OutFifo interrupt */
> +#define MSGSTAT_WFINT 0x00800000 /* WatchFifo interrupt */
> +
> +/* NPE messaging_control register bit definitions */
> +#define MSGCTL_OUT_FIFO       0x00010000 /* enable output FIFO */
> +#define MSGCTL_IN_FIFO        0x00020000 /* enable input FIFO */
> +#define MSGCTL_OUT_FIFO_WRITE 0x01000000 /* enable FIFO + WRITE */
> +#define MSGCTL_IN_FIFO_WRITE  0x02000000
> +
> +/* NPE mailbox_status value for reset */
> +#define RESET_MBOX_STAT          0x0000F0F0
> +
> +#define print_npe(npe, fmt, ...) fprintf(stderr, "%s: " fmt, npe->name, ## __VA_ARGS__)
no printf use dev_dbg
> +
> +#if DEBUG_MSG
> +#define debug_msg(npe, fmt, ...) print_npe(npe, fmt, ## __VA_ARGS__)
> +#else
> +#define debug_msg(npe, fmt, ...)
> +#endif
> +
> +static struct {
> +	u32 reg, val;
> +} ecs_reset[] = {
> +	{ECS_BG_CTXT_REG_0,    0xA0000000},
> +	{ECS_BG_CTXT_REG_1,    0x01000000},
> +	{ECS_BG_CTXT_REG_2,    0x00008000},
> +	{ECS_PRI_1_CTXT_REG_0, 0x20000080},
> +	{ECS_PRI_1_CTXT_REG_1, 0x01000000},
> +	{ECS_PRI_1_CTXT_REG_2, 0x00008000},
> +	{ECS_PRI_2_CTXT_REG_0, 0x20000080},
> +	{ECS_PRI_2_CTXT_REG_1, 0x01000000},
> +	{ECS_PRI_2_CTXT_REG_2, 0x00008000},
> +	{ECS_DBG_CTXT_REG_0,   0x20000000},
> +	{ECS_DBG_CTXT_REG_1,   0x00000000},
> +	{ECS_DBG_CTXT_REG_2,   0x001E0000},
> +	{ECS_INSTRUCT_REG,     0x1003C00F},
> +};
> +
> +static struct npe npe_tab[] = {
> +	{
> +		.regs = (struct npe_regs *)IXP4XX_NPEA_BASE,
> +		.id = 0,
> +		.name = "NPE-A",
> +	}, {
> +		.regs = (struct npe_regs *)IXP4XX_NPEB_BASE,
> +		.id = 1,
> +		.name = "NPE-B",
> +	}, {
> +		.regs = (struct npe_regs *)IXP4XX_NPEC_BASE,
> +		.id = 2,
> +		.name = "NPE-C",
> +	}
> +};
> +
> +int npe_running(struct npe *npe)
> +{
> +	return (__raw_readl(&npe->regs->exec_status_cmd) & STAT_RUN) != 0;
> +}
> +
> +static void npe_cmd_write(struct npe *npe, u32 addr, int cmd, u32 data)
> +{
> +	__raw_writel(data, &npe->regs->exec_data);
> +	__raw_writel(addr, &npe->regs->exec_addr);
> +	__raw_writel(cmd, &npe->regs->exec_status_cmd);
> +}
> +
> +static u32 npe_cmd_read(struct npe *npe, u32 addr, int cmd)
> +{
> +	__raw_writel(addr, &npe->regs->exec_addr);
> +	__raw_writel(cmd, &npe->regs->exec_status_cmd);
> +	/* Iintroduce extra read cycles after issuing read command to NPE
> +	   so that we read the register after the NPE has updated it.
> +	   This is to overcome race condition between XScale and NPE */
> +	__raw_readl(&npe->regs->exec_data);
> +	__raw_readl(&npe->regs->exec_data);
> +	return __raw_readl(&npe->regs->exec_data);
> +}
> +
> +static void npe_clear_active(struct npe *npe, u32 reg)
> +{
> +	u32 val = npe_cmd_read(npe, reg, CMD_RD_ECS_REG);
> +	npe_cmd_write(npe, reg, CMD_WR_ECS_REG, val & ~ECS_REG_0_ACTIVE);
> +}
> +
> +static void npe_start(struct npe *npe)
> +{
> +	/* ensure only Background Context Stack Level is active */
> +	npe_clear_active(npe, ECS_PRI_1_CTXT_REG_0);
> +	npe_clear_active(npe, ECS_PRI_2_CTXT_REG_0);
> +	npe_clear_active(npe, ECS_DBG_CTXT_REG_0);
> +
> +	__raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);
> +	__raw_writel(CMD_NPE_START, &npe->regs->exec_status_cmd);
> +}
> +
> +static void npe_stop(struct npe *npe)
> +{
> +	__raw_writel(CMD_NPE_STOP, &npe->regs->exec_status_cmd);
> +	__raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd); /*FIXME?*/
> +}
> +
> +static int npe_debug_instr(struct npe *npe, u32 instr, u32 ctx, u32 ldur)
> +{
> +	u32 wc;
> +	int i;
> +
> +	/* set the Active bit, and the LDUR, in the debug level */
> +	npe_cmd_write(npe, ECS_DBG_CTXT_REG_0, CMD_WR_ECS_REG,
> +		      ECS_REG_0_ACTIVE | (ldur << ECS_REG_0_LDUR_BITS));
> +
> +	/* set CCTXT at ECS DEBUG L3 to specify in which context to execute
> +	   the instruction, and set SELCTXT at ECS DEBUG Level to specify
> +	   which context store to access.
> +	   Debug ECS Level Reg 1 has form 0x000n000n, where n = context number
> +	*/
> +	npe_cmd_write(npe, ECS_DBG_CTXT_REG_1, CMD_WR_ECS_REG,
> +		      (ctx << ECS_REG_1_CCTXT_BITS) |
> +		      (ctx << ECS_REG_1_SELCTXT_BITS));
> +
> +	/* clear the pipeline */
> +	__raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);
> +
> +	/* load NPE instruction into the instruction register */
> +	npe_cmd_write(npe, ECS_INSTRUCT_REG, CMD_WR_ECS_REG, instr);
> +
> +	/* we need this value later to wait for completion of NPE execution
> +	   step */
> +	wc = __raw_readl(&npe->regs->watch_count);
> +
> +	/* issue a Step One command via the Execution Control register */
> +	__raw_writel(CMD_NPE_STEP, &npe->regs->exec_status_cmd);
> +
> +	/* Watch Count register increments when NPE completes an instruction */
> +	for (i = 0; i < MAX_RETRIES; i++) {
> +		if (wc != __raw_readl(&npe->regs->watch_count))
> +			return 0;
> +		udelay(1);
> +	}
> +
> +	print_npe(npe, "reset: npe_debug_instr(): timeout\n");
> +	return -ETIMEDOUT;
> +}
> +
> +static int npe_logical_reg_write8(struct npe *npe, u32 addr, u8 val, u32 ctx)
> +{
> +	/* here we build the NPE assembler instruction: mov8 d0, #0 */
> +	u32 instr = INSTR_WR_REG_BYTE | /* OpCode */
> +		addr << 9 |             /* base Operand */
> +		(val & 0x1F) << 4 |     /* lower 5 bits to immediate data */
> +		(val & ~0x1F) << (18 - 5);/* higher 3 bits to CoProc instr. */
> +	return npe_debug_instr(npe, instr, ctx, 1); /* execute it */
> +}
> +
> +static int npe_logical_reg_write16(struct npe *npe, u32 addr, u16 val, u32 ctx)
> +{
> +	/* here we build the NPE assembler instruction: mov16 d0, #0 */
> +	u32 instr = INSTR_WR_REG_SHORT | /* OpCode */
> +		addr << 9 |             /* base Operand */
> +		(val & 0x1F) << 4 |     /* lower 5 bits to immediate data */
> +		(val & ~0x1F) << (18 - 5);/* higher 11 bits to CoProc instr. */
> +	return npe_debug_instr(npe, instr, ctx, 1); /* execute it */
> +}
> +
> +static int npe_logical_reg_write32(struct npe *npe, u32 addr, u32 val, u32 ctx)
> +{
> +	/* write in 16 bit steps first the high and then the low value */
> +	if (npe_logical_reg_write16(npe, addr, val >> 16, ctx))
> +		return -ETIMEDOUT;
> +	return npe_logical_reg_write16(npe, addr + 2, val & 0xFFFF, ctx);
> +}
> +
> +static int npe_reset(struct npe *npe)
> +{
> +	u32 val, ctl, exec_count, ctx_reg2;
> +	int i;
> +
> +	ctl = (__raw_readl(&npe->regs->messaging_control) | 0x3F000000) &
> +		0x3F3FFFFF;
> +
> +	/* disable parity interrupt */
> +	__raw_writel(ctl & 0x3F00FFFF, &npe->regs->messaging_control);
> +
> +	/* pre exec - debug instruction */
> +	/* turn off the halt bit by clearing Execution Count register. */
> +	exec_count = __raw_readl(&npe->regs->exec_count);
> +	__raw_writel(0, &npe->regs->exec_count);
> +	/* ensure that IF and IE are on (temporarily), so that we don't end up
> +	   stepping forever */
> +	ctx_reg2 = npe_cmd_read(npe, ECS_DBG_CTXT_REG_2, CMD_RD_ECS_REG);
> +	npe_cmd_write(npe, ECS_DBG_CTXT_REG_2, CMD_WR_ECS_REG, ctx_reg2 |
> +		      ECS_DBG_REG_2_IF | ECS_DBG_REG_2_IE);
> +
> +	/* clear the FIFOs */
> +	while (__raw_readl(&npe->regs->watchpoint_fifo) & WFIFO_VALID)
> +		;
> +	while (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_OFNE)
> +		/* read from the outFIFO until empty */
> +		print_npe(npe, "npe_reset: read FIFO = 0x%X\n",
> +			  __raw_readl(&npe->regs->in_out_fifo));
> +
> +	while (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE)
> +		/* step execution of the NPE intruction to read inFIFO using
> +		   the Debug Executing Context stack */
> +		if (npe_debug_instr(npe, INSTR_RD_FIFO, 0, 0))
> +			return -ETIMEDOUT;
> +
> +	/* reset the mailbox reg from the XScale side */
> +	__raw_writel(RESET_MBOX_STAT, &npe->regs->mailbox_status);
> +	/* from NPE side */
> +	if (npe_debug_instr(npe, INSTR_RESET_MBOX, 0, 0))
> +		return -ETIMEDOUT;
> +
> +	/* Reset the physical registers in the NPE register file */
> +	for (val = 0; val < NPE_PHYS_REG; val++) {
> +		if (npe_logical_reg_write16(npe, NPE_REGMAP, val >> 1, 0))
> +			return -ETIMEDOUT;
> +		/* address is either 0 or 4 */
> +		if (npe_logical_reg_write32(npe, (val & 1) * 4, 0, 0))
> +			return -ETIMEDOUT;
> +	}
> +
> +	/* Reset the context store = each context's Context Store registers */
> +
> +	/* Context 0 has no STARTPC. Instead, this value is used to set NextPC
> +	   for Background ECS, to set where NPE starts executing code */
> +	val = npe_cmd_read(npe, ECS_BG_CTXT_REG_0, CMD_RD_ECS_REG);
> +	val &= ~ECS_REG_0_NEXTPC_MASK;
> +	val |= (0 /* NextPC */ << 16) & ECS_REG_0_NEXTPC_MASK;
> +	npe_cmd_write(npe, ECS_BG_CTXT_REG_0, CMD_WR_ECS_REG, val);
> +
> +	for (i = 0; i < 16; i++) {
> +		if (i) { /* Context 0 has no STEVT nor STARTPC */
> +			/* STEVT = off, 0x80 */
> +			if (npe_logical_reg_write8(npe, NPE_STEVT, 0x80, i))
> +				return -ETIMEDOUT;
> +			if (npe_logical_reg_write16(npe, NPE_STARTPC, 0, i))
> +				return -ETIMEDOUT;
> +		}
> +		/* REGMAP = d0->p0, d8->p2, d16->p4 */
> +		if (npe_logical_reg_write16(npe, NPE_REGMAP, 0x820, i))
> +			return -ETIMEDOUT;
> +		if (npe_logical_reg_write8(npe, NPE_CINDEX, 0, i))
> +			return -ETIMEDOUT;
> +	}
> +
> +	/* post exec */
> +	/* clear active bit in debug level */
> +	npe_cmd_write(npe, ECS_DBG_CTXT_REG_0, CMD_WR_ECS_REG, 0);
> +	/* clear the pipeline */
> +	__raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);
> +	/* restore previous values */
> +	__raw_writel(exec_count, &npe->regs->exec_count);
> +	npe_cmd_write(npe, ECS_DBG_CTXT_REG_2, CMD_WR_ECS_REG, ctx_reg2);
> +
> +	/* write reset values to Execution Context Stack registers */
> +	for (val = 0; val < ARRAY_SIZE(ecs_reset); val++)
> +		npe_cmd_write(npe, ecs_reset[val].reg, CMD_WR_ECS_REG,
> +			      ecs_reset[val].val);
> +
> +	/* clear the profile counter */
> +	__raw_writel(CMD_CLR_PROFILE_CNT, &npe->regs->exec_status_cmd);
> +
> +	__raw_writel(0, &npe->regs->exec_count);
> +	__raw_writel(0, &npe->regs->action_points[0]);
> +	__raw_writel(0, &npe->regs->action_points[1]);
> +	__raw_writel(0, &npe->regs->action_points[2]);
> +	__raw_writel(0, &npe->regs->action_points[3]);
> +	__raw_writel(0, &npe->regs->watch_count);
> +
> +	val = ixp4xx_read_feature_bits();
> +	/* reset the NPE */
> +	ixp4xx_write_feature_bits(val &
> +				  ~(IXP4XX_FEATURE_RESET_NPEA << npe->id));
> +	/* deassert reset */
> +	ixp4xx_write_feature_bits(val |
> +				  (IXP4XX_FEATURE_RESET_NPEA << npe->id));
> +	for (i = 0; i < MAX_RETRIES; i++) {
> +		if (ixp4xx_read_feature_bits() &
> +		    (IXP4XX_FEATURE_RESET_NPEA << npe->id))
> +			break; /* NPE is back alive */
> +		udelay(1);
> +	}
> +	if (i == MAX_RETRIES)
> +		return -ETIMEDOUT;
> +
> +	npe_stop(npe);
> +
> +	/* restore NPE configuration bus Control Register - parity settings */
> +	__raw_writel(ctl, &npe->regs->messaging_control);
> +	return 0;
> +}
> +
> +
> +int npe_send_message(struct npe *npe, const void *msg, const char *what)
> +{
> +	const u32 *send = msg;
> +	int cycles = 0;
> +
> +	debug_msg(npe, "Trying to send message %s [%08X:%08X]\n",
> +		  what, send[0], send[1]);
> +
> +	if (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE) {
> +		debug_msg(npe, "NPE input FIFO not empty\n");
> +		return -EIO;
> +	}
> +
> +	__raw_writel(send[0], &npe->regs->in_out_fifo);
> +
> +	if (!(__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNF)) {
> +		debug_msg(npe, "NPE input FIFO full\n");
> +		return -EIO;
> +	}
> +
> +	__raw_writel(send[1], &npe->regs->in_out_fifo);
> +
> +	while ((cycles < MAX_RETRIES) &&
> +	       (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE)) {
> +		udelay(1);
> +		cycles++;
> +	}
> +
> +	if (cycles == MAX_RETRIES) {
> +		debug_msg(npe, "Timeout sending message\n");
> +		return -ETIMEDOUT;
> +	}
> +
> +#if DEBUG_MSG > 1
> +	debug_msg(npe, "Sending a message took %i cycles\n", cycles);
> +#endif
> +	return 0;
> +}
> +
> +int npe_recv_message(struct npe *npe, void *msg, const char *what)
> +{
> +	u32 *recv = msg;
> +	int cycles = 0, cnt = 0;
> +
> +	debug_msg(npe, "Trying to receive message %s\n", what);
> +
> +	while (cycles < MAX_RETRIES) {
> +		if (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_OFNE) {
> +			recv[cnt++] = __raw_readl(&npe->regs->in_out_fifo);
> +			if (cnt == 2)
> +				break;
> +		} else {
> +			udelay(1);
> +			cycles++;
> +		}
> +	}
> +
> +	switch(cnt) {
> +	case 1:
> +		debug_msg(npe, "Received [%08X]\n", recv[0]);
> +		break;
> +	case 2:
> +		debug_msg(npe, "Received [%08X:%08X]\n", recv[0], recv[1]);
> +		break;
> +	}
> +
> +	if (cycles == MAX_RETRIES) {
> +		debug_msg(npe, "Timeout waiting for message\n");
> +		return -ETIMEDOUT;
> +	}
> +
> +#if DEBUG_MSG > 1
> +	debug_msg(npe, "Receiving a message took %i cycles\n", cycles);
> +#endif
> +	return 0;
> +}
> +
> +int npe_send_recv_message(struct npe *npe, void *msg, const char *what)
> +{
> +	int result;
> +	u32 *send = msg, recv[2];
> +
> +	if ((result = npe_send_message(npe, msg, what)) != 0)
> +		return result;
> +	if ((result = npe_recv_message(npe, recv, what)) != 0)
> +		return result;
> +
> +	if ((recv[0] != send[0]) || (recv[1] != send[1])) {
> +		debug_msg(npe, "Message %s: unexpected message received\n",
> +			  what);
> +		return -EIO;
> +	}
> +	return 0;
> +}
> +
> +
> +int npe_load_firmware(struct npe *npe)
> +{
> +	struct dl_block {
> +		u32 type;
> +		u32 offset;
> +	} *blk;
> +
> +	struct dl_image {
> +		u32 magic;
> +		u32 id;
> +		u32 size;
> +		union {
> +			u32 data[0];
> +			struct dl_block blocks[0];
> +		};
> +	} *image;
> +
> +	struct dl_codeblock {
> +		u32 npe_addr;
> +		u32 size;
> +		u32 data[0];
> +	} *cb;
> +
> +	int i, j, err, data_size, instr_size, blocks, table_end;
> +	u32 cmd;
> +	char name[10 /* "/firmware/" */ + NPE_NAME_LENGTH + 1 /* NUL */];
> +	size_t image_size;
> +
> +	sprintf(name, "/firmware/%s", npe->name);
> +	if (!(image = read_file(name, &image_size))) {
> +		print_npe(npe, "bad or missing microcode file %s\n", name);
> +		return -EIO;
> +	}
> +
> +	err = -EINVAL;
> +	if (image_size < sizeof(struct dl_image)) {
> +		print_npe(npe, "incomplete microcode file %s\n", name);
> +		goto err;
> +	}
> +
> +#if DEBUG_FW
> +	print_npe(npe, "microcode: %08X %08X %08X (0x%X bytes)\n",
> +		  image->magic, image->id, image->size, image->size * 4);
> +#endif
> +
> +	if (image->magic == swab32(FW_MAGIC)) { /* swapped file */
> +		image->id = swab32(image->id);
> +		image->size = swab32(image->size);
> +	} else if (image->magic != FW_MAGIC) {
> +		print_npe(npe, "bad microcode file %s magic: 0x%X\n", name, image->magic);
> +		goto err;
> +	}
> +	if ((image->size * 4 + sizeof(struct dl_image)) > image_size) {
> +		print_npe(npe, "incomplete microcode file %s\n", name);
> +		goto err;
> +	}
> +	if (((image->id >> 24) & 0xF /* NPE ID */) != npe->id) {
> +		print_npe(npe, "NPE ID mismatch in microcode file %s\n", name);
> +		goto err;
> +	}
> +	if (image->magic == swab32(FW_MAGIC))
> +		for (i = 0; i < image->size; i++)
> +			image->data[i] = swab32(image->data[i]);
> +
> +	if (cpu_is_ixp42x() && ((image->id >> 28) & 0xF /* device ID */)) {
> +		print_npe(npe, "IXP43x/IXP46x microcode ignored on IXP42x\n");
> +		goto err;
> +	}
> +
> +	if (npe_running(npe)) {
> +		print_npe(npe, "unable to load microcode file %s, NPE is already running\n", name);
> +		err = -EBUSY;
> +		goto err;
> +	}
> +
> +	if (cpu_is_ixp42x()) {
> +		if (!npe->id)
> +			instr_size = NPE_A_42X_INSTR_SIZE;
> +		else
> +			instr_size = NPE_B_AND_C_42X_INSTR_SIZE;
> +		data_size = NPE_42X_DATA_SIZE;
> +	} else {
> +		instr_size = NPE_46X_INSTR_SIZE;
> +		data_size = NPE_46X_DATA_SIZE;
> +	}
> +
> +	for (blocks = 0; blocks * sizeof(struct dl_block) / 4 < image->size;
> +	     blocks++)
> +		if (image->blocks[blocks].type == FW_BLOCK_TYPE_EOF)
> +			break;
> +	if (blocks * sizeof(struct dl_block) / 4 >= image->size) {
> +		print_npe(npe, "microcode EOF block marker not found\n");
> +		goto err;
> +	}
> +
> +#if DEBUG_FW
> +	print_npe(npe, "%i microcode blocks found\n", blocks);
> +#endif
> +
> +	table_end = blocks * sizeof(struct dl_block) / 4 + 1 /* EOF marker */;
> +	for (i = 0, blk = image->blocks; i < blocks; i++, blk++) {
> +		if (blk->offset > image->size - sizeof(struct dl_codeblock) / 4
> +		    || blk->offset < table_end) {
> +			print_npe(npe, "invalid offset 0x%X of "
> +				  "microcode block #%i\n", blk->offset, i);
> +			goto err;
> +		}
> +
> +		cb = (struct dl_codeblock*)&image->data[blk->offset];
> +		if (blk->type == FW_BLOCK_TYPE_INSTR) {
> +			if (cb->npe_addr + cb->size > instr_size)
> +				goto too_big;
> +			cmd = CMD_WR_INS_MEM;
> +		} else if (blk->type == FW_BLOCK_TYPE_DATA) {
> +			if (cb->npe_addr + cb->size > data_size)
> +				goto too_big;
> +			cmd = CMD_WR_DATA_MEM;
> +		} else {
> +			print_npe(npe, "invalid microcode block #%i type 0x%X\n",
> +				  i, blk->type);
> +			goto err;
> +		}
> +		if (blk->offset + sizeof(*cb) / 4 + cb->size > image->size) {
> +			print_npe(npe, "microcode block #%i doesn't "
> +				  "fit in microcode image: type %c, start 0x%X,"
> +				  " length 0x%X\n", i,
> +				  blk->type == FW_BLOCK_TYPE_INSTR ? 'I' : 'D',
> +				  cb->npe_addr, cb->size);
> +			goto err;
> +		}
> +
> +		for (j = 0; j < cb->size; j++)
> +			npe_cmd_write(npe, cb->npe_addr + j, cmd, cb->data[j]);
> +	}
> +
> +	npe_start(npe);
> +	if (!npe_running(npe))
> +		print_npe(npe, "unable to start\n");
> +	free(image);
> +	return 0;
> +
> +too_big:
> +	print_npe(npe, "microcode block #%i doesn't fit in NPE "
> +		  "memory: type %c, start 0x%X, length 0x%X\n", i,
> +		  blk->type == FW_BLOCK_TYPE_INSTR ? 'I' : 'D',
> +		  cb->npe_addr, cb->size);
> +err:
> +	free(image);
> +	return err;
> +}
> +
> +
> +struct npe *npe_request(int id)
> +{
> +	if (id < ARRAY_SIZE(npe_tab))
> +		if (npe_tab[id].valid)
> +			return &npe_tab[id];
> +	return NULL;
> +}
> +
> +static int __init npe_init(void)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(npe_tab); i++) {
> +		struct npe *npe = &npe_tab[i];
> +		if (!(ixp4xx_read_feature_bits() & (IXP4XX_FEATURE_RESET_NPEA << i)))
> +			continue; /* NPE already disabled or not present */
> +		if (npe_reset(npe))
> +			continue;
> +		npe->valid = 1;
> +	}
> +	return 0;
> +}
> +
> +coredevice_initcall(npe_init);
> 
> _______________________________________________
> barebox mailing list
> barebox@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] ARM: Support for IXP4xx hardware Queue Manager.
  2013-04-07 19:55       ` [PATCH] ARM: Support for IXP4xx hardware Queue Manager Krzysztof Halasa
@ 2013-04-08  7:31         ` Jean-Christophe PLAGNIOL-VILLARD
  0 siblings, 0 replies; 24+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2013-04-08  7:31 UTC (permalink / raw)
  To: Krzysztof Halasa; +Cc: barebox

same here no printf use dev_dbg or pr_debug

On 21:55 Sun 07 Apr     , Krzysztof Halasa wrote:
> Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>
> 
> diff --git a/arch/arm/mach-ixp4xx/Kconfig b/arch/arm/mach-ixp4xx/Kconfig
> index e69de29..9244be9 100644
> --- a/arch/arm/mach-ixp4xx/Kconfig
> +++ b/arch/arm/mach-ixp4xx/Kconfig
> @@ -0,0 +1,9 @@
> +if ARCH_IXP4XX
> +
> +config IXP4XX_QMGR
> +	tristate "IXP4xx Queue Manager support"
> +	help
> +	  This driver supports IXP4xx built-in hardware queue manager
> +	  and is required by the Ethernet driver.
> +
> +endif
> diff --git a/arch/arm/mach-ixp4xx/Makefile b/arch/arm/mach-ixp4xx/Makefile
> index d8a3d7f..09a0d63 100644
> --- a/arch/arm/mach-ixp4xx/Makefile
> +++ b/arch/arm/mach-ixp4xx/Makefile
> @@ -1 +1,2 @@
>  obj-y += generic.o
> +obj-$(CONFIG_IXP4XX_QMGR) += qmgr.o
> diff --git a/arch/arm/mach-ixp4xx/include/mach/qmgr.h b/arch/arm/mach-ixp4xx/include/mach/qmgr.h
> new file mode 100644
> index 0000000..4e9b8d4
> --- /dev/null
> +++ b/arch/arm/mach-ixp4xx/include/mach/qmgr.h
> @@ -0,0 +1,164 @@
> +/*
> + * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of version 2 of the GNU General Public License
> + * as published by the Free Software Foundation.
> + */
> +
> +#ifndef IXP4XX_QMGR_H
> +#define IXP4XX_QMGR_H
> +
> +#include <common.h>
> +#include <mach/ixp4xx-regs.h>
> +#include <asm/io.h>
> +
> +#define DEBUG_QMGR       0
> +
> +#define HALF_QUEUES     32
> +#define QUEUES          64
> +#define MAX_QUEUE_LENGTH 4 /* in dwords */
> +
> +#define QUEUE_STAT1_EMPTY               1 /* queue status bits */
> +#define QUEUE_STAT1_NEARLY_EMPTY        2
> +#define QUEUE_STAT1_NEARLY_FULL         4
> +#define QUEUE_STAT1_FULL                8
> +#define QUEUE_STAT2_UNDERFLOW           1
> +#define QUEUE_STAT2_OVERFLOW            2
> +
> +#define QUEUE_WATERMARK_0_ENTRIES       0
> +#define QUEUE_WATERMARK_1_ENTRY         1
> +#define QUEUE_WATERMARK_2_ENTRIES       2
> +#define QUEUE_WATERMARK_4_ENTRIES       3
> +#define QUEUE_WATERMARK_8_ENTRIES       4
> +#define QUEUE_WATERMARK_16_ENTRIES      5
> +#define QUEUE_WATERMARK_32_ENTRIES      6
> +#define QUEUE_WATERMARK_64_ENTRIES      7
> +
> +/* queue interrupt request conditions */
> +#define QUEUE_IRQ_SRC_EMPTY             0
> +#define QUEUE_IRQ_SRC_NEARLY_EMPTY      1
> +#define QUEUE_IRQ_SRC_NEARLY_FULL       2
> +#define QUEUE_IRQ_SRC_FULL              3
> +#define QUEUE_IRQ_SRC_NOT_EMPTY         4
> +#define QUEUE_IRQ_SRC_NOT_NEARLY_EMPTY  5
> +#define QUEUE_IRQ_SRC_NOT_NEARLY_FULL   6
> +#define QUEUE_IRQ_SRC_NOT_FULL          7
> +
> +struct qmgr_regs {
> +	u32 acc[QUEUES][MAX_QUEUE_LENGTH]; /* 0x000 - 0x3FF */
> +	u32 stat1[4];         /* 0x400 - 0x40F */
> +	u32 stat2[2];         /* 0x410 - 0x417 */
> +	u32 statne_h;         /* 0x418 - queue nearly empty */
> +	u32 statf_h;          /* 0x41C - queue full */
> +	u32 irqsrc[4];        /* 0x420 - 0x42F IRC source */
> +	u32 irqen[2];         /* 0x430 - 0x437 IRQ enabled */
> +	u32 irqstat[2];       /* 0x438 - 0x43F - IRQ access only */
> +	u32 reserved[1776];
> +	u32 sram[2048];       /* 0x2000 - 0x3FFF - config and buffer */
> +};
> +
> +static const struct qmgr_regs *qmgr_regs = (struct qmgr_regs *)IXP4XX_QMGR_BASE;
> +
> +void qmgr_set_irq(unsigned int queue, int src,
> +		  void (*handler)(void *pdev), void *pdev);
> +void qmgr_enable_irq(unsigned int queue);
> +void qmgr_disable_irq(unsigned int queue);
> +
> +/* request_ and release_queue() must be called from non-IRQ context */
> +
> +#if DEBUG_QMGR
> +extern char qmgr_queue_descs[HALF_QUEUES][32];
> +
> +void qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
> +			unsigned int nearly_empty_watermark,
> +			unsigned int nearly_full_watermark,
> +			const char *desc_format, const char* name);
> +#else
> +void __qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
> +			  unsigned int nearly_empty_watermark,
> +			  unsigned int nearly_full_watermark);
> +#define qmgr_request_queue(queue, len, nearly_empty_watermark,       \
> +			   nearly_full_watermark, desc_format, name) \
> +	__qmgr_request_queue(queue, len, nearly_empty_watermark,     \
> +			     nearly_full_watermark)
> +#endif
> +
> +void qmgr_release_queue(unsigned int queue);
> +
> +
> +static inline void qmgr_put_entry(unsigned int queue, u32 val)
> +{
> +#if DEBUG_QMGR
> +	BUG_ON(!qmgr_queue_descs[queue]); /* not yet requested */
> +
> +	fprintf(stderr, "Queue %s(%i) put %X\n",
> +		qmgr_queue_descs[queue], queue, val);
> +#endif
> +	__raw_writel(val, &qmgr_regs->acc[queue][0]);
> +}
> +
> +static inline u32 qmgr_get_entry(unsigned int queue)
> +{
> +	u32 val;
> +	val = __raw_readl(&qmgr_regs->acc[queue][0]);
> +#if DEBUG_QMGR
> +	BUG_ON(!qmgr_queue_descs[queue]); /* not yet requested */
> +
> +	fprintf(stderr, "Queue %s(%i) get %X\n",
> +		qmgr_queue_descs[queue], queue, val);
> +#endif
> +	return val;
> +}
> +
> +static inline int __qmgr_get_stat1(unsigned int queue)
> +{
> +	return (__raw_readl(&qmgr_regs->stat1[queue >> 3])
> +		>> ((queue & 7) << 2)) & 0xF;
> +}
> +
> +/**
> + * qmgr_stat_empty() - checks if a hardware queue is empty
> + * @queue: queue number
> + *
> + * Returns non-zero value if the queue is empty.
> + */
> +static inline int qmgr_stat_empty(unsigned int queue)
> +{
> +	return __qmgr_get_stat1(queue) & QUEUE_STAT1_EMPTY;
> +}
> +
> +/**
> + * qmgr_stat_below_low_watermark() - checks if a queue is below low watermark
> + * @queue: queue number
> + *
> + * Returns non-zero value if the queue is below low watermark.
> + */
> +static inline int qmgr_stat_below_low_watermark(unsigned int queue)
> +{
> +	return __qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_EMPTY;
> +}
> +
> +/**
> + * qmgr_stat_above_high_watermark() - checks if a queue is above high watermark
> + * @queue: queue number
> + *
> + * Returns non-zero value if the queue is above high watermark
> + */
> +static inline int qmgr_stat_above_high_watermark(unsigned int queue)
> +{
> +	return __qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_FULL;
> +}
> +
> +/**
> + * qmgr_stat_full() - checks if a hardware queue is full
> + * @queue: queue number
> + *
> + * Returns non-zero value if the queue is full.
> + */
> +static inline int qmgr_stat_full(unsigned int queue)
> +{
> +	return __qmgr_get_stat1(queue) & QUEUE_STAT1_FULL;
> +}
> +
> +#endif
> diff --git a/arch/arm/mach-ixp4xx/qmgr.c b/arch/arm/mach-ixp4xx/qmgr.c
> new file mode 100644
> index 0000000..81b6522
> --- /dev/null
> +++ b/arch/arm/mach-ixp4xx/qmgr.c
> @@ -0,0 +1,259 @@
> +/*
> + * Intel IXP4xx Queue Manager driver for Linux
> + *
> + * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of version 2 of the GNU General Public License
> + * as published by the Free Software Foundation.
> + */
> +
> +#include <init.h>
> +#include <errno.h>
> +#include <mach/qmgr.h>
> +
> +static u32 used_sram_bitmap[4]; /* 128 16-dword pages */
> +
> +#if DEBUG_QMGR
> +char qmgr_queue_descs[HALF_QUEUES][32];
> +#endif
> +
> +#ifdef CONFIG_USE_IRQ
> +
> +static void (*irq_handlers[HALF_QUEUES])(void *pdev);
> +static void *irq_pdevs[HALF_QUEUES];
> +
> +void qmgr_set_irq(unsigned int queue, int src,
> +		  void (*handler)(void *pdev), void *pdev)
> +{
> +	const u32 *reg;
> +	int bit;
> +	BUG_ON(src > QUEUE_IRQ_SRC_NOT_FULL);
> +	reg = &qmgr_regs->irqsrc[queue >> 3]; /* 8 queues per u32 */
> +	bit = (queue % 8) * 4; /* 3 bits + 1 reserved bit per queue */
> +	__raw_writel((__raw_readl(reg) & ~(7 << bit)) | (src << bit), reg);
> +
> +	irq_handlers[queue] = handler;
> +	irq_pdevs[queue] = pdev;
> +}
> +
> +
> +static void qmgr_irq1_a0(void *data)
> +{
> +	int i;
> +	u32 en_bitmap, src, stat;
> +
> +	/* ACK - it may clear any bits so don't rely on it */
> +	__raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[0]);
> +
> +	en_bitmap = qmgr_regs->irqen[0];
> +	while (en_bitmap) {
> +		i = fls(en_bitmap) - 1; /* number of the last "low" queue */
> +		en_bitmap &= ~BIT(i);
> +		src = qmgr_regs->irqsrc[i >> 3];
> +		stat = qmgr_regs->stat1[i >> 3];
> +		if (src & 4) /* the IRQ condition is inverted */
> +			stat = ~stat;
> +		if (stat & BIT(src & 3))
> +			irq_handlers[i](irq_pdevs[i]);
> +	}
> +}
> +
> +
> +static void qmgr_irq1(void *data)
> +{
> +	int i;
> +	u32 req_bitmap = __raw_readl(&qmgr_regs->irqstat[0]);
> +
> +	if (!req_bitmap)
> +		return;
> +	__raw_writel(req_bitmap, &qmgr_regs->irqstat[0]); /* ACK */
> +
> +	while (req_bitmap) {
> +		i = fls(req_bitmap) - 1; /* number of the last queue */
> +		req_bitmap &= ~BIT(i);
> +		irq_handlers[i](irq_pdevs[i]);
> +	}
> +}
> +
> +
> +void qmgr_enable_irq(unsigned int queue)
> +{
> +	u32 mask = 1 << queue;
> +
> +	__raw_writel(__raw_readl(&qmgr_regs->irqen[0]) | mask,
> +		     &qmgr_regs->irqen[0]);
> +}
> +
> +void qmgr_disable_irq(unsigned int queue)
> +{
> +	u32 mask = 1 << queue;
> +
> +	__raw_writel(__raw_readl(&qmgr_regs->irqen[0]) & ~mask,
> +		     &qmgr_regs->irqen[0]);
> +	__raw_writel(mask, &qmgr_regs->irqstat[0]); /* clear */
> +}
> +
> +#endif /* CONFIG_USE_IRQ */
> +
> +static inline void shift_mask(u32 *mask)
> +{
> +	mask[3] = mask[3] << 1 | mask[2] >> 31;
> +	mask[2] = mask[2] << 1 | mask[1] >> 31;
> +	mask[1] = mask[1] << 1 | mask[0] >> 31;
> +	mask[0] <<= 1;
> +}
> +
> +#if DEBUG_QMGR
> +void qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
> +			unsigned int nearly_empty_watermark,
> +			unsigned int nearly_full_watermark,
> +			const char *desc_format, const char* name)
> +#else
> +void __qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
> +			  unsigned int nearly_empty_watermark,
> +			  unsigned int nearly_full_watermark)
> +#endif
??
> +{
> +	u32 cfg, addr = 0, mask[4]; /* in 16-dwords */
> +
> +	BUG_ON(queue >= HALF_QUEUES);
> +	BUG_ON((nearly_empty_watermark | nearly_full_watermark) & ~7);
> +
> +	switch (len) {
> +	case  16:
> +		cfg = 0 << 24;
> +		mask[0] = 0x1;
> +		break;
> +	case  32:
> +		cfg = 1 << 24;
> +		mask[0] = 0x3;
> +		break;
> +	case  64:
> +		cfg = 2 << 24;
> +		mask[0] = 0xF;
> +		break;
> +	case 128:
> +		cfg = 3 << 24;
> +		mask[0] = 0xFF;
> +		break;
> +	default:
> +		BUG();
> +	}
> +
> +	cfg |= nearly_empty_watermark << 26;
> +	cfg |= nearly_full_watermark << 29;
> +	len /= 16; /* in 16-dwords: 1, 2, 4 or 8 */
> +	mask[1] = mask[2] = mask[3] = 0;
> +
> +	BUG_ON(__raw_readl(&qmgr_regs->sram[queue]));
> +
> +	while (1) {
> +		if (!(used_sram_bitmap[0] & mask[0]) &&
> +		    !(used_sram_bitmap[1] & mask[1]) &&
> +		    !(used_sram_bitmap[2] & mask[2]) &&
> +		    !(used_sram_bitmap[3] & mask[3]))
> +			break; /* found free space */
> +
> +		addr++;
> +		shift_mask(mask);
> +		if (addr + len > ARRAY_SIZE(qmgr_regs->sram)) {
> +			fprintf(stderr, "qmgr: no free SRAM space for"
> +				" queue %i\n", queue);
> +			BUG();
> +		}
> +	}
> +
> +	used_sram_bitmap[0] |= mask[0];
> +	used_sram_bitmap[1] |= mask[1];
> +	used_sram_bitmap[2] |= mask[2];
> +	used_sram_bitmap[3] |= mask[3];
> +	__raw_writel(cfg | (addr << 14), &qmgr_regs->sram[queue]);
> +#if DEBUG_QMGR
> +	/* no snprintf() */
> +	sprintf(qmgr_queue_descs[queue], desc_format, name);
> +	fprintf(stderr, "qmgr: requested queue %s(%i) addr = 0x%02X\n",
> +		qmgr_queue_descs[queue], queue, addr);
> +#endif
> +}
> +
> +void qmgr_release_queue(unsigned int queue)
> +{
> +	u32 cfg, addr, mask[4];
> +
> +	BUG_ON(queue >= HALF_QUEUES); /* not in valid range */
> +
> +	cfg = __raw_readl(&qmgr_regs->sram[queue]);
> +	addr = (cfg >> 14) & 0xFF;
> +
> +	BUG_ON(!addr); /* not requested */
> +
> +	switch ((cfg >> 24) & 3) {
> +	case 0: mask[0] = 0x1; break;
> +	case 1: mask[0] = 0x3; break;
> +	case 2: mask[0] = 0xF; break;
> +	case 3: mask[0] = 0xFF; break;
> +	}
> +
> +	mask[1] = mask[2] = mask[3] = 0;
> +
> +	while (addr--)
> +		shift_mask(mask);
> +
> +#if DEBUG_QMGR
> +	fprintf(stderr, "qmgr: releasing queue %s(%i)\n",
> +		qmgr_queue_descs[queue], queue);
> +	qmgr_queue_descs[queue][0] = '\x0';
> +#endif
> +	__raw_writel(0, &qmgr_regs->sram[queue]);
> +
> +	used_sram_bitmap[0] &= ~mask[0];
> +	used_sram_bitmap[1] &= ~mask[1];
> +	used_sram_bitmap[2] &= ~mask[2];
> +	used_sram_bitmap[3] &= ~mask[3];
> +#ifdef CONFIG_USE_IRQ
> +	irq_handlers[queue] = NULL; /* catch IRQ bugs */
> +#endif
> +
> +	while ((addr = qmgr_get_entry(queue)))
> +		fprintf(stderr, "qmgr: released queue %i not empty: 0x%08X\n",
> +			queue, addr);
> +}
> +
> +static int __init qmgr_init(void)
> +{
> +	int i;
> +#ifdef CONFIG_USE_IRQ
> +	interrupt_handler_t *handler;
we have no irq support on barebox
> +#endif
> +
> +	/* reset qmgr registers */
> +	for (i = 0; i < 4; i++) {
> +		__raw_writel(0x33333333, &qmgr_regs->stat1[i]);
> +		__raw_writel(0, &qmgr_regs->irqsrc[i]);
> +	}
> +	for (i = 0; i < 2; i++) {
> +		__raw_writel(0, &qmgr_regs->stat2[i]);
> +		__raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[i]); /* clear */
> +		__raw_writel(0, &qmgr_regs->irqen[i]);
> +	}
> +
> +	__raw_writel(0xFFFFFFFF, &qmgr_regs->statne_h);
> +	__raw_writel(0, &qmgr_regs->statf_h);
> +
> +	for (i = 0; i < QUEUES; i++)
> +		__raw_writel(0, &qmgr_regs->sram[i]);
> +
> +#ifdef CONFIG_USE_IRQ
> +	if (cpu_is_ixp42x_rev_a0())
> +		handler = qmgr_irq1_a0;
> +	else
> +		handler = qmgr_irq1;
> +
> +	irq_install_handler(IXP425_QM1_IRQ, handler, NULL);
> +#endif
> +	used_sram_bitmap[0] = 0xF; /* 4 first pages reserved for config */
> +	return 0;
> +}
> +
> +coredevice_initcall(qmgr_init);
> 
> _______________________________________________
> barebox mailing list
> barebox@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] ARM: Add support for IXP4xx CPU and for Goramo Multilink router platform.
  2013-04-07 11:42     ` Krzysztof Halasa
                         ` (3 preceding siblings ...)
  2013-04-07 19:58       ` [PATCH] ARM: Support for IXP4xx built-in Ethernet interfaces Krzysztof Halasa
@ 2013-04-08  7:56       ` Sascha Hauer
  4 siblings, 0 replies; 24+ messages in thread
From: Sascha Hauer @ 2013-04-08  7:56 UTC (permalink / raw)
  To: Krzysztof Halasa; +Cc: barebox

On Sun, Apr 07, 2013 at 01:42:21PM +0200, Krzysztof Halasa wrote:
> Sascha Hauer <s.hauer@pengutronix.de> writes:
> 
> >> +static struct eth_plat_info eth_pinfo[2] = {
> >
> > Why not use dynamically sized arrays?
> 
> What do you mean?

I mean:

static struct eth_plat_info eth_pinfo[]

Sascha


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] ARM: Support for IXP4xx CPU.
  2013-04-08  7:27         ` Jean-Christophe PLAGNIOL-VILLARD
@ 2013-04-14 10:30           ` Krzysztof Halasa
  2013-04-14 11:51             ` Jean-Christophe PLAGNIOL-VILLARD
  0 siblings, 1 reply; 24+ messages in thread
From: Krzysztof Halasa @ 2013-04-14 10:30 UTC (permalink / raw)
  To: Jean-Christophe PLAGNIOL-VILLARD; +Cc: barebox

Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> writes:

>> +static int ixp4xx_console_init(void)
>> +{
>> +	/* Register the serial port */
>> +	add_ns16550_device(0, (u32)IXP4XX_UART1_BASE, 1024, IORESOURCE_MEM_8BIT, &serial_plat);
> we have multiple uart on ixp do no hard code it

Yes, but there is a single console, at least on all devices I have
access to. I can add CONFIG_* item for this, but it will be forced to 0
for now anyway (on all supported boards).

>> --- a/drivers/serial/serial_ns16550.c
>> +++ b/drivers/serial/serial_ns16550.c
> please split this in an other patch
>
> and pass this as a pdata
>> @@ -137,7 +137,11 @@ static void ns16550_serial_init_port(struct console_device *cdev)
>>  {
>>  	/* initializing the device for the first time */
>>  	ns16550_write(cdev, 0x00, lcr); /* select ier reg */
>> +#ifdef CONFIG_ARCH_IXP4XX
>> +	ns16550_write(cdev, IER_UUE, ier); /* Enable UART operation */
>> +#else
>>  	ns16550_write(cdev, 0x00, ier);
>> +#endif
>>  
>>  #ifdef CONFIG_DRIVER_SERIAL_NS16550_OMAP_EXTENSIONS
>>  	ns16550_write(cdev, 0x07, mdr1);	/* Disable */

What do you mean?

ns16550_probe() doesn't seem to accept anything which could be used for
custom init:

static int ns16550_probe(struct device_d *dev)
{
	struct console_device *cdev;
	struct NS16550_plat *plat = (struct NS16550_plat *)dev->platform_data;

	/* we do expect platform specific data */
	if (plat == NULL)
		return -EINVAL;
	dev->priv = dev_request_mem_region(dev, 0);

	cdev = xzalloc(sizeof(*cdev));

	cdev->dev = dev;
	if (plat->f_caps)
		cdev->f_caps = plat->f_caps;
	else
		cdev->f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR;
	cdev->tstc = ns16550_tstc;
	cdev->putc = ns16550_putc;
	cdev->getc = ns16550_getc;
	cdev->setbrg = ns16550_setbaudrate;

	ns16550_serial_init_port(cdev);

	return console_register(cdev);
}

-- 
Krzysztof Halasa

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] ARM: Support for IXP4xx CPU.
  2013-04-14 10:30           ` Krzysztof Halasa
@ 2013-04-14 11:51             ` Jean-Christophe PLAGNIOL-VILLARD
  0 siblings, 0 replies; 24+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2013-04-14 11:51 UTC (permalink / raw)
  To: Krzysztof Halasa; +Cc: barebox

On 12:30 Sun 14 Apr     , Krzysztof Halasa wrote:
> Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> writes:
> 
> >> +static int ixp4xx_console_init(void)
> >> +{
> >> +	/* Register the serial port */
> >> +	add_ns16550_device(0, (u32)IXP4XX_UART1_BASE, 1024, IORESOURCE_MEM_8BIT, &serial_plat);
> > we have multiple uart on ixp do no hard code it
> 
> Yes, but there is a single console, at least on all devices I have
> access to. I can add CONFIG_* item for this, but it will be forced to 0
> for now anyway (on all supported boards).

this is board specific not arch

no CONFIG_

and we can have multiple uart as console

you can create helper as we do for at91, imx or omap but do not hardcode it
> 
> >> --- a/drivers/serial/serial_ns16550.c
> >> +++ b/drivers/serial/serial_ns16550.c
> > please split this in an other patch
> >
> > and pass this as a pdata
> >> @@ -137,7 +137,11 @@ static void ns16550_serial_init_port(struct console_device *cdev)
> >>  {
> >>  	/* initializing the device for the first time */
> >>  	ns16550_write(cdev, 0x00, lcr); /* select ier reg */
> >> +#ifdef CONFIG_ARCH_IXP4XX
> >> +	ns16550_write(cdev, IER_UUE, ier); /* Enable UART operation */
> >> +#else
> >>  	ns16550_write(cdev, 0x00, ier);
> >> +#endif
> >>  
> >>  #ifdef CONFIG_DRIVER_SERIAL_NS16550_OMAP_EXTENSIONS
> >>  	ns16550_write(cdev, 0x07, mdr1);	/* Disable */
> 
> What do you mean?
> 
> ns16550_probe() doesn't seem to accept anything which could be used for
> custom init:
so update it

as we want to have 1 binary for multiple arch
> 
> static int ns16550_probe(struct device_d *dev)
> {
> 	struct console_device *cdev;
> 	struct NS16550_plat *plat = (struct NS16550_plat *)dev->platform_data;
> 
> 	/* we do expect platform specific data */
> 	if (plat == NULL)
> 		return -EINVAL;
> 	dev->priv = dev_request_mem_region(dev, 0);
> 
> 	cdev = xzalloc(sizeof(*cdev));
> 
> 	cdev->dev = dev;
> 	if (plat->f_caps)
> 		cdev->f_caps = plat->f_caps;
> 	else
> 		cdev->f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR;
> 	cdev->tstc = ns16550_tstc;
> 	cdev->putc = ns16550_putc;
> 	cdev->getc = ns16550_getc;
> 	cdev->setbrg = ns16550_setbaudrate;
> 
> 	ns16550_serial_init_port(cdev);
> 
> 	return console_register(cdev);
> }
> 
> -- 
> Krzysztof Halasa

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2013-04-14 12:12 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-03-30 11:19 IXP4xx again Krzysztof Halasa
2013-03-30 11:24 ` [PATCH] ARM: XScale processors don't support "clean+invalidate D entry" operation Krzysztof Halasa
2013-03-30 11:25 ` [PATCH] Implement ALTERNATE memory layout Krzysztof Halasa
2013-03-30 12:01   ` Alexander Shiyan
2013-03-30 13:15     ` Krzysztof Halasa
2013-03-30 13:23       ` Re[2]: " Alexander Shiyan
2013-03-30 19:57         ` Krzysztof Halasa
2013-03-30 18:45   ` Antony Pavlov
2013-04-01 18:04   ` Sascha Hauer
2013-04-02  7:20   ` Sascha Hauer
2013-03-30 11:26 ` [PATCH] ARM: Add support for IXP4xx CPU and for Goramo Multilink router platform Krzysztof Halasa
2013-04-02  6:52   ` Sascha Hauer
2013-04-07 11:42     ` Krzysztof Halasa
2013-04-07 19:54       ` [PATCH] ARM: Support for IXP4xx CPU Krzysztof Halasa
2013-04-08  7:27         ` Jean-Christophe PLAGNIOL-VILLARD
2013-04-14 10:30           ` Krzysztof Halasa
2013-04-14 11:51             ` Jean-Christophe PLAGNIOL-VILLARD
2013-04-07 19:55       ` [PATCH] ARM: Support for IXP4xx hardware Queue Manager Krzysztof Halasa
2013-04-08  7:31         ` Jean-Christophe PLAGNIOL-VILLARD
2013-04-07 19:57       ` [PATCH] ARM: Support for IXP4xx Network Processor Engines (NPEs) Krzysztof Halasa
2013-04-08  7:30         ` Jean-Christophe PLAGNIOL-VILLARD
2013-04-07 19:58       ` [PATCH] ARM: Support for IXP4xx built-in Ethernet interfaces Krzysztof Halasa
2013-04-08  7:29         ` Jean-Christophe PLAGNIOL-VILLARD
2013-04-08  7:56       ` [PATCH] ARM: Add support for IXP4xx CPU and for Goramo Multilink router platform Sascha Hauer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox