* [PATCH 0/3] XBurst JZ4730 support
@ 2010-02-25 6:28 Graham Gower
2010-02-25 6:29 ` [PATCH 1/3] Add " Graham Gower
` (3 more replies)
0 siblings, 4 replies; 10+ messages in thread
From: Graham Gower @ 2010-02-25 6:28 UTC (permalink / raw)
To: linux-mips
This patch set contains support for Ingenic's XBurst cpu, plus basic
support for their JZ4730 reference boards.
Graham Gower (3):
Add XBurst JZ4730 support.
8250: serial driver changes for XBurst SoCs.
net: add driver for JZ4730 ethernet controller.
arch/mips/Kconfig | 13 +
arch/mips/Makefile | 14 +-
arch/mips/boot/Makefile | 15 +-
arch/mips/include/asm/bootinfo.h | 7 +
arch/mips/include/asm/cpu.h | 9 +
arch/mips/include/asm/mach-generic/irq.h | 2 +-
arch/mips/include/asm/mach-xburst/clock-jz4730.h | 41 +
arch/mips/include/asm/mach-xburst/dma-jz4730.h | 156 +++
arch/mips/include/asm/mach-xburst/irq-jz4730.h | 33 +
arch/mips/include/asm/mach-xburst/uart-jz4730.h | 141 +++
arch/mips/include/asm/mach-xburst/war.h | 25 +
arch/mips/include/asm/mach-xburst/xburst.h | 20 +
arch/mips/include/asm/r4kcache.h | 240 +++++
arch/mips/kernel/cpu-probe.c | 21 +
arch/mips/mm/c-r4k.c | 30 +
arch/mips/mm/tlbex.c | 5 +
arch/mips/xburst/Kconfig | 23 +
arch/mips/xburst/Makefile | 3 +
arch/mips/xburst/jz4730/Makefile | 11 +
arch/mips/xburst/jz4730/board-libra.c | 32 +
arch/mips/xburst/jz4730/board-pmp.c | 32 +
arch/mips/xburst/jz4730/clocks.c | 294 +++++
arch/mips/xburst/jz4730/irq.c | 104 ++
arch/mips/xburst/jz4730/platform.c | 49 +
arch/mips/xburst/jz4730/prom.c | 104 ++
arch/mips/xburst/jz4730/setup.c | 136 +++
arch/mips/xburst/jz4730/time.c | 140 +++
drivers/net/Kconfig | 10 +
drivers/net/Makefile | 1 +
drivers/net/jz_eth.c | 1232 ++++++++++++++++++++++
drivers/net/jz_eth.h | 403 +++++++
drivers/serial/8250.c | 12 +
32 files changed, 3355 insertions(+), 3 deletions(-)
create mode 100644 arch/mips/include/asm/mach-xburst/clock-jz4730.h
create mode 100644 arch/mips/include/asm/mach-xburst/dma-jz4730.h
create mode 100644 arch/mips/include/asm/mach-xburst/irq-jz4730.h
create mode 100644 arch/mips/include/asm/mach-xburst/uart-jz4730.h
create mode 100644 arch/mips/include/asm/mach-xburst/war.h
create mode 100644 arch/mips/include/asm/mach-xburst/xburst.h
create mode 100644 arch/mips/xburst/Kconfig
create mode 100644 arch/mips/xburst/Makefile
create mode 100644 arch/mips/xburst/jz4730/Makefile
create mode 100644 arch/mips/xburst/jz4730/board-libra.c
create mode 100644 arch/mips/xburst/jz4730/board-pmp.c
create mode 100644 arch/mips/xburst/jz4730/clocks.c
create mode 100644 arch/mips/xburst/jz4730/irq.c
create mode 100644 arch/mips/xburst/jz4730/platform.c
create mode 100644 arch/mips/xburst/jz4730/prom.c
create mode 100644 arch/mips/xburst/jz4730/setup.c
create mode 100644 arch/mips/xburst/jz4730/time.c
create mode 100644 drivers/net/jz_eth.c
create mode 100644 drivers/net/jz_eth.h
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 1/3] Add XBurst JZ4730 support.
2010-02-25 6:28 [PATCH 0/3] XBurst JZ4730 support Graham Gower
@ 2010-02-25 6:29 ` Graham Gower
2010-02-25 6:30 ` [PATCH 2/3] 8250: serial driver changes for XBurst SoCs Graham Gower
` (2 subsequent siblings)
3 siblings, 0 replies; 10+ messages in thread
From: Graham Gower @ 2010-02-25 6:29 UTC (permalink / raw)
To: linux-mips
Provides support for Ingenic's XBurst cpu. With initial support for
their JZ4730 SoC based PMP reference platform and Libra dev board.
Signed-off-by: Graham Gower <graham.gower@gmail.com>
---
arch/mips/Kconfig | 13 +
arch/mips/Makefile | 14 +-
arch/mips/boot/Makefile | 15 +-
arch/mips/include/asm/bootinfo.h | 7 +
arch/mips/include/asm/cpu.h | 9 +
arch/mips/include/asm/mach-generic/irq.h | 2 +-
arch/mips/include/asm/mach-xburst/clock-jz4730.h | 41 +++
arch/mips/include/asm/mach-xburst/dma-jz4730.h | 156 ++++++++++++
arch/mips/include/asm/mach-xburst/irq-jz4730.h | 33 +++
arch/mips/include/asm/mach-xburst/uart-jz4730.h | 141 +++++++++++
arch/mips/include/asm/mach-xburst/war.h | 25 ++
arch/mips/include/asm/mach-xburst/xburst.h | 20 ++
arch/mips/include/asm/r5kcache.h | 240 ++++++++++++++++++
arch/mips/kernel/cpu-probe.c | 21 ++
arch/mips/mm/c-r4k.c | 30 +++
arch/mips/mm/tlbex.c | 5 +
arch/mips/xburst/Kconfig | 23 ++
arch/mips/xburst/Makefile | 3 +
arch/mips/xburst/jz4730/Makefile | 11 +
arch/mips/xburst/jz4730/board-libra.c | 32 +++
arch/mips/xburst/jz4730/board-pmp.c | 32 +++
arch/mips/xburst/jz4730/clocks.c | 294 ++++++++++++++++++++++
arch/mips/xburst/jz4730/irq.c | 104 ++++++++
arch/mips/xburst/jz4730/platform.c | 49 ++++
arch/mips/xburst/jz4730/prom.c | 104 ++++++++
arch/mips/xburst/jz4730/setup.c | 136 ++++++++++
arch/mips/xburst/jz4730/time.c | 140 ++++++++++
27 files changed, 1697 insertions(+), 3 deletions(-)
create mode 100644 arch/mips/include/asm/mach-xburst/clock-jz4730.h
create mode 100644 arch/mips/include/asm/mach-xburst/dma-jz4730.h
create mode 100644 arch/mips/include/asm/mach-xburst/irq-jz4730.h
create mode 100644 arch/mips/include/asm/mach-xburst/uart-jz4730.h
create mode 100644 arch/mips/include/asm/mach-xburst/war.h
create mode 100644 arch/mips/include/asm/mach-xburst/xburst.h
create mode 100644 arch/mips/xburst/Kconfig
create mode 100644 arch/mips/xburst/Makefile
create mode 100644 arch/mips/xburst/jz4730/Makefile
create mode 100644 arch/mips/xburst/jz4730/board-libra.c
create mode 100644 arch/mips/xburst/jz4730/board-pmp.c
create mode 100644 arch/mips/xburst/jz4730/clocks.c
create mode 100644 arch/mips/xburst/jz4730/irq.c
create mode 100644 arch/mips/xburst/jz4730/platform.c
create mode 100644 arch/mips/xburst/jz4730/prom.c
create mode 100644 arch/mips/xburst/jz4730/setup.c
create mode 100644 arch/mips/xburst/jz4730/time.c
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 8b5d174..ec5bd51 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -679,6 +679,18 @@ config CAVIUM_OCTEON_REFERENCE_BOARD
Hikari
Say Y here for most Octeon reference boards.
+config XBURST
+ bool "Ingenic XBurst based machines"
+ select SYS_HAS_CPU_MIPS32_R1
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+ select DMA_NONCOHERENT
+ select IRQ_CPU
+ select GENERIC_GPIO
+ select ARCH_REQUIRE_GPIOLIB
+ select SYS_HAS_EARLY_PRINTK
+ select BOOT_RAW
+
endchoice
source "arch/mips/alchemy/Kconfig"
@@ -693,6 +705,7 @@ source "arch/mips/txx9/Kconfig"
source "arch/mips/vr41xx/Kconfig"
source "arch/mips/cavium-octeon/Kconfig"
source "arch/mips/loongson/Kconfig"
+source "arch/mips/xburst/Kconfig"
endmenu
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index 1893efd..f153e23 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -637,6 +637,13 @@ else
load-$(CONFIG_CPU_CAVIUM_OCTEON) += 0xffffffff81100000
endif
+#
+# Ingenic XBurst
+#
+core-$(CONFIG_XBURST) += arch/mips/xburst/
+cflags-$(CONFIG_XBURST) += -I$(srctree)/arch/mips/include/asm/mach-xburst
+load-$(CONFIG_XBURST) += 0xffffffff80010000
+
cflags-y += -I$(srctree)/arch/mips/include/asm/mach-generic
drivers-$(CONFIG_PCI) += arch/mips/pci/
@@ -711,7 +718,8 @@ vmlinux.32: vmlinux
vmlinux.64: vmlinux
$(OBJCOPY) -O $(64bit-bfd) $(OBJCOPYFLAGS) $< $@
-makeboot =$(Q)$(MAKE) $(build)=arch/mips/boot VMLINUX=$(vmlinux-32) $(1)
+makeboot =$(Q)$(MAKE) $(build)=arch/mips/boot VMLINUX=$(vmlinux-32) \
+ VMLINUX_LOAD_ADDRESS=$(load-y) $(1)
makezboot =$(Q)$(MAKE) $(build)=arch/mips/boot/compressed \
VMLINUX_LOAD_ADDRESS=$(load-y) 32bit-bfd=$(32bit-bfd) $(1)
@@ -738,6 +746,9 @@ vmlinux.ecoff: $(vmlinux-32)
vmlinux.srec: $(vmlinux-32)
+@$(call makeboot,$@)
+uImage: $(vmlinux-32)
+ +@$(call makeboot,$@)
+
CLEAN_FILES += vmlinux.ecoff \
vmlinux.srec
@@ -771,6 +782,7 @@ define archhelp
echo ' vmlinuz.ecoff - ECOFF zboot image'
echo ' vmlinuz.bin - Raw binary zboot image'
echo ' vmlinuz.srec - SREC zboot image'
+ echo ' uImage - U-Boot image'
echo
echo ' These will be default as apropriate for a configured platform.'
endef
diff --git a/arch/mips/boot/Makefile b/arch/mips/boot/Makefile
index e39a08e..5215534 100644
--- a/arch/mips/boot/Makefile
+++ b/arch/mips/boot/Makefile
@@ -24,6 +24,7 @@ drop-sections = .reginfo .mdebug .comment .note .pdr .options .MIPS.options
strip-flags = $(addprefix --remove-section=,$(drop-sections))
VMLINUX = vmlinux
+MKIMAGE := $(srctree)/scripts/mkuboot.sh
all: vmlinux.ecoff vmlinux.srec
@@ -39,7 +40,19 @@ vmlinux.bin: $(VMLINUX)
vmlinux.srec: $(VMLINUX)
$(OBJCOPY) -S -O srec $(strip-flags) $(VMLINUX) $(obj)/vmlinux.srec
+uImage: vmlinux.bin
+ rm -f $(obj)/vmlinux.bin.gz
+ gzip -9 $(obj)/vmlinux.bin
+ $(CONFIG_SHELL) $(MKIMAGE) \
+ -A mips -O linux -T kernel -C gzip \
+ -a $(VMLINUX_LOAD_ADDRESS) -e $(VMLINUX_LOAD_ADDRESS) \
+ -n 'Linux-$(KERNELRELEASE)' \
+ -d $(obj)/vmlinux.bin.gz \
+ $(obj)/uImage
+
clean-files += elf2ecoff \
vmlinux.bin \
+ vmlinux.bin.gz \
vmlinux.ecoff \
- vmlinux.srec
+ vmlinux.srec \
+ uImage
diff --git a/arch/mips/include/asm/bootinfo.h b/arch/mips/include/asm/bootinfo.h
index 09eee09..e21c0fb 100644
--- a/arch/mips/include/asm/bootinfo.h
+++ b/arch/mips/include/asm/bootinfo.h
@@ -71,6 +71,13 @@
#define MACH_LEMOTE_LL2F 7
#define MACH_LOONGSON_END 8
+/*
+ * Valid machtype for XBurst
+ */
+#define MACH_XBURST_UNKNOWN 0
+#define MACH_XBURST_JZ4730 1
+#define MACH_XBURST_JZ4740 2
+
extern char *system_type;
const char *get_system_type(void);
diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h
index cf373a9..dd91d72 100644
--- a/arch/mips/include/asm/cpu.h
+++ b/arch/mips/include/asm/cpu.h
@@ -34,6 +34,7 @@
#define PRID_COMP_LSI 0x080000
#define PRID_COMP_LEXRA 0x0b0000
#define PRID_COMP_CAVIUM 0x0d0000
+#define PRID_COMP_INGENIC 0xd00000
/*
@@ -133,6 +134,13 @@
#define PRID_IMP_CAVIUM_CN52XX 0x0700
/*
+ * These are the PRID's for when 23:16 == PRID_COMP_INGENIC
+ */
+
+#define PRID_IMP_XBURST 0x0200
+
+
+/*
* Definitions for 7:0 on legacy processors
*/
@@ -219,6 +227,7 @@ enum cpu_type_enum {
CPU_4KC, CPU_4KEC, CPU_4KSC, CPU_24K, CPU_34K, CPU_1004K, CPU_74K,
CPU_ALCHEMY, CPU_PR4450, CPU_BCM3302, CPU_BCM4710,
CPU_BCM6338, CPU_BCM6345, CPU_BCM6348, CPU_BCM6358,
+ CPU_XBURST,
/*
* MIPS64 class processors
diff --git a/arch/mips/include/asm/mach-generic/irq.h b/arch/mips/include/asm/mach-generic/irq.h
index 70d9a25..73b7a83 100644
--- a/arch/mips/include/asm/mach-generic/irq.h
+++ b/arch/mips/include/asm/mach-generic/irq.h
@@ -9,7 +9,7 @@
#define __ASM_MACH_GENERIC_IRQ_H
#ifndef NR_IRQS
-#define NR_IRQS 128
+#define NR_IRQS 256
#endif
#ifdef CONFIG_I8259
diff --git a/arch/mips/include/asm/mach-xburst/clock-jz4730.h b/arch/mips/include/asm/mach-xburst/clock-jz4730.h
new file mode 100644
index 0000000..884738c
--- /dev/null
+++ b/arch/mips/include/asm/mach-xburst/clock-jz4730.h
@@ -0,0 +1,41 @@
+/*
+ * JZ4730 clocks definition.
+ *
+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc.
+ *
+ * Author: <jlwei@ingenic.cn>
+ *
+ * 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_MACH_XBURST_CLOCK_JZ4730_H__
+#define __ASM_MACH_XBURST_CLOCK_JZ4730_H__
+
+/*
+ * JZ4730 clocks structure
+ */
+struct jz_clocks {
+ unsigned int extal;
+ unsigned int extal2;
+
+ unsigned int iclk; /* CPU core clock */
+ unsigned int sclk; /* AHB bus clock */
+ unsigned int mclk; /* Memory bus clock */
+ unsigned int pclk; /* APB bus clock */
+ unsigned int devclk; /* Devcie clock to specific modules */
+ unsigned int rtcclk; /* RTC module clock */
+ unsigned int uartclk; /* UART module clock */
+ unsigned int lcdclk; /* LCD module clock */
+ unsigned int pixclk; /* LCD pixel clock */
+ unsigned int usbclk; /* USB module clock */
+ unsigned int i2sclk; /* I2S module clock */
+ unsigned int mscclk; /* MMC/SD module clock */
+};
+
+extern struct jz_clocks jz_clocks;
+
+void jz_cpm_set_usbclk(int external);
+
+#endif /* __ASM_MACH_XBURST_CLOCK_JZ4730_H__ */
diff --git a/arch/mips/include/asm/mach-xburst/dma-jz4730.h b/arch/mips/include/asm/mach-xburst/dma-jz4730.h
new file mode 100644
index 0000000..d02b443
--- /dev/null
+++ b/arch/mips/include/asm/mach-xburst/dma-jz4730.h
@@ -0,0 +1,156 @@
+
+#ifndef __ASM_MACH_XBURST_DMA_JZ4730_H
+#define __ASM_MACH_XBURST_DMA_JZ4730_H
+
+#define DMAC_BASE 0xB3020000
+
+#define DMAC_DSAR(n) (DMAC_BASE + (0x00 + (n) * 0x20))
+#define DMAC_DDAR(n) (DMAC_BASE + (0x04 + (n) * 0x20))
+#define DMAC_DTCR(n) (DMAC_BASE + (0x08 + (n) * 0x20))
+#define DMAC_DRSR(n) (DMAC_BASE + (0x0c + (n) * 0x20))
+#define DMAC_DCCSR(n) (DMAC_BASE + (0x10 + (n) * 0x20))
+#define DMAC_DMAIPR (DMAC_BASE + 0xf8)
+#define DMAC_DMACR (DMAC_BASE + 0xfc)
+
+#define DMAC_DRSR_RS_BIT 0
+#define DMAC_DRSR_RS_MASK (0x1f << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_EXTREXTR (0 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_PCMCIAOUT (4 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_PCMCIAIN (5 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_AUTO (8 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_DESOUT (10 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_DESIN (11 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART3OUT (14 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART3IN (15 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART2OUT (16 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART2IN (17 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART1OUT (18 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART1IN (19 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART0OUT (20 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART0IN (21 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_SSIOUT (22 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_SSIIN (23 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_AICOUT (24 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_AICIN (25 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_MSCOUT (26 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_MSCIN (27 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_OST2 (28 << DMAC_DRSR_RS_BIT)
+
+#define DMAC_DCCSR_EACKS (1 << 31)
+#define DMAC_DCCSR_EACKM (1 << 30)
+#define DMAC_DCCSR_ERDM_BIT 28
+#define DMAC_DCCSR_ERDM_MASK (0x03 << DMAC_DCCSR_ERDM_BIT)
+ #define DMAC_DCCSR_ERDM_LLEVEL (0 << DMAC_DCCSR_ERDM_BIT)
+ #define DMAC_DCCSR_ERDM_FEDGE (1 << DMAC_DCCSR_ERDM_BIT)
+ #define DMAC_DCCSR_ERDM_HLEVEL (2 << DMAC_DCCSR_ERDM_BIT)
+ #define DMAC_DCCSR_ERDM_REDGE (3 << DMAC_DCCSR_ERDM_BIT)
+#define DMAC_DCCSR_EOPM (1 << 27)
+#define DMAC_DCCSR_SAM (1 << 23)
+#define DMAC_DCCSR_DAM (1 << 22)
+#define DMAC_DCCSR_RDIL_BIT 16
+#define DMAC_DCCSR_RDIL_MASK (0x0f << DMAC_DCCSR_RDIL_BIT)
+ #define DMAC_DCCSR_RDIL_IGN (0 << DMAC_DCCSR_RDIL_BIT)
+ #define DMAC_DCCSR_RDIL_2 (1 << DMAC_DCCSR_RDIL_BIT)
+ #define DMAC_DCCSR_RDIL_4 (2 << DMAC_DCCSR_RDIL_BIT)
+ #define DMAC_DCCSR_RDIL_8 (3 << DMAC_DCCSR_RDIL_BIT)
+ #define DMAC_DCCSR_RDIL_12 (4 << DMAC_DCCSR_RDIL_BIT)
+ #define DMAC_DCCSR_RDIL_16 (5 << DMAC_DCCSR_RDIL_BIT)
+ #define DMAC_DCCSR_RDIL_20 (6 << DMAC_DCCSR_RDIL_BIT)
+ #define DMAC_DCCSR_RDIL_24 (7 << DMAC_DCCSR_RDIL_BIT)
+ #define DMAC_DCCSR_RDIL_28 (8 << DMAC_DCCSR_RDIL_BIT)
+ #define DMAC_DCCSR_RDIL_32 (9 << DMAC_DCCSR_RDIL_BIT)
+ #define DMAC_DCCSR_RDIL_48 (10 << DMAC_DCCSR_RDIL_BIT)
+ #define DMAC_DCCSR_RDIL_60 (11 << DMAC_DCCSR_RDIL_BIT)
+ #define DMAC_DCCSR_RDIL_64 (12 << DMAC_DCCSR_RDIL_BIT)
+ #define DMAC_DCCSR_RDIL_124 (13 << DMAC_DCCSR_RDIL_BIT)
+ #define DMAC_DCCSR_RDIL_128 (14 << DMAC_DCCSR_RDIL_BIT)
+ #define DMAC_DCCSR_RDIL_200 (15 << DMAC_DCCSR_RDIL_BIT)
+#define DMAC_DCCSR_SWDH_BIT 14
+#define DMAC_DCCSR_SWDH_MASK (0x03 << DMAC_DCCSR_SWDH_BIT)
+ #define DMAC_DCCSR_SWDH_32 (0 << DMAC_DCCSR_SWDH_BIT)
+ #define DMAC_DCCSR_SWDH_8 (1 << DMAC_DCCSR_SWDH_BIT)
+ #define DMAC_DCCSR_SWDH_16 (2 << DMAC_DCCSR_SWDH_BIT)
+#define DMAC_DCCSR_DWDH_BIT 12
+#define DMAC_DCCSR_DWDH_MASK (0x03 << DMAC_DCCSR_DWDH_BIT)
+ #define DMAC_DCCSR_DWDH_32 (0 << DMAC_DCCSR_DWDH_BIT)
+ #define DMAC_DCCSR_DWDH_8 (1 << DMAC_DCCSR_DWDH_BIT)
+ #define DMAC_DCCSR_DWDH_16 (2 << DMAC_DCCSR_DWDH_BIT)
+#define DMAC_DCCSR_DS_BIT 8
+#define DMAC_DCCSR_DS_MASK (0x07 << DMAC_DCCSR_DS_BIT)
+ #define DMAC_DCCSR_DS_32b (0 << DMAC_DCCSR_DS_BIT)
+ #define DMAC_DCCSR_DS_8b (1 << DMAC_DCCSR_DS_BIT)
+ #define DMAC_DCCSR_DS_16b (2 << DMAC_DCCSR_DS_BIT)
+ #define DMAC_DCCSR_DS_16B (3 << DMAC_DCCSR_DS_BIT)
+ #define DMAC_DCCSR_DS_32B (4 << DMAC_DCCSR_DS_BIT)
+#define DMAC_DCCSR_TM (1 << 7)
+#define DMAC_DCCSR_AR (1 << 4)
+#define DMAC_DCCSR_TC (1 << 3)
+#define DMAC_DCCSR_HLT (1 << 2)
+#define DMAC_DCCSR_TCIE (1 << 1)
+#define DMAC_DCCSR_CHDE (1 << 0)
+
+#define DMAC_DMAIPR_CINT_BIT 8
+#define DMAC_DMAIPR_CINT_MASK (0xff << DMAC_DMAIPR_CINT_BIT)
+
+#define DMAC_DMACR_PR_BIT 8
+#define DMAC_DMACR_PR_MASK (0x03 << DMAC_DMACR_PR_BIT)
+ #define DMAC_DMACR_PR_01234567 (0 << DMAC_DMACR_PR_BIT)
+ #define DMAC_DMACR_PR_02314675 (1 << DMAC_DMACR_PR_BIT)
+ #define DMAC_DMACR_PR_20136457 (2 << DMAC_DMACR_PR_BIT)
+ #define DMAC_DMACR_PR_ROUNDROBIN (3 << DMAC_DMACR_PR_BIT)
+#define DMAC_DMACR_HTR (1 << 3)
+#define DMAC_DMACR_AER (1 << 2)
+#define DMAC_DMACR_DME (1 << 0)
+
+#define IRQ_DMA_0 32
+#define NUM_DMA 6
+
+#define DMAC_DSAR0 DMAC_DSAR(0)
+#define DMAC_DDAR0 DMAC_DDAR(0)
+#define DMAC_DTCR0 DMAC_DTCR(0)
+#define DMAC_DRSR0 DMAC_DRSR(0)
+#define DMAC_DCCSR0 DMAC_DCCSR(0)
+
+#define DMAC_DSAR1 DMAC_DSAR(1)
+#define DMAC_DDAR1 DMAC_DDAR(1)
+#define DMAC_DTCR1 DMAC_DTCR(1)
+#define DMAC_DRSR1 DMAC_DRSR(1)
+#define DMAC_DCCSR1 DMAC_DCCSR(1)
+
+#define DMAC_DSAR2 DMAC_DSAR(2)
+#define DMAC_DDAR2 DMAC_DDAR(2)
+#define DMAC_DTCR2 DMAC_DTCR(2)
+#define DMAC_DRSR2 DMAC_DRSR(2)
+#define DMAC_DCCSR2 DMAC_DCCSR(2)
+
+#define DMAC_DSAR3 DMAC_DSAR(3)
+#define DMAC_DDAR3 DMAC_DDAR(3)
+#define DMAC_DTCR3 DMAC_DTCR(3)
+#define DMAC_DRSR3 DMAC_DRSR(3)
+#define DMAC_DCCSR3 DMAC_DCCSR(3)
+
+#define DMAC_DSAR4 DMAC_DSAR(4)
+#define DMAC_DDAR4 DMAC_DDAR(4)
+#define DMAC_DTCR4 DMAC_DTCR(4)
+#define DMAC_DRSR4 DMAC_DRSR(4)
+#define DMAC_DCCSR4 DMAC_DCCSR(4)
+
+#define DMAC_DSAR5 DMAC_DSAR(5)
+#define DMAC_DDAR5 DMAC_DDAR(5)
+#define DMAC_DTCR5 DMAC_DTCR(5)
+#define DMAC_DRSR5 DMAC_DRSR(5)
+#define DMAC_DCCSR5 DMAC_DCCSR(5)
+
+#define DMAC_DSAR6 DMAC_DSAR(6)
+#define DMAC_DDAR6 DMAC_DDAR(6)
+#define DMAC_DTCR6 DMAC_DTCR(6)
+#define DMAC_DRSR6 DMAC_DRSR(6)
+#define DMAC_DCCSR6 DMAC_DCCSR(6)
+
+#define DMAC_DSAR7 DMAC_DSAR(7)
+#define DMAC_DDAR7 DMAC_DDAR(7)
+#define DMAC_DTCR7 DMAC_DTCR(7)
+#define DMAC_DRSR7 DMAC_DRSR(7)
+#define DMAC_DCCSR7 DMAC_DCCSR(7)
+
+#endif /* __ASM_MACH_XBURST_DMA_JZ4730_H */
diff --git a/arch/mips/include/asm/mach-xburst/irq-jz4730.h b/arch/mips/include/asm/mach-xburst/irq-jz4730.h
new file mode 100644
index 0000000..087b99e
--- /dev/null
+++ b/arch/mips/include/asm/mach-xburst/irq-jz4730.h
@@ -0,0 +1,33 @@
+#ifndef __ASM_MACH_XBURST_IRQ_JZ4730_H
+#define __ASM_MACH_XBURST_IRQ_JZ4730_H
+
+#define IRQ_I2C 1
+#define IRQ_PS2 2
+#define IRQ_UPRT 3
+#define IRQ_CORE 4
+#define IRQ_UART3 6
+#define IRQ_UART2 7
+#define IRQ_UART1 8
+#define IRQ_UART0 9
+#define IRQ_SCC1 10
+#define IRQ_SCC0 11
+#define IRQ_UDC 12
+#define IRQ_UHC 13
+#define IRQ_MSC 14
+#define IRQ_RTC 15
+#define IRQ_FIR 16
+#define IRQ_SSI 17
+#define IRQ_CIM 18
+#define IRQ_ETH 19
+#define IRQ_AIC 20
+#define IRQ_DMAC 21
+#define IRQ_OST2 22
+#define IRQ_OST1 23
+#define IRQ_OST0 24
+#define IRQ_GPIO3 25
+#define IRQ_GPIO2 26
+#define IRQ_GPIO1 27
+#define IRQ_GPIO0 28
+#define IRQ_LCD 30
+
+#endif /* __ASM_MACH_XBURST_IRQ_JZ4730_H */
diff --git a/arch/mips/include/asm/mach-xburst/uart-jz4730.h b/arch/mips/include/asm/mach-xburst/uart-jz4730.h
new file mode 100644
index 0000000..f7f6fcd
--- /dev/null
+++ b/arch/mips/include/asm/mach-xburst/uart-jz4730.h
@@ -0,0 +1,141 @@
+/*
+ * UART registers for jz4730.
+ *
+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor 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_MACH_XBURST_UART_JZ4730_H
+#define __ASM_MACH_XBURST_UART_JZ4730_H
+
+#define UART0_BASE 0xB0030000
+#define UART1_BASE 0xB0031000
+#define UART2_BASE 0xB0032000
+#define UART3_BASE 0xB0033000
+
+/* register offset */
+#define OFF_RDR 0x00 /* R 8b H'xx */
+#define OFF_TDR 0x00 /* W 8b H'xx */
+#define OFF_DLLR 0x00 /* RW 8b H'00 */
+#define OFF_DLHR 0x04 /* RW 8b H'00 */
+#define OFF_IER 0x04 /* RW 8b H'00 */
+#define OFF_ISR 0x08 /* R 8b H'01 */
+#define OFF_FCR 0x08 /* W 8b H'00 */
+#define OFF_LCR 0x0C /* RW 8b H'00 */
+#define OFF_MCR 0x10 /* RW 8b H'00 */
+#define OFF_LSR 0x14 /* R 8b H'00 */
+#define OFF_MSR 0x18 /* R 8b H'00 */
+#define OFF_SPR 0x1C /* RW 8b H'00 */
+#define OFF_MCR 0x10 /* RW 8b H'00 */
+#define OFF_SIRCR 0x20 /* RW 8b H'00, UART0 */
+
+/*
+ * Define macros for UARTIER
+ * UART Interrupt Enable Register
+ */
+#define UARTIER_RIE (1 << 0) /* 0: receive fifo "full" interrupt disable */
+#define UARTIER_TIE (1 << 1) /* 0: transmit fifo "empty" interrupt disable */
+#define UARTIER_RLIE (1 << 2) /* 0: receive line status interrupt disable */
+#define UARTIER_MIE (1 << 3) /* 0: modem status interrupt disable */
+#define UARTIER_RTIE (1 << 4) /* 0: receive timeout interrupt disable */
+
+/*
+ * Define macros for UARTISR
+ * UART Interrupt Status Register
+ */
+#define UARTISR_IP (1 << 0) /* 0: interrupt is pending 1: no interrupt */
+#define UARTISR_IID (7 << 1) /* Source of Interrupt */
+#define UARTISR_IID_MSI (0 << 1) /* Modem status interrupt */
+#define UARTISR_IID_THRI (1 << 1) /* Transmitter holding register empty */
+#define UARTISR_IID_RDI (2 << 1) /* Receiver data interrupt */
+#define UARTISR_IID_RLSI (3 << 1) /* Receiver line status interrupt */
+#define UARTISR_FFMS (3 << 6) /* FIFO mode select, set when UARTFCR.FE is set to 1 */
+#define UARTISR_FFMS_NO_FIFO (0 << 6)
+#define UARTISR_FFMS_FIFO_MODE (3 << 6)
+
+/*
+ * Define macros for UARTFCR
+ * UART FIFO Control Register
+ */
+#define UARTFCR_FE (1 << 0) /* 0: non-FIFO mode 1: FIFO mode */
+#define UARTFCR_RFLS (1 << 1) /* write 1 to flush receive FIFO */
+#define UARTFCR_TFLS (1 << 2) /* write 1 to flush transmit FIFO */
+#define UARTFCR_DMS (1 << 3) /* 0: disable DMA mode */
+#define UARTFCR_UUE (1 << 4) /* 0: disable UART */
+#define UARTFCR_RTRG (3 << 6) /* Receive FIFO Data Trigger */
+#define UARTFCR_RTRG_1 (0 << 6)
+#define UARTFCR_RTRG_4 (1 << 6)
+#define UARTFCR_RTRG_8 (2 << 6)
+#define UARTFCR_RTRG_15 (3 << 6)
+
+/*
+ * Define macros for UARTLCR
+ * UART Line Control Register
+ */
+#define UARTLCR_WLEN (3 << 0) /* word length */
+#define UARTLCR_WLEN_5 (0 << 0)
+#define UARTLCR_WLEN_6 (1 << 0)
+#define UARTLCR_WLEN_7 (2 << 0)
+#define UARTLCR_WLEN_8 (3 << 0)
+#define UARTLCR_STOP (1 << 2) /* 0: 1 stop bit when word length is 5,6,7,8
+ 1: 1.5 stop bits when 5; 2 stop bits when 6,7,8 */
+#define UARTLCR_PE (1 << 3) /* 0: parity disable */
+#define UARTLCR_PROE (1 << 4) /* 0: even parity 1: odd parity */
+#define UARTLCR_SPAR (1 << 5) /* 0: sticky parity disable */
+#define UARTLCR_SBRK (1 << 6) /* write 0 normal, write 1 send break */
+#define UARTLCR_DLAB (1 << 7) /* 0: access UARTRDR/TDR/IER 1: access UARTDLLR/DLHR */
+
+/*
+ * Define macros for UARTLSR
+ * UART Line Status Register
+ */
+#define UARTLSR_DR (1 << 0) /* 0: receive FIFO is empty 1: receive data is ready */
+#define UARTLSR_ORER (1 << 1) /* 0: no overrun error */
+#define UARTLSR_PER (1 << 2) /* 0: no parity error */
+#define UARTLSR_FER (1 << 3) /* 0; no framing error */
+#define UARTLSR_BRK (1 << 4) /* 0: no break detected 1: receive a break signal */
+#define UARTLSR_TDRQ (1 << 5) /* 1: transmit FIFO half "empty" */
+#define UARTLSR_TEMT (1 << 6) /* 1: transmit FIFO and shift registers empty */
+#define UARTLSR_RFER (1 << 7) /* 0: no receive error 1: receive error in FIFO mode */
+
+/*
+ * Define macros for UARTMCR
+ * UART Modem Control Register
+ */
+#define UARTMCR_DTR (1 << 0) /* 0: DTR_ ouput high */
+#define UARTMCR_RTS (1 << 1) /* 0: RTS_ output high */
+#define UARTMCR_OUT1 (1 << 2) /* 0: UARTMSR.RI is set to 0 and RI_ input high */
+#define UARTMCR_OUT2 (1 << 3) /* 0: UARTMSR.DCD is set to 0 and DCD_ input high */
+#define UARTMCR_LOOP (1 << 4) /* 0: normal 1: loopback mode */
+#define UARTMCR_MCE (1 << 7) /* 0: modem function is disable */
+
+/*
+ * Define macros for UARTMSR
+ * UART Modem Status Register
+ */
+#define UARTMSR_DCTS (1 << 0) /* 0: no change on CTS_ pin since last read of UARTMSR */
+#define UARTMSR_DDSR (1 << 1) /* 0: no change on DSR_ pin since last read of UARTMSR */
+#define UARTMSR_DRI (1 << 2) /* 0: no change on RI_ pin since last read of UARTMSR */
+#define UARTMSR_DDCD (1 << 3) /* 0: no change on DCD_ pin since last read of UARTMSR */
+#define UARTMSR_CTS (1 << 4) /* 0: CTS_ pin is high */
+#define UARTMSR_DSR (1 << 5) /* 0: DSR_ pin is high */
+#define UARTMSR_RI (1 << 6) /* 0: RI_ pin is high */
+#define UARTMSR_DCD (1 << 7) /* 0: DCD_ pin is high */
+
+/*
+ * Define macros for SIRCR
+ * Slow IrDA Control Register
+ */
+#define SIRCR_TSIRE (1 << 0) /* 0: transmitter is in UART mode 1: IrDA mode */
+#define SIRCR_RSIRE (1 << 1) /* 0: receiver is in UART mode 1: IrDA mode */
+#define SIRCR_TPWS (1 << 2) /* 0: transmit 0 pulse width is 3/16 of bit length
+ 1: 0 pulse width is 1.6us for 115.2Kbps */
+#define SIRCR_TXPL (1 << 3) /* 0: encoder generates a positive pulse for 0 */
+#define SIRCR_RXPL (1 << 4) /* 0: decoder interprets positive pulse as 0 */
+
+
+
+#endif /* __ASM_MACH_XBURST_UART_JZ4730_H */
diff --git a/arch/mips/include/asm/mach-xburst/war.h b/arch/mips/include/asm/mach-xburst/war.h
new file mode 100644
index 0000000..5acdf58
--- /dev/null
+++ b/arch/mips/include/asm/mach-xburst/war.h
@@ -0,0 +1,25 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2002, 2004, 2007 by Ralf Baechle <ralf@linux-mips.org>
+ */
+#ifndef __ASM_MACH_XBURST_WAR_H
+#define __ASM_MACH_XBURST_WAR_H
+
+#define R4600_V1_INDEX_ICACHEOP_WAR 0
+#define R4600_V1_HIT_CACHEOP_WAR 0
+#define R4600_V2_HIT_CACHEOP_WAR 0
+#define R5432_CP0_INTERRUPT_WAR 0
+#define BCM1250_M3_WAR 0
+#define SIBYTE_1956_WAR 0
+#define MIPS4K_ICACHE_REFILL_WAR 0
+#define MIPS_CACHE_SYNC_WAR 0
+#define TX49XX_ICACHE_INDEX_INV_WAR 0
+#define RM9000_CDEX_SMP_WAR 0
+#define ICACHE_REFILLS_WORKAROUND_WAR 0
+#define R10000_LLSC_WAR 0
+#define MIPS34K_MISSED_ITLB_WAR 0
+
+#endif /* __ASM_MACH_XBURST_WAR_H */
diff --git a/arch/mips/include/asm/mach-xburst/xburst.h b/arch/mips/include/asm/mach-xburst/xburst.h
new file mode 100644
index 0000000..4b2c40c
--- /dev/null
+++ b/arch/mips/include/asm/mach-xburst/xburst.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2010 Ubiq Technologies <graham.gower@gmail.com>
+ *
+ * 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_XBURST_H
+#define __ASM_XBURST_H
+
+#ifdef CONFIG_XBURST_JZ4730
+#include "clock-jz4730.h"
+#include "irq-jz4730.h"
+#include "uart-jz4730.h"
+#endif
+
+void jz_usb0_set_function(int host);
+
+#endif /* __ASM_XBURST_H */
diff --git a/arch/mips/include/asm/r4kcache.h b/arch/mips/include/asm/r4kcache.h
index 387bf59..f0bb7c3 100644
--- a/arch/mips/include/asm/r4kcache.h
+++ b/arch/mips/include/asm/r4kcache.h
@@ -17,6 +17,59 @@
#include <asm/cpu-features.h>
#include <asm/mipsmtregs.h>
+#ifdef CONFIG_XBURST
+
+#define K0_TO_K1() \
+do { \
+ unsigned long __k0_addr; \
+ \
+ __asm__ __volatile__( \
+ "la %0, 1f\n\t" \
+ "or %0, %0, %1\n\t" \
+ "jr %0\n\t" \
+ "nop\n\t" \
+ "1: nop\n" \
+ : "=&r"(__k0_addr) \
+ : "r" (0x20000000) ); \
+} while(0)
+
+#define K1_TO_K0() \
+do { \
+ unsigned long __k0_addr; \
+ __asm__ __volatile__( \
+ "nop;nop;nop;nop;nop;nop;nop\n\t" \
+ "la %0, 1f\n\t" \
+ "jr %0\n\t" \
+ "nop\n\t" \
+ "1: nop\n" \
+ : "=&r" (__k0_addr)); \
+} while (0)
+
+#define INVALIDATE_BTB() \
+do { \
+ unsigned long tmp; \
+ __asm__ __volatile__( \
+ ".set mips32\n\t" \
+ "mfc0 %0, $16, 7\n\t" \
+ "nop\n\t" \
+ "ori %0, 2\n\t" \
+ "mtc0 %0, $16, 7\n\t" \
+ "nop\n\t" \
+ : "=&r" (tmp)); \
+} while (0)
+
+#define SYNC_WB() __asm__ __volatile__ ("sync")
+
+#else /* CONFIG_XBURST */
+
+#define K0_TO_K1() do { } while (0)
+#define K1_TO_K0() do { } while (0)
+#define INVALIDATE_BTB() do { } while (0)
+#define SYNC_WB() do { } while (0)
+
+#endif /* CONFIG_XBURST */
+
+
/*
* This macro return a properly sign-extended address suitable as base address
* for indexed cache operations. Two issues here:
@@ -144,6 +197,7 @@ static inline void flush_icache_line_indexed(unsigned long addr)
{
__iflush_prologue
cache_op(Index_Invalidate_I, addr);
+ INVALIDATE_BTB();
__iflush_epilogue
}
@@ -151,6 +205,7 @@ static inline void flush_dcache_line_indexed(unsigned long addr)
{
__dflush_prologue
cache_op(Index_Writeback_Inv_D, addr);
+ SYNC_WB();
__dflush_epilogue
}
@@ -163,6 +218,7 @@ static inline void flush_icache_line(unsigned long addr)
{
__iflush_prologue
cache_op(Hit_Invalidate_I, addr);
+ INVALIDATE_BTB();
__iflush_epilogue
}
@@ -170,6 +226,7 @@ static inline void flush_dcache_line(unsigned long addr)
{
__dflush_prologue
cache_op(Hit_Writeback_Inv_D, addr);
+ SYNC_WB();
__dflush_epilogue
}
@@ -177,6 +234,7 @@ static inline void invalidate_dcache_line(unsigned long addr)
{
__dflush_prologue
cache_op(Hit_Invalidate_D, addr);
+ SYNC_WB();
__dflush_epilogue
}
@@ -209,6 +267,7 @@ static inline void flush_scache_line(unsigned long addr)
static inline void protected_flush_icache_line(unsigned long addr)
{
protected_cache_op(Hit_Invalidate_I, addr);
+ INVALIDATE_BTB();
}
/*
@@ -220,6 +279,7 @@ static inline void protected_flush_icache_line(unsigned long addr)
static inline void protected_writeback_dcache_line(unsigned long addr)
{
protected_cache_op(Hit_Writeback_Inv_D, addr);
+ SYNC_WB();
}
static inline void protected_writeback_scache_line(unsigned long addr)
@@ -396,8 +456,12 @@ static inline void blast_##pfx##cache##lsize##_page_indexed(unsigned long page)
__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 16)
__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 16)
__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 16)
+
+#ifndef CONFIG_XBURST
__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 32)
__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 32)
+#endif
+
__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 32)
__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 64)
__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 64)
@@ -405,12 +469,124 @@ __BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 64)
__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 128)
__BUILD_BLAST_CACHE(inv_d, dcache, Index_Writeback_Inv_D, Hit_Invalidate_D, 16)
+
+#ifndef CONFIG_XBURST
__BUILD_BLAST_CACHE(inv_d, dcache, Index_Writeback_Inv_D, Hit_Invalidate_D, 32)
+#endif
+
__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 16)
__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 32)
__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 64)
__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 128)
+#ifdef CONFIG_XBURST
+
+static inline void blast_dcache32(void)
+{
+ unsigned long start = INDEX_BASE;
+ unsigned long end = start + current_cpu_data.dcache.waysize;
+ unsigned long ws_inc = 1UL << current_cpu_data.dcache.waybit;
+ unsigned long ws_end = current_cpu_data.dcache.ways <<
+ current_cpu_data.dcache.waybit;
+ unsigned long ws, addr;
+
+ for (ws = 0; ws < ws_end; ws += ws_inc)
+ for (addr = start; addr < end; addr += 0x400)
+ cache32_unroll32(addr|ws,Index_Writeback_Inv_D);
+
+ SYNC_WB();
+}
+
+static inline void blast_dcache32_page(unsigned long page)
+{
+ unsigned long start = page;
+ unsigned long end = page + PAGE_SIZE;
+
+ do {
+ cache32_unroll32(start,Hit_Writeback_Inv_D);
+ start += 0x400;
+ } while (start < end);
+
+ SYNC_WB();
+}
+
+static inline void blast_dcache32_page_indexed(unsigned long page)
+{
+ unsigned long indexmask = current_cpu_data.dcache.waysize - 1;
+ unsigned long start = INDEX_BASE + (page & indexmask);
+ unsigned long end = start + PAGE_SIZE;
+ unsigned long ws_inc = 1UL << current_cpu_data.dcache.waybit;
+ unsigned long ws_end = current_cpu_data.dcache.ways <<
+ current_cpu_data.dcache.waybit;
+ unsigned long ws, addr;
+
+ for (ws = 0; ws < ws_end; ws += ws_inc)
+ for (addr = start; addr < end; addr += 0x400)
+ cache32_unroll32(addr|ws,Index_Writeback_Inv_D);
+
+ SYNC_WB();
+}
+
+static inline void blast_icache32(void)
+{
+ unsigned long start = INDEX_BASE;
+ unsigned long end = start + current_cpu_data.icache.waysize;
+ unsigned long ws_inc = 1UL << current_cpu_data.icache.waybit;
+ unsigned long ws_end = current_cpu_data.icache.ways <<
+ current_cpu_data.icache.waybit;
+ unsigned long ws, addr;
+
+ K0_TO_K1();
+
+ for (ws = 0; ws < ws_end; ws += ws_inc)
+ for (addr = start; addr < end; addr += 0x400)
+ cache32_unroll32(addr|ws,Index_Invalidate_I);
+
+ INVALIDATE_BTB();
+
+ K1_TO_K0();
+}
+
+static inline void blast_icache32_page(unsigned long page)
+{
+ unsigned long start = page;
+ unsigned long end = page + PAGE_SIZE;
+
+ K0_TO_K1();
+
+ do {
+ cache32_unroll32(start,Hit_Invalidate_I);
+ start += 0x400;
+ } while (start < end);
+
+ INVALIDATE_BTB();
+
+ K1_TO_K0();
+}
+
+static inline void blast_icache32_page_indexed(unsigned long page)
+{
+ unsigned long indexmask = current_cpu_data.icache.waysize - 1;
+ unsigned long start = INDEX_BASE + (page & indexmask);
+ unsigned long end = start + PAGE_SIZE;
+ unsigned long ws_inc = 1UL << current_cpu_data.icache.waybit;
+ unsigned long ws_end = current_cpu_data.icache.ways <<
+ current_cpu_data.icache.waybit;
+ unsigned long ws, addr;
+
+ K0_TO_K1();
+
+ for (ws = 0; ws < ws_end; ws += ws_inc)
+ for (addr = start; addr < end; addr += 0x400)
+ cache32_unroll32(addr|ws,Index_Invalidate_I);
+
+ INVALIDATE_BTB();
+
+ K1_TO_K0();
+}
+
+#endif /* CONFIG_XBURST */
+
/* build blast_xxx_range, protected_blast_xxx_range */
#define __BUILD_BLAST_CACHE_RANGE(pfx, desc, hitop, prot) \
static inline void prot##blast_##pfx##cache##_range(unsigned long start, \
@@ -432,13 +608,77 @@ static inline void prot##blast_##pfx##cache##_range(unsigned long start, \
__##pfx##flush_epilogue \
}
+#ifndef CONFIG_XBURST
__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, protected_)
+#endif
+
__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, protected_)
+
+#ifndef CONFIG_XBURST
__BUILD_BLAST_CACHE_RANGE(i, icache, Hit_Invalidate_I, protected_)
__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, )
+#endif
+
__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, )
/* blast_inv_dcache_range */
__BUILD_BLAST_CACHE_RANGE(inv_d, dcache, Hit_Invalidate_D, )
__BUILD_BLAST_CACHE_RANGE(inv_s, scache, Hit_Invalidate_SD, )
+
+#ifdef CONFIG_XBURST
+
+static inline void protected_blast_dcache_range(unsigned long start,
+ unsigned long end)
+{
+ unsigned long lsize = cpu_dcache_line_size();
+ unsigned long addr = start & ~(lsize - 1);
+ unsigned long aend = (end - 1) & ~(lsize - 1);
+
+ while (1) {
+ protected_cache_op(Hit_Writeback_Inv_D, addr);
+ if (addr == aend)
+ break;
+ addr += lsize;
+ }
+ SYNC_WB();
+}
+
+static inline void protected_blast_icache_range(unsigned long start,
+ unsigned long end)
+{
+ unsigned long lsize = cpu_icache_line_size();
+ unsigned long addr = start & ~(lsize - 1);
+ unsigned long aend = (end - 1) & ~(lsize - 1);
+
+ K0_TO_K1();
+
+ while (1) {
+ protected_cache_op(Hit_Invalidate_I, addr);
+ if (addr == aend)
+ break;
+ addr += lsize;
+ }
+ INVALIDATE_BTB();
+
+ K1_TO_K0();
+}
+
+static inline void blast_dcache_range(unsigned long start,
+ unsigned long end)
+{
+ unsigned long lsize = cpu_dcache_line_size();
+ unsigned long addr = start & ~(lsize - 1);
+ unsigned long aend = (end - 1) & ~(lsize - 1);
+
+ while (1) {
+ cache_op(Hit_Writeback_Inv_D, addr);
+ if (addr == aend)
+ break;
+ addr += lsize;
+ }
+ SYNC_WB();
+}
+
+#endif /* CONFIG_XBURST */
+
#endif /* _ASM_R4KCACHE_H */
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index 758ad42..89a9468 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -162,6 +162,7 @@ void __init check_wait(void)
case CPU_BCM6348:
case CPU_BCM6358:
case CPU_CAVIUM_OCTEON:
+ case CPU_XBURST:
cpu_wait = r4k_wait;
break;
@@ -913,6 +914,23 @@ static inline void cpu_probe_cavium(struct cpuinfo_mips *c, unsigned int cpu)
}
}
+static inline void cpu_probe_ingenic(struct cpuinfo_mips *c, unsigned int cpu)
+{
+ decode_configs(c);
+ c->options &= ~MIPS_CPU_COUNTER; /* XBurst has no CP0 counter. */
+ switch (c->processor_id & 0xff00) {
+ case PRID_IMP_XBURST:
+ c->cputype = CPU_XBURST;
+ c->isa_level = MIPS_CPU_ISA_M32R1;
+ c->tlbsize = 32;
+ __cpu_name[cpu] = "Ingenic XBurst";
+ break;
+ default:
+ panic("Unknown Ingenic Processor ID!");
+ break;
+ }
+}
+
const char *__cpu_name[NR_CPUS];
__cpuinit void cpu_probe(void)
@@ -950,6 +968,9 @@ __cpuinit void cpu_probe(void)
case PRID_COMP_CAVIUM:
cpu_probe_cavium(c, cpu);
break;
+ case PRID_COMP_INGENIC:
+ cpu_probe_ingenic(c, cpu);
+ break;
}
BUG_ON(!__cpu_name[cpu]);
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
index 6721ee2..8cae4e3 100644
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -928,6 +928,36 @@ static void __cpuinit probe_pcache(void)
c->dcache.waybit = 0;
break;
+ case CPU_XBURST:
+ config1 = read_c0_config1();
+ config1 = (config1 >> 22) & 0x07;
+ if (config1 == 0x07)
+ config1 = 10;
+ else
+ config1 = config1 + 11;
+ config1 += 2;
+ icache_size = (1 << config1);
+ c->icache.linesz = 32;
+ c->icache.ways = 4;
+ c->icache.waybit = __ffs(icache_size / c->icache.ways);
+
+ config1 = read_c0_config1();
+ config1 = (config1 >> 13) & 0x07;
+ if (config1 == 0x07)
+ config1 = 10;
+ else
+ config1 = config1 + 11;
+ config1 += 2;
+ dcache_size = (1 << config1);
+ c->dcache.linesz = 32;
+ c->dcache.ways = 4;
+ c->dcache.waybit = __ffs(dcache_size / c->dcache.ways);
+
+ c->dcache.flags = 0;
+ c->options |= MIPS_CPU_PREFETCH;
+
+ break;
+
default:
if (!(config & MIPS_CONF_M))
panic("Don't know how to probe P-caches on this cpu.");
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index badcf5e..34ef8c9 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -390,6 +390,11 @@ static void __cpuinit build_tlb_write_entry(u32 **p, struct uasm_label **l,
tlbw(p);
break;
+ case CPU_XBURST:
+ tlbw(p);
+ uasm_i_nop(p);
+ break;
+
default:
panic("No TLB refill handler yet (CPU type: %d)",
current_cpu_data.cputype);
diff --git a/arch/mips/xburst/Kconfig b/arch/mips/xburst/Kconfig
new file mode 100644
index 0000000..fc12741
--- /dev/null
+++ b/arch/mips/xburst/Kconfig
@@ -0,0 +1,23 @@
+choice
+ prompt "XBurst SoC Type"
+ depends on XBURST
+
+config XBURST_JZ4730
+ bool "Ingenic JZ4730"
+
+#config XBURST_JZ4740
+# bool "Ingenic JZ4740"
+
+endchoice
+
+choice
+ prompt "JZ4730 board"
+ depends on XBURST_JZ4730
+
+config JZ4730_PMP
+ bool "Ingenic PMP reference board"
+
+config JZ4730_LIBRA
+ bool "Ingenic Libra dev board"
+
+endchoice
diff --git a/arch/mips/xburst/Makefile b/arch/mips/xburst/Makefile
new file mode 100644
index 0000000..a96d462
--- /dev/null
+++ b/arch/mips/xburst/Makefile
@@ -0,0 +1,3 @@
+#
+# jz4730 SoC based systems
+obj-$(CONFIG_XBURST_JZ4730) += jz4730/
diff --git a/arch/mips/xburst/jz4730/Makefile b/arch/mips/xburst/jz4730/Makefile
new file mode 100644
index 0000000..100c64b
--- /dev/null
+++ b/arch/mips/xburst/jz4730/Makefile
@@ -0,0 +1,11 @@
+#
+# JZ4730 SoC based systems.
+#
+
+obj-y += irq.o prom.o setup.o time.o clocks.o platform.o
+
+# Ingenic's Libra dev board
+obj-$(CONFIG_JZ4730_LIBRA) += board-libra.o
+
+# Ingenic's Portable Media Player reference platform
+obj-$(CONFIG_JZ4730_PMP) += board-pmp.o
diff --git a/arch/mips/xburst/jz4730/board-libra.c b/arch/mips/xburst/jz4730/board-libra.c
new file mode 100644
index 0000000..795bdd5
--- /dev/null
+++ b/arch/mips/xburst/jz4730/board-libra.c
@@ -0,0 +1,32 @@
+/*
+ * board-libra.c
+ *
+ * Copyright (C) 2010 Ubiq Technologies <graham.gower@gmail.com>
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <xburst.h>
+
+void __init
+jz_board_get_extal(struct jz_clocks *cks)
+{
+ cks->extal = 3686400; /* 3.6864 MHz */
+ cks->extal2 = 32768; /* 32.768 KHz */
+}
+
+void __init
+jz_board_setup(void)
+{
+ /*
+ * USB is much more reliable using the external USB clock,
+ * not the PLL divider.
+ */
+ jz_cpm_set_usbclk(1);
+
+ /* USB0 as host. */
+ jz_usb0_set_function(1);
+}
diff --git a/arch/mips/xburst/jz4730/board-pmp.c b/arch/mips/xburst/jz4730/board-pmp.c
new file mode 100644
index 0000000..90c5692
--- /dev/null
+++ b/arch/mips/xburst/jz4730/board-pmp.c
@@ -0,0 +1,32 @@
+/*
+ * board-pmp.c
+ *
+ * Copyright (C) 2010 Ubiq Technologies <graham.gower@gmail.com>
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <xburst.h>
+
+void __init
+jz_board_get_extal(struct jz_clocks *cks)
+{
+ cks->extal = 12000000; /* 12 MHz */
+ cks->extal2 = 32768; /* 32.768 KHz */
+}
+
+void __init
+jz_board_setup(void)
+{
+ /*
+ * USB is much more reliable using the external USB clock,
+ * not the PLL divider.
+ */
+ jz_cpm_set_usbclk(1);
+
+ /* USB0 as device. */
+ jz_usb0_set_function(0);
+}
diff --git a/arch/mips/xburst/jz4730/clocks.c b/arch/mips/xburst/jz4730/clocks.c
new file mode 100644
index 0000000..abc887f
--- /dev/null
+++ b/arch/mips/xburst/jz4730/clocks.c
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2010 Ubiq Technologies <graham.gower@gmail.com>
+ *
+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc.
+ * Author: <jlwei@ingenic.cn>
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <xburst.h>
+
+extern void __init jz_board_get_extal(struct jz_clocks *);
+
+struct jz_clocks jz_clocks;
+EXPORT_SYMBOL(jz_clocks);
+
+static void __iomem *cpm_base;
+
+#define CPM_BASE 0x10000000
+
+#define CPM_CFCR 0x00
+#define CPM_LPCR 0x04
+#define CPM_RSTR 0x08
+#define CPM_PLCR1 0x10
+#define CPM_OCR 0x1c
+#define CPM_MSCR 0x20
+#define CPM_SCR 0x24
+#define CPM_WRER 0x28
+#define CPM_WFER 0x2c
+#define CPM_WER 0x30
+#define CPM_WSR 0x34
+#define CPM_GSR0 0x38
+#define CPM_GSR1 0x3c
+#define CPM_GSR2 0x40
+#define CPM_SPR 0x44
+#define CPM_GSR3 0x48
+#define CPM_CFCR2 0x60
+
+#define CPM_CFCR_SSI (1 << 31)
+#define CPM_CFCR_LCD (1 << 30)
+#define CPM_CFCR_I2S (1 << 29)
+#define CPM_CFCR_UCS (1 << 28)
+#define CPM_CFCR_UFR_BIT 25
+#define CPM_CFCR_UFR_MASK (0x07 << CPM_CFCR_UFR_BIT)
+#define CPM_CFCR_MSC (1 << 24)
+#define CPM_CFCR_CKOEN2 (1 << 23)
+#define CPM_CFCR_CKOEN1 (1 << 22)
+#define CPM_CFCR_UPE (1 << 20)
+#define CPM_CFCR_MFR_BIT 16
+#define CPM_CFCR_MFR_MASK (0x0f << CPM_CFCR_MFR_BIT)
+#define CPM_CFCR_LFR_BIT 12
+#define CPM_CFCR_LFR_MASK (0x0f << CPM_CFCR_LFR_BIT)
+#define CPM_CFCR_PFR_BIT 8
+#define CPM_CFCR_PFR_MASK (0x0f << CPM_CFCR_PFR_BIT)
+#define CPM_CFCR_SFR_BIT 4
+#define CPM_CFCR_SFR_MASK (0x0f << CPM_CFCR_SFR_BIT)
+#define CPM_CFCR_IFR_BIT 0
+#define CPM_CFCR_IFR_MASK (0x0f << CPM_CFCR_IFR_BIT)
+
+#define CPM_PLCR1_PLL1FD_BIT 23
+#define CPM_PLCR1_PLL1FD_MASK (0x1ff << CPM_PLCR1_PLL1FD_BIT)
+#define CPM_PLCR1_PLL1RD_BIT 18
+#define CPM_PLCR1_PLL1RD_MASK (0x1f << CPM_PLCR1_PLL1RD_BIT)
+#define CPM_PLCR1_PLL1OD_BIT 16
+#define CPM_PLCR1_PLL1OD_MASK (0x03 << CPM_PLCR1_PLL1OD_BIT)
+#define CPM_PLCR1_PLL1S (1 << 10)
+#define CPM_PLCR1_PLL1BP (1 << 9)
+#define CPM_PLCR1_PLL1EN (1 << 8)
+#define CPM_PLCR1_PLL1ST_BIT 0
+#define CPM_PLCR1_PLL1ST_MASK (0xff << CPM_PLCR1_PLL1ST_BIT)
+
+#define CPM_LPCR_DUTY_BIT 3
+#define CPM_LPCR_DUTY_MASK (0x1f << CPM_LPCR_DUTY_BIT)
+#define CPM_LPCR_DOZE (1 << 2)
+#define CPM_LPCR_LPM_BIT 0
+#define CPM_LPCR_LPM_MASK (0x03 << CPM_LPCR_LPM_BIT)
+ #define CPM_LPCR_LPM_IDLE (0 << CPM_LPCR_LPM_BIT)
+ #define CPM_LPCR_LPM_SLEEP (1 << CPM_LPCR_LPM_BIT)
+ #define CPM_LPCR_LPM_HIBERNATE (2 << CPM_LPCR_LPM_BIT)
+
+
+static __inline__ unsigned int
+cpm_get_pllout(void)
+{
+ unsigned int nf, nr, no, pllout;
+ unsigned long plcr = readl(cpm_base + CPM_PLCR1);
+ unsigned long od[4] = {1, 2, 2, 4};
+ if (plcr & CPM_PLCR1_PLL1EN) {
+ nf = (plcr & CPM_PLCR1_PLL1FD_MASK) >> CPM_PLCR1_PLL1FD_BIT;
+ nr = (plcr & CPM_PLCR1_PLL1RD_MASK) >> CPM_PLCR1_PLL1RD_BIT;
+ no = od[((plcr & CPM_PLCR1_PLL1OD_MASK) >> CPM_PLCR1_PLL1OD_BIT)];
+ pllout = (jz_clocks.extal) / ((nr+2) * no) * (nf+2);
+ } else
+ pllout = jz_clocks.extal;
+ return pllout;
+}
+
+static __inline__ unsigned int
+cpm_get_iclk(void)
+{
+ unsigned int iclk;
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+ unsigned long cfcr = readl(cpm_base + CPM_CFCR);
+ unsigned long plcr = readl(cpm_base + CPM_PLCR1);
+ if (plcr & CPM_PLCR1_PLL1EN)
+ iclk = cpm_get_pllout() /
+ div[(cfcr & CPM_CFCR_IFR_MASK) >> CPM_CFCR_IFR_BIT];
+ else
+ iclk = jz_clocks.extal;
+ return iclk;
+}
+
+static __inline__ unsigned int
+cpm_get_sclk(void)
+{
+ unsigned int sclk;
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+ unsigned long cfcr = readl(cpm_base + CPM_CFCR);
+ unsigned long plcr = readl(cpm_base + CPM_PLCR1);
+ if (plcr & CPM_PLCR1_PLL1EN)
+ sclk = cpm_get_pllout() /
+ div[(cfcr & CPM_CFCR_SFR_MASK) >> CPM_CFCR_SFR_BIT];
+ else
+ sclk = jz_clocks.extal;
+ return sclk;
+}
+
+static __inline__ unsigned int
+cpm_get_mclk(void)
+{
+ unsigned int mclk;
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+ unsigned long cfcr = readl(cpm_base + CPM_CFCR);
+ unsigned long plcr = readl(cpm_base + CPM_PLCR1);
+ if (plcr & CPM_PLCR1_PLL1EN)
+ mclk = cpm_get_pllout() /
+ div[(cfcr & CPM_CFCR_MFR_MASK) >> CPM_CFCR_MFR_BIT];
+ else
+ mclk = jz_clocks.extal;
+ return mclk;
+}
+
+static __inline__ unsigned int
+cpm_get_pclk(void)
+{
+ unsigned int devclk;
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+ unsigned long cfcr = readl(cpm_base + CPM_CFCR);
+ unsigned long plcr = readl(cpm_base + CPM_PLCR1);
+ if (plcr & CPM_PLCR1_PLL1EN)
+ devclk = cpm_get_pllout() /
+ div[(cfcr & CPM_CFCR_PFR_MASK) >> CPM_CFCR_PFR_BIT];
+ else
+ devclk = jz_clocks.extal;
+ return devclk;
+}
+
+static __inline__ unsigned int
+cpm_get_lcdclk(void)
+{
+ unsigned int lcdclk;
+ unsigned long cfcr = readl(cpm_base + CPM_CFCR);
+ unsigned long plcr = readl(cpm_base + CPM_PLCR1);
+ if (plcr & CPM_PLCR1_PLL1EN)
+ lcdclk = cpm_get_pllout() /
+ (((cfcr & CPM_CFCR_LFR_MASK) >> CPM_CFCR_LFR_BIT) + 1);
+ else
+ lcdclk = jz_clocks.extal;
+ return lcdclk;
+}
+
+static __inline__ unsigned int
+cpm_get_pixclk(void)
+{
+ unsigned int pixclk;
+ unsigned long cfcr2 = readl(cpm_base + CPM_CFCR2);
+ pixclk = cpm_get_pllout() / (cfcr2 + 1);
+ return pixclk;
+}
+
+static __inline__ unsigned int
+cpm_get_devclk(void)
+{
+ return jz_clocks.extal;
+}
+
+static __inline__ unsigned int
+cpm_get_rtcclk(void)
+{
+ return jz_clocks.extal2;
+}
+
+static __inline__ unsigned int
+cpm_get_uartclk(void)
+{
+ return jz_clocks.extal;
+}
+
+static __inline__ unsigned int
+cpm_get_usbclk(void)
+{
+ unsigned int usbclk;
+ unsigned long cfcr = readl(cpm_base + CPM_CFCR);
+ if (cfcr & CPM_CFCR_UCS)
+ usbclk = 48000000;
+ else
+ usbclk = cpm_get_pllout() /
+ (((cfcr &CPM_CFCR_UFR_MASK) >> CPM_CFCR_UFR_BIT) + 1);
+ return usbclk;
+}
+
+static __inline__ unsigned int
+cpm_get_i2sclk(void)
+{
+ unsigned int i2sclk;
+ unsigned long cfcr = readl(cpm_base + CPM_CFCR);
+ i2sclk = cpm_get_pllout() /
+ ((cfcr & CPM_CFCR_I2S) ? 2: 1);
+ return i2sclk;
+}
+
+static __inline__ unsigned int
+cpm_get_mscclk(void)
+{
+ if (readl(cpm_base + CPM_CFCR) & CPM_CFCR_MSC)
+ return 24000000;
+ else
+ return 16000000;
+}
+
+
+void
+jz_cpm_set_usbclk(int external)
+{
+ u32 cfcr = readl(cpm_base + CPM_CFCR);
+
+ if (external)
+ cfcr |= CPM_CFCR_UCS;
+ else
+ cfcr &= ~CPM_CFCR_UCS;
+
+ writel(cfcr, cpm_base + CPM_CFCR);
+
+ jz_clocks.usbclk = cpm_get_usbclk();
+}
+
+void __init
+jz_cpm_setup(void)
+{
+ u32 lcr, cfcr;
+
+ cpm_base = ioremap_nocache(CPM_BASE, 0xfff);
+ if (cpm_base == NULL) {
+ panic(KERN_ERR "Couldn't map CPM_BASE(0x%x)\n", CPM_BASE);
+ }
+
+ /* Enter idle mode when sleep instruction is executed. */
+ lcr = readl(cpm_base + CPM_LPCR) & ~CPM_LPCR_LPM_MASK;
+ lcr |= CPM_LPCR_LPM_IDLE;
+ writel(lcr, cpm_base + CPM_LPCR);
+
+ /* Enable SDRAM clock. */
+ cfcr = readl(cpm_base + CPM_CFCR) | CPM_CFCR_CKOEN1;
+ writel(cfcr, cpm_base + CPM_CFCR);
+
+ /* Enable all clocks. */
+ writel(0, cpm_base + CPM_MSCR);
+
+ /* Fill in jz_extal, jz_extal2. */
+ jz_board_get_extal(&jz_clocks);
+
+ jz_clocks.iclk = cpm_get_iclk();
+ jz_clocks.sclk = cpm_get_sclk();
+ jz_clocks.mclk = cpm_get_mclk();
+ jz_clocks.pclk = cpm_get_pclk();
+ jz_clocks.devclk = cpm_get_devclk();
+ jz_clocks.rtcclk = cpm_get_rtcclk();
+ jz_clocks.uartclk = cpm_get_uartclk();
+ jz_clocks.lcdclk = cpm_get_lcdclk();
+ jz_clocks.pixclk = cpm_get_pixclk();
+ jz_clocks.usbclk = cpm_get_usbclk();
+ jz_clocks.i2sclk = cpm_get_i2sclk();
+ jz_clocks.mscclk = cpm_get_mscclk();
+
+ printk("CPU clock: %dMHz, System clock: %dMHz, Memory clock: %dMHz, Peripheral clock: %dMHz\n",
+ (jz_clocks.iclk + 500000) / 1000000,
+ (jz_clocks.sclk + 500000) / 1000000,
+ (jz_clocks.mclk + 500000) / 1000000,
+ (jz_clocks.pclk + 500000) / 1000000);
+}
diff --git a/arch/mips/xburst/jz4730/irq.c b/arch/mips/xburst/jz4730/irq.c
new file mode 100644
index 0000000..7e12e69
--- /dev/null
+++ b/arch/mips/xburst/jz4730/irq.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2010 Ubiq Technologies <graham.gower@gmail.com>
+ *
+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <asm/irq_cpu.h>
+#include <asm/system.h>
+#include <xburst.h>
+
+#define INTC_BASE 0x10001000
+
+#define INTC_ISR 0x00
+#define INTC_IMR 0x04
+#define INTC_IMSR 0x08
+#define INTC_IMCR 0x0c
+#define INTC_IPR 0x10
+
+static void __iomem *intc_base;
+
+static void
+mask_intc_irq(unsigned int irq)
+{
+ writel(1<<irq, intc_base + INTC_IMSR);
+}
+
+static void
+unmask_intc_irq(unsigned int irq)
+{
+ writel(1<<irq, intc_base + INTC_IMCR);
+}
+
+static void
+ack_intc_irq(unsigned int irq)
+{
+ writel(1<<irq, intc_base + INTC_IPR);
+}
+
+static void
+end_intc_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
+ unmask_intc_irq(irq);
+ }
+}
+
+static struct irq_chip intc_irq_type = {
+ .name = "INTC",
+ .mask = mask_intc_irq,
+ .unmask = unmask_intc_irq,
+ .ack = ack_intc_irq,
+ .end = end_intc_irq,
+};
+
+asmlinkage void
+plat_irq_dispatch(void)
+{
+ int irq;
+ static u32 pending = 0;
+
+ pending |= readl(intc_base + INTC_IPR);
+
+ if (!pending)
+ return;
+
+ irq = ffs(pending) - 1;
+ pending &= ~(1<<irq);
+
+ switch (irq) {
+ case IRQ_GPIO0:
+ case IRQ_GPIO1:
+ case IRQ_GPIO2:
+ case IRQ_GPIO3:
+ case IRQ_DMAC:
+ /* unhandled for now */
+ printk(KERN_WARNING "%s: %d unhandled\n", __FUNCTION__,
+ irq);
+ return;
+ }
+
+ generic_handle_irq(irq);
+}
+
+void __init
+arch_init_irq(void)
+{
+ int i;
+
+ intc_base = ioremap_nocache(INTC_BASE, 0xfff);
+
+ for (i=0; i<32; i++) {
+ mask_intc_irq(i);
+ set_irq_chip_and_handler(i, &intc_irq_type, handle_level_irq);
+ }
+}
+
diff --git a/arch/mips/xburst/jz4730/platform.c b/arch/mips/xburst/jz4730/platform.c
new file mode 100644
index 0000000..cff660a
--- /dev/null
+++ b/arch/mips/xburst/jz4730/platform.c
@@ -0,0 +1,49 @@
+/*
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <xburst.h>
+
+#define ETH_BASE 0x13100000
+
+static struct resource jz_eth_resources[] = {
+ [0] = {
+ .start = ETH_BASE,
+ .end = ETH_BASE + 0xffff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_ETH,
+ .end = IRQ_ETH,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static u64 jz_eth_dmamask = ~(u32)0;
+
+static struct platform_device jz_eth_device = {
+ .name = "jz-eth",
+ .id = 0,
+ .dev = {
+ .dma_mask = &jz_eth_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(jz_eth_resources),
+ .resource = jz_eth_resources,
+};
+
+static struct platform_device *jz4730_devices[] __initdata = {
+ &jz_eth_device,
+};
+
+static int __init
+jz4730_platform_init(void)
+{
+ return platform_add_devices(jz4730_devices, ARRAY_SIZE(jz4730_devices));
+}
+
+arch_initcall(jz4730_platform_init);
diff --git a/arch/mips/xburst/jz4730/prom.c b/arch/mips/xburst/jz4730/prom.c
new file mode 100644
index 0000000..60c46bc
--- /dev/null
+++ b/arch/mips/xburst/jz4730/prom.c
@@ -0,0 +1,104 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ * PROM library initialisation code, supports YAMON and U-Boot.
+ *
+ * Copyright 2000, 2001, 2006 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ppopov@mvista.com or source@mvista.com
+ *
+ * This file was derived from Carsten Langgaard's
+ * arch/mips/mips-boards/xx files.
+ *
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/string.h>
+
+#include <asm/bootinfo.h>
+#include <xburst.h>
+
+int prom_argc;
+char **prom_argv, **prom_envp;
+
+char *prom_getcmdline(void)
+{
+ return &(arcs_cmdline[0]);
+}
+
+void prom_init_cmdline(void)
+{
+ char *cp;
+ int actr;
+
+ actr = 1; /* Always ignore argv[0] */
+
+ cp = &(arcs_cmdline[0]);
+ while(actr < prom_argc) {
+ strcpy(cp, prom_argv[actr]);
+ cp += strlen(prom_argv[actr]);
+ *cp++ = ' ';
+ actr++;
+ }
+ if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
+ --cp;
+ if (prom_argc > 1)
+ *cp = '\0';
+}
+
+void __init prom_free_prom_memory(void)
+{
+}
+
+void __init prom_init(void)
+{
+ prom_argc = (int) fw_arg0;
+ prom_argv = (char **) fw_arg1;
+ prom_envp = (char **) fw_arg2;
+
+ mips_machtype = MACH_XBURST_JZ4730;
+
+ prom_init_cmdline();
+ add_memory_region(0, 0x04000000, BOOT_MEM_RAM);
+}
+
+/* used by early printk */
+void prom_putchar(char c)
+{
+ volatile u8 *uart_lsr = (volatile u8 *)(UART3_BASE + OFF_LSR);
+ volatile u8 *uart_tdr = (volatile u8 *)(UART3_BASE + OFF_TDR);
+
+ /* Wait for fifo to shift out some bytes */
+ while ( !((*uart_lsr & (UARTLSR_TDRQ | UARTLSR_TEMT)) == 0x60) );
+
+ *uart_tdr = (u8)c;
+}
+
+const char *get_system_type(void)
+{
+ return "JZ4730";
+}
diff --git a/arch/mips/xburst/jz4730/setup.c b/arch/mips/xburst/jz4730/setup.c
new file mode 100644
index 0000000..777ac27
--- /dev/null
+++ b/arch/mips/xburst/jz4730/setup.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2010 Ubiq Technologies <graham.gower@gmail.com>
+ *
+ * Copyright (C) 2006-2007 Ingenic Semiconductor Inc.
+ * Author: <jlwei@ingenic.cn>
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
+#include <asm/mips-boards/prom.h>
+#include <xburst.h>
+
+extern void __init jz_board_setup(void);
+extern void __init jz_cpm_setup(void);
+
+/* System Bus Arbiter control*/
+#define SBA_CNTL 0x13000000
+void __iomem *sba_cntl;
+
+#define DMAC_BASE 0x13020000
+#define DMAC_DMACR 0xfc
+#define DMAC_DMACR_PR_BIT 8
+#define DMAC_DMACR_PR_MASK (0x03 << DMAC_DMACR_PR_BIT)
+ #define DMAC_DMACR_PR_01234567 (0 << DMAC_DMACR_PR_BIT)
+ #define DMAC_DMACR_PR_02314675 (1 << DMAC_DMACR_PR_BIT)
+ #define DMAC_DMACR_PR_20136457 (2 << DMAC_DMACR_PR_BIT)
+ #define DMAC_DMACR_PR_ROUNDROBIN (3 << DMAC_DMACR_PR_BIT)
+#define DMAC_DMACR_HTR (1 << 3)
+#define DMAC_DMACR_AER (1 << 2)
+#define DMAC_DMACR_DME (1 << 0)
+
+
+static void __init
+jz_serial_setup(void)
+{
+#ifdef CONFIG_SERIAL_8250
+ struct uart_port s;
+
+ memset(&s, 0, sizeof(s));
+
+ s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
+ s.iotype = UPIO_MEM;
+ s.regshift = 2;
+ s.uartclk = jz_clocks.uartclk;
+
+ s.line = 0;
+ s.membase = (u8 *)UART0_BASE;
+ s.irq = IRQ_UART0;
+ if (early_serial_setup(&s) != 0) {
+ printk(KERN_ERR "Serial ttyS0 setup failed!\n");
+ }
+
+ s.line = 1;
+ s.membase = (u8 *)UART1_BASE;
+ s.irq = IRQ_UART1;
+ if (early_serial_setup(&s) != 0) {
+ printk(KERN_ERR "Serial ttyS1 setup failed!\n");
+ }
+
+ s.line = 2;
+ s.membase = (u8 *)UART2_BASE;
+ s.irq = IRQ_UART2;
+ if (early_serial_setup(&s) != 0) {
+ printk(KERN_ERR "Serial ttyS2 setup failed!\n");
+ }
+
+ s.line = 3;
+ s.membase = (u8 *)UART3_BASE;
+ s.irq = IRQ_UART3;
+ if (early_serial_setup(&s) != 0) {
+ printk(KERN_ERR "Serial ttyS3 setup failed!\n");
+ }
+#endif
+}
+
+static void __init
+jz_dma_setup(void)
+{
+ void __iomem *dmac_base;
+ u32 dmacr;
+
+ dmac_base = ioremap_nocache(DMAC_BASE, 0xffff);
+ if (dmac_base == NULL) {
+ panic(KERN_ERR "Couldn't map DMAC_BASE(0x%x)\n", DMAC_BASE);
+ }
+
+ /* Set DMA priority and enable all channels. */
+ dmacr = readl(dmac_base + DMAC_DMACR);
+ dmacr |= DMAC_DMACR_DME | DMAC_DMACR_PR_ROUNDROBIN;
+ writel(dmacr, dmac_base + DMAC_DMACR);
+
+}
+
+void
+jz_usb0_set_function(int host)
+{
+ u32 sba = readl(sba_cntl);
+
+ if (host)
+ sba |= (1<<7);
+ else /* device */
+ sba &= ~(1<<7);
+
+ writel(sba, sba_cntl);
+}
+
+void __init
+plat_mem_setup(void)
+{
+ /* IO/MEM resources. */
+ set_io_port_base(0);
+ ioport_resource.start = 0x00000000;
+ ioport_resource.end = 0xffffffff;
+ iomem_resource.start = 0x00000000;
+ iomem_resource.end = 0xffffffff;
+
+ jz_cpm_setup();
+
+ sba_cntl = ioremap_nocache(SBA_CNTL, 0xffff);
+ if (sba_cntl == NULL) {
+ panic(KERN_ERR "Couldn't map SBA_CNTL(0x%x)\n", SBA_CNTL);
+ }
+
+ /* Set bus priority: DMAC > LCD > CIM > ETH > USB > CIM */
+ writel((readl(sba_cntl) & 0xfffffff0) | 0x08, sba_cntl);
+
+ jz_serial_setup();
+ jz_dma_setup();
+ jz_board_setup();
+}
diff --git a/arch/mips/xburst/jz4730/time.c b/arch/mips/xburst/jz4730/time.c
new file mode 100644
index 0000000..c3bd06a
--- /dev/null
+++ b/arch/mips/xburst/jz4730/time.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2010 Ubiq Technologies. <graham.gower@gmail.com>
+ *
+ * Copyright (c) 2006-2008 Ingenic Semiconductor Inc.
+ * Author: <jlwei@ingenic.cn>
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/clockchips.h>
+
+#include <xburst.h>
+
+#define OST_BASE 0x10002000
+#define OST_TER 0x00 /* 8bit reg */
+#define OST_TRDR0 0x10
+#define OST_TCNT0 0x14
+#define OST_TCSR0 0x18 /* 16bit reg */
+#define OST_TCRB0 0x1c
+
+#define OST_TCSR_BUSY (1 << 7)
+#define OST_TCSR_UF (1 << 6)
+#define OST_TCSR_UIE (1 << 5)
+#define OST_TCSR_CKS_BIT 0
+#define OST_TCSR_CKS_MASK (0x07 << OST_TCSR_CKS_BIT)
+ #define OST_TCSR_CKS_PCLK_4 (0 << OST_TCSR_CKS_BIT)
+ #define OST_TCSR_CKS_PCLK_16 (1 << OST_TCSR_CKS_BIT)
+ #define OST_TCSR_CKS_PCLK_64 (2 << OST_TCSR_CKS_BIT)
+ #define OST_TCSR_CKS_PCLK_256 (3 << OST_TCSR_CKS_BIT)
+ #define OST_TCSR_CKS_RTCCLK (4 << OST_TCSR_CKS_BIT)
+ #define OST_TCSR_CKS_EXTAL (5 << OST_TCSR_CKS_BIT)
+
+static void __iomem *ost_base;
+static u32 timer_max;
+
+static cycle_t
+jz_get_cycles(struct clocksource *cs)
+{
+ u32 cnt;
+
+ cnt = readl(ost_base + OST_TCNT0);
+
+ /* Wait for clock sync. */
+ while ((readw(ost_base + OST_TCSR0) & OST_TCSR_BUSY))
+ ;
+
+ cnt = readl(ost_base + OST_TCRB0);
+
+ return jiffies*(jz_clocks.extal/HZ) + (timer_max - cnt);
+}
+
+static void
+jz_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+}
+
+static irqreturn_t
+jz_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *cd = dev_id;
+ u16 tcsr0;
+
+ /* ACK timer */
+ tcsr0 = readw(ost_base + OST_TCSR0);
+ tcsr0 &= ~OST_TCSR_UF;
+ writew(tcsr0, ost_base + OST_TCSR0);
+
+ cd->event_handler(cd);
+ return IRQ_HANDLED;
+}
+
+static struct clocksource jz_clocksource = {
+ .name = "jz4730-ost0",
+ .rating = 300,
+ .read = jz_get_cycles,
+ .mask = CLOCKSOURCE_MASK(32),
+ .shift = 10,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static struct clock_event_device jz_clockevent_device = {
+ .name = "jz4730-ckevent-ost0",
+ .features = CLOCK_EVT_FEAT_PERIODIC,
+ .rating = 300,
+ .irq = IRQ_OST0,
+ .set_mode = jz_set_mode,
+};
+
+static struct irqaction jz_irqaction = {
+ .name = "jz4730-irq-ost0",
+ .handler = jz_timer_interrupt,
+ .flags = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER,
+};
+
+void __init
+plat_time_init(void)
+{
+ ost_base = ioremap_nocache(OST_BASE, 0xfff);
+ if (ost_base == NULL) {
+ panic(KERN_ERR "Couldn't map OST_BASE(0x%x)\n", OST_BASE);
+ }
+
+ jz_clockevent_device.cpumask = cpumask_of(0);
+ clockevents_register_device(&jz_clockevent_device);
+
+ jz_irqaction.dev_id = &jz_clockevent_device;
+ setup_irq(IRQ_OST0, &jz_irqaction);
+
+ jz_clocksource.mult = clocksource_hz2mult(jz_clocks.extal,
+ jz_clocksource.shift);
+ clocksource_register(&jz_clocksource);
+
+ timer_max = (jz_clocks.extal + (HZ>>1)) / HZ;
+
+ /* Disable timers. */
+ writeb(0, ost_base + OST_TER);
+
+ /* Use extal as the clock source, interrupt when timer 0 underflows. */
+ writew(OST_TCSR_CKS_EXTAL|OST_TCSR_UIE, ost_base + OST_TCSR0);
+
+ /* Set timer 0's reset value upon underflow. */
+ writel(timer_max, ost_base + OST_TRDR0);
+
+ /* Set timer 0's initial value. */
+ writel(timer_max, ost_base + OST_TCNT0);
+
+ /* Wait for clock sync. */
+ while ((readw(ost_base + OST_TCSR0) & OST_TCSR_BUSY))
+ ;
+
+ /* Enable timer 0.*/
+ writeb(0x1, ost_base + OST_TER);
+
+}
--
1.6.4
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 2/3] 8250: serial driver changes for XBurst SoCs.
2010-02-25 6:28 [PATCH 0/3] XBurst JZ4730 support Graham Gower
2010-02-25 6:29 ` [PATCH 1/3] Add " Graham Gower
@ 2010-02-25 6:30 ` Graham Gower
2010-02-25 6:31 ` [PATCH 3/3] net: add driver for JZ4730 ethernet controller Graham Gower
2010-02-25 7:52 ` [PATCH 0/3] XBurst JZ4730 support Florian Fainelli
3 siblings, 0 replies; 10+ messages in thread
From: Graham Gower @ 2010-02-25 6:30 UTC (permalink / raw)
To: linux-mips
Signed-off-by: Graham Gower <graham.gower@gmail.com>
---
drivers/serial/8250.c | 12 ++++++++++++
1 files changed, 12 insertions(+), 0 deletions(-)
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index e9b15c3..dfe6640 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -199,7 +199,11 @@ static const struct serial8250_config uart_config[] = {
[PORT_16550A] = {
.name = "16550A",
.fifo_size = 16,
+#ifndef CONFIG_XBURST
.tx_loadsz = 16,
+#else
+ .tx_loadsz = 8,
+#endif
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
.flags = UART_CAP_FIFO,
},
@@ -406,6 +410,10 @@ static unsigned int mem_serial_in(struct uart_port *p, int offset)
static void mem_serial_out(struct uart_port *p, int offset, int value)
{
offset = map_8250_out_reg(p, offset) << p->regshift;
+#if defined(CONFIG_XBURST)
+ if (offset == (UART_FCR << p->regshift))
+ value |= 0x10; /* set FCR.UUE */
+#endif
writeb(value, p->membase + offset);
}
@@ -2354,6 +2362,10 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
if (up->capabilities & UART_CAP_UUE)
up->ier |= UART_IER_UUE | UART_IER_RTOIE;
+#ifdef CONFIG_XBURST
+ up->ier |= UART_IER_RTOIE; /* Set this flag, or very slow */
+#endif
+
serial_out(up, UART_IER, up->ier);
if (up->capabilities & UART_CAP_EFR) {
--
1.6.4
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 3/3] net: add driver for JZ4730 ethernet controller.
2010-02-25 6:28 [PATCH 0/3] XBurst JZ4730 support Graham Gower
2010-02-25 6:29 ` [PATCH 1/3] Add " Graham Gower
2010-02-25 6:30 ` [PATCH 2/3] 8250: serial driver changes for XBurst SoCs Graham Gower
@ 2010-02-25 6:31 ` Graham Gower
2010-02-25 7:52 ` [PATCH 0/3] XBurst JZ4730 support Florian Fainelli
3 siblings, 0 replies; 10+ messages in thread
From: Graham Gower @ 2010-02-25 6:31 UTC (permalink / raw)
To: linux-mips
Signed-off-by: Graham Gower <graham.gower@gmail.com>
---
drivers/net/Kconfig | 10 +
drivers/net/Makefile | 1 +
drivers/net/jz_eth.c | 1232 ++++++++++++++++++++++++++++++++++++++++++++++++++
drivers/net/jz_eth.h | 403 +++++++++++++++++
4 files changed, 1646 insertions(+), 0 deletions(-)
create mode 100644 drivers/net/jz_eth.c
create mode 100644 drivers/net/jz_eth.h
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 7f8ad5d..7e8060a 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1951,6 +1951,16 @@ config BCM63XX_ENET
This driver supports the ethernet MACs in the Broadcom 63xx
MIPS chipset family (BCM63XX).
+config JZ_ETH
+ tristate "JZ4730/JZ5730 On-Chip Ethernet support"
+ depends on XBURST_JZ4730
+ select MII
+ help
+ This driver supports the JZ4730/JZ5730 On-Chip Ethernet interface.
+
+ To compile this driver as a module, choose M here: the module
+ will be called jz_eth.
+
source "drivers/net/fs_enet/Kconfig"
source "drivers/net/octeon/Kconfig"
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 657ccc3..da8ff86 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -141,6 +141,7 @@ obj-$(CONFIG_FORCEDETH) += forcedeth.o
obj-$(CONFIG_NE_H8300) += ne-h8300.o 8390.o
obj-$(CONFIG_AX88796) += ax88796.o
obj-$(CONFIG_BCM63XX_ENET) += bcm63xx_enet.o
+obj-$(CONFIG_JZ_ETH) += jz_eth.o
obj-$(CONFIG_TSI108_ETH) += tsi108_eth.o
obj-$(CONFIG_MV643XX_ETH) += mv643xx_eth.o
diff --git a/drivers/net/jz_eth.c b/drivers/net/jz_eth.c
new file mode 100644
index 0000000..624c081
--- /dev/null
+++ b/drivers/net/jz_eth.c
@@ -0,0 +1,1232 @@
+/*
+ * Jz4730/Jz5730 On-Chip ethernet driver.
+ *
+ * Copyright (C) 2009, 2010 Ubiq Technologies <graham.gower@gmail.com>
+ * Copyright (C) 2005 - 2007 Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/kthread.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <xburst.h>
+
+#include "jz_eth.h"
+
+#define DRV_NAME "jz_eth"
+#define DRV_VERSION "1.2"
+
+MODULE_AUTHOR("Peter Wei <jlwei@ingenic.cn>");
+MODULE_DESCRIPTION("JzSOC On-chip Ethernet driver");
+MODULE_LICENSE("GPL");
+
+static void __iomem *jz_eth_base;
+static char *hwaddr = NULL;
+static int debug = -1;
+static struct mii_if_info mii_info;
+
+MODULE_PARM_DESC(debug, "i");
+MODULE_PARM_DESC(hwaddr,"s");
+
+static irqreturn_t jz_eth_interrupt(int irq, void *dev_id);
+
+static int link_check_thread (void *data);
+
+static inline void
+ring_inv(jz_desc_t ring[], int ring_index)
+{
+ unsigned long addr = (unsigned long)&ring[ring_index];
+ dma_cache_inv(addr, sizeof(jz_desc_t));
+}
+
+static inline void
+ring_wback(jz_desc_t ring[], int ring_index)
+{
+ unsigned long addr = (unsigned long)&ring[ring_index];
+ dma_cache_wback(addr, sizeof(jz_desc_t));
+}
+
+static inline unsigned char str2hexnum(unsigned char c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ return 0; /* foo */
+}
+
+static inline void str2eaddr(unsigned char *ea, unsigned char *str)
+{
+ int i;
+
+ for (i = 0; i < 6; i++) {
+ unsigned char num;
+
+ if((*str == '.') || (*str == ':'))
+ str++;
+ num = str2hexnum(*str++) << 4;
+ num |= (str2hexnum(*str++));
+ ea[i] = num;
+ }
+}
+
+static int ethaddr_cmd = 0;
+static unsigned char ethaddr_hex[6];
+
+static int __init ethernet_addr_setup(char *str)
+{
+ if (!str) {
+ printk("ethaddr not set in command line\n");
+ return -1;
+ }
+ ethaddr_cmd = 1;
+ str2eaddr(ethaddr_hex, str);
+
+ return 0;
+}
+
+__setup("ethaddr=", ethernet_addr_setup);
+
+static int get_mac_address(struct net_device *dev)
+{
+ int i;
+ unsigned char flag0=0;
+ unsigned char flag1=0xff;
+
+ dev->dev_addr[0] = 0xff;
+ if (hwaddr != NULL) {
+ /* insmod jz-ethc.o hwaddr=00:ef:a3:c1:00:10 */
+ str2eaddr(dev->dev_addr, hwaddr);
+ } else if (ethaddr_cmd) {
+ /* linux command line: ethaddr=00:ef:a3:c1:00:10 */
+ for (i=0; i<6; i++)
+ dev->dev_addr[i] = ethaddr_hex[i];
+ }
+
+ /* check whether valid MAC address */
+ for (i=0; i<6; i++) {
+ flag0 |= dev->dev_addr[i];
+ flag1 &= dev->dev_addr[i];
+ }
+ if ((dev->dev_addr[0] & 0xC0) || (flag0 == 0) || (flag1 == 0xff)) {
+ printk("WARNING: There is not MAC address, use default ..\n");
+ dev->dev_addr[0] = 0x00;
+ dev->dev_addr[1] = 0xef;
+ dev->dev_addr[2] = 0xa3;
+ dev->dev_addr[3] = 0xc1;
+ dev->dev_addr[4] = 0x00;
+ dev->dev_addr[5] = 0x10;
+ dev->dev_addr[5] = 0x03;
+ }
+ memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN);
+ if (!is_valid_ether_addr(dev->perm_addr))
+ printk(KERN_ERR "%s: ethaddr is b0rken!\n", dev->name);
+ return 0;
+}
+
+/*---------------------------------------------------------------------*/
+
+static u32 jz_eth_curr_mode(struct net_device *dev);
+
+/*
+ * Ethernet START/STOP routines
+ */
+#define START_ETH() \
+ do { \
+ s32 val; \
+ val = readl(jz_eth_base + DMA_OMR); \
+ val |= OMR_ST | OMR_SR; \
+ writel(val, jz_eth_base + DMA_OMR); \
+ } while(0)
+
+#define STOP_ETH() \
+ do { \
+ s32 val; \
+ val = readl(jz_eth_base + DMA_OMR); \
+ val &= ~(OMR_ST|OMR_SR); \
+ writel(val, jz_eth_base + DMA_OMR); \
+ } while(0)
+
+/*
+ * Link check routines
+ */
+static void start_check(struct net_device *dev)
+{
+ struct jz_eth_private *np = netdev_priv(dev);
+
+ np->thread_die = 0;
+ init_waitqueue_head(&np->thr_wait);
+ init_completion (&np->thr_exited);
+
+ np->thread = kthread_run(link_check_thread,(void *)dev,
+ "%s-linkcheck", dev->name);
+ if (IS_ERR(np->thread))
+ printk(KERN_ERR "%s: unable to start kernel thread\n", dev->name);
+}
+
+static int close_check(struct net_device *dev)
+{
+ struct jz_eth_private *np = netdev_priv(dev);
+ int ret = 0;
+
+ if (np->thread != NULL) {
+ np->thread_die = 1;
+ wmb();
+ ret = send_sig(SIGTERM, np->thread, 1);
+ if (ret) {
+ printk(KERN_ERR "%s: unable to signal thread\n", dev->name);
+ return 1;
+ }
+ wait_for_completion (&np->thr_exited);
+ }
+ return 0;
+}
+
+static int link_check_thread(void *data)
+{
+ struct net_device *dev=(struct net_device *)data;
+ struct jz_eth_private *np = netdev_priv(dev);
+ unsigned char current_link;
+ unsigned long timeout;
+
+ while (1) {
+ timeout = 3*HZ;
+ do {
+ timeout = interruptible_sleep_on_timeout (&np->thr_wait, timeout);
+ /* make swsusp happy with our thread */
+// if (current->flags & PF_FREEZE)
+// refrigerator(PF_FREEZE);
+ } while (!signal_pending (current) && (timeout > 0));
+
+ if (signal_pending (current)) {
+ spin_lock_irq(¤t->sighand->siglock);
+ flush_signals(current);
+ spin_unlock_irq(¤t->sighand->siglock);
+ }
+
+ if (np->thread_die)
+ break;
+
+ current_link=mii_link_ok(&mii_info);
+ if (np->link_state!=current_link) {
+ if (current_link) {
+ printk(KERN_INFO "%s: Ethernet Link OK!\n",dev->name);
+ jz_eth_curr_mode(dev);
+ netif_carrier_on(dev);
+ }
+ else {
+ printk(KERN_WARNING "%s: Ethernet Link offline!\n",dev->name);
+ netif_carrier_off(dev);
+ }
+ }
+ np->link_state=current_link;
+
+ }
+ complete_and_exit (&np->thr_exited, 0);
+}
+
+
+/*
+ * Reset ethernet device
+ */
+static inline void jz_eth_reset(void)
+{
+ u32 i;
+ i = readl(jz_eth_base + DMA_BMR);
+ writel(i | BMR_SWR, jz_eth_base + DMA_BMR);
+ for(i = 0; i < 1000; i++) {
+ if(!(readl(jz_eth_base + DMA_BMR) & BMR_SWR)) break;
+ mdelay(1);
+ }
+}
+
+/*
+ * MII operation routines
+ */
+static inline void mii_wait(void)
+{
+ int i;
+ for(i = 0; i < 10000; i++) {
+ if(!(readl(jz_eth_base + MAC_MIIA) & 0x1))
+ break;
+ mdelay(1);
+ }
+ if (i >= 10000)
+ printk("MII wait timeout : %d.\n", i);
+}
+
+static int mdio_read(struct net_device *dev,int phy_id, int location)
+{
+ u32 mii_cmd = (phy_id << 11) | (location << 6) | 1;
+ int retval = 0;
+
+ writel(mii_cmd, jz_eth_base + MAC_MIIA);
+ mii_wait();
+ retval = readl(jz_eth_base + MAC_MIID) & 0x0000ffff;
+
+ return retval;
+
+}
+
+static void mdio_write(struct net_device *dev,int phy_id, int location, int data)
+{
+ u32 mii_cmd = (phy_id << 11) | (location << 6) | 0x2 /*| 1*/;
+
+ writel(mii_cmd, jz_eth_base + MAC_MIIA);
+ writel(data & 0x0000ffff, jz_eth_base + MAC_MIID);
+ mii_cmd = (phy_id << 11) | (location << 6) | 0x2 | 1;
+ writel(mii_cmd, jz_eth_base + MAC_MIIA);
+ mii_wait();
+}
+
+
+/*
+ * Search MII phy
+ */
+static int jz_search_mii_phy(struct net_device *dev)
+{
+
+ struct jz_eth_private *np = netdev_priv(dev);
+ int phy, phy_idx = 0;
+
+ np->valid_phy = 0xff;
+ for (phy = 0; phy < 32; phy++) {
+ int mii_status = mdio_read(dev,phy, 1);
+ if (mii_status != 0xffff && mii_status != 0x0000) {
+ np->phys[phy_idx] = phy;
+ np->ecmds[phy_idx].speed=SPEED_100;
+ np->ecmds[phy_idx].duplex=DUPLEX_FULL;
+ np->ecmds[phy_idx].port=PORT_MII;
+ np->ecmds[phy_idx].transceiver=XCVR_INTERNAL;
+ np->ecmds[phy_idx].phy_address=np->phys[phy_idx];
+ np->ecmds[phy_idx].autoneg=AUTONEG_ENABLE;
+ np->ecmds[phy_idx].advertising=(ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full);
+ phy_idx++;
+ break;
+ }
+ }
+ if (phy_idx == 1) {
+ np->valid_phy = np->phys[0];
+ np->phy_type = 0;
+ }
+ if (phy_idx != 0) {
+ phy = np->valid_phy;
+ np->advertising = mdio_read(dev,phy, 4);
+ }
+ return phy_idx;
+}
+
+/*
+ * CRC calc for Destination Address for gets hashtable index
+ */
+
+#define POLYNOMIAL 0x04c11db7UL
+static u16 jz_hashtable_index(u8 *addr)
+{
+ u32 crc = 0xffffffff, msb;
+ int i, j;
+ u32 byte;
+ for (i = 0; i < 6; i++) {
+ byte = *addr++;
+ for (j = 0; j < 8; j++) {
+ msb = crc >> 31;
+ crc <<= 1;
+ if (msb ^ (byte & 1)) crc ^= POLYNOMIAL;
+ byte >>= 1;
+ }
+ }
+ return ((int)(crc >> 26));
+}
+
+/*
+ * Multicast filter and config multicast hash table
+ */
+#define MULTICAST_FILTER_LIMIT 64
+
+static void jz_set_multicast_list(struct net_device *dev)
+{
+ int i, hash_index;
+ u32 mcr, hash_h, hash_l, hash_bit;
+
+ mcr = readl(jz_eth_base + MAC_MCR);
+ mcr &= ~(MCR_PR | MCR_PM | MCR_HP);
+
+ if (dev->flags & IFF_PROMISC) {
+ /* Accept any kinds of packets */
+ mcr |= MCR_PR;
+ hash_h = 0xffffffff;
+ hash_l = 0xffffffff;
+ }
+ else if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > MULTICAST_FILTER_LIMIT)){
+ /* Accept all multicast packets */
+ mcr |= MCR_PM;
+ hash_h = 0xffffffff;
+ hash_l = 0xffffffff;
+ }
+ else if (dev->flags & IFF_MULTICAST)
+ {
+ /* Update multicast hash table */
+ struct dev_mc_list *mclist;
+ hash_h = readl(jz_eth_base + MAC_HTH);
+ hash_l = readl(jz_eth_base + MAC_HTL);
+ for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+ i++, mclist = mclist->next)
+ {
+ hash_index = jz_hashtable_index(mclist->dmi_addr);
+ hash_bit=0x00000001;
+ hash_bit <<= (hash_index & 0x1f);
+ if (hash_index > 0x1f)
+ hash_h |= hash_bit;
+ else
+ hash_l |= hash_bit;
+ }
+ writel(hash_h, jz_eth_base + MAC_HTH);
+ writel(hash_l, jz_eth_base + MAC_HTL);
+ mcr |= MCR_HP;
+ }
+ writel(mcr, jz_eth_base + MAC_MCR);
+}
+
+static inline int jz_phy_reset(struct net_device *dev)
+{
+ struct jz_eth_private *np = netdev_priv(dev);
+ unsigned int mii_reg0;
+ int i;
+
+ mii_reg0 = mdio_read(dev,np->valid_phy,MII_BMCR);
+ mii_reg0 |= MII_CR_RST;
+ mdio_write(dev, np->valid_phy, MII_BMCR, mii_reg0);
+
+ for (i=0; i<1000; i++) {
+ mdelay(1);
+ mii_reg0 = mdio_read(dev, np->valid_phy, MII_BMCR);
+ if (!(mii_reg0 & MII_CR_RST))
+ break;
+ }
+
+ if (i >= 1000)
+ /* phy error */
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Start Auto-Negotiation function for PHY
+ */
+static int jz_autonet_complete(struct net_device *dev)
+{
+ struct jz_eth_private *np = netdev_priv(dev);
+ int i;
+ u32 mii_reg1, timeout = 3000;
+
+ for (i=0; i<timeout; i++) {
+ mdelay(1);
+ mii_reg1 = mdio_read(dev, np->valid_phy, MII_BMSR);
+ if (mii_reg1 & MII_SR_ASSC)
+ break;
+ }
+
+ if (i >= timeout)
+ /* auto negotiation error */
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Get current mode of eth phy
+ */
+static u32 jz_eth_curr_mode(struct net_device *dev)
+{
+ struct jz_eth_private *np = netdev_priv(dev);
+ unsigned int mii_reg17;
+ u32 flag = 0;
+
+ mii_reg17 = mdio_read(dev,np->valid_phy,MII_DSCSR);
+ np->media = mii_reg17>>12;
+ if (np->media==8) {
+ printk(KERN_INFO "%s: Current Mode is [100M Full Duplex]",dev->name);
+ flag = 0;
+ np->full_duplex=1;
+ }
+ if (np->media==4) {
+ printk(KERN_INFO "%s: Current Mode is [100M Half Duplex]",dev->name);
+ flag = 0;
+ np->full_duplex=0;
+ }
+ if (np->media==2) {
+ printk(KERN_INFO "%s: Current Mode is [10M Full Duplex]",dev->name);
+ flag = OMR_TTM;
+ np->full_duplex=1;
+ }
+ if (np->media==1) {
+ printk(KERN_INFO "%s: Current Mode is [10M Half Duplex]",dev->name);
+ flag = OMR_TTM;
+ np->full_duplex=0;
+ }
+ printk("\n");
+ return flag;
+}
+
+/*
+ * Ethernet device hardware init
+ * This routine initializes the ethernet device hardware and PHY
+ */
+static int jz_init_hw(struct net_device *dev)
+{
+ struct jz_eth_private *np = netdev_priv(dev);
+ struct ethtool_cmd ecmd;
+ u32 mcr, omr;
+ u32 sts, flag = 0;
+ int i;
+
+ jz_eth_reset();
+ STOP_ETH();
+
+ /* Set MAC address */
+ writel(le32_to_cpu(*(unsigned long *)&dev->dev_addr[0]),
+ jz_eth_base + MAC_MAL);
+ writel(le32_to_cpu(*(unsigned long *)&dev->dev_addr[4]),
+ jz_eth_base + MAC_MAH);
+ printk("%s: JZ On-Chip ethernet (MAC ", dev->name);
+ for (i = 0; i < 5; i++) {
+ printk("%2.2x:", dev->dev_addr[i]);
+ }
+ printk("%2.2x, IRQ %d)\n", dev->dev_addr[i], dev->irq);
+
+ if ((np->mii_phy_cnt = jz_search_mii_phy(dev)) == 0) {
+ printk("%s: PHY not found, bailing.\n", dev->name);
+ return -ENXIO;
+ }
+
+ printk("%s: Found %d PHY on JZ MAC\n", dev->name, np->mii_phy_cnt);
+
+ mii_info.phy_id = np->valid_phy;
+ mii_info.dev = dev;
+ mii_info.mdio_read = &mdio_read;
+ mii_info.mdio_write = &mdio_write;
+
+ ecmd.speed = SPEED_100;
+ ecmd.duplex = DUPLEX_FULL;
+ ecmd.port = PORT_MII;
+ ecmd.transceiver = XCVR_INTERNAL;
+ ecmd.phy_address = np->valid_phy;
+ ecmd.autoneg = AUTONEG_ENABLE;
+ ecmd.advertising = ADVERTISED_10baseT_Half
+ | ADVERTISED_10baseT_Full
+ | ADVERTISED_100baseT_Half
+ | ADVERTISED_100baseT_Full;
+
+ mii_ethtool_sset(&mii_info,&ecmd);
+
+ if (jz_autonet_complete(dev))
+ printk(KERN_WARNING "%s: Ethernet Module AutoNegotiation failed\n",dev->name);
+ mii_ethtool_gset(&mii_info,&ecmd);
+
+ printk(KERN_INFO "%s: Provide Modes: ",dev->name);
+ for (i = 0; i < 5;i++)
+ if (ecmd.advertising & (1<<i))
+ printk("(%d)%s", i+1, media_types[i]);
+ printk("\n");
+
+ flag = jz_eth_curr_mode(dev);
+
+ /* Config OMR register */
+ omr = readl(jz_eth_base + DMA_OMR) & ~OMR_TTM;
+ omr |= flag;
+ //omr |= OMR_OSF;
+ omr |= OMR_SF;
+ writel(omr, jz_eth_base + DMA_OMR);
+
+ readl(jz_eth_base + DMA_MFC); //through read operation to clear the register for 0x0000000
+
+ /* Set the programmable burst length (value 1 or 4 is validate)*/
+#if 0 /* __BIG_ENDIAN__ */
+ writel(PBL_4 | DSL_0 | 0x100080, jz_eth_base + DMA_BMR); /* DSL_0: see DESC_SKIP_LEN and DESC_ALIGN */
+#else /* __LITTLE_ENDIAN__ */
+ writel(PBL_4 | DSL_0, jz_eth_base + DMA_BMR); /* DSL_0: see DESC_SKIP_LEN and DESC_ALIGN */
+#endif
+
+ /* Config MCR register*/
+ mcr = (readl(jz_eth_base + MAC_MCR) & ~(MCR_PS | MCR_HBD | MCR_FDX));
+ if(np->full_duplex)
+ mcr |= MCR_FDX;
+ mcr |= MCR_BFD | MCR_TE | MCR_RE | MCR_OWD|MCR_HBD;
+ writel(mcr, jz_eth_base + MAC_MCR);
+
+ /* Set base address of TX and RX descriptors */
+ writel(np->dma_rx_ring, jz_eth_base + DMA_RRBA);
+ writel(np->dma_tx_ring, jz_eth_base + DMA_TRBA);
+
+ START_ETH();
+
+ /* set interrupt mask */
+ writel(IMR_DEFAULT | IMR_ENABLE, jz_eth_base + DMA_IMR);
+
+ /* Reset any pending (stale) interrupts */
+ sts = readl(jz_eth_base + DMA_STS);
+ writel(sts, jz_eth_base + DMA_STS);
+
+ return 0;
+}
+
+static void jz_eth_ring_init(struct net_device *dev)
+{
+ struct jz_eth_private *np = netdev_priv(dev);
+ int i;
+
+ for (i = 0; i < NUM_RX_DESCS; i++) {
+ np->rx_ring[i].status = cpu_to_le32(R_OWN);
+ np->rx_ring[i].desc1 = cpu_to_le32(RX_BUF_SIZE | RD_RCH);
+ np->rx_ring[i].buf1_addr = cpu_to_le32(np->dma_rx_buf + i*RX_BUF_SIZE);
+ np->rx_ring[i].next_addr = cpu_to_le32(np->dma_rx_ring + (i+1) * sizeof (jz_desc_t));
+ }
+ np->rx_ring[NUM_RX_DESCS - 1].next_addr = cpu_to_le32(np->dma_rx_ring);
+
+ for (i = 0; i < NUM_TX_DESCS; i++) {
+ np->tx_ring[i].status = cpu_to_le32(0);
+ np->tx_ring[i].desc1 = cpu_to_le32(TD_TCH);
+ np->tx_ring[i].buf1_addr = 0;
+ np->tx_ring[i].next_addr = cpu_to_le32(np->dma_tx_ring + (i+1) * sizeof (jz_desc_t));
+ }
+ np->tx_ring[NUM_TX_DESCS - 1].next_addr = cpu_to_le32(np->dma_tx_ring);
+
+ np->rx_head = 0;
+ np->tx_head = np->tx_tail = 0;
+
+ dma_cache_wback((unsigned long)np->rx_ring, sizeof(jz_desc_t)*NUM_RX_DESCS);
+ dma_cache_wback((unsigned long)np->tx_ring, sizeof(jz_desc_t)*NUM_TX_DESCS);
+}
+
+static int jz_eth_open(struct net_device *dev)
+{
+ int retval;
+
+ jz_eth_ring_init(dev);
+
+ if ((retval = jz_init_hw(dev)) != 0)
+ return retval;
+
+ retval = request_irq(dev->irq, jz_eth_interrupt, 0, dev->name, dev);
+ if (retval) {
+ printk(KERN_WARNING "%s: unable to get IRQ %d .\n", dev->name, dev->irq);
+ return -EAGAIN;
+ }
+
+ dev->trans_start = jiffies;
+ netif_start_queue(dev);
+ start_check(dev);
+
+ return 0;
+}
+
+static int jz_eth_close(struct net_device *dev)
+{
+ netif_stop_queue(dev);
+ close_check(dev);
+ STOP_ETH();
+ free_irq(dev->irq, dev);
+ return 0;
+}
+
+/*
+ * Get the current statistics.
+ * This may be called with the device open or closed.
+ */
+static struct net_device_stats * jz_eth_get_stats(struct net_device *dev)
+{
+ struct jz_eth_private *np = netdev_priv(dev);
+ int tmp;
+
+ tmp = readl(jz_eth_base + DMA_MFC); // After read clear to zero
+ np->stats.rx_missed_errors += (tmp & MFC_CNT2) + ((tmp & MFC_CNT1) >> 16);
+
+ return &np->stats;
+}
+
+/*
+ * ethtool routines
+ */
+static int jz_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+ struct jz_eth_private *np = netdev_priv(dev);
+ u32 ethcmd;
+
+ /* dev_ioctl() in ../../net/core/dev.c has already checked
+ capable(CAP_NET_ADMIN), so don't bother with that here. */
+
+ if (get_user(ethcmd, (u32 *)useraddr))
+ return -EFAULT;
+
+ switch (ethcmd) {
+
+ case ETHTOOL_GDRVINFO: {
+ struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+ strcpy (info.driver, DRV_NAME);
+ strcpy (info.version, DRV_VERSION);
+ strcpy (info.bus_info, "OCS");
+ if (copy_to_user (useraddr, &info, sizeof (info)))
+ return -EFAULT;
+ return 0;
+ }
+
+ /* get settings */
+ case ETHTOOL_GSET: {
+ struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+ spin_lock_irq(&np->lock);
+ mii_ethtool_gset(&mii_info, &ecmd);
+ spin_unlock_irq(&np->lock);
+ if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+ return -EFAULT;
+ return 0;
+ }
+ /* set settings */
+ case ETHTOOL_SSET: {
+ int r;
+ struct ethtool_cmd ecmd;
+ if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
+ return -EFAULT;
+ spin_lock_irq(&np->lock);
+ r = mii_ethtool_sset(&mii_info, &ecmd);
+ spin_unlock_irq(&np->lock);
+ return r;
+ }
+ /* restart autonegotiation */
+ case ETHTOOL_NWAY_RST: {
+ return mii_nway_restart(&mii_info);
+ }
+ /* get link status */
+ case ETHTOOL_GLINK: {
+ struct ethtool_value edata = {ETHTOOL_GLINK};
+ edata.data = mii_link_ok(&mii_info);
+ if (copy_to_user(useraddr, &edata, sizeof(edata)))
+ return -EFAULT;
+ return 0;
+ }
+
+ /* get message-level */
+ case ETHTOOL_GMSGLVL: {
+ struct ethtool_value edata = {ETHTOOL_GMSGLVL};
+ edata.data = debug;
+ if (copy_to_user(useraddr, &edata, sizeof(edata)))
+ return -EFAULT;
+ return 0;
+ }
+ /* set message-level */
+ case ETHTOOL_SMSGLVL: {
+ struct ethtool_value edata;
+ if (copy_from_user(&edata, useraddr, sizeof(edata)))
+ return -EFAULT;
+ debug = edata.data;
+ return 0;
+ }
+
+
+ default:
+ break;
+ }
+
+ return -EOPNOTSUPP;
+
+}
+
+/*
+ * Config device
+ */
+static int jz_eth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct jz_eth_private *np = netdev_priv(dev);
+ struct mii_ioctl_data *data, rdata;
+
+ switch (cmd) {
+ case SIOCETHTOOL:
+ return jz_ethtool_ioctl(dev, (void *) rq->ifr_data);
+ case SIOCGMIIPHY:
+ case SIOCDEVPRIVATE:
+ data = (struct mii_ioctl_data *)&rq->ifr_data;
+ data->phy_id = np->valid_phy;
+ case SIOCGMIIREG:
+ case SIOCDEVPRIVATE+1:
+ data = (struct mii_ioctl_data *)&rq->ifr_data;
+ data->val_out = mdio_read(dev,np->valid_phy, data->reg_num & 0x1f);
+ return 0;
+ case SIOCSMIIREG:
+ case SIOCDEVPRIVATE+2:
+ data = (struct mii_ioctl_data *)&rq->ifr_data;
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ mdio_write(dev,np->valid_phy, data->reg_num & 0x1f, data->val_in);
+ return 0;
+ case READ_COMMAND:
+ data = (struct mii_ioctl_data *)rq->ifr_data;
+ if (copy_from_user(&rdata,data,sizeof(rdata)))
+ return -EFAULT;
+ rdata.val_out = mdio_read(dev,rdata.phy_id, rdata.reg_num & 0x1f);
+ if (copy_to_user(data,&rdata,sizeof(rdata)))
+ return -EFAULT;
+ return 0;
+ case WRITE_COMMAND:
+ if (np->phy_type==1) {
+ data = (struct mii_ioctl_data *)rq->ifr_data;
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (copy_from_user(&rdata,data,sizeof(rdata)))
+ return -EFAULT;
+ mdio_write(dev,rdata.phy_id, rdata.reg_num & 0x1f, rdata.val_in);
+ }
+ return 0;
+ case GETDRIVERINFO:
+ if (np->phy_type==1) {
+ data = (struct mii_ioctl_data *)rq->ifr_data;
+ if (copy_from_user(&rdata,data,sizeof(rdata)))
+ return -EFAULT;
+ rdata.val_in = 0x1;
+ rdata.val_out = 0x00d0;
+ if (copy_to_user(data,&rdata,sizeof(rdata)))
+ return -EFAULT;
+ }
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+/*
+ * Received one packet
+ */
+static void eth_rxready(struct net_device *dev)
+{
+ struct jz_eth_private *np = netdev_priv(dev);
+ struct sk_buff *skb;
+ unsigned char *pkt_ptr;
+ u32 pkt_len;
+ u32 status;
+
+ ring_inv(np->rx_ring, np->rx_head);
+ status = le32_to_cpu(np->rx_ring[np->rx_head].status);
+ while (!(status & R_OWN)) { /* owner bit = 0 */
+ if (status & RD_ES) { /* error summary */
+ np->stats.rx_errors++; /* Update the error stats. */
+ if (status & (RD_RF | RD_TL))
+ np->stats.rx_frame_errors++;
+ if (status & RD_CE)
+ np->stats.rx_crc_errors++;
+ if (status & RD_TL)
+ np->stats.rx_length_errors++;
+ } else {
+ pkt_ptr = bus_to_virt(le32_to_cpu(np->rx_ring[np->rx_head].buf1_addr));
+ pkt_len = ((status & RD_FL) >> 16) - 4;
+
+ skb = dev_alloc_skb(pkt_len + 2);
+ if (skb == NULL) {
+ printk("%s: Memory squeeze, dropping.\n",
+ dev->name);
+ np->stats.rx_dropped++;
+ break;
+ }
+ skb->dev = dev;
+ skb_reserve(skb, 2); /* 16 byte align */
+
+ memcpy(skb->data, pkt_ptr, pkt_len);
+ skb_put(skb, pkt_len);
+
+ skb->protocol = eth_type_trans(skb,dev);
+ netif_rx(skb); /* pass the packet to upper layers */
+ dev->last_rx = jiffies;
+ np->stats.rx_packets++;
+ np->stats.rx_bytes += pkt_len;
+ }
+ np->rx_ring[np->rx_head].status = cpu_to_le32(R_OWN);
+
+ np->rx_head ++;
+ if (np->rx_head >= NUM_RX_DESCS)
+ np->rx_head = 0;
+ ring_inv(np->rx_ring, np->rx_head);
+ status = le32_to_cpu(np->rx_ring[np->rx_head].status);
+ }
+}
+
+/*
+ * Tx timeout routine
+ */
+static void jz_eth_tx_timeout(struct net_device *dev)
+{
+ struct jz_eth_private *np = netdev_priv(dev);
+
+ jz_init_hw(dev);
+ np->stats.tx_errors ++;
+ netif_wake_queue(dev);
+}
+
+/*
+ * One packet was transmitted
+ */
+static void eth_txdone(struct net_device *dev)
+{
+ struct jz_eth_private *np = netdev_priv(dev);
+ int tx_tail = np->tx_tail;
+ int entry;
+ u32 status;
+
+ while (tx_tail != np->tx_head) {
+ entry = tx_tail % NUM_TX_DESCS;
+ ring_inv(np->tx_ring, entry);
+ status = le32_to_cpu(np->tx_ring[entry].status);
+ if (status & T_OWN)
+ break;
+ if (status & TD_ES ) { /* Error summary */
+ np->stats.tx_errors++;
+ if (status & TD_NC) np->stats.tx_carrier_errors++;
+ if (status & TD_LC) np->stats.tx_window_errors++;
+ if (status & TD_UF) np->stats.tx_fifo_errors++;
+ if (status & TD_DE) np->stats.tx_aborted_errors++;
+ if (np->tx_head != np->tx_tail)
+ writel(1, jz_eth_base + DMA_TPD); /* Restart a stalled TX */
+ } else
+ np->stats.tx_packets++;
+ /* Update the collision counter */
+ np->stats.collisions += ((status & TD_EC) ? 16 : ((status & TD_CC) >> 3));
+ /* Free the original skb */
+ if (np->tx_skb[entry]) {
+ dev_kfree_skb_irq(np->tx_skb[entry]);
+ np->tx_skb[entry] = 0;
+ }
+ tx_tail++;
+ }
+ if (np->tx_full && (tx_tail + NUM_TX_DESCS > np->tx_head + 1)) {
+ /* The ring is no longer full */
+ np->tx_full = 0;
+ netif_wake_queue(dev);
+ }
+ np->tx_tail = tx_tail;
+}
+
+/*
+ * Update the tx descriptor
+ */
+static void load_tx_packet(struct net_device *dev, char *buf, u32 flags, struct sk_buff *skb)
+{
+ struct jz_eth_private *np = netdev_priv(dev);
+ int entry = np->tx_head % NUM_TX_DESCS;
+
+ np->tx_ring[entry].buf1_addr = cpu_to_le32(virt_to_bus(buf));
+ np->tx_ring[entry].desc1 &= cpu_to_le32((TD_TER | TD_TCH));
+ np->tx_ring[entry].desc1 |= cpu_to_le32(flags);
+ np->tx_ring[entry].status = cpu_to_le32(T_OWN);
+ np->tx_skb[entry] = skb;
+
+ ring_wback(np->tx_ring, entry);
+}
+
+/*
+ * Transmit one packet
+ */
+static int jz_eth_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+ struct jz_eth_private *np = netdev_priv(dev);
+ u32 length;
+
+ if (np->tx_full) {
+ return 0;
+ }
+
+ length = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
+ dma_cache_wback((unsigned long)skb->data, length);
+ load_tx_packet(dev, (char *)skb->data,
+ TD_IC | TD_LS | TD_FS | (length & TD_TBS1), skb);
+
+ spin_lock_irq(&np->lock);
+ np->tx_head ++;
+ np->stats.tx_bytes += length;
+ writel(1, jz_eth_base + DMA_TPD); /* Start the TX */
+
+ dev->trans_start = jiffies; /* for timeout */
+ if (np->tx_tail + NUM_TX_DESCS > np->tx_head + 1) {
+ np->tx_full = 0;
+ }
+ else {
+ np->tx_full = 1;
+ netif_stop_queue(dev);
+ }
+ spin_unlock_irq(&np->lock);
+
+ return 0;
+}
+
+/*
+ * Interrupt service routine
+ */
+static irqreturn_t jz_eth_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = (struct net_device *)dev_id;
+ struct jz_eth_private *np = netdev_priv(dev);
+ u32 sts;
+ int i;
+
+ spin_lock(&np->lock);
+
+ writel((readl(jz_eth_base + DMA_IMR) & ~IMR_ENABLE),
+ jz_eth_base + DMA_IMR);
+
+ for (i = 0; i < 100; i++) {
+ /* clear status */
+ sts = readl(jz_eth_base + DMA_STS);
+ writel(sts, jz_eth_base + DMA_STS);
+
+ if (!(sts & IMR_DEFAULT))
+ break;
+
+ if (sts & (DMA_INT_RI | DMA_INT_RU))
+ /* Rx IRQ */
+ eth_rxready(dev);
+ if (sts & (DMA_INT_TI | DMA_INT_TU)) {
+ /* Tx IRQ */
+ eth_txdone(dev);
+ }
+
+ /* check error conditions */
+ if (sts & DMA_INT_FB){
+ STOP_ETH();
+ printk(KERN_ERR "%s: Fatal bus error occurred, sts=%#8x, "
+ "device stopped.\n",dev->name, sts);
+ break;
+ }
+
+ /* Transmit underrun */
+ if (sts & DMA_INT_UN) {
+ u32 omr;
+ omr = readl(jz_eth_base + DMA_OMR);
+ if (!(omr & OMR_SF)) {
+ omr &= ~(OMR_ST | OMR_SR);
+ writel(omr, jz_eth_base + DMA_OMR);
+
+ /* wait for stop */
+ while (readl(jz_eth_base + DMA_STS) & STS_TS)
+ ;
+
+ /* increase transmit threshold if possible */
+ if ((omr & OMR_TR) < OMR_TR) {
+ omr += TR_24;
+ } else {
+ omr |= OMR_SF;
+ }
+ writel(omr | OMR_ST | OMR_SR,
+ jz_eth_base + DMA_OMR);
+ }
+ }
+ }
+
+ writel(readl(jz_eth_base + DMA_IMR)|IMR_ENABLE, jz_eth_base + DMA_IMR);
+
+ spin_unlock(&np->lock);
+
+ return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_PM
+/*
+ * Suspend the ETH interface.
+ */
+static int jz_eth_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct jz_eth_private *jep = netdev_priv(dev);
+ unsigned long flags, tmp;
+
+ if (!netif_running(dev))
+ return 0;
+
+ netif_device_detach(dev);
+
+ spin_lock_irqsave(&jep->lock, flags);
+
+ /* Disable interrupts, stop Tx and Rx. */
+ writel(0, jz_eth_base + DMA_IMR);
+ STOP_ETH();
+
+ /* Update the error counts. */
+ tmp = readl(jz_eth_base + DMA_MFC);
+ jep->stats.rx_missed_errors += (tmp & 0x1ffff);
+ jep->stats.rx_fifo_errors += ((tmp >> 17) & 0x7ff);
+
+ spin_unlock_irqrestore(&jep->lock, flags);
+
+ return 0;
+}
+
+/*
+ * Resume the ETH interface.
+ */
+static int jz_eth_resume(struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+
+ if (!netif_running(dev))
+ return 0;
+
+ jz_eth_ring_init(dev);
+ jz_init_hw(dev);
+
+ netif_device_attach(dev);
+ netif_wake_queue(dev);
+
+ return 0;
+}
+#else
+#define jz_eth_suspend NULL
+#define jz_eth_resume NULL
+#endif /* CONFIG_PM */
+
+static const struct net_device_ops jz_netdev_ops = {
+ .ndo_open = jz_eth_open,
+ .ndo_stop = jz_eth_close,
+ .ndo_start_xmit = jz_eth_send_packet,
+ .ndo_set_multicast_list = jz_set_multicast_list,
+ .ndo_tx_timeout = jz_eth_tx_timeout,
+ .ndo_get_stats = jz_eth_get_stats,
+ .ndo_do_ioctl = jz_eth_ioctl,
+};
+
+static int jz_eth_probe(struct platform_device *pdev)
+{
+ struct net_device *dev;
+ struct jz_eth_private *np;
+ int ret;
+
+ dev = alloc_etherdev(sizeof(struct jz_eth_private));
+ if (!dev) {
+ printk(KERN_ERR "%s: alloc_etherdev failed\n", DRV_NAME);
+ ret = -ENOMEM;
+ goto err0;
+ }
+
+ SET_NETDEV_DEV(dev, &pdev->dev);
+
+ np = netdev_priv(dev);
+ memset(np, 0, sizeof(struct jz_eth_private));
+
+ np->vaddr_rx_buf = (u32)dma_alloc_noncoherent(NULL,
+ NUM_RX_DESCS*RX_BUF_SIZE,
+ &np->dma_rx_buf, 0);
+
+ if (!np->vaddr_rx_buf) {
+ printk(KERN_ERR "%s: Cannot alloc dma buffers\n", DRV_NAME);
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ np->dma_rx_ring = virt_to_bus(np->rx_ring);
+ np->dma_tx_ring = virt_to_bus(np->tx_ring);
+ np->full_duplex = 1;
+ np->link_state = 1;
+
+ dev->irq = platform_get_irq(pdev, 0);
+ if (dev->irq < 0) {
+ ret = -ENXIO;
+ goto err2;
+ }
+
+ np->iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!np->iores) {
+ ret = -ENXIO;
+ goto err2;
+ }
+
+ np->iores = request_mem_region(np->iores->start,
+ resource_size(np->iores), pdev->name);
+ if (!np->iores) {
+ ret = -ENOMEM;
+ goto err2;
+ }
+
+ jz_eth_base = ioremap_nocache(np->iores->start,
+ resource_size(np->iores));
+ if (!jz_eth_base) {
+ ret = -EBUSY;
+ goto err3;
+ }
+
+ spin_lock_init(&np->lock);
+
+ dev->netdev_ops = &jz_netdev_ops;
+ dev->watchdog_timeo = ETH_TX_TIMEOUT;
+
+ /* configure MAC address */
+ get_mac_address(dev);
+
+ platform_set_drvdata(pdev, dev);
+
+ if ((ret = register_netdev(dev)) != 0) {
+ printk(KERN_ERR "%s: Cannot register net device, error %d\n",
+ DRV_NAME, ret);
+ goto err4;
+ }
+
+ return 0;
+
+err4:
+ iounmap(jz_eth_base);
+err3:
+ release_mem_region(np->iores->start, 0x10000);
+err2:
+ dma_free_noncoherent(NULL, NUM_RX_DESCS * RX_BUF_SIZE,
+ (void *)np->vaddr_rx_buf, np->dma_rx_buf);
+err1:
+ free_netdev(dev);
+err0:
+ return ret;
+}
+
+static int jz_eth_remove(struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct jz_eth_private *np = netdev_priv(dev);
+
+ unregister_netdev(dev);
+ iounmap(jz_eth_base);
+ release_mem_region(np->iores->start, 0x10000);
+ dma_free_noncoherent(NULL, NUM_RX_DESCS * RX_BUF_SIZE,
+ (void *)np->vaddr_rx_buf, np->dma_rx_buf);
+ free_netdev(dev);
+ return 0;
+}
+
+static struct platform_driver jz_eth_driver = {
+ .driver = {
+ .name = "jz-eth"
+ },
+ .probe = jz_eth_probe,
+ .remove = jz_eth_remove,
+ .suspend = jz_eth_suspend,
+ .resume = jz_eth_resume,
+};
+
+static int __init jz_eth_init(void)
+{
+ return platform_driver_register(&jz_eth_driver);
+}
+
+static void __exit jz_eth_exit(void)
+{
+ platform_driver_unregister(&jz_eth_driver);
+}
+
+module_init(jz_eth_init);
+module_exit(jz_eth_exit);
diff --git a/drivers/net/jz_eth.h b/drivers/net/jz_eth.h
new file mode 100644
index 0000000..62d147c
--- /dev/null
+++ b/drivers/net/jz_eth.h
@@ -0,0 +1,403 @@
+/*
+ * Jz4730/Jz5730 On-Chip ethernet driver.
+ *
+ * Copyright (C) 2005 - 2007 Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#ifndef __JZ_ETH_H__
+#define __JZ_ETH_H__
+
+/* DMA control and status registers */
+#define DMA_BMR 0x1000 // Bus mode
+#define DMA_TPD 0x1004 // Transmit poll demand register
+#define DMA_RPD 0x1008 // Receieve poll demand register
+#define DMA_RRBA 0x100C // Receieve descriptor base address
+#define DMA_TRBA 0x1010 // Transmit descriptor base address
+#define DMA_STS 0x1014 // Status register
+#define DMA_OMR 0x1018 // Command register
+#define DMA_IMR 0x101C
+#define DMA_MFC 0x1020
+
+/* DMA CSR8-CSR19 reserved */
+#define DMA_CTA 0x1050
+#define DMA_CRA 0x1054
+
+/* Mac control and status registers */
+#define MAC_MCR 0x0000
+#define MAC_MAH 0x0004
+#define MAC_MAL 0x0008
+#define MAC_HTH 0x000C
+#define MAC_HTL 0x0010
+#define MAC_MIIA 0x0014
+#define MAC_MIID 0x0018
+#define MAC_FCR 0x001C
+#define MAC_VTR1 0x0020
+#define MAC_VTR2 0x0024
+
+/*
+ * Bus Mode Register (DMA_BMR)
+ */
+#define BMR_PBL 0x00003f00 /* Programmable Burst Length */
+#define BMR_DSL 0x0000007c /* Descriptor Skip Length */
+#define BMR_BAR 0x00000002 /* Bus ARbitration */
+#define BMR_SWR 0x00000001 /* Software Reset */
+
+#define PBL_0 0x00000000 /* DMA burst length = amount in RX FIFO */
+#define PBL_1 0x00000100 /* 1 longword DMA burst length */
+#define PBL_2 0x00000200 /* 2 longwords DMA burst length */
+#define PBL_4 0x00000400 /* 4 longwords DMA burst length */
+#define PBL_8 0x00000800 /* 8 longwords DMA burst length */
+#define PBL_16 0x00001000 /* 16 longwords DMA burst length */
+#define PBL_32 0x00002000 /* 32 longwords DMA burst length */
+
+#define DSL_0 0x00000000 /* 0 longword / descriptor */
+#define DSL_1 0x00000004 /* 1 longword / descriptor */
+#define DSL_2 0x00000008 /* 2 longwords / descriptor */
+#define DSL_4 0x00000010 /* 4 longwords / descriptor */
+#define DSL_8 0x00000020 /* 8 longwords / descriptor */
+#define DSL_16 0x00000040 /* 16 longwords / descriptor */
+#define DSL_32 0x00000080 /* 32 longwords / descriptor */
+
+/*
+ * Status Register (DMA_STS)
+ */
+#define STS_BE 0x03800000 /* Bus Error Bits */
+#define STS_TS 0x00700000 /* Transmit Process State */
+#define STS_RS 0x000e0000 /* Receive Process State */
+
+#define TS_STOP 0x00000000 /* Stopped */
+#define TS_FTD 0x00100000 /* Running Fetch Transmit Descriptor */
+#define TS_WEOT 0x00200000 /* Running Wait for End Of Transmission */
+#define TS_QDAT 0x00300000 /* Running Queue skb data into TX FIFO */
+#define TS_RES 0x00400000 /* Reserved */
+#define TS_SPKT 0x00500000 /* Reserved */
+#define TS_SUSP 0x00600000 /* Suspended */
+#define TS_CLTD 0x00700000 /* Running Close Transmit Descriptor */
+
+#define RS_STOP 0x00000000 /* Stopped */
+#define RS_FRD 0x00020000 /* Running Fetch Receive Descriptor */
+#define RS_CEOR 0x00040000 /* Running Check for End of Receive Packet */
+#define RS_WFRP 0x00060000 /* Running Wait for Receive Packet */
+#define RS_SUSP 0x00080000 /* Suspended */
+#define RS_CLRD 0x000a0000 /* Running Close Receive Descriptor */
+#define RS_FLUSH 0x000c0000 /* Running Flush RX FIFO */
+#define RS_QRFS 0x000e0000 /* Running Queue RX FIFO into RX Skb */
+
+/*
+ * Operation Mode Register (DMA_OMR)
+ */
+#define OMR_TTM 0x00400000 /* Transmit Threshold Mode */
+#define OMR_SF 0x00200000 /* Store and Forward */
+#define OMR_TR 0x0000c000 /* Threshold Control Bits */
+#define OMR_ST 0x00002000 /* Start/Stop Transmission Command */
+#define OMR_OSF 0x00000004 /* Operate on Second Frame */
+#define OMR_SR 0x00000002 /* Start/Stop Receive */
+
+#define TR_18 0x00000000 /* Threshold set to 18 (32) bytes */
+#define TR_24 0x00004000 /* Threshold set to 24 (64) bytes */
+#define TR_32 0x00008000 /* Threshold set to 32 (128) bytes */
+#define TR_40 0x0000c000 /* Threshold set to 40 (256) bytes */
+
+/*
+ * Missed Frames Counters (DMA_MFC)
+ */
+//#define MFC_CNT1 0xffff0000 /* Missed Frames Counter Bits by application */
+#define MFC_CNT1 0x0ffe0000 /* Missed Frames Counter Bits by application */
+#define MFC_CNT2 0x0000ffff /* Missed Frames Counter Bits by controller */
+
+/*
+ * Mac control Register (MAC_MCR)
+ */
+#define MCR_RA 0x80000000 /* Receive All */
+#define MCR_HBD 0x10000000 /* HeartBeat Disable */
+#define MCR_PS 0x08000000 /* Port Select */
+#define MCR_OWD 0x00800000 /* Receive own Disable */
+#define MCR_OM 0x00600000 /* Operating(loopback) Mode */
+#define MCR_FDX 0x00100000 /* Full Duplex Mode */
+#define MCR_PM 0x00080000 /* Pass All Multicast */
+#define MCR_PR 0x00040000 /* Promiscuous Mode */
+#define MCR_IF 0x00020000 /* Inverse Filtering */
+#define MCR_PB 0x00010000 /* Pass Bad Frames */
+#define MCR_HO 0x00008000 /* Hash Only Filtering Mode */
+#define MCR_HP 0x00002000 /* Hash/Perfect Receive Filtering Mode */
+#define MCR_FC 0x00001000 /* Late Collision control */
+#define MCR_BFD 0x00000800 /* Boardcast frame Disable */
+#define MCR_RED 0x00000400 /* Retry Disable */
+#define MCR_APS 0x00000100 /* Automatic pad stripping */
+#define MCR_BL 0x000000c0 /* Back off Limit */
+#define MCR_DC 0x00000020 /* Deferral check */
+#define MCR_TE 0x00000008 /* Transmitter enable */
+#define MCR_RE 0x00000004 /* Receiver enable */
+
+#define MCR_MII_10 ( OMR_TTM | MCR_PS)
+#define MCR_MII_100 ( MCR_HBD | MCR_PS)
+
+/* Flow control Register (MAC_FCR) */
+#define FCR_PT 0xffff0000 /* Pause time */
+#define FCR_PCF 0x00000004 /* Pass control frames */
+#define FCR_FCE 0x00000002 /* Flow control enable */
+#define FCR_FCB 0x00000001 /* Flow control busy */
+
+
+/* Constants for the interrupt mask and
+ * interrupt status registers. (DMA_SIS and DMA_IMR)
+ */
+#define DMA_INT_NI 0x00010000 // Normal interrupt summary
+#define DMA_INT_AI 0x00008000 // Abnormal interrupt summary
+#define DMA_INT_ER 0x00004000 // Early receive interrupt
+#define DMA_INT_FB 0x00002000 // Fatal bus error
+#define DMA_INT_ET 0x00000400 // Early transmit interrupt
+#define DMA_INT_RW 0x00000200 // Receive watchdog timeout
+#define DMA_INT_RS 0x00000100 // Receive stop
+#define DMA_INT_RU 0x00000080 // Receive buffer unavailble
+#define DMA_INT_RI 0x00000040 // Receive interrupt
+#define DMA_INT_UN 0x00000020 // Underflow
+#define DMA_INT_TJ 0x00000008 // Transmit jabber timeout
+#define DMA_INT_TU 0x00000004 // Transmit buffer unavailble
+#define DMA_INT_TS 0x00000002 // Transmit stop
+#define DMA_INT_TI 0x00000001 // Transmit interrupt
+
+/*
+ * Receive Descriptor Bit Summary
+ */
+#define R_OWN 0x80000000 /* Own Bit */
+#define RD_FF 0x40000000 /* Filtering Fail */
+#define RD_FL 0x3fff0000 /* Frame Length */
+#define RD_ES 0x00008000 /* Error Summary */
+#define RD_DE 0x00004000 /* Descriptor Error */
+#define RD_LE 0x00001000 /* Length Error */
+#define RD_RF 0x00000800 /* Runt Frame */
+#define RD_MF 0x00000400 /* Multicast Frame */
+#define RD_FS 0x00000200 /* First Descriptor */
+#define RD_LS 0x00000100 /* Last Descriptor */
+#define RD_TL 0x00000080 /* Frame Too Long */
+#define RD_CS 0x00000040 /* Collision Seen */
+#define RD_FT 0x00000020 /* Frame Type */
+#define RD_RJ 0x00000010 /* Receive Watchdog timeout*/
+#define RD_RE 0x00000008 /* Report on MII Error */
+#define RD_DB 0x00000004 /* Dribbling Bit */
+#define RD_CE 0x00000002 /* CRC Error */
+
+#define RD_RER 0x02000000 /* Receive End Of Ring */
+#define RD_RCH 0x01000000 /* Second Address Chained */
+#define RD_RBS2 0x003ff800 /* Buffer 2 Size */
+#define RD_RBS1 0x000007ff /* Buffer 1 Size */
+
+/*
+ * Transmit Descriptor Bit Summary
+ */
+#define T_OWN 0x80000000 /* Own Bit */
+#define TD_ES 0x00008000 /* Frame Aborted (error summary)*/
+#define TD_LO 0x00000800 /* Loss Of Carrier */
+#define TD_NC 0x00000400 /* No Carrier */
+#define TD_LC 0x00000200 /* Late Collision */
+#define TD_EC 0x00000100 /* Excessive Collisions */
+#define TD_HF 0x00000080 /* Heartbeat Fail */
+#define TD_CC 0x0000003c /* Collision Counter */
+#define TD_UF 0x00000002 /* Underflow Error */
+#define TD_DE 0x00000001 /* Deferred */
+
+#define TD_IC 0x80000000 /* Interrupt On Completion */
+#define TD_LS 0x40000000 /* Last Segment */
+#define TD_FS 0x20000000 /* First Segment */
+#define TD_FT1 0x10000000 /* Filtering Type */
+#define TD_SET 0x08000000 /* Setup Packet */
+#define TD_AC 0x04000000 /* Add CRC Disable */
+#define TD_TER 0x02000000 /* Transmit End Of Ring */
+#define TD_TCH 0x01000000 /* Second Address Chained */
+#define TD_DPD 0x00800000 /* Disabled Padding */
+#define TD_FT0 0x00400000 /* Filtering Type */
+#define TD_TBS2 0x003ff800 /* Buffer 2 Size */
+#define TD_TBS1 0x000007ff /* Buffer 1 Size */
+
+#define PERFECT_F 0x00000000
+#define HASH_F TD_FT0
+#define INVERSE_F TD_FT1
+#define HASH_O_F (TD_FT1 | TD_F0)
+
+/*
+ * Constant setting
+ */
+
+#define IMR_DEFAULT ( DMA_INT_TI | DMA_INT_RI | \
+ DMA_INT_TS | DMA_INT_RS | \
+ DMA_INT_TU | DMA_INT_RU | \
+ DMA_INT_FB )
+
+#define IMR_ENABLE (DMA_INT_NI | DMA_INT_AI)
+
+#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
+#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
+
+#define HASH_TABLE_LEN 512 /* Bits */
+#define HASH_BITS 0x01ff /* 9 LS bits */
+
+#define SETUP_FRAME_LEN 192 /* Bytes */
+#define IMPERF_PA_OFFSET 156 /* Bytes */
+
+/*
+ * Address Filtering Modes
+ */
+#define PERFECT 0 /* 16 perfect physical addresses */
+#define HASH_PERF 1 /* 1 perfect, 512 multicast addresses */
+#define PERFECT_REJ 2 /* Reject 16 perfect physical addresses */
+#define ALL_HASH 3 /* Hashes all physical & multicast addrs */
+
+#define ALL 0 /* Clear out all the setup frame */
+#define PHYS_ADDR_ONLY 1 /* Update the physical address only */
+
+/* MII register */
+#define MII_BMCR 0x00 /* MII Basic Mode Control Register */
+#define MII_BMSR 0x01 /* MII Basic Mode Status Register */
+#define MII_ID1 0x02 /* PHY Identifier Register 1 */
+#define MII_ID2 0x03 /* PHY Identifier Register 2 */
+#define MII_ANAR 0x04 /* Auto Negotiation Advertisement Register */
+#define MII_ANLPAR 0x05 /* Auto Negotiation Link Partner Ability */
+#define MII_ANER 0x06 /* Auto Negotiation Expansion */
+#define MII_DSCR 0x10 /* Davicom Specified Configration Register */
+#define MII_DSCSR 0x11 /* Davicom Specified Configration/Status Register */
+#define MII_10BTCSR 0x12 /* 10base-T Specified Configration/Status Register */
+
+
+#define MII_PREAMBLE 0xffffffff /* MII Management Preamble */
+#define MII_TEST 0xaaaaaaaa /* MII Test Signal */
+#define MII_STRD 0x06 /* Start of Frame+Op Code: use low nibble */
+#define MII_STWR 0x0a /* Start of Frame+Op Code: use low nibble */
+
+/*
+ * MII Management Control Register
+ */
+#define MII_CR_RST 0x8000 /* RESET the PHY chip */
+#define MII_CR_LPBK 0x4000 /* Loopback enable */
+#define MII_CR_SPD 0x2000 /* 0: 10Mb/s; 1: 100Mb/s */
+#define MII_CR_ASSE 0x1000 /* Auto Speed Select Enable */
+#define MII_CR_PD 0x0800 /* Power Down */
+#define MII_CR_ISOL 0x0400 /* Isolate Mode */
+#define MII_CR_RAN 0x0200 /* Restart Auto Negotiation */
+#define MII_CR_FDM 0x0100 /* Full Duplex Mode */
+#define MII_CR_CTE 0x0080 /* Collision Test Enable */
+
+/*
+ * MII Management Status Register
+ */
+#define MII_SR_T4C 0x8000 /* 100BASE-T4 capable */
+#define MII_SR_TXFD 0x4000 /* 100BASE-TX Full Duplex capable */
+#define MII_SR_TXHD 0x2000 /* 100BASE-TX Half Duplex capable */
+#define MII_SR_TFD 0x1000 /* 10BASE-T Full Duplex capable */
+#define MII_SR_THD 0x0800 /* 10BASE-T Half Duplex capable */
+#define MII_SR_ASSC 0x0020 /* Auto Speed Selection Complete*/
+#define MII_SR_RFD 0x0010 /* Remote Fault Detected */
+#define MII_SR_ANC 0x0008 /* Auto Negotiation capable */
+#define MII_SR_LKS 0x0004 /* Link Status */
+#define MII_SR_JABD 0x0002 /* Jabber Detect */
+#define MII_SR_XC 0x0001 /* Extended Capabilities */
+
+/*
+ * MII Management Auto Negotiation Advertisement Register
+ */
+#define MII_ANA_TAF 0x03e0 /* Technology Ability Field */
+#define MII_ANA_T4AM 0x0200 /* T4 Technology Ability Mask */
+#define MII_ANA_TXAM 0x0180 /* TX Technology Ability Mask */
+#define MII_ANA_FDAM 0x0140 /* Full Duplex Technology Ability Mask */
+#define MII_ANA_HDAM 0x02a0 /* Half Duplex Technology Ability Mask */
+#define MII_ANA_100M 0x0380 /* 100Mb Technology Ability Mask */
+#define MII_ANA_10M 0x0060 /* 10Mb Technology Ability Mask */
+#define MII_ANA_CSMA 0x0001 /* CSMA-CD Capable */
+
+/*
+ * MII Management Auto Negotiation Remote End Register
+ */
+#define MII_ANLPA_NP 0x8000 /* Next Page (Enable) */
+#define MII_ANLPA_ACK 0x4000 /* Remote Acknowledge */
+#define MII_ANLPA_RF 0x2000 /* Remote Fault */
+#define MII_ANLPA_TAF 0x03e0 /* Technology Ability Field */
+#define MII_ANLPA_T4AM 0x0200 /* T4 Technology Ability Mask */
+#define MII_ANLPA_TXAM 0x0180 /* TX Technology Ability Mask */
+#define MII_ANLPA_FDAM 0x0140 /* Full Duplex Technology Ability Mask */
+#define MII_ANLPA_HDAM 0x02a0 /* Half Duplex Technology Ability Mask */
+#define MII_ANLPA_100M 0x0380 /* 100Mb Technology Ability Mask */
+#define MII_ANLPA_10M 0x0060 /* 10Mb Technology Ability Mask */
+#define MII_ANLPA_CSMA 0x0001 /* CSMA-CD Capable */
+
+/*
+ * MII Management DAVICOM Specified Configuration And Status Register
+ */
+#define MII_DSCSR_100FDX 0x8000 /* 100M Full Duplex Operation Mode */
+#define MII_DSCSR_100HDX 0x4000 /* 100M Half Duplex Operation Mode */
+#define MII_DSCSR_10FDX 0x2000 /* 10M Full Duplex Operation Mode */
+#define MII_DSCSR_10HDX 0x1000 /* 10M Half Duplex Operation Mode */
+#define MII_DSCSR_ANMB 0x000f /* Auto-Negotiation Monitor Bits */
+
+
+/*
+ * Used by IOCTL
+ */
+#define READ_COMMAND (SIOCDEVPRIVATE+4)
+#define WRITE_COMMAND (SIOCDEVPRIVATE+5)
+#define GETDRIVERINFO (SIOCDEVPRIVATE+6)
+
+/*
+ * Device data and structure
+ */
+
+#define ETH_TX_TIMEOUT (6*HZ)
+
+#define RX_BUF_SIZE 1536
+
+#define NUM_RX_DESCS 32
+#define NUM_TX_DESCS 16
+
+static const char *media_types[] = {
+ "10BaseT-HD ", "10BaseT-FD ","100baseTx-HD ",
+ "100baseTx-FD", "100baseT4", 0
+};
+
+typedef struct {
+ unsigned int status;
+ unsigned int desc1;
+ unsigned int buf1_addr;
+ unsigned int next_addr;
+} jz_desc_t;
+
+struct jz_eth_private {
+ jz_desc_t tx_ring[NUM_TX_DESCS]; /* transmit descriptors */
+ jz_desc_t rx_ring[NUM_RX_DESCS]; /* receive descriptors */
+ dma_addr_t dma_tx_ring; /* bus address of tx ring */
+ dma_addr_t dma_rx_ring; /* bus address of rx ring */
+ dma_addr_t dma_rx_buf; /* DMA address of rx buffer */
+ unsigned int vaddr_rx_buf; /* virtual address of rx buffer */
+
+ unsigned int rx_head; /* first rx descriptor */
+ unsigned int tx_head; /* first tx descriptor */
+ unsigned int tx_tail; /* last unacked transmit packet */
+ unsigned int tx_full; /* transmit buffers are full */
+ struct sk_buff *tx_skb[NUM_TX_DESCS]; /* skbuffs for packets to transmit */
+
+ struct net_device_stats stats;
+ spinlock_t lock;
+
+ int media; /* Media (eg TP), mode (eg 100B)*/
+ int full_duplex; /* Current duplex setting. */
+ int link_state;
+ char phys[32]; /* List of attached PHY devices */
+ char valid_phy; /* Current linked phy-id with MAC */
+ int mii_phy_cnt;
+ int phy_type; /* 1-RTL8309,0-DVCOM */
+ struct ethtool_cmd ecmds[32];
+ u16 advertising; /* NWay media advertisement */
+
+ struct task_struct *thread; /* Link check thread */
+ int thread_die;
+ struct completion thr_exited;
+ wait_queue_head_t thr_wait;
+
+ struct pm_dev *pmdev;
+
+ struct resource *iores;
+};
+
+#endif /* __JZ_ETH_H__ */
--
1.6.4
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH 0/3] XBurst JZ4730 support
2010-02-25 6:28 [PATCH 0/3] XBurst JZ4730 support Graham Gower
` (2 preceding siblings ...)
2010-02-25 6:31 ` [PATCH 3/3] net: add driver for JZ4730 ethernet controller Graham Gower
@ 2010-02-25 7:52 ` Florian Fainelli
2010-02-25 21:12 ` Graham Gower
3 siblings, 1 reply; 10+ messages in thread
From: Florian Fainelli @ 2010-02-25 7:52 UTC (permalink / raw)
To: Graham Gower, Mirko Vogt, Lars-Peter Clausen; +Cc: linux-mips
Hi Graham,
On Thursday 25 February 2010 07:28:32 Graham Gower wrote:
> This patch set contains support for Ingenic's XBurst cpu, plus basic
> support for their JZ4730 reference boards.
>
>
> Graham Gower (3):
> Add XBurst JZ4730 support.
> 8250: serial driver changes for XBurst SoCs.
> net: add driver for JZ4730 ethernet controller.
Seems like patches 1 and 3 were too big and got retained by the mailing-list
program.
Maybe you should work with the OpenWrt and qi-hardware guys to get the jz4740
also merged in the same time?
>
> arch/mips/Kconfig | 13 +
> arch/mips/Makefile | 14 +-
> arch/mips/boot/Makefile | 15 +-
> arch/mips/include/asm/bootinfo.h | 7 +
> arch/mips/include/asm/cpu.h | 9 +
> arch/mips/include/asm/mach-generic/irq.h | 2 +-
> arch/mips/include/asm/mach-xburst/clock-jz4730.h | 41 +
> arch/mips/include/asm/mach-xburst/dma-jz4730.h | 156 +++
> arch/mips/include/asm/mach-xburst/irq-jz4730.h | 33 +
> arch/mips/include/asm/mach-xburst/uart-jz4730.h | 141 +++
> arch/mips/include/asm/mach-xburst/war.h | 25 +
> arch/mips/include/asm/mach-xburst/xburst.h | 20 +
> arch/mips/include/asm/r4kcache.h | 240 +++++
> arch/mips/kernel/cpu-probe.c | 21 +
> arch/mips/mm/c-r4k.c | 30 +
> arch/mips/mm/tlbex.c | 5 +
> arch/mips/xburst/Kconfig | 23 +
> arch/mips/xburst/Makefile | 3 +
> arch/mips/xburst/jz4730/Makefile | 11 +
> arch/mips/xburst/jz4730/board-libra.c | 32 +
> arch/mips/xburst/jz4730/board-pmp.c | 32 +
> arch/mips/xburst/jz4730/clocks.c | 294 +++++
> arch/mips/xburst/jz4730/irq.c | 104 ++
> arch/mips/xburst/jz4730/platform.c | 49 +
> arch/mips/xburst/jz4730/prom.c | 104 ++
> arch/mips/xburst/jz4730/setup.c | 136 +++
> arch/mips/xburst/jz4730/time.c | 140 +++
> drivers/net/Kconfig | 10 +
> drivers/net/Makefile | 1 +
> drivers/net/jz_eth.c | 1232
> ++++++++++++++++++++++ drivers/net/jz_eth.h |
> 403 +++++++
> drivers/serial/8250.c | 12 +
> 32 files changed, 3355 insertions(+), 3 deletions(-)
> create mode 100644 arch/mips/include/asm/mach-xburst/clock-jz4730.h
> create mode 100644 arch/mips/include/asm/mach-xburst/dma-jz4730.h
> create mode 100644 arch/mips/include/asm/mach-xburst/irq-jz4730.h
> create mode 100644 arch/mips/include/asm/mach-xburst/uart-jz4730.h
> create mode 100644 arch/mips/include/asm/mach-xburst/war.h
> create mode 100644 arch/mips/include/asm/mach-xburst/xburst.h
> create mode 100644 arch/mips/xburst/Kconfig
> create mode 100644 arch/mips/xburst/Makefile
> create mode 100644 arch/mips/xburst/jz4730/Makefile
> create mode 100644 arch/mips/xburst/jz4730/board-libra.c
> create mode 100644 arch/mips/xburst/jz4730/board-pmp.c
> create mode 100644 arch/mips/xburst/jz4730/clocks.c
> create mode 100644 arch/mips/xburst/jz4730/irq.c
> create mode 100644 arch/mips/xburst/jz4730/platform.c
> create mode 100644 arch/mips/xburst/jz4730/prom.c
> create mode 100644 arch/mips/xburst/jz4730/setup.c
> create mode 100644 arch/mips/xburst/jz4730/time.c
> create mode 100644 drivers/net/jz_eth.c
> create mode 100644 drivers/net/jz_eth.h
>
--
Regards, Florian
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 0/3] XBurst JZ4730 support
2010-02-25 7:52 ` [PATCH 0/3] XBurst JZ4730 support Florian Fainelli
@ 2010-02-25 21:12 ` Graham Gower
2010-02-26 1:51 ` Lars-Peter Clausen
0 siblings, 1 reply; 10+ messages in thread
From: Graham Gower @ 2010-02-25 21:12 UTC (permalink / raw)
To: Florian Fainelli; +Cc: Mirko Vogt, Lars-Peter Clausen, linux-mips
On 25 February 2010 18:22, Florian Fainelli <florian@openwrt.org> wrote:
> Hi Graham,
>
> On Thursday 25 February 2010 07:28:32 Graham Gower wrote:
>> This patch set contains support for Ingenic's XBurst cpu, plus basic
>> support for their JZ4730 reference boards.
>>
>>
>> Graham Gower (3):
>> Add XBurst JZ4730 support.
>> 8250: serial driver changes for XBurst SoCs.
>> net: add driver for JZ4730 ethernet controller.
>
> Seems like patches 1 and 3 were too big and got retained by the mailing-list
> program.
They seem to have made it to the list archives now. Thread here:
http://www.linux-mips.org/archives/linux-mips/2010-02/msg00243.html
>
> Maybe you should work with the OpenWrt and qi-hardware guys to get the jz4740
> also merged in the same time?
>
I've not seen any active attempt to get xburst code merged before and
assumed there was no interest from others. I'm happy to be wrong on
this.
My patch does not preclude adding jz4740 support. I don't have any of
these devices however, so have only included code for the jz4730.
-Graham
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 0/3] XBurst JZ4730 support
2010-02-25 21:12 ` Graham Gower
@ 2010-02-26 1:51 ` Lars-Peter Clausen
2010-02-26 3:34 ` Graham Gower
0 siblings, 1 reply; 10+ messages in thread
From: Lars-Peter Clausen @ 2010-02-26 1:51 UTC (permalink / raw)
To: Graham Gower; +Cc: Florian Fainelli, Mirko Vogt, linux-mips
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Hi
Graham Gower wrote:
> On 25 February 2010 18:22, Florian Fainelli <florian@openwrt.org> wrote:
>> Maybe you should work with the OpenWrt and qi-hardware guys to get the
jz4740
>> also merged in the same time?
>
> I've not seen any active attempt to get xburst code merged before and
> assumed there was no interest from others. I'm happy to be wrong on
> this.
I'm currently working on linux support for a few jz4740 hbased devices.
And it's definitely a goal get the code merged upstream once it is in
proper shape, but there is still some stuff that needs to be done.
Mostly documentation and smaller cleanups.
>
> My patch does not preclude adding jz4740 support. I don't have any of
> these devices however, so have only included code for the jz4730.
Unfortunately I don't have a jz4730 programmers manual to check so I
can't say for sure, but I guess there is quite some code that could be
shared between between both SoCS(and other jz47xx). I think we don't
want to do what Ingenic did with their codebase and copy 'n paste the
same file with minor modifications for each soc type.
You can find the patches (and files) adding jz4740 support to the
linux kernel at [1] and [2].
I suggest you take a look at it and see if we could use some of the
files(irq, gpio, dma, ...) for a common base between all jz47xx SoCs.
>
> -Graham
- - Lars
[1]
https://dev.openwrt.org/browser/trunk/target/linux/xburst/patches-2.6.32
[2] https://dev.openwrt.org/browser/trunk/target/linux/xburst/files-2.6.32
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
iEYEARECAAYFAkuHKQMACgkQBX4mSR26RiOGCgCdGzATziYC4wYLvz0HNhqwFOYi
OXAAn2mZx0e8qmqHtl+Vfm9vau9urpW+
=nIni
-----END PGP SIGNATURE-----
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 0/3] XBurst JZ4730 support
2010-02-26 1:51 ` Lars-Peter Clausen
@ 2010-02-26 3:34 ` Graham Gower
2010-02-26 11:41 ` Anoop P.A.
0 siblings, 1 reply; 10+ messages in thread
From: Graham Gower @ 2010-02-26 3:34 UTC (permalink / raw)
To: Lars-Peter Clausen; +Cc: Florian Fainelli, Mirko Vogt, linux-mips
On 26 February 2010 12:21, Lars-Peter Clausen <lars@metafoo.de> wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> Hi
>
> Graham Gower wrote:
>> On 25 February 2010 18:22, Florian Fainelli <florian@openwrt.org> wrote:
>>> Maybe you should work with the OpenWrt and qi-hardware guys to get the
> jz4740
>>> also merged in the same time?
>>
>> I've not seen any active attempt to get xburst code merged before and
>> assumed there was no interest from others. I'm happy to be wrong on
>> this.
> I'm currently working on linux support for a few jz4740 hbased devices.
> And it's definitely a goal get the code merged upstream once it is in
> proper shape, but there is still some stuff that needs to be done.
> Mostly documentation and smaller cleanups.
I was hoping to get something simple (i.e. bootable with serial) into
the tree and submit other drivers later, as time permits.
>>
>> My patch does not preclude adding jz4740 support. I don't have any of
>> these devices however, so have only included code for the jz4730.
> Unfortunately I don't have a jz4730 programmers manual to check so I
> can't say for sure, but I guess there is quite some code that could be
> shared between between both SoCS(and other jz47xx). I think we don't
> want to do what Ingenic did with their codebase and copy 'n paste the
> same file with minor modifications for each soc type.
The 4740 docs are a copy/paste of the 4730 docs with changes here and
there and lots of register shuffling.
>
> You can find the patches (and files) adding jz4740 support to the
> linux kernel at [1] and [2].
> I suggest you take a look at it and see if we could use some of the
> files(irq, gpio, dma, ...) for a common base between all jz47xx SoCs.
The interrupt controllers look quite similar (the irq numbers have
been shuffled around). The gpio and dma controllers are quite
different however.
The MMC and LCD controllers look almost identical. I don't have any
docs for the nand, but Ingenic's code for the 4730 and 4740 look very
similar. The USB gadget code differs (udc controller info is missing
from my 4740 docs) - the jz4730 gadget driver they are shipping is
broken and they ignored my patch to fix it.
-Graham
^ permalink raw reply [flat|nested] 10+ messages in thread
* blast_dcache32 problem with PREEMPT kernel
@ 2010-02-26 11:41 ` Anoop P.A.
0 siblings, 0 replies; 10+ messages in thread
From: Anoop P.A. @ 2010-02-26 11:41 UTC (permalink / raw)
To: linux-mips
Hi list,
I am hitting following bug with CONFIG_PREEMP enabled VSMP kernel (
2.6.24) compiled for mips34K core.
BUG: using smp_processor_id() in preemptible [00000001] code:
usb-storage/190
caller is blast_dcache32+0x30/0x25c
Call Trace:
[<8012f338>] vprintk+0x2e8/0x584
[<8012f354>] vprintk+0x304/0x584
[<801111a0>] blast_dcache32+0x30/0x25c
[<80387d5c>] debug_smp_processor_id+0xcc/0xe0
[<801111a0>] blast_dcache32+0x30/0x25c
[<80387d5c>] debug_smp_processor_id+0xcc/0xe0
[<801111a0>] blast_dcache32+0x30/0x25c
[<8010d9e4>] dma_map_sg+0x128/0x144
[<80410a84>] urb_destroy+0x0/0x38
[<801827b0>] kfree+0x8c/0x20c
[<80411944>] usb_sg_init+0x310/0x324
[<8042a708>] usb_stor_bulk_transfer_sg+0xd0/0x174
[<8042a914>] usb_stor_Bulk_transport+0x168/0x324
[<80121a94>] enqueue_entity+0xcc/0x130
[<8042a3f4>] usb_stor_invoke_transport+0x38/0x27c
[<80149ee8>] remove_wait_queue+0x1c/0x60
[<8054568c>] _spin_unlock_irqrestore+0x24/0x44
[<805425fc>] __down_interruptible+0x144/0x1e4
[<801239f0>] default_wake_function+0x0/0x8
[<8042bd58>] usb_stor_control_thread+0x268/0x320
[<801497c0>] kthread+0x0/0xa4
[<80149800>] kthread+0x40/0xa4
[<801241d8>] complete+0x4c/0x6c
[<8042baf0>] usb_stor_control_thread+0x0/0x320
[<80149818>] kthread+0x58/0xa4
[<8010476c>] kernel_thread_helper+0x10/0x18
Any pointers to debug this / fix this will be greatly appreciated.
Thanking you,
Anoop
^ permalink raw reply [flat|nested] 10+ messages in thread
* blast_dcache32 problem with PREEMPT kernel
@ 2010-02-26 11:41 ` Anoop P.A.
0 siblings, 0 replies; 10+ messages in thread
From: Anoop P.A. @ 2010-02-26 11:41 UTC (permalink / raw)
To: linux-mips
Hi list,
I am hitting following bug with CONFIG_PREEMP enabled VSMP kernel (
2.6.24) compiled for mips34K core.
BUG: using smp_processor_id() in preemptible [00000001] code:
usb-storage/190
caller is blast_dcache32+0x30/0x25c
Call Trace:
[<8012f338>] vprintk+0x2e8/0x584
[<8012f354>] vprintk+0x304/0x584
[<801111a0>] blast_dcache32+0x30/0x25c
[<80387d5c>] debug_smp_processor_id+0xcc/0xe0
[<801111a0>] blast_dcache32+0x30/0x25c
[<80387d5c>] debug_smp_processor_id+0xcc/0xe0
[<801111a0>] blast_dcache32+0x30/0x25c
[<8010d9e4>] dma_map_sg+0x128/0x144
[<80410a84>] urb_destroy+0x0/0x38
[<801827b0>] kfree+0x8c/0x20c
[<80411944>] usb_sg_init+0x310/0x324
[<8042a708>] usb_stor_bulk_transfer_sg+0xd0/0x174
[<8042a914>] usb_stor_Bulk_transport+0x168/0x324
[<80121a94>] enqueue_entity+0xcc/0x130
[<8042a3f4>] usb_stor_invoke_transport+0x38/0x27c
[<80149ee8>] remove_wait_queue+0x1c/0x60
[<8054568c>] _spin_unlock_irqrestore+0x24/0x44
[<805425fc>] __down_interruptible+0x144/0x1e4
[<801239f0>] default_wake_function+0x0/0x8
[<8042bd58>] usb_stor_control_thread+0x268/0x320
[<801497c0>] kthread+0x0/0xa4
[<80149800>] kthread+0x40/0xa4
[<801241d8>] complete+0x4c/0x6c
[<8042baf0>] usb_stor_control_thread+0x0/0x320
[<80149818>] kthread+0x58/0xa4
[<8010476c>] kernel_thread_helper+0x10/0x18
Any pointers to debug this / fix this will be greatly appreciated.
Thanking you,
Anoop
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2010-02-26 11:41 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-02-25 6:28 [PATCH 0/3] XBurst JZ4730 support Graham Gower
2010-02-25 6:29 ` [PATCH 1/3] Add " Graham Gower
2010-02-25 6:30 ` [PATCH 2/3] 8250: serial driver changes for XBurst SoCs Graham Gower
2010-02-25 6:31 ` [PATCH 3/3] net: add driver for JZ4730 ethernet controller Graham Gower
2010-02-25 7:52 ` [PATCH 0/3] XBurst JZ4730 support Florian Fainelli
2010-02-25 21:12 ` Graham Gower
2010-02-26 1:51 ` Lars-Peter Clausen
2010-02-26 3:34 ` Graham Gower
2010-02-26 11:41 ` blast_dcache32 problem with PREEMPT kernel Anoop P.A.
2010-02-26 11:41 ` Anoop P.A.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.