1
0
mirror of git://projects.qi-hardware.com/openwrt-xburst.git synced 2025-04-21 12:27:27 +03:00

[lantiq] adds new lantiq kernel. once the codebase is fully tested and know to be working on all the devices previously supported by ifxmips, we will drop ifxmips support.

git-svn-id: svn://svn.openwrt.org/openwrt/trunk@24526 3c298f89-4303-0410-b956-a3cf2f4a3e73
This commit is contained in:
blogic
2010-12-12 22:57:16 +00:00
parent 8d8d887cb0
commit 18a076fccd
52 changed files with 40307 additions and 0 deletions

View File

@@ -0,0 +1,25 @@
#
# Copyright (C) 2007-2010 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
ARCH:=mips
BOARD:=lantiq
BOARDNAME:=Lantiq GPON/XWAY
FEATURES:=squashfs jffs2 atm
SUBTARGETS:=xway
LINUX_VERSION:=2.6.35.9
CFLAGS=-Os -pipe -mips32r2 -mtune=mips32r2 -funit-at-a-time
include $(INCLUDE_DIR)/target.mk
define Target/Description
Build firmware images for Lantiq SoC
endef
$(eval $(call BuildTarget))

View File

@@ -0,0 +1,26 @@
config interface loopback
option ifname lo
option proto static
option ipaddr 127.0.0.1
option netmask 255.0.0.0
config interface lan
option ifname eth0
option type bridge
option proto static
option ipaddr 192.168.1.1
option netmask 255.255.255.0
config atm-bridge
option unit 0
option encaps llc
option vpi 1
option vci 32
option payload bridged # some ISPs need this set to 'routed'
config interface wan
option ifname nas0
option proto pppoe
option username ""
option password ""
option unit 0

View File

@@ -0,0 +1,4 @@
::sysinit:/etc/init.d/rcS S boot
::shutdown:/etc/init.d/rcS K stop
ttyS0::askfirst:/bin/ash --login
ttyS1::askfirst:/bin/ash --login

View File

@@ -0,0 +1,25 @@
PART_NAME=linux
platform_check_image() {
[ "$ARGC" -gt 1 ] && return 1
case "$(get_magic_word "$1")" in
# .trx files
2705) return 0;;
*)
echo "Invalid image type"
return 1
;;
esac
}
# use default for platform_do_upgrade()
disable_watchdog() {
killall watchdog
( ps | grep -v 'grep' | grep '/dev/watchdog' ) && {
echo 'Could not disable watchdog'
return 1
}
}
append sysupgrade_pre_upgrade disable_watchdog

View File

@@ -0,0 +1,163 @@
# CONFIG_TC35815 is not set
# CONFIG_TINY_RCU is not set
# CONFIG_TREE_PREEMPT_RCU is not set
# CONFIG_HAVE_IDE is not set
# CONFIG_64BIT is not set
# CONFIG_ALCHEMY_GPIO_INDIRECT is not set
# CONFIG_AR7 is not set
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
# CONFIG_ARCH_SUPPORTS_MSI is not set
# CONFIG_BCM47XX is not set
# CONFIG_BCM63XX is not set
# CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD is not set
# CONFIG_CAVIUM_OCTEON_SIMULATOR is not set
# CONFIG_CPU_CAVIUM_OCTEON is not set
# CONFIG_CPU_LITTLE_ENDIAN is not set
# CONFIG_CPU_LOONGSON2E is not set
# CONFIG_CPU_LOONGSON2F is not set
# CONFIG_CPU_MIPS32_R1 is not set
# CONFIG_CPU_MIPS64_R1 is not set
# CONFIG_CPU_MIPS64_R2 is not set
# CONFIG_CPU_NEVADA is not set
# CONFIG_CPU_R10000 is not set
# CONFIG_CPU_R3000 is not set
# CONFIG_CPU_R4300 is not set
# CONFIG_CPU_R4X00 is not set
# CONFIG_CPU_R5000 is not set
# CONFIG_CPU_R5432 is not set
# CONFIG_CPU_R5500 is not set
# CONFIG_CPU_R6000 is not set
# CONFIG_CPU_R8000 is not set
# CONFIG_CPU_RM7000 is not set
# CONFIG_CPU_RM9000 is not set
# CONFIG_CPU_SB1 is not set
# CONFIG_CPU_TX39XX is not set
# CONFIG_CPU_TX49XX is not set
# CONFIG_CPU_VR41XX is not set
# CONFIG_DM9000 is not set
# CONFIG_FSNOTIFY is not set
# CONFIG_HZ_100 is not set
# CONFIG_LOONGSON_UART_BASE is not set
# CONFIG_MACH_ALCHEMY is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MACH_JAZZ is not set
# CONFIG_MACH_LOONGSON is not set
# CONFIG_MACH_TX39XX is not set
# CONFIG_MACH_TX49XX is not set
# CONFIG_MACH_VR41XX is not set
# CONFIG_MIKROTIK_RB532 is not set
# CONFIG_MIPS_COBALT is not set
# CONFIG_MIPS_MALTA is not set
# CONFIG_MIPS_MT_SMP is not set
# CONFIG_MIPS_MT_SMTC is not set
# CONFIG_MIPS_SIM is not set
# CONFIG_MIPS_VPE_LOADER is not set
# CONFIG_NO_IOPORT is not set
# CONFIG_NXP_STB220 is not set
# CONFIG_NXP_STB225 is not set
# CONFIG_PMC_MSP is not set
# CONFIG_PMC_YOSEMITE is not set
# CONFIG_PNX8550_JBS is not set
# CONFIG_PNX8550_STB810 is not set
# CONFIG_POWERTV is not set
# CONFIG_SCSI_DMA is not set
# CONFIG_SERIAL_8250 is not set
# CONFIG_SERIAL_8250_EXTENDED is not set
# CONFIG_SGI_IP22 is not set
# CONFIG_SGI_IP27 is not set
# CONFIG_SGI_IP28 is not set
# CONFIG_SGI_IP32 is not set
# CONFIG_SIBYTE_BIGSUR is not set
# CONFIG_SIBYTE_CARMEL is not set
# CONFIG_SIBYTE_CRHINE is not set
# CONFIG_SIBYTE_CRHONE is not set
# CONFIG_SIBYTE_LITTLESUR is not set
# CONFIG_SIBYTE_RHONE is not set
# CONFIG_SIBYTE_SENTOSA is not set
# CONFIG_SIBYTE_SWARM is not set
CONFIG_32BIT=y
CONFIG_ADM6996_PHY=y
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_ARCH_REQUIRE_GPIOLIB=y
CONFIG_ARCH_SUPPORTS_OPROFILE=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_BITREVERSE=y
CONFIG_CEVT_R4K=y
CONFIG_CEVT_R4K_LIB=y
CONFIG_CPU_BIG_ENDIAN=y
CONFIG_CPU_HAS_PREFETCH=y
CONFIG_CPU_HAS_SYNC=y
CONFIG_CPU_MIPS32=y
CONFIG_CPU_MIPS32_R2=y
CONFIG_CPU_MIPSR2=y
CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
CONFIG_CPU_SUPPORTS_HIGHMEM=y
CONFIG_CRYPTO_BLKCIPHER=y
CONFIG_CRYPTO_BLKCIPHER2=y
CONFIG_CRYPTO_HW=y
CONFIG_CRYPTO_RNG2=y
CONFIG_CRYPTO_WORKQUEUE=y
CONFIG_CSRC_R4K=y
CONFIG_CSRC_R4K_LIB=y
CONFIG_DECOMPRESS_LZMA=y
CONFIG_DEVPORT=y
CONFIG_DMA_NEED_PCI_MAP_STATE=y
CONFIG_DMA_NONCOHERENT=y
CONFIG_EARLY_PRINTK=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
CONFIG_GENERIC_CMOS_UPDATE=y
CONFIG_GENERIC_FIND_LAST_BIT=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_GPIO=y
CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_SYSFS=y
CONFIG_HARDWARE_WATCHPOINTS=y
CONFIG_HAS_DMA=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAVE_ARCH_KGDB=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
CONFIG_HAVE_GENERIC_DMA_COHERENT=y
CONFIG_HAVE_OPROFILE=y
CONFIG_HW_RANDOM=y
CONFIG_HZ=250
CONFIG_HZ_250=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_IRQ_CPU=y
CONFIG_LANTIQ=y
CONFIG_MIPS=y
CONFIG_MIPS_L1_CACHE_SHIFT=5
CONFIG_MIPS_MACHINE=y
CONFIG_MIPS_MT_DISABLED=y
CONFIG_MTD_CFI_ADV_OPTIONS=y
CONFIG_MTD_CFI_GEOMETRY=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_LANTIQ=y
CONFIG_NLS=y
CONFIG_PAGEFLAGS_EXTENDED=y
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
CONFIG_PHYLIB=y
CONFIG_SCHED_OMIT_FRAME_POINTER=y
CONFIG_SERIAL_LANTIQ=y
CONFIG_SWAP_IO_SPACE=y
CONFIG_SWCONFIG=y
CONFIG_SYS_HAS_CPU_MIPS32_R1=y
CONFIG_SYS_HAS_CPU_MIPS32_R2=y
CONFIG_SYS_HAS_EARLY_PRINTK=y
CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
CONFIG_SYS_SUPPORTS_MULTITHREADING=y
CONFIG_TRAD_SIGNALS=y
CONFIG_TREE_RCU=y
CONFIG_ZONE_DMA_FLAG=0
CONFIG_IFX_UDP_REDIRECT=y

View File

@@ -0,0 +1,89 @@
#
# Copyright (C) 2010 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/image.mk
JFFS2_BLOCKSIZE = 64k 128k 256k
xway_cmdline=-console=ttyS1,115200 rootfstype=squashfs,jffs2
falcon_cmdline=-console=ttyS0,115200 rootfstype=squashfs,jffs2
define CompressLzma
$(STAGING_DIR_HOST)/bin/lzma e $(1) $(2)
endef
define PatchKernelLzma
cp $(KDIR)/vmlinux $(KDIR)/vmlinux-$(1)
$(STAGING_DIR_HOST)/bin/patch-cmdline $(KDIR)/vmlinux-$(1) '$(strip $(2))'
$(call CompressLzma,$(KDIR)/vmlinux-$(1),$(KDIR)/vmlinux-$(1).lzma)
endef
define MkImageLzma
mkimage -A mips -O linux -T kernel -a 0x80002000 -C lzma \
-e 0x80002000 -n 'MIPS OpenWrt Linux-$(LINUX_VERSION)' \
-d $(KDIR)/vmlinux-$(1).lzma $(KDIR)/uImage-$(1)
endef
define Image/Build/squashfs
cat $(KDIR)/uImage-$(2) $(KDIR)/root.$(1) > $(BIN_DIR)/$(IMG_PREFIX)-$(2)-$(1).image
$(call prepare_generic_squashfs,$(BIN_DIR)/$(IMG_PREFIX)-$(2)-$(1).image)
endef
define Image/Build/jffs2-64k
dd if=$(KDIR)/uImage-$(2) of=$(KDIR)/uImage-$(2)-$(1) bs=64k conv=sync
cat $(KDIR)/uImage-$(2)-$(1) $(KDIR)/root.$(1) > $(BIN_DIR)/$(IMG_PREFIX)-$(2)-$(1).image
endef
define Image/Build/jffs2-128k
dd if=$(KDIR)/uImage-$(2) of=$(KDIR)/uImage-$(2)-$(1) bs=128k conv=sync
cat $(KDIR)/uImage-$(2)-$(1) $(KDIR)/root.$(1) > $(BIN_DIR)/$(IMG_PREFIX)-$(2)-$(1).image
endef
define Image/Build/jffs2-256k
dd if=$(KDIR)/uImage-$(2) of=$(KDIR)/uImage-$(2)-$(1) bs=256k conv=sync
cat $(KDIR)/uImage-$(2)-$(1) $(KDIR)/root.$(1) > $(BIN_DIR)/$(IMG_PREFIX)-$(2)-$(1).image
endef
define Image/BuildKernel/Template
$(call PatchKernelLzma,$(1),$(if $(2),$(2) machtype=$(1),))
$(call MkImageLzma,$(1))
$(CP) $(KDIR)/uImage-$(1) $(BIN_DIR)/$(IMG_PREFIX)-$(1)-uImage
endef
ifeq ($(CONFIG_SOC_LANTIQ_XWAY),y)
define Image/BuildKernel
$(call Image/BuildKernel/Template,EASY4010,$(xway_cmdline))
$(call Image/BuildKernel/Template,EASY50712,$(xway_cmdline))
$(call Image/BuildKernel/Template,EASY50812,$(xway_cmdline))
$(call Image/BuildKernel/Template,ARV452,$(xway_cmdline))
$(call Image/BuildKernel/Template,NONE)
endef
define Image/Build
$(call Image/Build/$(1),$(1),EASY4010)
$(call Image/Build/$(1),$(1),EASY50712)
$(call Image/Build/$(1),$(1),EASY50812)
$(call Image/Build/$(1),$(1),ARV452)
$(call Image/Build/$(1),$(1),NONE)
$(CP) $(KDIR)/root.$(1) $(BIN_DIR)/$(IMG_PREFIX)-$(1).rootfs
endef
endif
ifeq ($(CONFIG_SOC_LANTIQ_FALCON),y)
define Image/BuildKernel
$(call Image/BuildKernel/Template,EASY98000,$(falcon_cmdline))
$(call Image/BuildKernel/Template,NONE)
endef
define Image/Build
$(call Image/Build/$(1),$(1),EASY98000)
$(call Image/Build/$(1),$(1),NONE)
$(CP) $(KDIR)/root.$(1) $(BIN_DIR)/$(IMG_PREFIX)-$(1).rootfs
endef
endif
$(eval $(call BuildImage))

View File

@@ -0,0 +1,47 @@
#
# Copyright (C) 2010 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
define KernelPackage/lantiq-deu
TITLE:=Lantiq data encryption unit
SUBMENU:=$(CRYPTO_MENU)
DEPENDS:=@TARGET_lantiq
KCONFIG:=CONFIG_CRYPTO_DEV_LANTIQ \
CONFIG_CRYPTO_HW=y \
CONFIG_CRYPTO_DEV_LANTIQ_AES=y \
CONFIG_CRYPTO_DEV_LANTIQ_DES=y \
CONFIG_CRYPTO_DEV_LANTIQ_MD5=y \
CONFIG_CRYPTO_DEV_LANTIQ_SHA1=y
$(call AddDepends/crypto)
endef
define KernelPackage/lantiq-deu/description
Kernel support for the Lantiq crypto HW
endef
$(eval $(call KernelPackage,lantiq-deu))
USB_MENU:=USB Support
define KernelPackage/usb-dwc-otg
TITLE:=Synopsis DWC_OTG support
SUBMENU:=$(USB_MENU)
DEPENDS+=@TARGET_lantiq_xway +kmod-usb-core
KCONFIG:=CONFIG_DWC_OTG \
CONFIG_DWC_OTG_DEBUG=n \
CONFIG_DWC_OTG_LANTIQ=y \
CONFIG_DWC_OTG_HOST_ONLY=y
FILES:=$(LINUX_DIR)/drivers/usb/dwc_otg/dwc_otg.ko
AUTOLOAD:=$(call AutoLoad,50,dwc_otg)
endef
define KernelPackage/usb-dwc-otg/description
Kernel support for Synopsis USB on XWAY
endef
$(eval $(call KernelPackage,usb-dwc-otg))

View File

@@ -0,0 +1,35 @@
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -1496,7 +1496,18 @@ void __cpuinit per_cpu_trap_init(void)
if (cpu_has_mips_r2) {
cp0_compare_irq_shift = CAUSEB_TI - CAUSEB_IP;
cp0_compare_irq = (read_c0_intctl() >> INTCTLB_IPTI) & 7;
+
+ if (!cp0_compare_irq)
+ cp0_compare_irq = CP0_LEGACY_COMPARE_IRQ;
+
cp0_perfcount_irq = (read_c0_intctl() >> INTCTLB_IPPCI) & 7;
+
+ if (!cp0_perfcount_irq)
+ cp0_perfcount_irq = CP0_LEGACY_PERFCNT_IRQ;
+
+ if (arch_fixup_c0_irqs)
+ arch_fixup_c0_irqs();
+
if (cp0_perfcount_irq == cp0_compare_irq)
cp0_perfcount_irq = -1;
} else {
--- a/arch/mips/include/asm/irq.h
+++ b/arch/mips/include/asm/irq.h
@@ -133,9 +133,11 @@ extern void free_irqno(unsigned int irq)
* IE7. Since R2 their number has to be read from the c0_intctl register.
*/
#define CP0_LEGACY_COMPARE_IRQ 7
+#define CP0_LEGACY_PERFCNT_IRQ 7
extern int cp0_compare_irq;
extern int cp0_compare_irq_shift;
extern int cp0_perfcount_irq;
+extern void __weak arch_fixup_c0_irqs(void);
#endif /* _ASM_IRQ_H */

View File

@@ -0,0 +1,33 @@
--- a/arch/mips/kernel/cevt-r4k.c
+++ b/arch/mips/kernel/cevt-r4k.c
@@ -22,6 +22,22 @@
#ifndef CONFIG_MIPS_MT_SMTC
+/*
+ * Compare interrupt can be routed and latched outside the core,
+ * so a single execution hazard barrier may not be enough to give
+ * it time to clear as seen in the Cause register. 4 time the
+ * pipeline depth seems reasonably conservative, and empirically
+ * works better in configurations with high CPU/bus clock ratios.
+ */
+
+#define compare_change_hazard() \
+ do { \
+ irq_disable_hazard(); \
+ irq_disable_hazard(); \
+ irq_disable_hazard(); \
+ irq_disable_hazard(); \
+ } while (0)
+
static int mips_next_event(unsigned long delta,
struct clock_event_device *evt)
{
@@ -31,6 +47,7 @@ static int mips_next_event(unsigned long
cnt = read_c0_count();
cnt += delta;
write_c0_compare(cnt);
+ compare_change_hazard();
res = ((int)(read_c0_count() - cnt) > 0) ? -ETIME : 0;
return res;
}

View File

@@ -0,0 +1,12 @@
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -650,6 +650,9 @@ handle_percpu_irq(unsigned int irq, stru
kstat_incr_irqs_this_cpu(irq, desc);
+ if (unlikely(!desc->action || (desc->status & IRQ_DISABLED)))
+ return;
+
if (desc->chip->ack)
desc->chip->ack(irq);

View File

@@ -0,0 +1,641 @@
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -139,6 +139,9 @@ config MACH_DECSTATION
otherwise choose R3000.
+config LANTIQ
+ bool "Lantiq MIPS"
+
config MACH_JAZZ
bool "Jazz family of machines"
select ARC
@@ -693,6 +696,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/lantiq/Kconfig"
endmenu
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -317,6 +317,17 @@ cflags-$(CONFIG_MIPS_COBALT) += -I$(srct
load-$(CONFIG_MIPS_COBALT) += 0xffffffff80080000
#
+# Lantiq
+#
+load-$(CONFIG_LANTIQ) += 0xffffffff80002000
+core-$(CONFIG_LANTIQ) += arch/mips/lantiq/
+cflags-$(CONFIG_LANTIQ) += -I$(srctree)/arch/mips/include/asm/mach-lantiq
+core-$(CONFIG_SOC_LANTIQ_FALCON) += arch/mips/lantiq/falcon/
+cflags-$(CONFIG_SOC_LANTIQ_FALCON) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/falcon
+core-$(CONFIG_SOC_LANTIQ_XWAY) += arch/mips/lantiq/xway/
+cflags-$(CONFIG_SOC_LANTIQ_XWAY) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/xway
+
+#
# DECstation family
#
core-$(CONFIG_MACH_DECSTATION) += arch/mips/dec/
--- /dev/null
+++ b/arch/mips/lantiq/Kconfig
@@ -0,0 +1,36 @@
+if LANTIQ
+
+config SOC_LANTIQ
+ bool
+ select DMA_NONCOHERENT
+ select IRQ_CPU
+ select CEVT_R4K
+ select CSRC_R4K
+ select SYS_HAS_CPU_MIPS32_R1
+ select SYS_HAS_CPU_MIPS32_R2
+ select SYS_SUPPORTS_BIG_ENDIAN
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_MULTITHREADING
+ select SYS_HAS_EARLY_PRINTK
+ select HW_HAS_PCI
+ select ARCH_REQUIRE_GPIOLIB
+ select SWAP_IO_SPACE
+ select MIPS_MACHINE
+
+choice
+ prompt "SoC Type"
+ default SOC_LANTIQ_XWAY
+
+#config SOC_LANTIQ_FALCON
+# bool "FALCON"
+# select SOC_LANTIQ
+
+config SOC_LANTIQ_XWAY
+ bool "XWAY"
+ select SOC_LANTIQ
+endchoice
+
+#source "arch/mips/lantiq/falcon/Kconfig"
+source "arch/mips/lantiq/xway/Kconfig"
+
+endif
--- /dev/null
+++ b/arch/mips/lantiq/Makefile
@@ -0,0 +1,2 @@
+obj-y := irq.o setup.o clk.o prom.o
+obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
--- /dev/null
+++ b/arch/mips/lantiq/irq.c
@@ -0,0 +1,212 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+
+#include <asm/bootinfo.h>
+#include <asm/irq_cpu.h>
+
+#include <lantiq.h>
+#include <irq.h>
+
+#define LQ_ICU_BASE_ADDR (KSEG1 | 0x1F880200)
+
+#define LQ_ICU_IM0_ISR ((u32 *)(LQ_ICU_BASE_ADDR + 0x0000))
+#define LQ_ICU_IM0_IER ((u32 *)(LQ_ICU_BASE_ADDR + 0x0008))
+#define LQ_ICU_IM0_IOSR ((u32 *)(LQ_ICU_BASE_ADDR + 0x0010))
+#define LQ_ICU_IM0_IRSR ((u32 *)(LQ_ICU_BASE_ADDR + 0x0018))
+#define LQ_ICU_IM0_IMR ((u32 *)(LQ_ICU_BASE_ADDR + 0x0020))
+
+#define LQ_ICU_IM1_ISR ((u32 *)(LQ_ICU_BASE_ADDR + 0x0028))
+#define LQ_ICU_IM2_ISR ((u32 *)(LQ_ICU_BASE_ADDR + 0x0050))
+#define LQ_ICU_IM3_ISR ((u32 *)(LQ_ICU_BASE_ADDR + 0x0078))
+#define LQ_ICU_IM4_ISR ((u32 *)(LQ_ICU_BASE_ADDR + 0x00A0))
+
+#define LQ_ICU_OFFSET (LQ_ICU_IM1_ISR - LQ_ICU_IM0_ISR)
+
+void
+lq_disable_irq(unsigned int irq_nr)
+{
+ u32 *ier = LQ_ICU_IM0_IER;
+ irq_nr -= INT_NUM_IRQ0;
+ ier += LQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
+ irq_nr %= INT_NUM_IM_OFFSET;
+ lq_w32(lq_r32(ier) & ~(1 << irq_nr), ier);
+}
+EXPORT_SYMBOL(lq_disable_irq);
+
+void
+lq_mask_and_ack_irq(unsigned int irq_nr)
+{
+ u32 *ier = LQ_ICU_IM0_IER;
+ u32 *isr = LQ_ICU_IM0_ISR;
+ irq_nr -= INT_NUM_IRQ0;
+ ier += LQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
+ isr += LQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
+ irq_nr %= INT_NUM_IM_OFFSET;
+ lq_w32(lq_r32(ier) & ~(1 << irq_nr), ier);
+ lq_w32((1 << irq_nr), isr);
+}
+EXPORT_SYMBOL(lq_mask_and_ack_irq);
+
+static void
+lq_ack_irq(unsigned int irq_nr)
+{
+ u32 *isr = LQ_ICU_IM0_ISR;
+ irq_nr -= INT_NUM_IRQ0;
+ isr += LQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
+ irq_nr %= INT_NUM_IM_OFFSET;
+ lq_w32((1 << irq_nr), isr);
+}
+
+void
+lq_enable_irq(unsigned int irq_nr)
+{
+ u32 *ier = LQ_ICU_IM0_IER;
+ irq_nr -= INT_NUM_IRQ0;
+ ier += LQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
+ irq_nr %= INT_NUM_IM_OFFSET;
+ lq_w32(lq_r32(ier) | (1 << irq_nr), ier);
+}
+EXPORT_SYMBOL(lq_enable_irq);
+
+static unsigned int
+lq_startup_irq(unsigned int irq)
+{
+ lq_enable_irq(irq);
+ return 0;
+}
+
+static void
+lq_end_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+ lq_enable_irq(irq);
+}
+
+static struct irq_chip
+lq_irq_type = {
+ "lq_irq",
+ .startup = lq_startup_irq,
+ .enable = lq_enable_irq,
+ .disable = lq_disable_irq,
+ .unmask = lq_enable_irq,
+ .ack = lq_ack_irq,
+ .mask = lq_disable_irq,
+ .mask_ack = lq_mask_and_ack_irq,
+ .end = lq_end_irq,
+};
+
+static void
+lq_hw_irqdispatch(int module)
+{
+ u32 irq;
+
+ irq = lq_r32(LQ_ICU_IM0_IOSR + (module * LQ_ICU_OFFSET));
+ if (irq == 0)
+ return;
+
+ /* silicon bug causes only the msb set to 1 to be valid. all
+ other bits might be bogus */
+ irq = __fls(irq);
+ do_IRQ((int)irq + INT_NUM_IM0_IRL0 + (INT_NUM_IM_OFFSET * module));
+}
+
+#define DEFINE_HWx_IRQDISPATCH(x) \
+static void lq_hw ## x ## _irqdispatch(void)\
+{\
+ lq_hw_irqdispatch(x); \
+}
+static void lq_hw5_irqdispatch(void)
+{
+ do_IRQ(MIPS_CPU_TIMER_IRQ);
+}
+DEFINE_HWx_IRQDISPATCH(0)
+DEFINE_HWx_IRQDISPATCH(1)
+DEFINE_HWx_IRQDISPATCH(2)
+DEFINE_HWx_IRQDISPATCH(3)
+DEFINE_HWx_IRQDISPATCH(4)
+/*DEFINE_HWx_IRQDISPATCH(5)*/
+
+asmlinkage void
+plat_irq_dispatch(void)
+{
+ unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
+ unsigned int i;
+
+ if (pending & CAUSEF_IP7)
+ {
+ do_IRQ(MIPS_CPU_TIMER_IRQ);
+ goto out;
+ } else {
+ for (i = 0; i < 5; i++)
+ {
+ if (pending & (CAUSEF_IP2 << i))
+ {
+ lq_hw_irqdispatch(i);
+ goto out;
+ }
+ }
+ }
+ printk(KERN_ALERT "Spurious IRQ: CAUSE=0x%08x\n", read_c0_status());
+
+out:
+ return;
+}
+
+static struct irqaction
+cascade = {
+ .handler = no_action,
+ .flags = IRQF_DISABLED,
+ .name = "cascade",
+};
+
+void __init
+arch_init_irq(void)
+{
+ int i;
+
+ for (i = 0; i < 5; i++)
+ lq_w32(0, LQ_ICU_IM0_IER + (i * LQ_ICU_OFFSET));
+
+ mips_cpu_irq_init();
+
+ for (i = 2; i <= 6; i++)
+ setup_irq(i, &cascade);
+
+ if (cpu_has_vint) {
+ printk(KERN_INFO "Setting up vectored interrupts\n");
+ set_vi_handler(2, lq_hw0_irqdispatch);
+ set_vi_handler(3, lq_hw1_irqdispatch);
+ set_vi_handler(4, lq_hw2_irqdispatch);
+ set_vi_handler(5, lq_hw3_irqdispatch);
+ set_vi_handler(6, lq_hw4_irqdispatch);
+ set_vi_handler(7, lq_hw5_irqdispatch);
+ }
+
+ for (i = INT_NUM_IRQ0; i <= (INT_NUM_IRQ0 + (5 * INT_NUM_IM_OFFSET)); i++)
+ set_irq_chip_and_handler(i, &lq_irq_type,
+ handle_level_irq);
+
+ #if !defined(CONFIG_MIPS_MT_SMP) && !defined(CONFIG_MIPS_MT_SMTC)
+ set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 |
+ IE_IRQ3 | IE_IRQ4 | IE_IRQ5);
+ #else
+ set_c0_status(IE_SW0 | IE_SW1 | IE_IRQ0 | IE_IRQ1 |
+ IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5);
+ #endif
+}
+
+void __cpuinit
+arch_fixup_c0_irqs(void)
+{
+ /* FIXME: check for CPUID and only do fix for specific chips/versions */
+ cp0_compare_irq = CP0_LEGACY_COMPARE_IRQ;
+ cp0_perfcount_irq = CP0_LEGACY_PERFCNT_IRQ;
+}
--- /dev/null
+++ b/arch/mips/lantiq/setup.c
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+
+#include <lantiq.h>
+#include <lantiq_regs.h>
+
+void __init
+plat_mem_setup(void)
+{
+ /* assume 16M as default */
+ int memsize = 16;
+ char **envp = (char **) KSEG1ADDR(fw_arg2);
+ u32 status;
+
+ /* make sure to have no "reverse endian" for user mode! */
+ status = read_c0_status();
+ status &= (~(1<<25));
+ write_c0_status(status);
+
+ ioport_resource.start = IOPORT_RESOURCE_START;
+ ioport_resource.end = IOPORT_RESOURCE_END;
+ iomem_resource.start = IOMEM_RESOURCE_START;
+ iomem_resource.end = IOMEM_RESOURCE_END;
+
+ while (*envp)
+ {
+ char *e = (char *)KSEG1ADDR(*envp);
+ if (!strncmp(e, "memsize=", 8))
+ {
+ e += 8;
+ memsize = simple_strtoul(e, NULL, 10);
+ }
+ envp++;
+ }
+ memsize *= 1024 * 1024;
+ add_memory_region(0x00000000, memsize, BOOT_MEM_RAM);
+}
--- /dev/null
+++ b/arch/mips/lantiq/clk.c
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 Thomas Langer, Lantiq Deutschland
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/list.h>
+
+#include <asm/time.h>
+#include <asm/irq.h>
+#include <asm/div64.h>
+
+#include <lantiq.h>
+#ifdef CONFIG_SOC_LANTIQ_XWAY
+#include <xway.h>
+#endif
+
+extern unsigned long lq_get_cpu_hz(void);
+extern unsigned long lq_get_fpi_hz(void);
+extern unsigned long lq_get_io_region_clock(void);
+
+struct clk {
+ const char *name;
+ unsigned long rate;
+ unsigned long (*get_rate) (void);
+};
+
+static struct clk *cpu_clk = 0;
+static int cpu_clk_cnt = 0;
+
+static unsigned int r4k_offset;
+static unsigned int r4k_cur;
+
+static struct clk cpu_clk_generic[] = {
+ {
+ .name = "cpu",
+ .get_rate = lq_get_cpu_hz,
+ }, {
+ .name = "fpi",
+ .get_rate = lq_get_fpi_hz,
+ }, {
+ .name = "io",
+ .get_rate = lq_get_io_region_clock,
+ },
+};
+
+void
+clk_init(void)
+{
+ int i;
+ cpu_clk = cpu_clk_generic;
+ cpu_clk_cnt = ARRAY_SIZE(cpu_clk_generic);
+ for(i = 0; i < cpu_clk_cnt; i++)
+ printk("%s: %ld\n", cpu_clk[i].name, clk_get_rate(&cpu_clk[i]));
+}
+
+static inline int
+clk_good(struct clk *clk)
+{
+ return clk && !IS_ERR(clk);
+}
+
+unsigned long
+clk_get_rate(struct clk *clk)
+{
+ if (unlikely(!clk_good(clk)))
+ return 0;
+
+ if (clk->rate != 0)
+ return clk->rate;
+
+ if (clk->get_rate != NULL)
+ return clk->get_rate();
+
+ return 0;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+struct clk*
+clk_get(struct device *dev, const char *id)
+{
+ int i;
+ for(i = 0; i < cpu_clk_cnt; i++)
+ if (!strcmp(id, cpu_clk[i].name))
+ return &cpu_clk[i];
+ BUG();
+ return ERR_PTR(-ENOENT);
+}
+EXPORT_SYMBOL(clk_get);
+
+void
+clk_put(struct clk *clk)
+{
+ /* not used */
+}
+EXPORT_SYMBOL(clk_put);
+
+static inline u32
+lq_get_counter_resolution(void)
+{
+ u32 res;
+ __asm__ __volatile__(
+ ".set push\n"
+ ".set mips32r2\n"
+ ".set noreorder\n"
+ "rdhwr %0, $3\n"
+ "ehb\n"
+ ".set pop\n"
+ : "=&r" (res)
+ : /* no input */
+ : "memory");
+ instruction_hazard();
+ return res;
+}
+
+void __init
+plat_time_init(void)
+{
+ struct clk *clk = clk_get(0, "cpu");
+ mips_hpt_frequency = clk_get_rate(clk) / lq_get_counter_resolution();
+ r4k_cur = (read_c0_count() + r4k_offset);
+ write_c0_compare(r4k_cur);
+
+#ifdef CONFIG_SOC_LANTIQ_XWAY
+#define LQ_GPTU_GPT_CLC ((u32 *)(LQ_GPTU_BASE_ADDR + 0x0000))
+ lq_pmu_enable(PMU_GPT);
+ lq_pmu_enable(PMU_FPI);
+
+ lq_w32(0x100, LQ_GPTU_GPT_CLC);
+#endif
+}
--- /dev/null
+++ b/arch/mips/lantiq/prom.c
@@ -0,0 +1,118 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <asm/bootinfo.h>
+#include <asm/time.h>
+
+#include <lantiq.h>
+
+#include "prom.h"
+
+static struct lq_soc_info soc_info;
+
+/* for Multithreading (APRP) on MIPS34K */
+unsigned long physical_memsize;
+
+/* all access to the ebu must be locked */
+DEFINE_SPINLOCK(ebu_lock);
+EXPORT_SYMBOL_GPL(ebu_lock);
+
+extern void clk_init(void);
+
+unsigned int
+lq_get_cpu_ver(void)
+{
+ return soc_info.rev;
+}
+EXPORT_SYMBOL(lq_get_cpu_ver);
+
+unsigned int
+lq_get_soc_type(void)
+{
+ return soc_info.type;
+}
+EXPORT_SYMBOL(lq_get_soc_type);
+
+const char*
+get_system_type(void)
+{
+ return soc_info.sys_type;
+}
+
+void
+prom_free_prom_memory(void)
+{
+}
+
+#ifdef CONFIG_IMAGE_CMDLINE_HACK
+extern char __image_cmdline[];
+
+static void __init
+prom_init_image_cmdline(void)
+{
+ char *p = __image_cmdline;
+ int replace = 0;
+
+ if (*p == '-') {
+ replace = 1;
+ p++;
+ }
+
+ if (*p == '\0')
+ return;
+
+ if (replace) {
+ strlcpy(arcs_cmdline, p, sizeof(arcs_cmdline));
+ } else {
+ strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline));
+ strlcat(arcs_cmdline, p, sizeof(arcs_cmdline));
+ }
+}
+#else
+static void __init prom_init_image_cmdline(void) { return; }
+#endif
+
+static void __init
+prom_init_cmdline(void)
+{
+ int argc = fw_arg0;
+ char **argv = (char**)KSEG1ADDR(fw_arg1);
+ int i;
+
+ arcs_cmdline[0] = '\0';
+ if(argc)
+ for (i = 1; i < argc; i++)
+ {
+ strlcat(arcs_cmdline, (char*)KSEG1ADDR(argv[i]), COMMAND_LINE_SIZE);
+ if(i + 1 != argc)
+ strlcat(arcs_cmdline, " ", COMMAND_LINE_SIZE);
+ }
+
+ if (!*arcs_cmdline)
+ strcpy(&(arcs_cmdline[0]),
+ "console=ttyS1,115200 rootfstype=squashfs,jffs2");
+ prom_init_image_cmdline();
+}
+
+void __init
+prom_init(void)
+{
+ struct clk *clk;
+ lq_soc_detect(&soc_info);
+
+ clk_init();
+ clk = clk_get(0, "cpu");
+ snprintf(soc_info.sys_type, LQ_SYS_TYPE_LEN - 1, "%s rev1.%d %ldMhz",
+ soc_info.name, soc_info.rev, clk_get_rate(clk) / 1000000);
+ soc_info.sys_type[LQ_SYS_TYPE_LEN - 1] = '\0';
+ printk("SoC: %s\n", soc_info.sys_type);
+
+ prom_init_cmdline();
+}
--- /dev/null
+++ b/arch/mips/lantiq/prom.h
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef _LQ_PROM_H__
+#define _LQ_PROM_H__
+
+#define LQ_SYS_TYPE_LEN 0x100
+
+struct lq_soc_info {
+ unsigned char *name;
+ unsigned int rev;
+ unsigned int partnum;
+ unsigned int type;
+ unsigned char sys_type[LQ_SYS_TYPE_LEN];
+};
+
+void lq_soc_detect(struct lq_soc_info *i);
+
+#endif

View File

@@ -0,0 +1,136 @@
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/war.h
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ *
+ */
+#ifndef __ASM_MIPS_MACH_LANTIQ_WAR_H
+#define __ASM_MIPS_MACH_LANTIQ_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
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/lantiq.h
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef _LANTIQ_H__
+#define _LANTIQ_H__
+
+/* generic reg access functions */
+#define lq_r32(reg) __raw_readl(reg)
+#define lq_w32(val, reg) __raw_writel(val, reg)
+#define lq_w32_mask(clear, set, reg) lq_w32((lq_r32(reg) & ~clear) | set, reg)
+
+extern unsigned int lq_get_cpu_ver(void);
+extern unsigned int lq_get_soc_type(void);
+
+/* clock speeds */
+#define CLOCK_60M 60000000
+#define CLOCK_83M 83333333
+#define CLOCK_111M 111111111
+#define CLOCK_111M 111111111
+#define CLOCK_133M 133333333
+#define CLOCK_167M 166666667
+#define CLOCK_200M 200000000
+#define CLOCK_333M 333333333
+#define CLOCK_400M 400000000
+
+/* spinlock all ebu i/o */
+extern spinlock_t ebu_lock;
+
+/* some irq helpers */
+extern void lq_disable_irq(unsigned int irq_nr);
+extern void lq_mask_and_ack_irq(unsigned int irq_nr);
+extern void lq_enable_irq(unsigned int irq_nr);
+
+#define IOPORT_RESOURCE_START 0x10000000
+#define IOPORT_RESOURCE_END 0xffffffff
+#define IOMEM_RESOURCE_START 0x10000000
+#define IOMEM_RESOURCE_END 0xffffffff
+
+#define LQ_FLASH_START 0x10000000
+#define LQ_FLASH_MAX 0x04000000
+
+#endif
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/lantiq_regs.h
@@ -0,0 +1,17 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef _LANTIQ_REGS_H__
+#define _LANTIQ_REGS_H__
+
+#ifdef CONFIG_SOC_LANTIQ_XWAY
+#include <xway.h>
+#include <xway_irq.h>
+#endif
+
+#endif
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef _LANTIQ_PLATFORM_H__
+#define _LANTIQ_PLATFORM_H__
+
+#include <linux/mtd/partitions.h>
+
+/* struct used to pass info to network drivers */
+enum {
+ MII_MODE,
+ REV_MII_MODE,
+};
+
+struct lq_eth_data {
+ unsigned char *mac;
+ int mii_mode;
+};
+
+/* struct used to pass info to the pci core */
+enum {
+ PCI_CLOCK_INT = 0,
+ PCI_CLOCK_EXT
+};
+
+struct lq_pci_data {
+ int clock;
+ int req_mask;
+};
+
+#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,565 @@
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/xway/irq.h
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef __LANTIQ_IRQ_H
+#define __LANTIQ_IRQ_H
+
+#include <xway_irq.h>
+
+#define NR_IRQS 256
+
+#include_next <irq.h>
+
+#endif
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/lantiq_timer.h
@@ -0,0 +1,155 @@
+#ifndef __DANUBE_GPTU_DEV_H__2005_07_26__10_19__
+#define __DANUBE_GPTU_DEV_H__2005_07_26__10_19__
+
+
+/******************************************************************************
+ Copyright (c) 2002, Infineon Technologies. All rights reserved.
+
+ No Warranty
+ Because the program is licensed free of charge, there is no warranty for
+ the program, to the extent permitted by applicable law. Except when
+ otherwise stated in writing the copyright holders and/or other parties
+ provide the program "as is" without warranty of any kind, either
+ expressed or implied, including, but not limited to, the implied
+ warranties of merchantability and fitness for a particular purpose. The
+ entire risk as to the quality and performance of the program is with
+ you. should the program prove defective, you assume the cost of all
+ necessary servicing, repair or correction.
+
+ In no event unless required by applicable law or agreed to in writing
+ will any copyright holder, or any other party who may modify and/or
+ redistribute the program as permitted above, be liable to you for
+ damages, including any general, special, incidental or consequential
+ damages arising out of the use or inability to use the program
+ (including but not limited to loss of data or data being rendered
+ inaccurate or losses sustained by you or third parties or a failure of
+ the program to operate with any other programs), even if such holder or
+ other party has been advised of the possibility of such damages.
+******************************************************************************/
+
+
+/*
+ * ####################################
+ * Definition
+ * ####################################
+ */
+
+/*
+ * Available Timer/Counter Index
+ */
+#define TIMER(n, X) (n * 2 + (X ? 1 : 0))
+#define TIMER_ANY 0x00
+#define TIMER1A TIMER(1, 0)
+#define TIMER1B TIMER(1, 1)
+#define TIMER2A TIMER(2, 0)
+#define TIMER2B TIMER(2, 1)
+#define TIMER3A TIMER(3, 0)
+#define TIMER3B TIMER(3, 1)
+
+/*
+ * Flag of Timer/Counter
+ * These flags specify the way in which timer is configured.
+ */
+/* Bit size of timer/counter. */
+#define TIMER_FLAG_16BIT 0x0000
+#define TIMER_FLAG_32BIT 0x0001
+/* Switch between timer and counter. */
+#define TIMER_FLAG_TIMER 0x0000
+#define TIMER_FLAG_COUNTER 0x0002
+/* Stop or continue when overflowing/underflowing. */
+#define TIMER_FLAG_ONCE 0x0000
+#define TIMER_FLAG_CYCLIC 0x0004
+/* Count up or counter down. */
+#define TIMER_FLAG_UP 0x0000
+#define TIMER_FLAG_DOWN 0x0008
+/* Count on specific level or edge. */
+#define TIMER_FLAG_HIGH_LEVEL_SENSITIVE 0x0000
+#define TIMER_FLAG_LOW_LEVEL_SENSITIVE 0x0040
+#define TIMER_FLAG_RISE_EDGE 0x0010
+#define TIMER_FLAG_FALL_EDGE 0x0020
+#define TIMER_FLAG_ANY_EDGE 0x0030
+/* Signal is syncronous to module clock or not. */
+#define TIMER_FLAG_UNSYNC 0x0000
+#define TIMER_FLAG_SYNC 0x0080
+/* Different interrupt handle type. */
+#define TIMER_FLAG_NO_HANDLE 0x0000
+#if defined(__KERNEL__)
+ #define TIMER_FLAG_CALLBACK_IN_IRQ 0x0100
+#endif // defined(__KERNEL__)
+#define TIMER_FLAG_SIGNAL 0x0300
+/* Internal clock source or external clock source */
+#define TIMER_FLAG_INT_SRC 0x0000
+#define TIMER_FLAG_EXT_SRC 0x1000
+
+
+/*
+ * ioctl Command
+ */
+#define GPTU_REQUEST_TIMER 0x01 /* General method to setup timer/counter. */
+#define GPTU_FREE_TIMER 0x02 /* Free timer/counter. */
+#define GPTU_START_TIMER 0x03 /* Start or resume timer/counter. */
+#define GPTU_STOP_TIMER 0x04 /* Suspend timer/counter. */
+#define GPTU_GET_COUNT_VALUE 0x05 /* Get current count value. */
+#define GPTU_CALCULATE_DIVIDER 0x06 /* Calculate timer divider from given freq.*/
+#define GPTU_SET_TIMER 0x07 /* Simplified method to setup timer. */
+#define GPTU_SET_COUNTER 0x08 /* Simplified method to setup counter. */
+
+/*
+ * Data Type Used to Call ioctl
+ */
+struct gptu_ioctl_param {
+ unsigned int timer; /* In command GPTU_REQUEST_TIMER, GPTU_SET_TIMER, and *
+ * GPTU_SET_COUNTER, this field is ID of expected *
+ * timer/counter. If it's zero, a timer/counter would *
+ * be dynamically allocated and ID would be stored in *
+ * this field. *
+ * In command GPTU_GET_COUNT_VALUE, this field is *
+ * ignored. *
+ * In other command, this field is ID of timer/counter *
+ * allocated. */
+ unsigned int flag; /* In command GPTU_REQUEST_TIMER, GPTU_SET_TIMER, and *
+ * GPTU_SET_COUNTER, this field contains flags to *
+ * specify how to configure timer/counter. *
+ * In command GPTU_START_TIMER, zero indicate start *
+ * and non-zero indicate resume timer/counter. *
+ * In other command, this field is ignored. */
+ unsigned long value; /* In command GPTU_REQUEST_TIMER, this field contains *
+ * init/reload value. *
+ * In command GPTU_SET_TIMER, this field contains *
+ * frequency (0.001Hz) of timer. *
+ * In command GPTU_GET_COUNT_VALUE, current count *
+ * value would be stored in this field. *
+ * In command GPTU_CALCULATE_DIVIDER, this field *
+ * contains frequency wanted, and after calculation, *
+ * divider would be stored in this field to overwrite *
+ * the frequency. *
+ * In other command, this field is ignored. */
+ int pid; /* In command GPTU_REQUEST_TIMER and GPTU_SET_TIMER, *
+ * if signal is required, this field contains process *
+ * ID to which signal would be sent. *
+ * In other command, this field is ignored. */
+ int sig; /* In command GPTU_REQUEST_TIMER and GPTU_SET_TIMER, *
+ * if signal is required, this field contains signal *
+ * number which would be sent. *
+ * In other command, this field is ignored. */
+};
+
+/*
+ * ####################################
+ * Data Type
+ * ####################################
+ */
+typedef void (*timer_callback)(unsigned long arg);
+
+extern int ifxmips_request_timer(unsigned int, unsigned int, unsigned long, unsigned long, unsigned long);
+extern int ifxmips_free_timer(unsigned int);
+extern int ifxmips_start_timer(unsigned int, int);
+extern int ifxmips_stop_timer(unsigned int);
+extern int ifxmips_reset_counter_flags(u32 timer, u32 flags);
+extern int ifxmips_get_count_value(unsigned int, unsigned long *);
+extern u32 ifxmips_cal_divider(unsigned long);
+extern int ifxmips_set_timer(unsigned int, unsigned int, int, int, unsigned int, unsigned long, unsigned long);
+extern int ifxmips_set_counter(unsigned int timer, unsigned int flag,
+ u32 reload, unsigned long arg1, unsigned long arg2);
+
+#endif /* __DANUBE_GPTU_DEV_H__2005_07_26__10_19__ */
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/xway/xway.h
@@ -0,0 +1,121 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2005 infineon
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifdef CONFIG_SOC_LANTIQ_XWAY
+
+#ifndef _LQ_XWAY_H__
+#define _LQ_XWAY_H__
+
+#include <lantiq.h>
+
+/* request a non-gpio and set the PIO config */
+extern int lq_gpio_request(unsigned int pin, unsigned int alt0,
+ unsigned int alt1, unsigned int dir, const char *name);
+extern int lq_gpio_setconfig(unsigned int pin, unsigned int reg, unsigned int val);
+
+extern void lq_pmu_enable(unsigned int module);
+extern void lq_pmu_disable(unsigned int module);
+
+extern unsigned int lq_get_fpi_bus_clock(int bus);
+
+#define BOARD_SYSTEM_TYPE "LANTIQ"
+
+/*------------ Chip IDs */
+#define SOC_ID_DANUBE1 0x129
+#define SOC_ID_DANUBE2 0x12B
+#define SOC_ID_TWINPASS 0x12D
+#define SOC_ID_ARX188 0x16C
+#define SOC_ID_ARX168 0x16D
+#define SOC_ID_ARX182 0x16F
+
+/*------------ SoC Types */
+#define SOC_TYPE_DANUBE 0x01
+#define SOC_TYPE_TWINPASS 0x02
+#define SOC_TYPE_AR9 0x03
+
+/*------------ ASC0/1 */
+#define LQ_ASC0_BASE 0x1E100400
+#define LQ_ASC1_BASE 0x1E100C00
+#define LQ_ASC_SIZE 0x400
+
+/*------------ RCU */
+#define LQ_RCU_BASE_ADDR 0xBF203000
+
+/*------------ GPTU */
+#define LQ_GPTU_BASE_ADDR 0xB8000300
+
+/*------------ EBU */
+#define LQ_EBU_GPIO_START 0x14000000
+#define LQ_EBU_GPIO_SIZE 0x1000
+
+#define LQ_EBU_BASE_ADDR 0xBE105300
+
+#define LQ_EBU_BUSCON0 ((u32 *)(LQ_EBU_BASE_ADDR + 0x0060))
+#define LQ_EBU_PCC_CON ((u32 *)(LQ_EBU_BASE_ADDR + 0x0090))
+#define LQ_EBU_PCC_IEN ((u32 *)(LQ_EBU_BASE_ADDR + 0x00A4))
+#define LQ_EBU_PCC_ISTAT ((u32 *)(LQ_EBU_BASE_ADDR + 0x00A0))
+#define LQ_EBU_BUSCON1 ((u32 *)(LQ_EBU_BASE_ADDR + 0x0064))
+#define LQ_EBU_ADDRSEL1 ((u32 *)(LQ_EBU_BASE_ADDR + 0x0024))
+
+#define EBU_WRDIS 0x80000000
+
+/*------------ CGU */
+#define LQ_CGU_BASE_ADDR (KSEG1 + 0x1F103000)
+
+/*------------ PMU */
+#define LQ_PMU_BASE_ADDR (KSEG1 + 0x1F102000)
+
+#define PMU_DMA 0x0020
+#define PMU_USB 0x8041
+#define PMU_LED 0x0800
+#define PMU_GPT 0x1000
+#define PMU_PPE 0x2000
+#define PMU_FPI 0x4000
+#define PMU_SWITCH 0x10000000
+
+/*------------ ETOP */
+#define LQ_PPE32_BASE_ADDR 0xBE180000
+#define LQ_PPE32_SIZE 0x40000
+
+/*------------ DMA */
+#define LQ_DMA_BASE_ADDR 0xBE104100
+
+/*------------ PCI */
+#define PCI_CR_PR_BASE_ADDR (KSEG1 + 0x1E105400)
+#define PCI_CS_PR_BASE_ADDR (KSEG1 + 0x17000000)
+
+/*------------ WDT */
+#define LQ_WDT_BASE 0x1F880000
+#define LQ_WDT_SIZE 0x400
+
+/*------------ Serial To Parallel conversion */
+#define LQ_STP_BASE 0x1E100BB0
+#define LQ_STP_SIZE 0x40
+
+/*------------ GPIO */
+#define LQ_GPIO0_BASE_ADDR 0x1E100B10
+#define LQ_GPIO1_BASE_ADDR 0x1E100B40
+#define LQ_GPIO_SIZE 0x30
+
+/*------------ SSC */
+#define LQ_SSC_BASE_ADDR (KSEG1 + 0x1e100800)
+
+/*------------ MEI */
+#define LQ_MEI_BASE_ADDR (KSEG1 + 0x1E116000)
+
+/*------------ DEU */
+#define LQ_DEU_BASE (KSEG1 + 0x1E103100)
+
+/*------------ MPS */
+#define LQ_MPS_BASE_ADDR (KSEG1 + 0x1F107000)
+#define LQ_MPS_CHIPID ((u32 *)(LQ_MPS_BASE_ADDR + 0x0344))
+
+#endif
+
+#endif
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/xway/xway_dma.h
@@ -0,0 +1,144 @@
+/*
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) 2005 infineon
+ * Copyright (C) 2007 John Crispin <blogic@openwrt.org>
+ *
+ */
+#ifndef _LQ_DMA_H__
+#define _LQ_DMA_H__
+
+#define RCV_INT 1
+#define TX_BUF_FULL_INT 2
+#define TRANSMIT_CPT_INT 4
+#define LQ_DMA_CH_ON 1
+#define LQ_DMA_CH_OFF 0
+#define LQ_DMA_CH_DEFAULT_WEIGHT 100
+
+enum attr_t{
+ TX = 0,
+ RX = 1,
+ RESERVED = 2,
+ DEFAULT = 3,
+};
+
+#define DMA_OWN 1
+#define CPU_OWN 0
+#define DMA_MAJOR 250
+
+#define DMA_DESC_OWN_CPU 0x0
+#define DMA_DESC_OWN_DMA 0x80000000
+#define DMA_DESC_CPT_SET 0x40000000
+#define DMA_DESC_SOP_SET 0x20000000
+#define DMA_DESC_EOP_SET 0x10000000
+
+#define MISCFG_MASK 0x40
+#define RDERR_MASK 0x20
+#define CHOFF_MASK 0x10
+#define DESCPT_MASK 0x8
+#define DUR_MASK 0x4
+#define EOP_MASK 0x2
+
+#define DMA_DROP_MASK (1<<31)
+
+#define LQ_DMA_RX -1
+#define LQ_DMA_TX 1
+
+struct dma_chan_map {
+ const char *dev_name;
+ enum attr_t dir;
+ int pri;
+ int irq;
+ int rel_chan_no;
+};
+
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
+struct rx_desc {
+ u32 data_length:16;
+ volatile u32 reserved:7;
+ volatile u32 byte_offset:2;
+ volatile u32 Burst_length_offset:3;
+ volatile u32 EoP:1;
+ volatile u32 Res:1;
+ volatile u32 C:1;
+ volatile u32 OWN:1;
+ volatile u32 Data_Pointer; /* fixme: should be 28 bits here */
+};
+
+struct tx_desc {
+ volatile u32 data_length:16;
+ volatile u32 reserved1:7;
+ volatile u32 byte_offset:5;
+ volatile u32 EoP:1;
+ volatile u32 SoP:1;
+ volatile u32 C:1;
+ volatile u32 OWN:1;
+ volatile u32 Data_Pointer; /* fixme: should be 28 bits here */
+};
+#else /* BIG */
+struct rx_desc {
+ union {
+ struct {
+ volatile u32 OWN:1;
+ volatile u32 C:1;
+ volatile u32 SoP:1;
+ volatile u32 EoP:1;
+ volatile u32 Burst_length_offset:3;
+ volatile u32 byte_offset:2;
+ volatile u32 reserve:7;
+ volatile u32 data_length:16;
+ } field;
+ volatile u32 word;
+ } status;
+ volatile u32 Data_Pointer;
+};
+
+struct tx_desc {
+ union {
+ struct {
+ volatile u32 OWN:1;
+ volatile u32 C:1;
+ volatile u32 SoP:1;
+ volatile u32 EoP:1;
+ volatile u32 byte_offset:5;
+ volatile u32 reserved:7;
+ volatile u32 data_length:16;
+ } field;
+ volatile u32 word;
+ } status;
+ volatile u32 Data_Pointer;
+};
+#endif /* ENDIAN */
+
+struct dma_channel_info {
+ /* relative channel number */
+ int rel_chan_no;
+ /* class for this channel for QoS */
+ int pri;
+ /* specify byte_offset */
+ int byte_offset;
+ /* direction */
+ int dir;
+ /* irq number */
+ int irq;
+ /* descriptor parameter */
+ int desc_base;
+ int desc_len;
+ int curr_desc;
+ int prev_desc; /* only used if it is a tx channel*/
+ /* weight setting for WFQ algorithm*/
+ int weight;
+ int default_weight;
+ int packet_size;
+ int burst_len;
+ /* on or off of this channel */
+ int control;
+ /* optional information for the upper layer devices */
+#if defined(CONFIG_LQ_ETHERNET_D2) || defined(CONFIG_LQ_PPA)
+ void *opt[64];
+#else
+ void *opt[25];
+#endif
+ /* Pointer to the peripheral device who is using this channel */
+ void *dma_dev;
+ /* channel operations */
+ void (*open)(struct dma_channel_info *pCh);
+ void (*close)(struct dma_channel_info *pCh);
+ void (*reset)(struct dma_channel_info *pCh);
+ void (*enable_irq)(struct dma_channel_info *pCh);
+ void (*disable_irq)(struct dma_channel_info *pCh);
+};
+
+struct dma_device_info {
+ /* device name of this peripheral */
+ char device_name[15];
+ int reserved;
+ int tx_burst_len;
+ int rx_burst_len;
+ int default_weight;
+ int current_tx_chan;
+ int current_rx_chan;
+ int num_tx_chan;
+ int num_rx_chan;
+ int max_rx_chan_num;
+ int max_tx_chan_num;
+ struct dma_channel_info *tx_chan[20];
+ struct dma_channel_info *rx_chan[20];
+ /*functions, optional*/
+ u8 *(*buffer_alloc)(int len, int *offset, void **opt);
+ void (*buffer_free)(u8 *dataptr, void *opt);
+ int (*intr_handler)(struct dma_device_info *info, int status);
+ void *priv; /* used by peripheral driver only */
+};
+
+struct dma_device_info *dma_device_reserve(char *dev_name);
+void dma_device_release(struct dma_device_info *dev);
+void dma_device_register(struct dma_device_info *info);
+void dma_device_unregister(struct dma_device_info *info);
+int dma_device_read(struct dma_device_info *info, u8 **dataptr, void **opt);
+int dma_device_write(struct dma_device_info *info, u8 *dataptr, int len,
+ void *opt);
+
+#endif
+
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/xway/xway_irq.h
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef _LANTIQ_XWAY_IRQ_H__
+#define _LANTIQ_XWAY_IRQ_H__
+
+#define INT_NUM_IRQ0 8
+#define INT_NUM_IM0_IRL0 (INT_NUM_IRQ0 + 0)
+#define INT_NUM_IM1_IRL0 (INT_NUM_IRQ0 + 32)
+#define INT_NUM_IM2_IRL0 (INT_NUM_IRQ0 + 64)
+#define INT_NUM_IM3_IRL0 (INT_NUM_IRQ0 + 96)
+#define INT_NUM_IM4_IRL0 (INT_NUM_IRQ0 + 128)
+#define INT_NUM_IM_OFFSET (INT_NUM_IM1_IRL0 - INT_NUM_IM0_IRL0)
+
+#define LQ_ASC_TIR(x) (INT_NUM_IM3_IRL0 + (x * 7))
+#define LQ_ASC_RIR(x) (INT_NUM_IM3_IRL0 + (x * 7) + 2)
+#define LQ_ASC_EIR(x) (INT_NUM_IM3_IRL0 + (x * 7) + 3)
+
+#define LQ_SSC_TIR (INT_NUM_IM0_IRL0 + 15)
+#define LQ_SSC_RIR (INT_NUM_IM0_IRL0 + 14)
+#define LQ_SSC_EIR (INT_NUM_IM0_IRL0 + 16)
+
+#define LQ_MEI_DYING_GASP_INT (INT_NUM_IM1_IRL0 + 21)
+#define LQ_MEI_INT (INT_NUM_IM1_IRL0 + 23)
+
+#define LQ_TIMER6_INT (INT_NUM_IM1_IRL0 + 23)
+#define LQ_USB_INT (INT_NUM_IM1_IRL0 + 22)
+#define LQ_USB_OC_INT (INT_NUM_IM4_IRL0 + 23)
+
+#define MIPS_CPU_TIMER_IRQ 7
+
+#define LQ_DMA_CH0_INT (INT_NUM_IM2_IRL0)
+#define LQ_DMA_CH1_INT (INT_NUM_IM2_IRL0 + 1)
+#define LQ_DMA_CH2_INT (INT_NUM_IM2_IRL0 + 2)
+#define LQ_DMA_CH3_INT (INT_NUM_IM2_IRL0 + 3)
+#define LQ_DMA_CH4_INT (INT_NUM_IM2_IRL0 + 4)
+#define LQ_DMA_CH5_INT (INT_NUM_IM2_IRL0 + 5)
+#define LQ_DMA_CH6_INT (INT_NUM_IM2_IRL0 + 6)
+#define LQ_DMA_CH7_INT (INT_NUM_IM2_IRL0 + 7)
+#define LQ_DMA_CH8_INT (INT_NUM_IM2_IRL0 + 8)
+#define LQ_DMA_CH9_INT (INT_NUM_IM2_IRL0 + 9)
+#define LQ_DMA_CH10_INT (INT_NUM_IM2_IRL0 + 10)
+#define LQ_DMA_CH11_INT (INT_NUM_IM2_IRL0 + 11)
+#define LQ_DMA_CH12_INT (INT_NUM_IM2_IRL0 + 25)
+#define LQ_DMA_CH13_INT (INT_NUM_IM2_IRL0 + 26)
+#define LQ_DMA_CH14_INT (INT_NUM_IM2_IRL0 + 27)
+#define LQ_DMA_CH15_INT (INT_NUM_IM2_IRL0 + 28)
+#define LQ_DMA_CH16_INT (INT_NUM_IM2_IRL0 + 29)
+#define LQ_DMA_CH17_INT (INT_NUM_IM2_IRL0 + 30)
+#define LQ_DMA_CH18_INT (INT_NUM_IM2_IRL0 + 16)
+#define LQ_DMA_CH19_INT (INT_NUM_IM2_IRL0 + 21)
+
+#define LQ_PPE_MBOX_INT (INT_NUM_IM2_IRL0 + 24)
+
+#define INT_NUM_IM4_IRL14 (INT_NUM_IM4_IRL0 + 14)
+
+#endif

View File

@@ -0,0 +1,93 @@
--- a/arch/mips/lantiq/Kconfig
+++ b/arch/mips/lantiq/Kconfig
@@ -33,4 +33,19 @@ endchoice
source "arch/mips/lantiq/falcon/Kconfig"
source "arch/mips/lantiq/xway/Kconfig"
+if EARLY_PRINTK
+choice
+ prompt "Early printk port"
+ default LANTIQ_PROM_ASC1
+ help
+ Choose which serial port is used, until the console driver is loaded
+
+config LANTIQ_PROM_ASC0
+ bool "ASC0"
+
+config LANTIQ_PROM_ASC1
+ bool "ASC1"
+endchoice
+endif
+
endif
--- /dev/null
+++ b/arch/mips/lantiq/early_printk.c
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/cpu.h>
+
+#include <lantiq.h>
+
+#ifdef CONFIG_SOC_LANTIQ_XWAY
+#include <xway.h>
+#ifdef CONFIG_LANTIQ_PROM_ASC0
+#define LQ_ASC_BASE KSEG1ADDR(LQ_ASC0_BASE)
+#else
+#define LQ_ASC_BASE KSEG1ADDR(LQ_ASC1_BASE)
+#endif
+
+#elif CONFIG_SOC_LANTIQ_FALCON
+#include <falcon/gpon_reg_base.h>
+#ifdef CONFIG_LANTIQ_PROM_ASC0
+#define LQ_ASC_BASE GPON_ASC0_BASE
+#else
+#define LQ_ASC_BASE GPON_ASC1_BASE
+#endif
+
+#endif
+
+#define ASC_BUF 1024
+#define LQ_ASC_FSTAT 0x0048
+#define LQ_ASC_TBUF 0x0020
+#define TXMASK 0x3F00
+#define TXOFFSET 8
+
+static char buf[ASC_BUF];
+
+void
+prom_putchar(char c)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ while ((lq_r32((u32 *)(LQ_ASC_BASE + LQ_ASC_FSTAT)) & TXMASK) >> TXOFFSET);
+
+ if (c == '\n')
+ lq_w32('\r', (u32 *)(LQ_ASC_BASE + LQ_ASC_TBUF));
+ lq_w32(c, (u32 *)(LQ_ASC_BASE + LQ_ASC_TBUF));
+ local_irq_restore(flags);
+}
+
+void
+early_printf(const char *fmt, ...)
+{
+ va_list args;
+ int l;
+ char *p, *buf_end;
+
+ va_start(args, fmt);
+ l = vsnprintf(buf, ASC_BUF, fmt, args);
+ va_end(args);
+ buf_end = buf + l;
+
+ for (p = buf; p < buf_end; p++)
+ prom_putchar(*p);
+}

View File

@@ -0,0 +1,55 @@
--- a/arch/mips/lantiq/setup.c
+++ b/arch/mips/lantiq/setup.c
@@ -13,7 +13,8 @@
#include <linux/ioport.h>
#include <lantiq.h>
-#include <lantiq_regs.h>
+
+#include <machine.h>
void __init
plat_mem_setup(void)
@@ -46,3 +47,25 @@ plat_mem_setup(void)
memsize *= 1024 * 1024;
add_memory_region(0x00000000, memsize, BOOT_MEM_RAM);
}
+
+static int __init
+lq_machine_setup(void)
+{
+ mips_machine_setup();
+ return 0;
+}
+
+static void __init
+mach_generic_init(void)
+{
+}
+
+MIPS_MACHINE(LANTIQ_MACH_GENERIC,
+ "Generic",
+ "Generic",
+ mach_generic_init);
+
+arch_initcall(lq_machine_setup);
+
+/* for backward compatibility, define "board=" as alias for "machtype=" */
+__setup("board=", mips_machtype_setup);
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/machine.h
@@ -0,0 +1,14 @@
+#include <asm/mips_machine.h>
+
+enum lantiq_mach_type {
+ LANTIQ_MACH_GENERIC,
+
+ /* FALCON */
+ LANTIQ_MACH_EASY98000, /* Falcon Eval Board, NOR Flash */
+ LANTIQ_MACH_EASY98020, /* Falcon Reference Board */
+
+ /* XWAY */
+ LANTIQ_MACH_EASY4010, /* Twinpass evalkit */
+ LANTIQ_MACH_EASY50712, /* Danube evalkit */
+ LANTIQ_MACH_EASY50812, /* AR9 eval board */
+};

View File

@@ -0,0 +1,799 @@
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -1397,6 +1397,14 @@
help
Support for Console on the NWP serial ports.
+config SERIAL_LANTIQ
+ bool "Lantiq serial driver"
+ depends on LANTIQ
+ select SERIAL_CORE
+ select SERIAL_CORE_CONSOLE
+ help
+ Driver for the Lantiq SoC ASC hardware
+
config SERIAL_QE
tristate "Freescale QUICC Engine serial port support"
depends on QUICC_ENGINE
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -84,3 +84,4 @@
obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o
obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o
obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o
+obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o
--- /dev/null
+++ b/drivers/serial/lantiq.c
@@ -0,0 +1,772 @@
+/*
+ * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Copyright (C) 2004 Infineon IFAP DC COM CPE
+ * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2007 John Crispin <blogic@openwrt.org>
+ * Copyright (C) 2010 Thomas Langer, Lantiq Deutschland
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+
+#define lq_r32(reg) __raw_readl(reg)
+#define lq_r8(reg) __raw_readb(reg)
+#define lq_w32(val, reg) __raw_writel(val, reg)
+#define lq_w8(val, reg) __raw_writeb(val, reg)
+#define lq_w32_mask(clear, set, reg) lq_w32((lq_r32(reg) & ~(clear)) | (set), reg)
+
+#define PORT_IFXMIPSASC 111
+#define MAXPORTS 2
+
+#define UART_DUMMY_UER_RX 1
+
+#define DRVNAME "lq_asc"
+
+#ifdef __BIG_ENDIAN
+#define IFXMIPS_ASC_TBUF (0x0020 + 3)
+#define IFXMIPS_ASC_RBUF (0x0024 + 3)
+#else
+#define IFXMIPS_ASC_TBUF 0x0020
+#define IFXMIPS_ASC_RBUF 0x0024
+#endif
+
+#define IFXMIPS_ASC_FSTAT 0x0048
+#define IFXMIPS_ASC_WHBSTATE 0x0018
+#define IFXMIPS_ASC_STATE 0x0014
+#define IFXMIPS_ASC_IRNCR 0x00F8
+#define IFXMIPS_ASC_CLC 0x0000
+#define IFXMIPS_ASC_ID 0x0008
+#define IFXMIPS_ASC_PISEL 0x0004
+#define IFXMIPS_ASC_TXFCON 0x0044
+#define IFXMIPS_ASC_RXFCON 0x0040
+#define IFXMIPS_ASC_CON 0x0010
+#define IFXMIPS_ASC_BG 0x0050
+#define IFXMIPS_ASC_IRNREN 0x00F4
+
+#define ASC_IRNREN_TX 0x1
+#define ASC_IRNREN_RX 0x2
+#define ASC_IRNREN_ERR 0x4
+#define ASC_IRNREN_TX_BUF 0x8
+#define ASC_IRNCR_TIR 0x1
+#define ASC_IRNCR_RIR 0x2
+#define ASC_IRNCR_EIR 0x4
+
+#define ASCOPT_CSIZE 0x3
+#define ASCOPT_CS7 0x1
+#define ASCOPT_CS8 0x2
+#define ASCOPT_PARENB 0x4
+#define ASCOPT_STOPB 0x8
+#define ASCOPT_PARODD 0x0
+#define ASCOPT_CREAD 0x20
+#define TXFIFO_FL 1
+#define RXFIFO_FL 1
+#define ASCCLC_DISS 0x2
+#define ASCCLC_RMCMASK 0x0000FF00
+#define ASCCLC_RMCOFFSET 8
+#define ASCCON_M_8ASYNC 0x0
+#define ASCCON_M_7ASYNC 0x2
+#define ASCCON_ODD 0x00000020
+#define ASCCON_STP 0x00000080
+#define ASCCON_BRS 0x00000100
+#define ASCCON_FDE 0x00000200
+#define ASCCON_R 0x00008000
+#define ASCCON_FEN 0x00020000
+#define ASCCON_ROEN 0x00080000
+#define ASCCON_TOEN 0x00100000
+#define ASCSTATE_PE 0x00010000
+#define ASCSTATE_FE 0x00020000
+#define ASCSTATE_ROE 0x00080000
+#define ASCSTATE_ANY (ASCSTATE_ROE|ASCSTATE_PE|ASCSTATE_FE)
+#define ASCWHBSTATE_CLRREN 0x00000001
+#define ASCWHBSTATE_SETREN 0x00000002
+#define ASCWHBSTATE_CLRPE 0x00000004
+#define ASCWHBSTATE_CLRFE 0x00000008
+#define ASCWHBSTATE_CLRROE 0x00000020
+#define ASCTXFCON_TXFEN 0x0001
+#define ASCTXFCON_TXFFLU 0x0002
+#define ASCTXFCON_TXFITLMASK 0x3F00
+#define ASCTXFCON_TXFITLOFF 8
+#define ASCRXFCON_RXFEN 0x0001
+#define ASCRXFCON_RXFFLU 0x0002
+#define ASCRXFCON_RXFITLMASK 0x3F00
+#define ASCRXFCON_RXFITLOFF 8
+#define ASCFSTAT_RXFFLMASK 0x003F
+#define ASCFSTAT_TXFFLMASK 0x3F00
+#define ASCFSTAT_TXFFLOFF 8
+#define ASCFSTAT_RXFREEMASK 0x003F0000
+#define ASCFSTAT_RXFREEOFF 16
+#define ASCFSTAT_TXFREEMASK 0x3F000000
+#define ASCFSTAT_TXFREEOFF 24
+
+static void lqasc_tx_chars(struct uart_port *port);
+extern void prom_printf(const char *fmt, ...);
+static struct lq_uart_port *lqasc_port[2];
+static struct uart_driver lqasc_reg;
+
+struct lq_uart_port {
+ struct uart_port port;
+ struct clk *clk;
+ unsigned int tx_irq;
+ unsigned int rx_irq;
+ unsigned int err_irq;
+};
+
+static inline struct
+lq_uart_port *to_lq_uart_port(struct uart_port *port)
+{
+ return container_of(port, struct lq_uart_port, port);
+}
+
+static void
+lqasc_stop_tx(struct uart_port *port)
+{
+ return;
+}
+
+static void
+lqasc_start_tx(struct uart_port *port)
+{
+ unsigned long flags;
+ local_irq_save(flags);
+ lqasc_tx_chars(port);
+ local_irq_restore(flags);
+ return;
+}
+
+static void
+lqasc_stop_rx(struct uart_port *port)
+{
+ lq_w32(ASCWHBSTATE_CLRREN, port->membase + IFXMIPS_ASC_WHBSTATE);
+}
+
+static void
+lqasc_enable_ms(struct uart_port *port)
+{
+}
+
+static void
+lqasc_rx_chars(struct uart_port *port)
+{
+ struct tty_struct *tty = port->state->port.tty;
+ unsigned int ch = 0, rsr = 0, fifocnt;
+
+ fifocnt = lq_r32(port->membase + IFXMIPS_ASC_FSTAT) & ASCFSTAT_RXFFLMASK;
+ while (fifocnt--) {
+ u8 flag = TTY_NORMAL;
+ ch = lq_r8(port->membase + IFXMIPS_ASC_RBUF);
+ rsr = (lq_r32(port->membase + IFXMIPS_ASC_STATE)
+ & ASCSTATE_ANY) | UART_DUMMY_UER_RX;
+ tty_flip_buffer_push(tty);
+ port->icount.rx++;
+
+ /*
+ * Note that the error handling code is
+ * out of the main execution path
+ */
+ if (rsr & ASCSTATE_ANY) {
+ if (rsr & ASCSTATE_PE) {
+ port->icount.parity++;
+ lq_w32_mask(0, ASCWHBSTATE_CLRPE,
+ port->membase + IFXMIPS_ASC_WHBSTATE);
+ } else if (rsr & ASCSTATE_FE) {
+ port->icount.frame++;
+ lq_w32_mask(0, ASCWHBSTATE_CLRFE,
+ port->membase + IFXMIPS_ASC_WHBSTATE);
+ }
+ if (rsr & ASCSTATE_ROE) {
+ port->icount.overrun++;
+ lq_w32_mask(0, ASCWHBSTATE_CLRROE,
+ port->membase + IFXMIPS_ASC_WHBSTATE);
+ }
+
+ rsr &= port->read_status_mask;
+
+ if (rsr & ASCSTATE_PE)
+ flag = TTY_PARITY;
+ else if (rsr & ASCSTATE_FE)
+ flag = TTY_FRAME;
+ }
+
+ if ((rsr & port->ignore_status_mask) == 0)
+ tty_insert_flip_char(tty, ch, flag);
+
+ if (rsr & ASCSTATE_ROE)
+ /*
+ * Overrun is special, since it's reported
+ * immediately, and doesn't affect the current
+ * character
+ */
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ }
+ if (ch != 0)
+ tty_flip_buffer_push(tty);
+ return;
+}
+
+static void
+lqasc_tx_chars(struct uart_port *port)
+{
+ struct circ_buf *xmit = &port->state->xmit;
+ if (uart_tx_stopped(port)) {
+ lqasc_stop_tx(port);
+ return;
+ }
+
+ while (((lq_r32(port->membase + IFXMIPS_ASC_FSTAT) &
+ ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF) != 0) {
+ if (port->x_char) {
+ lq_w8(port->x_char, port->membase + IFXMIPS_ASC_TBUF);
+ port->icount.tx++;
+ port->x_char = 0;
+ continue;
+ }
+
+ if (uart_circ_empty(xmit))
+ break;
+
+ lq_w8(port->state->xmit.buf[port->state->xmit.tail],
+ port->membase + IFXMIPS_ASC_TBUF);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+ }
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+}
+
+static irqreturn_t
+lqasc_tx_int(int irq, void *_port)
+{
+ struct uart_port *port = (struct uart_port *)_port;
+ lq_w32(ASC_IRNCR_TIR, port->membase + IFXMIPS_ASC_IRNCR);
+ lqasc_start_tx(port);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+lqasc_err_int(int irq, void *_port)
+{
+ struct uart_port *port = (struct uart_port *)_port;
+ /* clear any pending interrupts */
+ lq_w32_mask(0, ASCWHBSTATE_CLRPE | ASCWHBSTATE_CLRFE | ASCWHBSTATE_CLRROE,
+ port->membase + IFXMIPS_ASC_WHBSTATE);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+lqasc_rx_int(int irq, void *_port)
+{
+ struct uart_port *port = (struct uart_port *)_port;
+ lq_w32(ASC_IRNCR_RIR, port->membase + IFXMIPS_ASC_IRNCR);
+ lqasc_rx_chars(port);
+ return IRQ_HANDLED;
+}
+
+static unsigned int
+lqasc_tx_empty(struct uart_port *port)
+{
+ int status;
+ status = lq_r32(port->membase + IFXMIPS_ASC_FSTAT) & ASCFSTAT_TXFFLMASK;
+ return status ? 0 : TIOCSER_TEMT;
+}
+
+static unsigned int
+lqasc_get_mctrl(struct uart_port *port)
+{
+ return TIOCM_CTS | TIOCM_CAR | TIOCM_DSR;
+}
+
+static void
+lqasc_set_mctrl(struct uart_port *port, u_int mctrl)
+{
+}
+
+static void
+lqasc_break_ctl(struct uart_port *port, int break_state)
+{
+}
+
+static int
+lqasc_startup(struct uart_port *port)
+{
+ struct lq_uart_port *ifx_port = to_lq_uart_port(port);
+ int retval;
+
+ port->uartclk = clk_get_rate(ifx_port->clk);
+
+ lq_w32_mask(ASCCLC_DISS | ASCCLC_RMCMASK, (1 << ASCCLC_RMCOFFSET),
+ port->membase + IFXMIPS_ASC_CLC);
+
+ lq_w32(0, port->membase + IFXMIPS_ASC_PISEL);
+ lq_w32(
+ ((TXFIFO_FL << ASCTXFCON_TXFITLOFF) & ASCTXFCON_TXFITLMASK) |
+ ASCTXFCON_TXFEN | ASCTXFCON_TXFFLU,
+ port->membase + IFXMIPS_ASC_TXFCON);
+ lq_w32(
+ ((RXFIFO_FL << ASCRXFCON_RXFITLOFF) & ASCRXFCON_RXFITLMASK)
+ | ASCRXFCON_RXFEN | ASCRXFCON_RXFFLU,
+ port->membase + IFXMIPS_ASC_RXFCON);
+ /* make sure other settings are written to hardware before setting enable bits */
+ wmb();
+ lq_w32_mask(0, ASCCON_M_8ASYNC | ASCCON_FEN | ASCCON_TOEN |
+ ASCCON_ROEN, port->membase + IFXMIPS_ASC_CON);
+
+ retval = request_irq(ifx_port->tx_irq, lqasc_tx_int,
+ IRQF_DISABLED, "asc_tx", port);
+ if (retval) {
+ pr_err("failed to request lqasc_tx_int\n");
+ return retval;
+ }
+
+ retval = request_irq(ifx_port->rx_irq, lqasc_rx_int,
+ IRQF_DISABLED, "asc_rx", port);
+ if (retval) {
+ pr_err("failed to request lqasc_rx_int\n");
+ goto err1;
+ }
+
+ retval = request_irq(ifx_port->err_irq, lqasc_err_int,
+ IRQF_DISABLED, "asc_err", port);
+ if (retval) {
+ pr_err("failed to request lqasc_err_int\n");
+ goto err2;
+ }
+
+ lq_w32(ASC_IRNREN_RX | ASC_IRNREN_ERR | ASC_IRNREN_TX,
+ port->membase + IFXMIPS_ASC_IRNREN);
+ return 0;
+
+err2:
+ free_irq(ifx_port->rx_irq, port);
+err1:
+ free_irq(ifx_port->tx_irq, port);
+ return retval;
+}
+
+static void
+lqasc_shutdown(struct uart_port *port)
+{
+ struct lq_uart_port *ifx_port = to_lq_uart_port(port);
+ free_irq(ifx_port->tx_irq, port);
+ free_irq(ifx_port->rx_irq, port);
+ free_irq(ifx_port->err_irq, port);
+
+ lq_w32(0, port->membase + IFXMIPS_ASC_CON);
+ lq_w32_mask(ASCRXFCON_RXFEN, ASCRXFCON_RXFFLU,
+ port->membase + IFXMIPS_ASC_RXFCON);
+ lq_w32_mask(ASCTXFCON_TXFEN, ASCTXFCON_TXFFLU,
+ port->membase + IFXMIPS_ASC_TXFCON);
+}
+
+static void
+lqasc_set_termios(struct uart_port *port,
+ struct ktermios *new, struct ktermios *old)
+{
+ unsigned int cflag;
+ unsigned int iflag;
+ unsigned int quot;
+ unsigned int baud;
+ unsigned int con = 0;
+ unsigned long flags;
+
+ cflag = new->c_cflag;
+ iflag = new->c_iflag;
+
+ switch (cflag & CSIZE) {
+ case CS7:
+ con = ASCCON_M_7ASYNC;
+ break;
+
+ case CS5:
+ case CS6:
+ default:
+ con = ASCCON_M_8ASYNC;
+ break;
+ }
+
+ if (cflag & CSTOPB)
+ con |= ASCCON_STP;
+
+ if (cflag & PARENB) {
+ if (!(cflag & PARODD))
+ con &= ~ASCCON_ODD;
+ else
+ con |= ASCCON_ODD;
+ }
+
+ port->read_status_mask = ASCSTATE_ROE;
+ if (iflag & INPCK)
+ port->read_status_mask |= ASCSTATE_FE | ASCSTATE_PE;
+
+ port->ignore_status_mask = 0;
+ if (iflag & IGNPAR)
+ port->ignore_status_mask |= ASCSTATE_FE | ASCSTATE_PE;
+
+ if (iflag & IGNBRK) {
+ /*
+ * If we're ignoring parity and break indicators,
+ * ignore overruns too (for real raw support).
+ */
+ if (iflag & IGNPAR)
+ port->ignore_status_mask |= ASCSTATE_ROE;
+ }
+
+ if ((cflag & CREAD) == 0)
+ port->ignore_status_mask |= UART_DUMMY_UER_RX;
+
+ /* set error signals - framing, parity and overrun, enable receiver */
+ con |= ASCCON_FEN | ASCCON_TOEN | ASCCON_ROEN;
+
+ local_irq_save(flags);
+
+ /* set up CON */
+ lq_w32_mask(0, con, port->membase + IFXMIPS_ASC_CON);
+
+ /* Set baud rate - take a divider of 2 into account */
+ baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16);
+ quot = uart_get_divisor(port, baud);
+ quot = quot / 2 - 1;
+
+ /* disable the baudrate generator */
+ lq_w32_mask(ASCCON_R, 0, port->membase + IFXMIPS_ASC_CON);
+
+ /* make sure the fractional divider is off */
+ lq_w32_mask(ASCCON_FDE, 0, port->membase + IFXMIPS_ASC_CON);
+
+ /* set up to use divisor of 2 */
+ lq_w32_mask(ASCCON_BRS, 0, port->membase + IFXMIPS_ASC_CON);
+
+ /* now we can write the new baudrate into the register */
+ lq_w32(quot, port->membase + IFXMIPS_ASC_BG);
+
+ /* turn the baudrate generator back on */
+ lq_w32_mask(0, ASCCON_R, port->membase + IFXMIPS_ASC_CON);
+
+ /* enable rx */
+ lq_w32(ASCWHBSTATE_SETREN, port->membase + IFXMIPS_ASC_WHBSTATE);
+
+ local_irq_restore(flags);
+}
+
+static const char*
+lqasc_type(struct uart_port *port)
+{
+ if (port->type == PORT_IFXMIPSASC)
+ return DRVNAME;
+ else
+ return NULL;
+}
+
+static void
+lqasc_release_port(struct uart_port *port)
+{
+ if (port->flags & UPF_IOREMAP) {
+ iounmap(port->membase);
+ port->membase = NULL;
+ }
+}
+
+static int
+lqasc_request_port(struct uart_port *port)
+{
+ struct platform_device *pdev = to_platform_device(port->dev);
+ struct resource *mmres;
+ int size;
+
+ mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mmres)
+ return -ENODEV;
+ size = resource_size(mmres);
+
+ if (port->flags & UPF_IOREMAP) {
+ port->membase = ioremap_nocache(port->mapbase, size);
+ if (port->membase == NULL)
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static void
+lqasc_config_port(struct uart_port *port, int flags)
+{
+ if (flags & UART_CONFIG_TYPE) {
+ port->type = PORT_IFXMIPSASC;
+ lqasc_request_port(port);
+ }
+}
+
+static int
+lqasc_verify_port(struct uart_port *port,
+ struct serial_struct *ser)
+{
+ int ret = 0;
+ if (ser->type != PORT_UNKNOWN && ser->type != PORT_IFXMIPSASC)
+ ret = -EINVAL;
+ if (ser->irq < 0 || ser->irq >= NR_IRQS)
+ ret = -EINVAL;
+ if (ser->baud_base < 9600)
+ ret = -EINVAL;
+ return ret;
+}
+
+static struct uart_ops lqasc_pops = {
+ .tx_empty = lqasc_tx_empty,
+ .set_mctrl = lqasc_set_mctrl,
+ .get_mctrl = lqasc_get_mctrl,
+ .stop_tx = lqasc_stop_tx,
+ .start_tx = lqasc_start_tx,
+ .stop_rx = lqasc_stop_rx,
+ .enable_ms = lqasc_enable_ms,
+ .break_ctl = lqasc_break_ctl,
+ .startup = lqasc_startup,
+ .shutdown = lqasc_shutdown,
+ .set_termios = lqasc_set_termios,
+ .type = lqasc_type,
+ .release_port = lqasc_release_port,
+ .request_port = lqasc_request_port,
+ .config_port = lqasc_config_port,
+ .verify_port = lqasc_verify_port,
+};
+
+static void
+lqasc_console_putchar(struct uart_port *port, int ch)
+{
+ int fifofree;
+
+ if (!port->membase)
+ return;
+
+ do {
+ fifofree = (lq_r32(port->membase + IFXMIPS_ASC_FSTAT)
+ & ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF;
+ } while (fifofree == 0);
+ lq_w8(ch, port->membase + IFXMIPS_ASC_TBUF);
+}
+
+
+static void
+lqasc_console_write(struct console *co, const char *s, u_int count)
+{
+ struct lq_uart_port *ifx_port;
+ struct uart_port *port;
+ unsigned long flags;
+
+ if (co->index >= MAXPORTS)
+ return;
+
+ ifx_port = lqasc_port[co->index];
+ if (!ifx_port)
+ return;
+
+ port = &ifx_port->port;
+
+ local_irq_save(flags);
+ uart_console_write(port, s, count, lqasc_console_putchar);
+ local_irq_restore(flags);
+}
+
+static int __init
+lqasc_console_setup(struct console *co, char *options)
+{
+ struct lq_uart_port *ifx_port;
+ struct uart_port *port;
+ int baud = 115200;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ if (co->index >= MAXPORTS)
+ return -ENODEV;
+
+ ifx_port = lqasc_port[co->index];
+ if (!ifx_port)
+ return -ENODEV;
+
+ port = &ifx_port->port;
+
+ port->uartclk = clk_get_rate(ifx_port->clk);
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct console lqasc_console = {
+ .name = "ttyS",
+ .write = lqasc_console_write,
+ .device = uart_console_device,
+ .setup = lqasc_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &lqasc_reg,
+};
+
+static int __init
+lqasc_console_init(void)
+{
+ register_console(&lqasc_console);
+ return 0;
+}
+console_initcall(lqasc_console_init);
+
+static struct uart_driver lqasc_reg = {
+ .owner = THIS_MODULE,
+ .driver_name = DRVNAME,
+ .dev_name = "ttyS",
+ .major = TTY_MAJOR,
+ .minor = 64,
+ .nr = MAXPORTS,
+ .cons = &lqasc_console,
+};
+
+static int __devinit
+lqasc_probe(struct platform_device *pdev)
+{
+ struct lq_uart_port *ifx_port;
+ struct uart_port *port;
+ struct resource *mmres, *irqres;
+ int tx_irq, rx_irq, err_irq;
+ struct clk *clk;
+ int ret;
+
+ mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!mmres || !irqres)
+ return -ENODEV;
+
+ if (pdev->id >= MAXPORTS)
+ return -EBUSY;
+
+ if (lqasc_port[pdev->id] != NULL)
+ return -EBUSY;
+
+ clk = clk_get(&pdev->dev, "fpi");
+ if (IS_ERR(clk)) {
+ pr_err("failed to get fpi clk\n");
+ return -ENOENT;
+ }
+
+ tx_irq = platform_get_irq_byname(pdev, "tx");
+ if (tx_irq < 0) {
+ /* without named resources: assume standard irq scheme */
+ tx_irq = irqres->start;
+ rx_irq = irqres->start+2;
+ err_irq = irqres->start+3;
+ } else {
+ /* other irqs must be named also! */
+ rx_irq = platform_get_irq_byname(pdev, "rx");
+ err_irq = platform_get_irq_byname(pdev, "err");
+ if ((rx_irq < 0) | (err_irq < 0))
+ return -ENODEV;
+ }
+
+ ifx_port = kzalloc(sizeof(struct lq_uart_port), GFP_KERNEL);
+ if (!ifx_port)
+ return -ENOMEM;
+
+ port = &ifx_port->port;
+
+ port->iotype = SERIAL_IO_MEM;
+ port->flags = ASYNC_BOOT_AUTOCONF | UPF_IOREMAP;
+ port->ops = &lqasc_pops;
+ port->fifosize = 16;
+ port->type = PORT_IFXMIPSASC,
+ port->line = pdev->id;
+ port->dev = &pdev->dev;
+
+ port->irq = tx_irq; /* unused, just to be backward-compatibe */
+ port->mapbase = mmres->start;
+
+ ifx_port->clk = clk;
+
+ ifx_port->tx_irq = tx_irq;
+ ifx_port->rx_irq = rx_irq;
+ ifx_port->err_irq = err_irq;
+
+ lqasc_port[pdev->id] = ifx_port;
+ platform_set_drvdata(pdev, ifx_port);
+
+ ret = uart_add_one_port(&lqasc_reg, port);
+
+ return ret;
+}
+
+static int __devexit
+lqasc_remove(struct platform_device *pdev)
+{
+ struct lq_uart_port *ifx_port = platform_get_drvdata(pdev);
+ int ret;
+
+ clk_put(ifx_port->clk);
+ platform_set_drvdata(pdev, NULL);
+ lqasc_port[pdev->id] = NULL;
+ ret = uart_remove_one_port(&lqasc_reg, &ifx_port->port);
+ kfree(ifx_port);
+
+ return 0;
+}
+
+static struct platform_driver lqasc_driver = {
+ .probe = lqasc_probe,
+ .remove = __devexit_p(lqasc_remove),
+
+ .driver = {
+ .name = DRVNAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+int __init
+init_lqasc(void)
+{
+ int ret;
+
+ ret = uart_register_driver(&lqasc_reg);
+ if (ret != 0)
+ return ret;
+
+ ret = platform_driver_register(&lqasc_driver);
+ if (ret != 0)
+ uart_unregister_driver(&lqasc_reg);
+
+ return ret;
+}
+
+void __exit
+exit_lqasc(void)
+{
+ platform_driver_unregister(&lqasc_driver);
+ uart_unregister_driver(&lqasc_reg);
+}
+
+module_init(init_lqasc);
+module_exit(exit_lqasc);
+
+MODULE_DESCRIPTION("Lantiq serial port driver");
+MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,245 @@
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -251,6 +251,12 @@
help
Support for flash chips on NETtel/SecureEdge/SnapGear boards.
+config MTD_LANTIQ
+ bool "Lantiq SoC NOR support"
+ depends on LANTIQ && MTD_PARTITIONS
+ help
+ Support for NOR flsh chips on Lantiq SoC
+
config MTD_DILNETPC
tristate "CFI Flash device mapped on DIL/Net PC"
depends on X86 && MTD_CONCAT && MTD_PARTITIONS && MTD_CFI_INTELEXT && BROKEN
--- a/drivers/mtd/maps/Makefile
+++ b/drivers/mtd/maps/Makefile
@@ -59,3 +59,4 @@
obj-$(CONFIG_MTD_RBTX4939) += rbtx4939-flash.o
obj-$(CONFIG_MTD_VMU) += vmu-flash.o
obj-$(CONFIG_MTD_GPIO_ADDR) += gpio-addr-flash.o
+obj-$(CONFIG_MTD_LANTIQ) += lantiq.o
--- /dev/null
+++ b/drivers/mtd/maps/lantiq.c
@@ -0,0 +1,169 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2004 Liu Peng Infineon IFAP DC COM CPE
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/cfi.h>
+#include <linux/magic.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/physmap.h>
+
+#include <lantiq.h>
+#include <lantiq_platform.h>
+
+static map_word
+lq_read16(struct map_info *map, unsigned long adr)
+{
+ unsigned long flags;
+ map_word temp;
+ spin_lock_irqsave(&ebu_lock, flags);
+ adr ^= 2;
+ temp.x[0] = *((__u16 *)(map->virt + adr));
+ spin_unlock_irqrestore(&ebu_lock, flags);
+ return temp;
+}
+
+static void
+lq_write16(struct map_info *map, map_word d, unsigned long adr)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&ebu_lock, flags);
+ adr ^= 2;
+ *((__u16 *)(map->virt + adr)) = d.x[0];
+ spin_unlock_irqrestore(&ebu_lock, flags);
+}
+
+void
+lq_copy_from(struct map_info *map, void *to,
+ unsigned long from, ssize_t len)
+{
+ unsigned char *p;
+ unsigned char *to_8;
+ unsigned long flags;
+ spin_lock_irqsave(&ebu_lock, flags);
+ from = (unsigned long)(from + map->virt);
+ p = (unsigned char *) from;
+ to_8 = (unsigned char *) to;
+ while (len--)
+ *to_8++ = *p++;
+ spin_unlock_irqrestore(&ebu_lock, flags);
+}
+
+void
+lq_copy_to(struct map_info *map, unsigned long to,
+ const void *from, ssize_t len)
+{
+ unsigned char *p = (unsigned char *)from;
+ unsigned char *to_8;
+ unsigned long flags;
+ spin_lock_irqsave(&ebu_lock, flags);
+ to += (unsigned long) map->virt;
+ to_8 = (unsigned char *)to;
+ while (len--)
+ *p++ = *to_8++;
+ spin_unlock_irqrestore(&ebu_lock, flags);
+}
+
+static const char *part_probe_types[] = { "cmdlinepart", NULL };
+
+static struct map_info lq_map = {
+ .name = "lq_nor",
+ .bankwidth = 2,
+ .read = lq_read16,
+ .write = lq_write16,
+ .copy_from = lq_copy_from,
+ .copy_to = lq_copy_to,
+};
+
+static int
+lq_mtd_probe(struct platform_device *pdev)
+{
+ struct physmap_flash_data *lq_mtd_data =
+ (struct physmap_flash_data*) dev_get_platdata(&pdev->dev);
+ struct mtd_info *lq_mtd = NULL;
+ struct mtd_partition *parts = NULL;
+ struct resource *res = 0;
+ int nr_parts = 0;
+
+#ifdef CONFIG_SOC_LANTIQ_XWAY
+ lq_w32(lq_r32(LQ_EBU_BUSCON0) & ~EBU_WRDIS, LQ_EBU_BUSCON0);
+#endif
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if(!res)
+ {
+ dev_err(&pdev->dev, "failed to get memory resource");
+ return -ENOENT;
+ }
+ res = request_mem_region(res->start, resource_size(res),
+ dev_name(&pdev->dev));
+ if(!res)
+ {
+ dev_err(&pdev->dev, "failed to request mem resource");
+ return -EBUSY;
+ }
+
+ lq_map.phys = res->start;
+ lq_map.size = resource_size(res);
+ lq_map.virt = ioremap_nocache(lq_map.phys, lq_map.size);
+
+ if (!lq_map.virt ) {
+ dev_err(&pdev->dev, "failed to ioremap!\n");
+ return -EIO;
+ }
+
+ lq_mtd = (struct mtd_info *) do_map_probe("cfi_probe", &lq_map);
+ if (!lq_mtd) {
+ iounmap(lq_map.virt);
+ dev_err(&pdev->dev, "probing failed\n");
+ return -ENXIO;
+ }
+
+ lq_mtd->owner = THIS_MODULE;
+
+ nr_parts = parse_mtd_partitions(lq_mtd, part_probe_types, &parts, 0);
+ if (nr_parts > 0) {
+ dev_info(&pdev->dev, "using %d partitions from cmdline", nr_parts);
+ } else {
+ nr_parts = lq_mtd_data->nr_parts;
+ parts = lq_mtd_data->parts;
+ }
+
+ add_mtd_partitions(lq_mtd, parts, nr_parts);
+ return 0;
+}
+
+static struct platform_driver lq_mtd_driver = {
+ .probe = lq_mtd_probe,
+ .driver = {
+ .name = "lq_nor",
+ .owner = THIS_MODULE,
+ },
+};
+
+int __init
+init_lq_mtd(void)
+{
+ int ret = platform_driver_register(&lq_mtd_driver);
+ if (ret)
+ printk(KERN_INFO "lq_nor: error registering platfom driver");
+ return ret;
+}
+
+module_init(init_lq_mtd);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
+MODULE_DESCRIPTION("Lantiq SoC NOR");
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -41,7 +41,11 @@
/* #define CMDSET0001_DISABLE_WRITE_SUSPEND */
// debugging, turns off buffer write mode if set to 1
-#define FORCE_WORD_WRITE 0
+#ifdef CONFIG_LANTIQ
+# define FORCE_WORD_WRITE 1
+#else
+# define FORCE_WORD_WRITE 0
+#endif
/* Intel chips */
#define I82802AB 0x00ad
@@ -1491,6 +1495,9 @@
int ret=0;
adr += chip->start;
+#ifdef CONFIG_LANTIQ
+ adr ^= 2;
+#endif
switch (mode) {
case FL_WRITING:
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -40,7 +40,11 @@
#include <linux/mtd/xip.h>
#define AMD_BOOTLOC_BUG
-#define FORCE_WORD_WRITE 0
+#ifdef CONFIG_LANTIQ
+# define FORCE_WORD_WRITE 1
+#else
+# define FORCE_WORD_WRITE 0
+#endif
#define MAX_WORD_RETRIES 3
@@ -1156,6 +1160,10 @@
adr += chip->start;
+#ifdef CONFIG_LANTIQ
+ adr ^= 2;
+#endif
+
mutex_lock(&chip->mutex);
ret = get_chip(map, chip, adr, FL_WRITING);
if (ret) {

View File

@@ -0,0 +1,99 @@
--- a/drivers/mtd/maps/lantiq.c
+++ b/drivers/mtd/maps/lantiq.c
@@ -24,6 +24,10 @@
#include <lantiq.h>
#include <lantiq_platform.h>
+#ifdef CONFIG_SOC_LANTIQ_XWAY
+#include <xway.h>
+#endif
+
static map_word
lq_read16(struct map_info *map, unsigned long adr)
{
@@ -77,6 +81,75 @@ lq_copy_to(struct map_info *map, unsigne
spin_unlock_irqrestore(&ebu_lock, flags);
}
+static unsigned long
+find_uImage_size(struct map_info *map, unsigned long offset)
+{
+#define UBOOT_MAGIC 0x56190527
+ unsigned long magic;
+ unsigned long temp;
+ map->copy_from(map, &magic, offset, 4);
+ if (le32_to_cpu(magic) != UBOOT_MAGIC)
+ return 0;
+ map->copy_from(map, &temp, offset + 12, 4);
+ return temp + 0x40;
+}
+
+static int
+detect_squashfs_partition(struct map_info *map, unsigned long offset)
+{
+ unsigned long temp;
+ map->copy_from(map, &temp, offset, 4);
+ return le32_to_cpu(temp) == SQUASHFS_MAGIC;
+}
+
+static struct mtd_partition split_partitions[] = {
+ {
+ .name = "kernel",
+ .offset = 0x0,
+ .size = 0x0,
+ }, {
+ .name = "rootfs",
+ .offset = 0x0,
+ .size = 0x0,
+ },
+};
+
+static int
+mtd_split_linux(struct map_info *map, struct mtd_info *mtd,
+ struct mtd_partition *parts, int nr_parts)
+{
+ int base_part = 0;
+ int i;
+ for (i = 0; i < nr_parts && !base_part; i++) {
+ if(!strcmp("linux", parts[i].name))
+ base_part = i;
+ }
+ if (!base_part)
+ return 0;
+ split_partitions[0].size = find_uImage_size(map, parts[base_part].offset);
+ if (!split_partitions[0].size) {
+ printk(KERN_INFO "lq_nor: no uImage found in linux partition");
+ return -1;
+ }
+ if (!detect_squashfs_partition(map,
+ parts[base_part].offset + split_partitions[0].size)) {
+ split_partitions[0].size &= ~(mtd->erasesize - 1);
+ split_partitions[0].size += mtd->erasesize;
+ }
+ split_partitions[0].offset = parts[base_part].offset;
+ split_partitions[1].offset =
+ parts[base_part].offset + split_partitions[0].size;
+ split_partitions[1].size =
+ parts[base_part].size - split_partitions[0].size;
+
+ base_part++;
+ add_mtd_partitions(mtd, parts, base_part);
+ add_mtd_partitions(mtd, split_partitions, 2);
+ if(nr_parts != base_part)
+ add_mtd_partitions(mtd, &parts[base_part], nr_parts - base_part);
+ return nr_parts + 2;
+}
+
static const char *part_probe_types[] = { "cmdlinepart", NULL };
static struct map_info lq_map = {
@@ -142,7 +215,8 @@ lq_mtd_probe(struct platform_device *pde
parts = lq_mtd_data->parts;
}
- add_mtd_partitions(lq_mtd, parts, nr_parts);
+ if (!mtd_split_linux(&lq_map, lq_mtd, parts, nr_parts))
+ add_mtd_partitions(lq_mtd, parts, nr_parts);
return 0;
}

View File

@@ -0,0 +1,580 @@
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -343,6 +343,12 @@ config MACB
source "drivers/net/arm/Kconfig"
+config LANTIQ_ETOP
+ tristate "Lantiq SoC ETOP driver"
+ depends on SOC_LANTIQ_XWAY
+ help
+ Support for the MII0 inside the Lantiq SoC
+
config AX88796
tristate "ASIX AX88796 NE2000 clone support"
depends on ARM || MIPS || SUPERH
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -204,6 +204,7 @@ obj-$(CONFIG_SNI_82596) += sni_82596.o
obj-$(CONFIG_MVME16x_NET) += 82596.o
obj-$(CONFIG_BVME6000_NET) += 82596.o
obj-$(CONFIG_SC92031) += sc92031.o
+obj-$(CONFIG_LANTIQ_ETOP) += lantiq_etop.o
# This is also a 82596 and should probably be merged
obj-$(CONFIG_LP486E) += lp486e.o
--- /dev/null
+++ b/drivers/net/lantiq_etop.c
@@ -0,0 +1,552 @@
+/*
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) 2005 Wu Qi Ming <Qi-Ming.Wu@infineon.com>
+ * Copyright (C) 2008 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/uaccess.h>
+#include <linux/in.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/phy.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/skbuff.h>
+#include <linux/mm.h>
+#include <linux/platform_device.h>
+#include <linux/ethtool.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <asm/checksum.h>
+
+#include <xway.h>
+#include <xway_dma.h>
+#include <lantiq_platform.h>
+
+#define ETHERNET_PACKET_DMA_BUFFER_SIZE 0x600
+#define LQ_PPE32_MEM_MAP ((u32 *)(LQ_PPE32_BASE_ADDR + 0x10000))
+#define LQ_PPE32_SRST ((u32 *)(LQ_PPE32_BASE_ADDR + 0x10080))
+
+/* mdio access */
+#define LQ_PPE32_MDIO_CFG ((u32 *)(LQ_PPE32_BASE_ADDR + 0x11800))
+#define LQ_PPE32_MDIO_ACC ((u32 *)(LQ_PPE32_BASE_ADDR + 0x11804))
+
+#define MDIO_ACC_REQUEST 0x80000000
+#define MDIO_ACC_READ 0x40000000
+#define MDIO_ACC_ADDR_MASK 0x1f
+#define MDIO_ACC_ADDR_OFFSET 0x15
+#define MDIO_ACC_REG_MASK 0x1f
+#define MDIO_ACC_REG_OFFSET 0x10
+#define MDIO_ACC_VAL_MASK 0xffff
+
+/* configuration */
+#define LQ_PPE32_CFG ((u32 *)(LQ_PPE32_MEM_MAP + 0x1808))
+
+#define PPE32_MII_MASK 0xfffffffc
+#define PPE32_MII_NORMAL 0x8
+#define PPE32_MII_REVERSE 0xe
+
+/* packet length */
+#define LQ_PPE32_IG_PLEN_CTRL ((u32 *)(LQ_PPE32_MEM_MAP + 0x1820))
+
+#define PPE32_PLEN_OVER 0x5ee
+#define PPE32_PLEN_UNDER 0x400000
+
+/* enet */
+#define LQ_PPE32_ENET_MAC_CFG ((u32 *)(LQ_PPE32_MEM_MAP + 0x1840))
+
+#define PPE32_CGEN 0x800
+
+struct lq_mii_priv {
+ struct net_device_stats stats;
+ struct dma_device_info *dma_device;
+ struct sk_buff *skb;
+
+ struct mii_bus *mii_bus;
+ struct phy_device *phydev;
+ int oldlink, oldspeed, oldduplex;
+};
+
+static struct net_device *lq_etop_dev;
+static unsigned char mac_addr[MAX_ADDR_LEN];
+
+static int lq_mdiobus_write(struct mii_bus *bus, int phy_addr,
+ int phy_reg, u16 phy_data)
+{
+ u32 val = MDIO_ACC_REQUEST |
+ ((phy_addr & MDIO_ACC_ADDR_MASK) << MDIO_ACC_ADDR_OFFSET) |
+ ((phy_reg & MDIO_ACC_REG_MASK) << MDIO_ACC_REG_OFFSET) |
+ phy_data;
+
+ while (lq_r32(LQ_PPE32_MDIO_ACC) & MDIO_ACC_REQUEST)
+ ;
+ lq_w32(val, LQ_PPE32_MDIO_ACC);
+
+ return 0;
+}
+
+static int lq_mdiobus_read(struct mii_bus *bus, int phy_addr, int phy_reg)
+{
+ u32 val = MDIO_ACC_REQUEST | MDIO_ACC_READ |
+ ((phy_addr & MDIO_ACC_ADDR_MASK) << MDIO_ACC_ADDR_OFFSET) |
+ ((phy_reg & MDIO_ACC_REG_MASK) << MDIO_ACC_REG_OFFSET);
+
+ while (lq_r32(LQ_PPE32_MDIO_ACC) & MDIO_ACC_REQUEST)
+ ;
+ lq_w32(val, LQ_PPE32_MDIO_ACC);
+ while (lq_r32(LQ_PPE32_MDIO_ACC) & MDIO_ACC_REQUEST)
+ ;
+ val = lq_r32(LQ_PPE32_MDIO_ACC) & MDIO_ACC_VAL_MASK;
+ return val;
+}
+
+int lq_mii_open(struct net_device *dev)
+{
+ struct lq_mii_priv *priv = (struct lq_mii_priv *)netdev_priv(dev);
+ struct dma_device_info *dma_dev = priv->dma_device;
+ int i;
+
+ for (i = 0; i < dma_dev->max_rx_chan_num; i++) {
+ if ((dma_dev->rx_chan[i])->control == LQ_DMA_CH_ON)
+ (dma_dev->rx_chan[i])->open(dma_dev->rx_chan[i]);
+ }
+ netif_start_queue(dev);
+ return 0;
+}
+
+int lq_mii_release(struct net_device *dev)
+{
+ struct lq_mii_priv *priv = (struct lq_mii_priv *)netdev_priv(dev);
+ struct dma_device_info *dma_dev = priv->dma_device;
+ int i;
+
+ for (i = 0; i < dma_dev->max_rx_chan_num; i++)
+ dma_dev->rx_chan[i]->close(dma_dev->rx_chan[i]);
+ netif_stop_queue(dev);
+ return 0;
+}
+
+int lq_mii_hw_receive(struct net_device *dev, struct dma_device_info *dma_dev)
+{
+ struct lq_mii_priv *priv = (struct lq_mii_priv *)netdev_priv(dev);
+ unsigned char *buf = NULL;
+ struct sk_buff *skb = NULL;
+ int len = 0;
+
+ len = dma_device_read(dma_dev, &buf, (void **)&skb);
+
+ if (len >= ETHERNET_PACKET_DMA_BUFFER_SIZE) {
+ printk(KERN_INFO "lq_etop: packet too large %d\n", len);
+ goto lq_mii_hw_receive_err_exit;
+ }
+
+ /* remove CRC */
+ len -= 4;
+ if (skb == NULL) {
+ printk(KERN_INFO "lq_etop: cannot restore pointer\n");
+ goto lq_mii_hw_receive_err_exit;
+ }
+
+ if (len > (skb->end - skb->tail)) {
+ printk(KERN_INFO "lq_etop: BUG, len:%d end:%p tail:%p\n",
+ (len+4), skb->end, skb->tail);
+ goto lq_mii_hw_receive_err_exit;
+ }
+
+ skb_put(skb, len);
+ skb->dev = dev;
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_rx(skb);
+
+ priv->stats.rx_packets++;
+ priv->stats.rx_bytes += len;
+ return 0;
+
+lq_mii_hw_receive_err_exit:
+ if (len == 0) {
+ if (skb)
+ dev_kfree_skb_any(skb);
+ priv->stats.rx_errors++;
+ priv->stats.rx_dropped++;
+ return -EIO;
+ } else {
+ return len;
+ }
+}
+
+int lq_mii_hw_tx(char *buf, int len, struct net_device *dev)
+{
+ int ret = 0;
+ struct lq_mii_priv *priv = netdev_priv(dev);
+ struct dma_device_info *dma_dev = priv->dma_device;
+ ret = dma_device_write(dma_dev, buf, len, priv->skb);
+ return ret;
+}
+
+int lq_mii_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ int len;
+ char *data;
+ struct lq_mii_priv *priv = netdev_priv(dev);
+ struct dma_device_info *dma_dev = priv->dma_device;
+
+ len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
+ data = skb->data;
+ priv->skb = skb;
+ dev->trans_start = jiffies;
+ /* TODO: we got more than 1 dma channel,
+ so we should do something intelligent here to select one */
+ dma_dev->current_tx_chan = 0;
+
+ wmb();
+
+ if (lq_mii_hw_tx(data, len, dev) != len) {
+ dev_kfree_skb_any(skb);
+ priv->stats.tx_errors++;
+ priv->stats.tx_dropped++;
+ } else {
+ priv->stats.tx_packets++;
+ priv->stats.tx_bytes += len;
+ }
+
+ return 0;
+}
+
+void lq_mii_tx_timeout(struct net_device *dev)
+{
+ int i;
+ struct lq_mii_priv *priv = (struct lq_mii_priv *)netdev_priv(dev);
+
+ priv->stats.tx_errors++;
+ for (i = 0; i < priv->dma_device->max_tx_chan_num; i++)
+ priv->dma_device->tx_chan[i]->disable_irq(priv->dma_device->tx_chan[i]);
+ netif_wake_queue(dev);
+ return;
+}
+
+int dma_intr_handler(struct dma_device_info *dma_dev, int status)
+{
+ int i;
+
+ switch (status) {
+ case RCV_INT:
+ lq_mii_hw_receive(lq_etop_dev, dma_dev);
+ break;
+
+ case TX_BUF_FULL_INT:
+ printk(KERN_INFO "lq_etop: tx buffer full\n");
+ netif_stop_queue(lq_etop_dev);
+ for (i = 0; i < dma_dev->max_tx_chan_num; i++) {
+ if ((dma_dev->tx_chan[i])->control == LQ_DMA_CH_ON)
+ dma_dev->tx_chan[i]->enable_irq(dma_dev->tx_chan[i]);
+ }
+ break;
+
+ case TRANSMIT_CPT_INT:
+ for (i = 0; i < dma_dev->max_tx_chan_num; i++)
+ dma_dev->tx_chan[i]->disable_irq(dma_dev->tx_chan[i]);
+
+ netif_wake_queue(lq_etop_dev);
+ break;
+ }
+
+ return 0;
+}
+
+unsigned char *lq_etop_dma_buffer_alloc(int len, int *byte_offset, void **opt)
+{
+ unsigned char *buffer = NULL;
+ struct sk_buff *skb = NULL;
+
+ skb = dev_alloc_skb(ETHERNET_PACKET_DMA_BUFFER_SIZE);
+ if (skb == NULL)
+ return NULL;
+
+ buffer = (unsigned char *)(skb->data);
+ skb_reserve(skb, 2);
+ *(int *)opt = (int)skb;
+ *byte_offset = 2;
+
+ return buffer;
+}
+
+void lq_etop_dma_buffer_free(unsigned char *dataptr, void *opt)
+{
+ struct sk_buff *skb = NULL;
+
+ if (opt == NULL) {
+ kfree(dataptr);
+ } else {
+ skb = (struct sk_buff *)opt;
+ dev_kfree_skb_any(skb);
+ }
+}
+
+static void
+lq_adjust_link(struct net_device *dev)
+{
+ struct lq_mii_priv *priv = netdev_priv(dev);
+ struct phy_device *phydev = priv->phydev;
+ int new_state = 0;
+
+ /* Did anything change? */
+ if (priv->oldlink != phydev->link ||
+ priv->oldduplex != phydev->duplex ||
+ priv->oldspeed != phydev->speed) {
+ /* Yes, so update status and mark as changed */
+ new_state = 1;
+ priv->oldduplex = phydev->duplex;
+ priv->oldspeed = phydev->speed;
+ priv->oldlink = phydev->link;
+ }
+
+ /* If link status changed, show new status */
+ if (new_state)
+ phy_print_status(phydev);
+}
+
+static int mii_probe(struct net_device *dev)
+{
+ struct lq_mii_priv *priv = netdev_priv(dev);
+ struct phy_device *phydev = NULL;
+ int phy_addr;
+
+ priv->oldlink = 0;
+ priv->oldspeed = 0;
+ priv->oldduplex = -1;
+
+ /* find the first (lowest address) PHY on the current MAC's MII bus */
+ for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
+ if (priv->mii_bus->phy_map[phy_addr]) {
+ phydev = priv->mii_bus->phy_map[phy_addr];
+ break; /* break out with first one found */
+ }
+ }
+
+ if (!phydev) {
+ printk (KERN_ERR "%s: no PHY found\n", dev->name);
+ return -ENODEV;
+ }
+
+ /* now we are supposed to have a proper phydev, to attach to... */
+ BUG_ON(!phydev);
+ BUG_ON(phydev->attached_dev);
+
+ phydev = phy_connect(dev, dev_name(&phydev->dev), &lq_adjust_link,
+ 0, PHY_INTERFACE_MODE_MII);
+
+ if (IS_ERR(phydev)) {
+ printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
+ return PTR_ERR(phydev);
+ }
+
+ /* mask with MAC supported features */
+ phydev->supported &= (SUPPORTED_10baseT_Half
+ | SUPPORTED_10baseT_Full
+ | SUPPORTED_100baseT_Half
+ | SUPPORTED_100baseT_Full
+ | SUPPORTED_Autoneg
+ /* | SUPPORTED_Pause | SUPPORTED_Asym_Pause */
+ | SUPPORTED_MII
+ | SUPPORTED_TP);
+
+ phydev->advertising = phydev->supported;
+
+ priv->phydev = phydev;
+
+ printk(KERN_INFO "%s: attached PHY driver [%s] "
+ "(mii_bus:phy_addr=%s, irq=%d)\n",
+ dev->name, phydev->drv->name, dev_name(&phydev->dev), phydev->irq);
+
+ return 0;
+}
+
+
+static int lq_mii_dev_init(struct net_device *dev)
+{
+ int i;
+ struct lq_mii_priv *priv = (struct lq_mii_priv *)netdev_priv(dev);
+ ether_setup(dev);
+ dev->watchdog_timeo = 10 * HZ;
+ dev->mtu = 1500;
+ memset(priv, 0, sizeof(struct lq_mii_priv));
+ priv->dma_device = dma_device_reserve("PPE");
+ if (!priv->dma_device) {
+ BUG();
+ return -ENODEV;
+ }
+ priv->dma_device->buffer_alloc = &lq_etop_dma_buffer_alloc;
+ priv->dma_device->buffer_free = &lq_etop_dma_buffer_free;
+ priv->dma_device->intr_handler = &dma_intr_handler;
+ priv->dma_device->max_rx_chan_num = 4;
+
+ for (i = 0; i < priv->dma_device->max_rx_chan_num; i++) {
+ priv->dma_device->rx_chan[i]->packet_size = ETHERNET_PACKET_DMA_BUFFER_SIZE;
+ priv->dma_device->rx_chan[i]->control = LQ_DMA_CH_ON;
+ }
+
+ for (i = 0; i < priv->dma_device->max_tx_chan_num; i++)
+ if (i == 0)
+ priv->dma_device->tx_chan[i]->control = LQ_DMA_CH_ON;
+ else
+ priv->dma_device->tx_chan[i]->control = LQ_DMA_CH_OFF;
+
+ dma_device_register(priv->dma_device);
+
+ printk(KERN_INFO "%s: using mac=", dev->name);
+ for (i = 0; i < 6; i++) {
+ dev->dev_addr[i] = mac_addr[i];
+ printk("%02X%c", dev->dev_addr[i], (i == 5) ? ('\n') : (':'));
+ }
+
+ priv->mii_bus = mdiobus_alloc();
+ if (priv->mii_bus == NULL)
+ return -ENOMEM;
+
+ priv->mii_bus->priv = dev;
+ priv->mii_bus->read = lq_mdiobus_read;
+ priv->mii_bus->write = lq_mdiobus_write;
+ priv->mii_bus->name = "lq_mii";
+ snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%x", 0);
+ priv->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
+ for(i = 0; i < PHY_MAX_ADDR; ++i)
+ priv->mii_bus->irq[i] = PHY_POLL;
+
+ mdiobus_register(priv->mii_bus);
+
+ return mii_probe(dev);
+}
+
+static void lq_mii_chip_init(int mode)
+{
+ lq_pmu_enable(PMU_DMA);
+ lq_pmu_enable(PMU_PPE);
+
+ if (mode == REV_MII_MODE)
+ lq_w32_mask(PPE32_MII_MASK, PPE32_MII_REVERSE, LQ_PPE32_CFG);
+ else if (mode == MII_MODE)
+ lq_w32_mask(PPE32_MII_MASK, PPE32_MII_NORMAL, LQ_PPE32_CFG);
+ lq_w32(PPE32_PLEN_UNDER | PPE32_PLEN_OVER, LQ_PPE32_IG_PLEN_CTRL);
+ lq_w32(PPE32_CGEN, LQ_PPE32_ENET_MAC_CFG);
+ wmb();
+}
+
+static int lq_mii_eth_mac_addr(struct net_device *dev, void *p)
+{
+ int retcode;
+
+ retcode = eth_mac_addr(dev, p);
+
+ if (retcode)
+ return retcode;
+
+ // set rx_addr for unicast filter
+ lq_w32(((dev->dev_addr[0]<<24)|(dev->dev_addr[1]<<16)|(dev->dev_addr[2]<< 8)|dev->dev_addr[3]), (u32*)(LQ_PPE32_BASE_ADDR|(0x461b<<2)));
+ lq_w32(((dev->dev_addr[4]<<24)|(dev->dev_addr[5]<<16)), (u32*)(LQ_PPE32_BASE_ADDR|(0x461c<<2)));
+
+ return 0;
+}
+
+static void lq_mii_set_rx_mode (struct net_device *dev)
+{
+ // rx_mode promisc: unset unicast filter
+ if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI))
+ lq_w32(lq_r32((u32*)(LQ_PPE32_BASE_ADDR|(0x4614<<2))) & ~(1<<28), (u32*)(LQ_PPE32_BASE_ADDR|(0x4614<<2)));
+ // enable unicast filter
+ else
+ lq_w32(lq_r32((u32*)(LQ_PPE32_BASE_ADDR|(0x4614<<2))) | (1<<28), (u32*)(LQ_PPE32_BASE_ADDR|(0x4614<<2)));
+}
+
+static const struct net_device_ops lq_eth_netdev_ops = {
+ .ndo_init = lq_mii_dev_init,
+ .ndo_open = lq_mii_open,
+ .ndo_stop = lq_mii_release,
+ .ndo_start_xmit = lq_mii_tx,
+ .ndo_tx_timeout = lq_mii_tx_timeout,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_set_mac_address = lq_mii_eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_multicast_list = lq_mii_set_rx_mode,
+};
+
+static int
+lq_mii_probe(struct platform_device *dev)
+{
+ int result = 0;
+ struct lq_eth_data *eth = (struct lq_eth_data*)dev->dev.platform_data;
+ lq_etop_dev = alloc_etherdev(sizeof(struct lq_mii_priv));
+ lq_etop_dev->netdev_ops = &lq_eth_netdev_ops;
+ memcpy(mac_addr, eth->mac, 6);
+ strcpy(lq_etop_dev->name, "eth%d");
+ lq_mii_chip_init(eth->mii_mode);
+ result = register_netdev(lq_etop_dev);
+ if (result) {
+ printk(KERN_INFO "lq_etop: error %i registering device \"%s\"\n", result, lq_etop_dev->name);
+ goto out;
+ }
+
+ printk(KERN_INFO "lq_etop: driver loaded!\n");
+
+out:
+ return result;
+}
+
+static int lq_mii_remove(struct platform_device *dev)
+{
+ struct lq_mii_priv *priv = (struct lq_mii_priv *)netdev_priv(lq_etop_dev);
+
+ printk(KERN_INFO "lq_etop: lq_etop cleanup\n");
+
+ dma_device_unregister(priv->dma_device);
+ dma_device_release(priv->dma_device);
+ kfree(priv->dma_device);
+ unregister_netdev(lq_etop_dev);
+ return 0;
+}
+
+static struct platform_driver lq_mii_driver = {
+ .probe = lq_mii_probe,
+ .remove = lq_mii_remove,
+ .driver = {
+ .name = "lq_etop",
+ .owner = THIS_MODULE,
+ },
+};
+
+int __init lq_mii_init(void)
+{
+ int ret = platform_driver_register(&lq_mii_driver);
+ if (ret)
+ printk(KERN_INFO "lq_etop: Error registering platfom driver!");
+ return ret;
+}
+
+static void __exit lq_mii_cleanup(void)
+{
+ platform_driver_unregister(&lq_mii_driver);
+}
+
+module_init(lq_mii_init);
+module_exit(lq_mii_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
+MODULE_DESCRIPTION("ethernet driver for IFXMIPS boards");

View File

@@ -0,0 +1,246 @@
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -840,6 +840,12 @@ config TXX9_WDT
help
Hardware driver for the built-in watchdog timer on TXx9 MIPS SoCs.
+config LANTIQ_WDT
+ bool "Lantiq SoC watchdog"
+ depends on LANTIQ
+ help
+ Hardware driver for the Lantiq SoC Watchdog Timer.
+
# PARISC Architecture
# POWERPC Architecture
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -112,6 +112,7 @@ obj-$(CONFIG_PNX833X_WDT) += pnx833x_wdt
obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o
obj-$(CONFIG_AR7_WDT) += ar7_wdt.o
obj-$(CONFIG_TXX9_WDT) += txx9wdt.o
+obj-$(CONFIG_LANTIQ_WDT) += lantiq_wdt.o
# PARISC Architecture
--- /dev/null
+++ b/drivers/watchdog/lantiq_wdt.c
@@ -0,0 +1,218 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ * Based on EP93xx wdt driver
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/clk.h>
+
+#include <lantiq.h>
+
+#define LQ_WDT_PW1 0x00BE0000
+#define LQ_WDT_PW2 0x00DC0000
+
+#define LQ_BIU_WDT_CR 0x3F0
+#define LQ_BIU_WDT_SR 0x3F8
+
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+static int wdt_ok_to_close;
+#endif
+
+static int wdt_timeout = 30;
+static __iomem void *wdt_membase = NULL;
+static unsigned long io_region_clk = 0;
+
+static int
+lq_wdt_enable(unsigned int timeout)
+{
+/* printk("%s:%s[%d] %08X\n",
+ __FILE__, __func__, __LINE__,
+ lq_r32(wdt_membase + LQ_BIU_WDT_SR));
+ if(!lq_r32(wdt_membase + LQ_BIU_WDT_SR))
+ {
+*/ lq_w32(LQ_WDT_PW1, wdt_membase + LQ_BIU_WDT_CR);
+ lq_w32(LQ_WDT_PW2 |
+ (0x3 << 26) | /* PWL */
+ (0x3 << 24) | /* CLKDIV */
+ (0x1 << 31) | /* enable */
+ ((timeout * (io_region_clk / 0x40000)) + 0x1000), /* reload */
+ wdt_membase + LQ_BIU_WDT_CR);
+// }
+ return 0;
+}
+
+static void
+lq_wdt_disable(void)
+{
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+ wdt_ok_to_close = 0;
+#endif
+ lq_w32(LQ_WDT_PW1, wdt_membase + LQ_BIU_WDT_CR);
+ lq_w32(LQ_WDT_PW2, wdt_membase+ LQ_BIU_WDT_CR);
+}
+
+static ssize_t
+lq_wdt_write(struct file *file, const char __user *data,
+ size_t len, loff_t *ppos)
+{
+ size_t i;
+
+ if (!len)
+ return 0;
+
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+ for (i = 0; i != len; i++) {
+ char c;
+ if (get_user(c, data + i))
+ return -EFAULT;
+ if (c == 'V')
+ wdt_ok_to_close = 1;
+ }
+#endif
+ lq_wdt_enable(wdt_timeout);
+ return len;
+}
+
+static struct watchdog_info ident = {
+ .options = WDIOF_MAGICCLOSE,
+ .identity = "lq_wdt",
+};
+
+static int
+lq_wdt_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret = -ENOTTY;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ ret = copy_to_user((struct watchdog_info __user *)arg, &ident,
+ sizeof(ident)) ? -EFAULT : 0;
+ break;
+
+ case WDIOC_GETTIMEOUT:
+ ret = put_user(wdt_timeout, (int __user *)arg);
+ break;
+
+ case WDIOC_SETTIMEOUT:
+ ret = get_user(wdt_timeout, (int __user *)arg);
+ break;
+
+ case WDIOC_KEEPALIVE:
+ lq_wdt_enable(wdt_timeout);
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+static int
+lq_wdt_open(struct inode *inode, struct file *file)
+{
+ lq_wdt_enable(wdt_timeout);
+ return nonseekable_open(inode, file);
+}
+
+static int
+lq_wdt_release(struct inode *inode, struct file *file)
+{
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+ if (wdt_ok_to_close)
+ lq_wdt_disable();
+ else
+#endif
+ printk(KERN_ERR "lq_wdt: watchdog closed without warning,"
+ " rebooting system\n");
+ return 0;
+}
+
+static const struct file_operations lq_wdt_fops = {
+ .owner = THIS_MODULE,
+ .write = lq_wdt_write,
+ .ioctl = lq_wdt_ioctl,
+ .open = lq_wdt_open,
+ .release = lq_wdt_release,
+};
+
+static struct miscdevice lq_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &lq_wdt_fops,
+};
+
+static int
+lq_wdt_probe(struct platform_device *pdev)
+{
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ struct clk *clk;
+ int ret = 0;
+ if(!res)
+ return -ENOENT;
+ res = request_mem_region(res->start, resource_size(res),
+ dev_name(&pdev->dev));
+ if(!res)
+ return -EBUSY;
+ wdt_membase = ioremap_nocache(res->start, resource_size(res));
+ if(!wdt_membase)
+ {
+ ret = -ENOMEM;
+ goto err_release_mem_region;
+ }
+ clk = clk_get(&pdev->dev, "io");
+ io_region_clk = clk_get_rate(clk);;
+ ret = misc_register(&lq_wdt_miscdev);
+ if(!ret)
+ return 0;
+
+ iounmap(wdt_membase);
+err_release_mem_region:
+ release_mem_region(res->start, resource_size(res));
+ return ret;
+}
+
+static int
+lq_wdt_remove(struct platform_device *dev)
+{
+ lq_wdt_disable();
+ misc_deregister(&lq_wdt_miscdev);
+ return 0;
+}
+
+static struct platform_driver lq_wdt_driver = {
+ .probe = lq_wdt_probe,
+ .remove = lq_wdt_remove,
+ .driver = {
+ .name = "lq_wdt",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init
+init_lq_wdt(void)
+{
+ return platform_driver_register(&lq_wdt_driver);
+}
+
+static void __exit
+exit_lq_wdt(void)
+{
+ platform_driver_unregister(&lq_wdt_driver);
+}
+
+module_init(init_lq_wdt);
+module_exit(exit_lq_wdt);
+
+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
+MODULE_DESCRIPTION("ifxmips Watchdog");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);

View File

@@ -0,0 +1,436 @@
--- a/arch/mips/pci/Makefile
+++ b/arch/mips/pci/Makefile
@@ -55,6 +55,7 @@ obj-$(CONFIG_ZAO_CAPCELLA) += fixup-capc
obj-$(CONFIG_WR_PPMC) += fixup-wrppmc.o
obj-$(CONFIG_MIKROTIK_RB532) += pci-rc32434.o ops-rc32434.o fixup-rc32434.o
obj-$(CONFIG_CPU_CAVIUM_OCTEON) += pci-octeon.o pcie-octeon.o
+obj-$(CONFIG_LANTIQ) += pci-lantiq.o ops-lantiq.o
ifdef CONFIG_PCI_MSI
obj-$(CONFIG_CPU_CAVIUM_OCTEON) += msi-octeon.o
--- /dev/null
+++ b/arch/mips/pci/ops-lantiq.c
@@ -0,0 +1,127 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <asm/addrspace.h>
+#include <linux/vmalloc.h>
+
+#include <xway.h>
+
+#define LQ_PCI_CFG_BUSNUM_SHF 16
+#define LQ_PCI_CFG_DEVNUM_SHF 11
+#define LQ_PCI_CFG_FUNNUM_SHF 8
+
+#define PCI_ACCESS_READ 0
+#define PCI_ACCESS_WRITE 1
+
+extern u32 lq_pci_mapped_cfg;
+
+static int
+lq_pci_config_access(unsigned char access_type,
+ struct pci_bus *bus, unsigned int devfn, unsigned int where, u32 *data)
+{
+ unsigned long cfg_base;
+ unsigned long flags;
+
+ u32 temp;
+
+ /* we support slot from 0 to 15 */
+ /* dev_fn 0&0x68 (AD29) is ifxmips itself */
+ if ((bus->number != 0) || ((devfn & 0xf8) > 0x78)
+ || ((devfn & 0xf8) == 0) || ((devfn & 0xf8) == 0x68))
+ return 1;
+
+ spin_lock_irqsave(&ebu_lock, flags);
+
+ cfg_base = lq_pci_mapped_cfg;
+ cfg_base |= (bus->number << LQ_PCI_CFG_BUSNUM_SHF) | (devfn <<
+ LQ_PCI_CFG_FUNNUM_SHF) | (where & ~0x3);
+
+ /* Perform access */
+ if (access_type == PCI_ACCESS_WRITE)
+ {
+#ifdef CONFIG_SWAP_IO_SPACE
+ lq_w32(swab32(*data), ((u32*)cfg_base));
+#else
+ lq_w32(*data, ((u32*)cfg_base));
+#endif
+ } else {
+ *data = lq_r32(((u32*)(cfg_base)));
+#ifdef CONFIG_SWAP_IO_SPACE
+ *data = swab32(*data);
+#endif
+ }
+ wmb();
+
+ /* clean possible Master abort */
+ cfg_base = (lq_pci_mapped_cfg | (0x0 << LQ_PCI_CFG_FUNNUM_SHF)) + 4;
+ temp = lq_r32(((u32*)(cfg_base)));
+#ifdef CONFIG_SWAP_IO_SPACE
+ temp = swab32 (temp);
+#endif
+ cfg_base = (lq_pci_mapped_cfg | (0x68 << LQ_PCI_CFG_FUNNUM_SHF)) + 4;
+ lq_w32(temp, ((u32*)cfg_base));
+
+ spin_unlock_irqrestore(&ebu_lock, flags);
+
+ if (((*data) == 0xffffffff) && (access_type == PCI_ACCESS_READ))
+ return 1;
+
+ return 0;
+}
+
+int
+lq_pci_read_config_dword(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 * val)
+{
+ u32 data = 0;
+
+ if (lq_pci_config_access(PCI_ACCESS_READ, bus, devfn, where, &data))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ if (size == 1)
+ *val = (data >> ((where & 3) << 3)) & 0xff;
+ else if (size == 2)
+ *val = (data >> ((where & 3) << 3)) & 0xffff;
+ else
+ *val = data;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int
+lq_pci_write_config_dword(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 val)
+{
+ u32 data = 0;
+
+ if (size == 4)
+ {
+ data = val;
+ } else {
+ if (lq_pci_config_access(PCI_ACCESS_READ, bus, devfn, where, &data))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ if (size == 1)
+ data = (data & ~(0xff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+ else if (size == 2)
+ data = (data & ~(0xffff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+ }
+
+ if (lq_pci_config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ return PCIBIOS_SUCCESSFUL;
+}
--- /dev/null
+++ b/arch/mips/pci/pci-lantiq.c
@@ -0,0 +1,293 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/platform_device.h>
+
+#include <asm/gpio.h>
+#include <asm/addrspace.h>
+
+#include <xway.h>
+#include <xway_irq.h>
+#include <lantiq_platform.h>
+
+#define LQ_PCI_CFG_BASE 0x17000000
+#define LQ_PCI_CFG_SIZE 0x00008000
+#define LQ_PCI_MEM_BASE 0x18000000
+#define LQ_PCI_MEM_SIZE 0x02000000
+#define LQ_PCI_IO_BASE 0x1AE00000
+#define LQ_PCI_IO_SIZE 0x00200000
+
+#define PCI_CR_FCI_ADDR_MAP0 ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x00C0))
+#define PCI_CR_FCI_ADDR_MAP1 ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x00C4))
+#define PCI_CR_FCI_ADDR_MAP2 ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x00C8))
+#define PCI_CR_FCI_ADDR_MAP3 ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x00CC))
+#define PCI_CR_FCI_ADDR_MAP4 ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x00D0))
+#define PCI_CR_FCI_ADDR_MAP5 ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x00D4))
+#define PCI_CR_FCI_ADDR_MAP6 ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x00D8))
+#define PCI_CR_FCI_ADDR_MAP7 ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x00DC))
+#define PCI_CR_CLK_CTRL ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x0000))
+#define PCI_CR_PCI_MOD ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x0030))
+#define PCI_CR_PC_ARB ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x0080))
+#define PCI_CR_FCI_ADDR_MAP11hg ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x00E4))
+#define PCI_CR_BAR11MASK ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x0044))
+#define PCI_CR_BAR12MASK ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x0048))
+#define PCI_CR_BAR13MASK ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x004C))
+#define PCI_CS_BASE_ADDR1 ((u32 *)(PCI_CS_PR_BASE_ADDR + 0x0010))
+#define PCI_CR_PCI_ADDR_MAP11 ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x0064))
+#define PCI_CR_FCI_BURST_LENGTH ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x00E8))
+#define PCI_CR_PCI_EOI ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x002C))
+
+
+#define PCI_CS_STS_CMD ((u32 *)(PCI_CS_PR_BASE_ADDR + 0x0004))
+
+#define PCI_MASTER0_REQ_MASK_2BITS 8
+#define PCI_MASTER1_REQ_MASK_2BITS 10
+#define PCI_MASTER2_REQ_MASK_2BITS 12
+#define INTERNAL_ARB_ENABLE_BIT 0
+
+#define LQ_CGU_IFCCR ((u32 *)(LQ_CGU_BASE_ADDR + 0x0018))
+#define LQ_CGU_PCICR ((u32 *)(LQ_CGU_BASE_ADDR + 0x0034))
+
+extern int lq_pci_read_config_dword(struct pci_bus *bus,
+ unsigned int devfn, int where, int size, u32 *val);
+extern int lq_pci_write_config_dword(struct pci_bus *bus,
+ unsigned int devfn, int where, int size, u32 val);
+
+u32 lq_pci_mapped_cfg;
+
+/* Since the PCI REQ pins can be reused for other functionality, make it possible
+ to exclude those from interpretation by the PCI controller */
+static int lq_pci_req_mask = 0xf;
+
+struct pci_ops lq_pci_ops =
+{
+ .read = lq_pci_read_config_dword,
+ .write = lq_pci_write_config_dword
+};
+
+static struct resource pci_io_resource =
+{
+ .name = "pci io space",
+ .start = LQ_PCI_IO_BASE,
+ .end = LQ_PCI_IO_BASE + LQ_PCI_IO_SIZE - 1,
+ .flags = IORESOURCE_IO
+};
+
+static struct resource pci_mem_resource =
+{
+ .name = "pci memory space",
+ .start = LQ_PCI_MEM_BASE,
+ .end = LQ_PCI_MEM_BASE + LQ_PCI_MEM_SIZE - 1,
+ .flags = IORESOURCE_MEM
+};
+
+static struct pci_controller lq_pci_controller =
+{
+ .pci_ops = &lq_pci_ops,
+ .mem_resource = &pci_mem_resource,
+ .mem_offset = 0x00000000UL,
+ .io_resource = &pci_io_resource,
+ .io_offset = 0x00000000UL,
+};
+
+int
+pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ u8 pin;
+
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+ switch(pin)
+ {
+ case 0:
+ break;
+ case 1:
+ //falling edge level triggered:0x4, low level:0xc, rising edge:0x2
+ lq_w32(lq_r32(LQ_EBU_PCC_CON) | 0xc, LQ_EBU_PCC_CON);
+ lq_w32(lq_r32(LQ_EBU_PCC_IEN) | 0x10, LQ_EBU_PCC_IEN);
+ break;
+ case 2:
+ case 3:
+ case 4:
+ printk ("WARNING: interrupt pin %d not supported yet!\n", pin);
+ default:
+ printk ("WARNING: invalid interrupt pin %d\n", pin);
+ return 1;
+ }
+ return 0;
+}
+
+static u32
+lq_calc_bar11mask(void)
+{
+ u32 mem, bar11mask;
+
+ /* BAR11MASK value depends on available memory on system. */
+ mem = num_physpages * PAGE_SIZE;
+ bar11mask = (0x0ffffff0 & ~((1 << (fls(mem) -1)) -1)) | 8;
+
+ return bar11mask;
+}
+
+static void
+lq_pci_setup_clk(int external_clock)
+{
+ /* set clock to 33Mhz */
+ lq_w32(lq_r32(LQ_CGU_IFCCR) & ~0xf00000, LQ_CGU_IFCCR);
+ lq_w32(lq_r32(LQ_CGU_IFCCR) | 0x800000, LQ_CGU_IFCCR);
+ if (external_clock)
+ {
+ lq_w32(lq_r32(LQ_CGU_IFCCR) & ~(1 << 16), LQ_CGU_IFCCR);
+ lq_w32((1 << 30), LQ_CGU_PCICR);
+ } else {
+ lq_w32(lq_r32(LQ_CGU_IFCCR) | (1 << 16), LQ_CGU_IFCCR);
+ lq_w32((1 << 31) | (1 << 30), LQ_CGU_PCICR);
+ }
+}
+
+static void
+lq_pci_setup_gpio(void)
+{
+ /* PCI reset line is gpio driven */
+ lq_gpio_request(21, 0, 0, 1, "pci-reset");
+
+ /* PCI_REQ line */
+ lq_gpio_request(29, 1, 0, 0, "pci-req");
+
+ /* PCI_GNT line */
+ lq_gpio_request(30, 1, 0, 1, "pci-gnt");
+}
+
+static int __init
+lq_pci_startup(void)
+{
+ u32 temp_buffer;
+
+ /* setup pci clock and gpis used by pci */
+ lq_pci_setup_gpio();
+
+ /* enable auto-switching between PCI and EBU */
+ lq_w32(0xa, PCI_CR_CLK_CTRL);
+
+ /* busy, i.e. configuration is not done, PCI access has to be retried */
+ lq_w32(lq_r32(PCI_CR_PCI_MOD) & ~(1 << 24), PCI_CR_PCI_MOD);
+ wmb ();
+ /* BUS Master/IO/MEM access */
+ lq_w32(lq_r32(PCI_CS_STS_CMD) | 7, PCI_CS_STS_CMD);
+
+ /* enable external 2 PCI masters */
+ temp_buffer = lq_r32(PCI_CR_PC_ARB);
+ temp_buffer &= (~(lq_pci_req_mask << 16));
+ /* enable internal arbiter */
+ temp_buffer |= (1 << INTERNAL_ARB_ENABLE_BIT);
+ /* enable internal PCI master reqest */
+ temp_buffer &= (~(3 << PCI_MASTER0_REQ_MASK_2BITS));
+
+ /* enable EBU request */
+ temp_buffer &= (~(3 << PCI_MASTER1_REQ_MASK_2BITS));
+
+ /* enable all external masters request */
+ temp_buffer &= (~(3 << PCI_MASTER2_REQ_MASK_2BITS));
+ lq_w32(temp_buffer, PCI_CR_PC_ARB);
+ wmb ();
+
+ /* setup BAR memory regions */
+ lq_w32(0x18000000, PCI_CR_FCI_ADDR_MAP0);
+ lq_w32(0x18400000, PCI_CR_FCI_ADDR_MAP1);
+ lq_w32(0x18800000, PCI_CR_FCI_ADDR_MAP2);
+ lq_w32(0x18c00000, PCI_CR_FCI_ADDR_MAP3);
+ lq_w32(0x19000000, PCI_CR_FCI_ADDR_MAP4);
+ lq_w32(0x19400000, PCI_CR_FCI_ADDR_MAP5);
+ lq_w32(0x19800000, PCI_CR_FCI_ADDR_MAP6);
+ lq_w32(0x19c00000, PCI_CR_FCI_ADDR_MAP7);
+ lq_w32(0x1ae00000, PCI_CR_FCI_ADDR_MAP11hg);
+ lq_w32(lq_calc_bar11mask(), PCI_CR_BAR11MASK);
+ lq_w32(0, PCI_CR_PCI_ADDR_MAP11);
+ lq_w32(0, PCI_CS_BASE_ADDR1);
+#ifdef CONFIG_SWAP_IO_SPACE
+ /* both TX and RX endian swap are enabled */
+ lq_w32(lq_r32(PCI_CR_PCI_EOI) | 3, PCI_CR_PCI_EOI);
+ wmb ();
+#endif
+ /*TODO: disable BAR2 & BAR3 - why was this in the origianl infineon code */
+ lq_w32(lq_r32(PCI_CR_BAR12MASK) | 0x80000000, PCI_CR_BAR12MASK);
+ lq_w32(lq_r32(PCI_CR_BAR13MASK) | 0x80000000, PCI_CR_BAR13MASK);
+ /*use 8 dw burst length */
+ lq_w32(0x303, PCI_CR_FCI_BURST_LENGTH);
+ lq_w32(lq_r32(PCI_CR_PCI_MOD) | (1 << 24), PCI_CR_PCI_MOD);
+ wmb();
+
+ /* toggle reset pin */
+ __gpio_set_value(21, 0);
+ wmb();
+ mdelay(1);
+ __gpio_set_value(21, 1);
+ return 0;
+}
+
+int __init
+pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin){
+ switch(slot)
+ {
+ case 13:
+ /* IDSEL = AD29 --> USB Host Controller */
+ return (INT_NUM_IM1_IRL0 + 17);
+ case 14:
+ /* IDSEL = AD30 --> mini PCI connector */
+ return (INT_NUM_IM0_IRL0 + 22);
+ default:
+ printk("lq_pci: no IRQ found for slot %d, pin %d\n", slot, pin);
+ return 0;
+ }
+}
+
+static int
+lq_pci_probe(struct platform_device *pdev)
+{
+ struct lq_pci_data *lq_pci_data = (struct lq_pci_data*) pdev->dev.platform_data;
+ extern int pci_probe_only;
+
+ pci_probe_only = 0;
+ lq_pci_req_mask = lq_pci_data->req_mask;
+ lq_pci_setup_clk(lq_pci_data->clock);
+
+ lq_pci_startup();
+ lq_pci_mapped_cfg =
+ (u32)ioremap_nocache(LQ_PCI_CFG_BASE, LQ_PCI_CFG_BASE);
+ lq_pci_controller.io_map_base =
+ (unsigned long)ioremap(LQ_PCI_IO_BASE, LQ_PCI_IO_SIZE - 1);
+
+ register_pci_controller(&lq_pci_controller);
+ return 0;
+}
+
+static struct platform_driver
+lq_pci_driver = {
+ .probe = lq_pci_probe,
+ .driver = {
+ .name = "lq_pci",
+ .owner = THIS_MODULE,
+ },
+};
+
+int __init
+pcibios_init(void)
+{
+ int ret = platform_driver_register(&lq_pci_driver);
+ if(ret)
+ printk(KERN_INFO "lq_pci: Error registering platfom driver!");
+ return ret;
+}
+
+arch_initcall(pcibios_init);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,346 @@
--- /dev/null
+++ b/include/linux/udp_redirect.h
@@ -0,0 +1,57 @@
+#ifndef _UDP_REDIRECT_H
+#define _UDP_REDIRECT_H
+
+/******************************************************************************
+
+ Copyright (c) 2006
+ Infineon Technologies AG
+ Am Campeon 1-12; 81726 Munich, Germany
+
+ THE DELIVERY OF THIS SOFTWARE AS WELL AS THE HEREBY GRANTED NON-EXCLUSIVE,
+ WORLDWIDE LICENSE TO USE, COPY, MODIFY, DISTRIBUTE AND SUBLICENSE THIS
+ SOFTWARE IS FREE OF CHARGE.
+
+ THE LICENSED SOFTWARE IS PROVIDED "AS IS" AND INFINEON EXPRESSLY DISCLAIMS
+ ALL REPRESENTATIONS AND WARRANTIES, WHETHER EXPRESS OR IMPLIED, INCLUDING
+ WITHOUT LIMITATION, WARRANTIES OR REPRESENTATIONS OF WORKMANSHIP,
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, DURABILITY, THAT THE
+ OPERATING OF THE LICENSED SOFTWARE WILL BE ERROR FREE OR FREE OF ANY THIRD
+ PARTY CLAIMS, INCLUDING WITHOUT LIMITATION CLAIMS OF THIRD PARTY INTELLECTUAL
+ PROPERTY INFRINGEMENT.
+
+ EXCEPT FOR ANY LIABILITY DUE TO WILFUL ACTS OR GROSS NEGLIGENCE AND EXCEPT
+ FOR ANY PERSONAL INJURY INFINEON SHALL IN NO EVENT BE LIABLE FOR ANY CLAIM
+ OR DAMAGES OF ANY KIND, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+
+******************************************************************************/
+
+/* ============================= */
+/* Includes */
+/* ============================= */
+#ifndef _LINUX_TYPES_H
+#include <linux/types.h>
+#endif
+
+
+/* ============================= */
+/* Definitions */
+/* ============================= */
+#define UDP_REDIRECT_MAGIC (void*)0x55445052L
+
+
+/* ============================= */
+/* Global variable declaration */
+/* ============================= */
+extern int (*udp_do_redirect_fn)(struct sock *sk, struct sk_buff *skb);
+extern int (*udpredirect_getfrag_fn)(void *p, char * to,
+ int offset, int fraglen, int odd,
+ struct sk_buff *skb);
+/* ============================= */
+/* Global function declaration */
+/* ============================= */
+
+extern int udpredirect_getfrag(void *p, char * to, int offset,
+ int fraglen, int odd, struct sk_buff *skb);
+#endif
--- /dev/null
+++ b/net/ipv4/udp_redirect_symb.c
@@ -0,0 +1,186 @@
+/******************************************************************************
+
+ Copyright (c) 2006
+ Infineon Technologies AG
+ Am Campeon 1-12; 81726 Munich, Germany
+
+ THE DELIVERY OF THIS SOFTWARE AS WELL AS THE HEREBY GRANTED NON-EXCLUSIVE,
+ WORLDWIDE LICENSE TO USE, COPY, MODIFY, DISTRIBUTE AND SUBLICENSE THIS
+ SOFTWARE IS FREE OF CHARGE.
+
+ THE LICENSED SOFTWARE IS PROVIDED "AS IS" AND INFINEON EXPRESSLY DISCLAIMS
+ ALL REPRESENTATIONS AND WARRANTIES, WHETHER EXPRESS OR IMPLIED, INCLUDING
+ WITHOUT LIMITATION, WARRANTIES OR REPRESENTATIONS OF WORKMANSHIP,
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, DURABILITY, THAT THE
+ OPERATING OF THE LICENSED SOFTWARE WILL BE ERROR FREE OR FREE OF ANY THIRD
+ PARTY CLAIMS, INCLUDING WITHOUT LIMITATION CLAIMS OF THIRD PARTY INTELLECTUAL
+ PROPERTY INFRINGEMENT.
+
+ EXCEPT FOR ANY LIABILITY DUE TO WILFUL ACTS OR GROSS NEGLIGENCE AND EXCEPT
+ FOR ANY PERSONAL INJURY INFINEON SHALL IN NO EVENT BE LIABLE FOR ANY CLAIM
+ OR DAMAGES OF ANY KIND, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+
+******************************************************************************/
+#if defined(CONFIG_IFX_UDP_REDIRECT) || defined(CONFIG_IFX_UDP_REDIRECT_MODULE)
+/* ============================= */
+/* Includes */
+/* ============================= */
+#include <net/checksum.h>
+#include <net/udp.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/udp_redirect.h>
+
+/* ============================= */
+/* Global variable definition */
+/* ============================= */
+int (*udpredirect_getfrag_fn) (void *p, char * to, int offset,
+ int fraglen, int odd, struct sk_buff *skb) = NULL;
+int (*udp_do_redirect_fn)(struct sock *sk, struct sk_buff *skb) = NULL;
+
+/* ============================= */
+/* Local type definitions */
+/* ============================= */
+struct udpfakehdr
+{
+ struct udphdr uh;
+ u32 saddr;
+ u32 daddr;
+ struct iovec *iov;
+ u32 wcheck;
+};
+
+/* ============================= */
+/* Local function declaration */
+/* ============================= */
+static int udpredirect_csum_partial_copy_fromiovecend(unsigned char *kdata,
+ struct iovec *iov, int offset, unsigned int len, __wsum *csump);
+
+static int udpredirect_memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset,
+ int len);
+
+/* ============================= */
+/* Global function definition */
+/* ============================= */
+
+/*
+ Copy of udp_getfrag() from udp.c
+ This function exists because no copy_from_user() is needed for udpredirect.
+*/
+
+int
+udpredirect_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb)
+{
+ struct iovec *iov = from;
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ if (udpredirect_memcpy_fromiovecend(to, iov, offset, len) < 0)
+ return -EFAULT;
+ } else {
+ __wsum csum = 0;
+ if (udpredirect_csum_partial_copy_fromiovecend(to, iov, offset, len, &csum) < 0)
+ return -EFAULT;
+ skb->csum = csum_block_add(skb->csum, csum, odd);
+ }
+ return 0;
+}
+
+static int udpredirect_memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset,
+ int len)
+{
+ /* Skip over the finished iovecs */
+ while (offset >= iov->iov_len) {
+ offset -= iov->iov_len;
+ iov++;
+ }
+
+ while (len > 0) {
+ u8 __user *base = iov->iov_base + offset;
+ int copy = min_t(unsigned int, len, iov->iov_len - offset);
+
+ offset = 0;
+ memcpy(kdata, base, copy);
+ len -= copy;
+ kdata += copy;
+ iov++;
+ }
+
+ return 0;
+}
+
+/*
+ Copy of csum_partial_copy_fromiovecend() from iovec.c
+ This function exists because no copy_from_user() is needed for udpredirect.
+*/
+
+int udpredirect_csum_partial_copy_fromiovecend(unsigned char *kdata, struct iovec *iov,
+ int offset, unsigned int len, __wsum *csump)
+{
+ __wsum csum = *csump;
+ int partial_cnt = 0, err = 0;
+
+ /* Skip over the finished iovecs */
+ while (offset >= iov->iov_len) {
+ offset -= iov->iov_len;
+ iov++;
+ }
+
+ while (len > 0) {
+ u8 __user *base = iov->iov_base + offset;
+ int copy = min_t(unsigned int, len, iov->iov_len - offset);
+
+ offset = 0;
+
+ /* There is a remnant from previous iov. */
+ if (partial_cnt) {
+ int par_len = 4 - partial_cnt;
+
+ /* iov component is too short ... */
+ if (par_len > copy) {
+ memcpy(kdata, base, copy);
+ kdata += copy;
+ base += copy;
+ partial_cnt += copy;
+ len -= copy;
+ iov++;
+ if (len)
+ continue;
+ *csump = csum_partial(kdata - partial_cnt,
+ partial_cnt, csum);
+ goto out;
+ }
+ memcpy(kdata, base, par_len);
+ csum = csum_partial(kdata - partial_cnt, 4, csum);
+ kdata += par_len;
+ base += par_len;
+ copy -= par_len;
+ len -= par_len;
+ partial_cnt = 0;
+ }
+
+ if (len > copy) {
+ partial_cnt = copy % 4;
+ if (partial_cnt) {
+ copy -= partial_cnt;
+ memcpy(kdata + copy, base + copy, partial_cnt);
+ }
+ }
+
+ if (copy) {
+ csum = csum_partial_copy_nocheck(base, kdata, copy, csum);
+ }
+ len -= copy + partial_cnt;
+ kdata += copy + partial_cnt;
+ iov++;
+ }
+ *csump = csum;
+out:
+ return err;
+}
+
+EXPORT_SYMBOL(udpredirect_getfrag);
+EXPORT_SYMBOL(udp_do_redirect_fn);
+EXPORT_SYMBOL(udpredirect_getfrag_fn);
+#endif /* CONFIG_IFX_UDP_REDIRECT* */
--- a/net/ipv4/Makefile
+++ b/net/ipv4/Makefile
@@ -14,6 +14,9 @@ obj-y := route.o inetpeer.o protocol
inet_fragment.o
obj-$(CONFIG_SYSCTL) += sysctl_net_ipv4.o
+ifneq ($(CONFIG_IFX_UDP_REDIRECT),)
+obj-$(CONFIG_IFX_UDP_REDIRECT) += udp_redirect_symb.o
+endif
obj-$(CONFIG_IP_FIB_HASH) += fib_hash.o
obj-$(CONFIG_IP_FIB_TRIE) += fib_trie.o
obj-$(CONFIG_PROC_FS) += proc.o
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -106,6 +106,10 @@
#include <net/xfrm.h>
#include "udp_impl.h"
+#if defined(CONFIG_IFX_UDP_REDIRECT) || defined(CONFIG_IFX_UDP_REDIRECT_MODULE)
+#include <linux/udp_redirect.h>
+#endif
+
struct udp_table udp_table __read_mostly;
EXPORT_SYMBOL(udp_table);
@@ -782,7 +786,7 @@ int udp_sendmsg(struct kiocb *iocb, stru
u8 tos;
int err, is_udplite = IS_UDPLITE(sk);
int corkreq = up->corkflag || msg->msg_flags&MSG_MORE;
- int (*getfrag)(void *, char *, int, int, int, struct sk_buff *);
+ int (*getfrag)(void *, char *, int, int, int, struct sk_buff *) = NULL;
if (len > 0xFFFF)
return -EMSGSIZE;
@@ -944,6 +948,12 @@ back_from_confirm:
do_append_data:
up->len += ulen;
+ /* UDPREDIRECT */
+#if defined(CONFIG_IFX_UDP_REDIRECT) || defined(CONFIG_IFX_UDP_REDIRECT_MODULE)
+ if(udpredirect_getfrag_fn && sk->sk_user_data == UDP_REDIRECT_MAGIC)
+ getfrag = udpredirect_getfrag_fn;
+ else
+#endif /* IFX_UDP_REDIRECT */
getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag;
err = ip_append_data(sk, getfrag, msg->msg_iov, ulen,
sizeof(struct udphdr), &ipc, &rt,
@@ -1518,6 +1528,7 @@ int __udp4_lib_rcv(struct sk_buff *skb,
struct rtable *rt = skb_rtable(skb);
__be32 saddr, daddr;
struct net *net = dev_net(skb->dev);
+ int ret = 0;
/*
* Validate the packet.
@@ -1550,7 +1561,16 @@ int __udp4_lib_rcv(struct sk_buff *skb,
sk = __udp4_lib_lookup_skb(skb, uh->source, uh->dest, udptable);
if (sk != NULL) {
- int ret = udp_queue_rcv_skb(sk, skb);
+ /* UDPREDIRECT */
+#if defined(CONFIG_IFX_UDP_REDIRECT) || defined(CONFIG_IFX_UDP_REDIRECT_MODULE)
+ if(udp_do_redirect_fn && sk->sk_user_data == UDP_REDIRECT_MAGIC)
+ {
+ udp_do_redirect_fn(sk,skb);
+ kfree_skb(skb);
+ return(0);
+ }
+#endif
+ ret = udp_queue_rcv_skb(sk, skb);
sock_put(sk);
/* a return value > 0 means to resubmit the input, but
@@ -1845,7 +1865,7 @@ struct proto udp_prot = {
#endif
};
EXPORT_SYMBOL(udp_prot);
-
+EXPORT_SYMBOL(udp_rcv);
/* ------------------------------------------------------------------------ */
#ifdef CONFIG_PROC_FS
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -72,6 +72,12 @@ config INET
Short answer: say Y.
+config IFX_UDP_REDIRECT
+ bool "IFX Kernel Packet Interface for UDP redirection"
+ help
+ You can say Y here if you want to use hooks from kernel for
+ UDP redirection.
+
if INET
source "net/ipv4/Kconfig"
source "net/ipv6/Kconfig"

View File

@@ -0,0 +1,42 @@
--- a/arch/mips/mm/cache.c
+++ b/arch/mips/mm/cache.c
@@ -52,6 +52,8 @@
void (*_dma_cache_inv)(unsigned long start, unsigned long size);
EXPORT_SYMBOL(_dma_cache_wback_inv);
+EXPORT_SYMBOL(_dma_cache_wback);
+EXPORT_SYMBOL(_dma_cache_inv);
#endif /* CONFIG_DMA_NONCOHERENT */
--- a/net/atm/proc.c
+++ b/net/atm/proc.c
@@ -153,7 +153,7 @@
static void pvc_info(struct seq_file *seq, struct atm_vcc *vcc)
{
static const char *const class_name[] = {
- "off", "UBR", "CBR", "VBR", "ABR"};
+ "off","UBR","CBR","NTR-VBR","ABR","ANY","RT-VBR","UBR+","GFR"};
static const char *const aal_name[] = {
"---", "1", "2", "3/4", /* 0- 3 */
"???", "5", "???", "???", /* 4- 7 */
--- a/net/atm/common.c
+++ b/net/atm/common.c
@@ -60,11 +60,17 @@
write_unlock_irq(&vcc_sklist_lock);
}
+struct sk_buff* (*ifx_atm_alloc_tx)(struct atm_vcc *, unsigned int) = NULL;
+EXPORT_SYMBOL(ifx_atm_alloc_tx);
+
static struct sk_buff *alloc_tx(struct atm_vcc *vcc, unsigned int size)
{
struct sk_buff *skb;
struct sock *sk = sk_atm(vcc);
+ if (ifx_atm_alloc_tx != NULL)
+ return ifx_atm_alloc_tx(vcc, size);
+
if (sk_wmem_alloc_get(sk) && !atm_may_send(vcc, size)) {
pr_debug("Sorry: wmem_alloc = %d, size = %d, sndbuf = %d\n",
sk_wmem_alloc_get(sk), size, sk->sk_sndbuf);

View File

@@ -0,0 +1,211 @@
--- a/arch/mips/include/asm/mach-lantiq/machine.h
+++ b/arch/mips/include/asm/mach-lantiq/machine.h
@@ -11,4 +11,7 @@
LANTIQ_MACH_EASY4010, /* Twinpass evalkit */
LANTIQ_MACH_EASY50712, /* Danube evalkit */
LANTIQ_MACH_EASY50812, /* AR9 eval board */
+ LANTIQ_MACH_ARV4518, /* Airties WAV-221, SMC-7908A-ISP */
+ LANTIQ_MACH_ARV452, /* Airties WAV-281, Arcor EasyboxA800 */
+ LANTIQ_MACH_ARV4525, /* Speedport W502V */
};
--- a/arch/mips/lantiq/xway/Kconfig
+++ b/arch/mips/lantiq/xway/Kconfig
@@ -14,6 +14,10 @@
bool "Easy4010"
default y
+config LANTIQ_MACH_ARV45XX
+ bool "ARV45XX"
+ default y
+
endmenu
endif
--- a/arch/mips/lantiq/xway/Makefile
+++ b/arch/mips/lantiq/xway/Makefile
@@ -3,3 +3,4 @@
obj-$(CONFIG_LANTIQ_MACH_EASY50812) += mach-easy50812.o
obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o
obj-$(CONFIG_LANTIQ_MACH_EASY4010) += mach-easy4010.o
+obj-$(CONFIG_LANTIQ_MACH_ARV45XX) += mach-arv45xx.o
--- /dev/null
+++ b/arch/mips/lantiq/xway/mach-arv45xx.c
@@ -0,0 +1,178 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/gpio.h>
+#include <linux/gpio_buttons.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/input.h>
+#include <linux/etherdevice.h>
+
+#include <machine.h>
+
+#include <xway.h>
+#include <lantiq_platform.h>
+
+#include "devices.h"
+
+#define ARV452_LATCH_SWITCH (1 << 10)
+
+#ifdef CONFIG_MTD_PARTITIONS
+static struct mtd_partition arv45xx_partitions[] =
+{
+ {
+ .name = "uboot",
+ .offset = 0x0,
+ .size = 0x20000,
+ },
+ {
+ .name = "uboot_env",
+ .offset = 0x20000,
+ .size = 0x10000,
+ },
+ {
+ .name = "linux",
+ .offset = 0x30000,
+ .size = 0x3c0000,
+ },
+ {
+ .name = "board_config",
+ .offset = 0x3f0000,
+ .size = 0x10000,
+ },
+};
+#endif
+
+static struct physmap_flash_data arv45xx_flash_data = {
+#ifdef CONFIG_MTD_PARTITIONS
+ .nr_parts = ARRAY_SIZE(arv45xx_partitions),
+ .parts = arv45xx_partitions,
+#endif
+};
+
+static struct lq_pci_data lq_pci_data = {
+ .clock = PCI_CLOCK_EXT,
+ .req_mask = 0xf,
+};
+
+static struct lq_eth_data lq_eth_data = {
+ .mii_mode = REV_MII_MODE,
+ .mac = "\xff\xff\xff\xff\xff\xff",
+};
+
+static struct gpio_led
+arv4518_leds_gpio[] __initdata = {
+ { .name = "soc:blue:power", .gpio = 3, .active_low = 1, },
+ { .name = "soc:blue:adsl", .gpio = 4, .active_low = 1, },
+ { .name = "soc:blue:internet", .gpio = 5, .active_low = 1, },
+ { .name = "soc:red:power", .gpio = 6, .active_low = 1, },
+ { .name = "soc:yello:wps", .gpio = 7, .active_low = 1, },
+ { .name = "soc:red:wps", .gpio = 9, .active_low = 1, },
+ { .name = "soc:blue:voip", .gpio = 32, .active_low = 1, },
+ { .name = "soc:blue:fxs1", .gpio = 33, .active_low = 1, },
+ { .name = "soc:blue:fxs2", .gpio = 34, .active_low = 1, },
+ { .name = "soc:blue:fxo", .gpio = 35, .active_low = 1, },
+ { .name = "soc:blue:voice", .gpio = 36, .active_low = 1, },
+ { .name = "soc:blue:usb", .gpio = 37, .active_low = 1, },
+ { .name = "soc:blue:wlan", .gpio = 38, .active_low = 1, },
+};
+
+static struct gpio_led
+arv452_leds_gpio[] __initdata = {
+ { .name = "soc:blue:power", .gpio = 3, .active_low = 1, },
+ { .name = "soc:blue:adsl", .gpio = 4, .active_low = 1, },
+ { .name = "soc:blue:internet", .gpio = 5, .active_low = 1, },
+ { .name = "soc:red:power", .gpio = 6, .active_low = 1, },
+ { .name = "soc:yello:wps", .gpio = 7, .active_low = 1, },
+ { .name = "soc:red:wps", .gpio = 9, .active_low = 1, },
+ { .name = "soc:blue:voip", .gpio = 32, .active_low = 1, },
+ { .name = "soc:blue:fxs1", .gpio = 33, .active_low = 1, },
+ { .name = "soc:blue:fxs2", .gpio = 34, .active_low = 1, },
+ { .name = "soc:blue:fxo", .gpio = 35, .active_low = 1, },
+ { .name = "soc:blue:voice", .gpio = 36, .active_low = 1, },
+ { .name = "soc:blue:usb", .gpio = 37, .active_low = 1, },
+ { .name = "soc:blue:wlan", .gpio = 38, .active_low = 1, },
+};
+
+static struct gpio_led arv4525_leds_gpio[] __initdata = {
+ { .name = "soc:green:festnetz", .gpio = 4, .active_low = 1, },
+ { .name = "soc:green:internet", .gpio = 5, .active_low = 1, },
+ { .name = "soc:green:dsl", .gpio = 6, .active_low = 1, },
+ { .name = "soc:green:wlan", .gpio = 8, .active_low = 1, },
+ { .name = "soc:green:online", .gpio = 9, .active_low = 1, },
+};
+
+static void
+arv45xx_register_ethernet(void)
+{
+#define ARV45XX_BRN_MAC 0x3f0016
+ memcpy_fromio(lq_eth_data.mac,
+ (void *)KSEG1ADDR(LQ_FLASH_START + ARV45XX_BRN_MAC), 6);
+ lq_register_ethernet(&lq_eth_data);
+}
+
+static void __init
+arv4518_init(void)
+{
+ lq_register_gpio();
+ lq_register_gpio_ebu(0);
+ lq_register_gpio_leds(arv4518_leds_gpio, ARRAY_SIZE(arv4518_leds_gpio));
+ lq_register_asc(0);
+ lq_register_asc(1);
+ lq_register_nor(&arv45xx_flash_data);
+ lq_register_pci(&lq_pci_data);
+ lq_register_wdt();
+ arv45xx_register_ethernet();
+}
+
+MIPS_MACHINE(LANTIQ_MACH_ARV4518,
+ "ARV4518",
+ "ARV4518 - SMC7908A-ISP",
+ arv4518_init);
+
+static void __init
+arv452_init(void)
+{
+ lq_register_gpio();
+ lq_register_gpio_ebu(ARV452_LATCH_SWITCH);
+ lq_register_gpio_leds(arv452_leds_gpio, ARRAY_SIZE(arv452_leds_gpio));
+ lq_register_asc(0);
+ lq_register_asc(1);
+ lq_register_nor(&arv45xx_flash_data);
+ lq_register_pci(&lq_pci_data);
+ lq_register_wdt();
+ arv45xx_register_ethernet();
+}
+
+MIPS_MACHINE(LANTIQ_MACH_ARV452,
+ "ARV452",
+ "ARV452 - Airties WAV-281, Arcor A800",
+ arv452_init);
+
+static void __init
+arv4525_init(void)
+{
+ lq_register_gpio();
+ lq_register_gpio_leds(arv4525_leds_gpio, ARRAY_SIZE(arv4525_leds_gpio));
+ lq_register_asc(0);
+ lq_register_asc(1);
+ lq_register_nor(&arv45xx_flash_data);
+ lq_register_pci(&lq_pci_data);
+ lq_register_wdt();
+ lq_eth_data.mii_mode = MII_MODE;
+ arv45xx_register_ethernet();
+}
+
+MIPS_MACHINE(LANTIQ_MACH_ARV4525,
+ "ARV4525",
+ "ARV4525 - Speedport W502V",
+ arv4525_init);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,301 @@
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -1706,6 +1706,28 @@
help
IFX included extensions in APRP
+config IFX_VPE_CACHE_SPLIT
+ bool "IFX Cache Split Ways"
+ depends on IFX_VPE_EXT
+ help
+ IFX extension for reserving (splitting) cache ways among VPEs. You must
+ give kernel command line arguments vpe_icache_shared=0 or
+ vpe_dcache_shared=0 to enable splitting of icache or dcache
+ respectively. Then you can specify which cache ways should be
+ assigned to which VPE. There are total 8 cache ways, 4 each
+ for dcache and icache: dcache_way0, dcache_way1,dcache_way2,
+ dcache_way3 and icache_way0,icache_way1, icache_way2,icache_way3.
+
+ For example, if you specify vpe_icache_shared=0 and icache_way2=1,
+ then the 3rd icache way will be assigned to VPE0 and denied in VPE1.
+
+ For icache, software is required to make at least one cache way available
+ for a VPE at all times i.e., one can't assign all the icache ways to one
+ VPE.
+
+ By default, vpe_dcache_shared and vpe_icache_shared are set to 1
+ (i.e., both icache and dcache are shared among VPEs)
+
config PERFCTRS
bool "34K Performance counters"
depends on MIPS_MT && PROC_FS
--- a/arch/mips/kernel/vpe.c
+++ b/arch/mips/kernel/vpe.c
@@ -128,6 +128,13 @@
EXPORT_SYMBOL(vpe1_wdog_timeout);
#endif
+
+#ifdef CONFIG_IFX_VPE_CACHE_SPLIT /* Code for splitting the cache ways among VPEs. */
+extern int vpe_icache_shared,vpe_dcache_shared;
+extern int icache_way0,icache_way1,icache_way2,icache_way3;
+extern int dcache_way0,dcache_way1,dcache_way2,dcache_way3;
+#endif
+
/* grab the likely amount of memory we will need. */
#ifdef CONFIG_MIPS_VPE_LOADER_TOM
#define P_SIZE (2 * 1024 * 1024)
@@ -866,6 +873,65 @@
/* enable this VPE */
write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA);
+#ifdef CONFIG_IFX_VPE_CACHE_SPLIT
+ if ( (!vpe_icache_shared) || (!vpe_dcache_shared) ) {
+
+ /* PCP bit must be 1 to split the cache */
+ if(read_c0_mvpconf0() & MVPCONF0_PCP) {
+
+ if ( !vpe_icache_shared ){
+ write_vpe_c0_vpeconf0((read_vpe_c0_vpeconf0()) & ~VPECONF0_ICS);
+
+ /*
+ * If any cache way is 1, then that way is denied
+ * in VPE1. Otherwise assign that way to VPE1.
+ */
+ if (!icache_way0)
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_IWX0 );
+ else
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_IWX0 );
+ if (!icache_way1)
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_IWX1 );
+ else
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_IWX1 );
+ if (!icache_way2)
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_IWX2 );
+ else
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_IWX2 );
+ if (!icache_way3)
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_IWX3 );
+ else
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_IWX3 );
+ }
+
+ if ( !vpe_dcache_shared ) {
+ write_vpe_c0_vpeconf0((read_vpe_c0_vpeconf0()) & ~VPECONF0_DCS);
+
+ /*
+ * If any cache way is 1, then that way is denied
+ * in VPE1. Otherwise assign that way to VPE1.
+ */
+ if (!dcache_way0)
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_DWX0 );
+ else
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_DWX0 );
+ if (!dcache_way1)
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_DWX1 );
+ else
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_DWX1 );
+ if (!dcache_way2)
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_DWX2 );
+ else
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_DWX2 );
+ if (!dcache_way3)
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_DWX3 );
+ else
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_DWX3 );
+ }
+ }
+ }
+#endif /* endif CONFIG_IFX_VPE_CACHE_SPLIT */
+
/* clear out any left overs from a previous program */
write_vpe_c0_status(0);
write_vpe_c0_cause(0);
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -1348,6 +1348,106 @@
__setup("coherentio", setcoherentio);
#endif
+#ifdef CONFIG_IFX_VPE_CACHE_SPLIT /* Code for splitting the cache ways among VPEs. */
+
+#include <asm/mipsmtregs.h>
+
+/*
+ * By default, vpe_icache_shared and vpe_dcache_shared
+ * values are 1 i.e., both icache and dcache are shared
+ * among the VPEs.
+ */
+
+int vpe_icache_shared = 1;
+static int __init vpe_icache_shared_val(char *str)
+{
+ get_option(&str, &vpe_icache_shared);
+ return 1;
+}
+__setup("vpe_icache_shared=", vpe_icache_shared_val);
+EXPORT_SYMBOL(vpe_icache_shared);
+
+int vpe_dcache_shared = 1;
+static int __init vpe_dcache_shared_val(char *str)
+{
+ get_option(&str, &vpe_dcache_shared);
+ return 1;
+}
+__setup("vpe_dcache_shared=", vpe_dcache_shared_val);
+EXPORT_SYMBOL(vpe_dcache_shared);
+
+/*
+ * Software is required to make atleast one icache
+ * way available for a VPE at all times i.e., one
+ * can't assign all the icache ways to one VPE.
+ */
+
+int icache_way0 = 0;
+static int __init icache_way0_val(char *str)
+{
+ get_option(&str, &icache_way0);
+ return 1;
+}
+__setup("icache_way0=", icache_way0_val);
+
+int icache_way1 = 0;
+static int __init icache_way1_val(char *str)
+{
+ get_option(&str, &icache_way1);
+ return 1;
+}
+__setup("icache_way1=", icache_way1_val);
+
+int icache_way2 = 0;
+static int __init icache_way2_val(char *str)
+{
+ get_option(&str, &icache_way2);
+ return 1;
+}
+__setup("icache_way2=", icache_way2_val);
+
+int icache_way3 = 0;
+static int __init icache_way3_val(char *str)
+{
+ get_option(&str, &icache_way3);
+ return 1;
+}
+__setup("icache_way3=", icache_way3_val);
+
+int dcache_way0 = 0;
+static int __init dcache_way0_val(char *str)
+{
+ get_option(&str, &dcache_way0);
+ return 1;
+}
+__setup("dcache_way0=", dcache_way0_val);
+
+int dcache_way1 = 0;
+static int __init dcache_way1_val(char *str)
+{
+ get_option(&str, &dcache_way1);
+ return 1;
+}
+__setup("dcache_way1=", dcache_way1_val);
+
+int dcache_way2 = 0;
+static int __init dcache_way2_val(char *str)
+{
+ get_option(&str, &dcache_way2);
+ return 1;
+}
+__setup("dcache_way2=", dcache_way2_val);
+
+int dcache_way3 = 0;
+static int __init dcache_way3_val(char *str)
+{
+ get_option(&str, &dcache_way3);
+ return 1;
+}
+__setup("dcache_way3=", dcache_way3_val);
+
+#endif /* endif CONFIG_IFX_VPE_CACHE_SPLIT */
+
void __cpuinit r4k_cache_init(void)
{
extern void build_clear_page(void);
@@ -1367,6 +1467,78 @@
break;
}
+#ifdef CONFIG_IFX_VPE_CACHE_SPLIT
+ /*
+ * We split the cache ways appropriately among the VPEs
+ * based on cache ways values we received as command line
+ * arguments
+ */
+ if ( (!vpe_icache_shared) || (!vpe_dcache_shared) ){
+
+ /* PCP bit must be 1 to split the cache */
+ if(read_c0_mvpconf0() & MVPCONF0_PCP) {
+
+ /* Set CPA bit which enables us to modify VPEOpt register */
+ write_c0_mvpcontrol((read_c0_mvpcontrol()) | MVPCONTROL_CPA);
+
+ if ( !vpe_icache_shared ){
+ write_c0_vpeconf0((read_c0_vpeconf0()) & ~VPECONF0_ICS);
+ /*
+ * If any cache way is 1, then that way is denied
+ * in VPE0. Otherwise assign that way to VPE0.
+ */
+ printk(KERN_DEBUG "icache is split\n");
+ printk(KERN_DEBUG "icache_way0=%d icache_way1=%d icache_way2=%d icache_way3=%d\n",
+ icache_way0, icache_way1,icache_way2, icache_way3);
+ if (icache_way0)
+ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_IWX0 );
+ else
+ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_IWX0 );
+ if (icache_way1)
+ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_IWX1 );
+ else
+ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_IWX1 );
+ if (icache_way2)
+ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_IWX2 );
+ else
+ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_IWX2 );
+ if (icache_way3)
+ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_IWX3 );
+ else
+ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_IWX3 );
+ }
+
+ if ( !vpe_dcache_shared ) {
+ /*
+ * If any cache way is 1, then that way is denied
+ * in VPE0. Otherwise assign that way to VPE0.
+ */
+ printk(KERN_DEBUG "dcache is split\n");
+ printk(KERN_DEBUG "dcache_way0=%d dcache_way1=%d dcache_way2=%d dcache_way3=%d\n",
+ dcache_way0, dcache_way1, dcache_way2, dcache_way3);
+ write_c0_vpeconf0((read_c0_vpeconf0()) & ~VPECONF0_DCS);
+ if (dcache_way0)
+ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_DWX0 );
+ else
+ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_DWX0 );
+ if (dcache_way1)
+ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_DWX1 );
+ else
+ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_DWX1 );
+ if (dcache_way2)
+ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_DWX2 );
+ else
+ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_DWX2 );
+ if (dcache_way3)
+ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_DWX3 );
+ else
+ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_DWX3 );
+ }
+ }
+ }
+
+#endif /* endif CONFIG_IFX_VPE_CACHE_SPLIT */
+
probe_pcache();
setup_scache();

View File

@@ -0,0 +1,40 @@
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/pci.h
@@ -0,0 +1,14 @@
+/*
+ * lantiq SoCs specific PCI definitions
+ *
+ * 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_LANTIQ_PCI_H
+#define __ASM_MACH_LANTIQ_PCI_H
+
+extern int (*ifxmips_pci_plat_dev_init)(struct pci_dev *dev);
+
+#endif
--- a/arch/mips/pci/pci-lantiq.c
+++ b/arch/mips/pci/pci-lantiq.c
@@ -68,6 +68,8 @@
u32 lq_pci_mapped_cfg;
+int (*lqpci_plat_dev_init)(struct pci_dev *dev) = NULL;
+
/* Since the PCI REQ pins can be reused for other functionality, make it possible
to exclude those from interpretation by the PCI controller */
static int lq_pci_req_mask = 0xf;
@@ -126,6 +128,10 @@
printk ("WARNING: invalid interrupt pin %d\n", pin);
return 1;
}
+
+ if (lqpci_plat_dev_init)
+ return lqpci_plat_dev_init(dev);
+
return 0;
}

View File

@@ -0,0 +1,21 @@
# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
# CONFIG_CRYPTO_HW is not set
CONFIG_HAVE_IDE=y
CONFIG_HW_HAS_PCI=y
CONFIG_IMAGE_CMDLINE_HACK=y
CONFIG_LANTIQ_ETOP=y
CONFIG_LANTIQ_MACH_ARV45XX=y
CONFIG_LANTIQ_MACH_EASY4010=y
CONFIG_LANTIQ_MACH_EASY50712=y
CONFIG_LANTIQ_MACH_EASY50812=y
# CONFIG_LANTIQ_PROM_ASC0 is not set
CONFIG_LANTIQ_PROM_ASC1=y
CONFIG_LANTIQ_WDT=y
CONFIG_LEDS_GPIO=y
# CONFIG_LOONGSON_MC146818 is not set
CONFIG_LOONGSON_UART_BASE=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_SCSI_MOD=y
CONFIG_SOC_LANTIQ=y
CONFIG_SOC_LANTIQ_XWAY=y
CONFIG_USB_SUPPORT=y

View File

@@ -0,0 +1,11 @@
ARCH:=mips
SUBTARGET:=xway
BOARDNAME:=Xway
FEATURES:=squashfs jffs2 atm
DEFAULT_PACKAGES+=uboot-lantiq-easy50712 kmod-pppoa ppp-mod-pppoa linux-atm atm-tools br2684ctl ifxmips-dsl-api ifxmips-dsl-control ifx-tapidemo
define Target/Description
Lantiq XWAY (danube/twinpass/ar9)
endef