cns21xx: add initial support for the Cavium CNS21xx SoC

SVN-Revision: 24859
This commit is contained in:
Gabor Juhos 2010-12-30 17:19:16 +00:00
parent a718ebf1ed
commit 72ba27ae72
54 changed files with 17066 additions and 3 deletions

View file

@ -0,0 +1,27 @@
#
# 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
ARCH:=arm
BOARD:=cns21xx
BOARDNAME:=Cavium Networks CNS21xx
FEATURES:=squashfs broken
CFLAGS:=-Os -pipe -march=armv4 -mtune=arm9tdmi -funit-at-a-time
LINUX_VERSION:=2.6.36.2
include $(INCLUDE_DIR)/target.mk
DEFAULT_PACKAGES += \
kmod-leds-gpio kmod-input-core kmod-input-gpio-keys \
kmod-button-hotplug
define Target/Description
Build firmware images for Cavium Networks CNS21XX based boards.
endef
$(eval $(call BuildTarget))

View file

@ -0,0 +1,54 @@
#!/bin/sh
#
# Copyright (C) 2010 OpenWrt.org
#
#
. /lib/cns21xx.sh
status_led=""
led_set_attr() {
[ -f "/sys/class/leds/$1/$2" ] && echo "$3" > "/sys/class/leds/$1/$2"
}
status_led_set_timer() {
led_set_attr $status_led "trigger" "timer"
led_set_attr $status_led "delay_on" "$1"
led_set_attr $status_led "delay_off" "$2"
}
status_led_on() {
led_set_attr $status_led "trigger" "none"
led_set_attr $status_led "brightness" 255
}
status_led_off() {
led_set_attr $status_led "trigger" "none"
led_set_attr $status_led "brightness" 0
}
get_status_led() {
case $(get_board_name) in
ns-k330)
status_led="ns-k330:red:link"
;;
esac;
}
set_state() {
get_status_led
case "$1" in
preinit)
insmod leds-gpio
status_led_set_timer 200 200
;;
failsafe)
status_led_set_timer 50 50
;;
done)
status_led_on
;;
esac
}

View file

@ -0,0 +1,42 @@
#!/bin/sh
#
# Copyright (C) 2010 OpenWrt.org
#
. /lib/cns21xx.sh
board=$(get_board_name)
ns_k330_set_leds() {
uci batch <<EOF
set system.led_eth_orange='led'
set system.led_eth_orange.name='eth_orange'
set system.led_eth_orange.sysfs='ns-k330:orange:eth'
set system.led_eth_orange.trigger='netdev'
set system.led_eth_orange.dev='eth0'
set system.led_eth_orange.mode='link'
set system.led_eth_green='led'
set system.led_eth_green.name='eth_green'
set system.led_eth_green.sysfs='ns-k330:green:eth'
set system.led_eth_green.trigger='netdev'
set system.led_eth_green.dev='eth0'
set system.led_eth_green.mode='tx rx'
set system.usb_led1=led
set system.usb_led1.name='USB'
set system.usb_led1.sysfs='ns-k330:green:usb1'
set system.usb_led1.trigger='usbdev'
set system.usb_led1.dev='1-1'
set system.usb_led1.interval='50'
set system.usb_led2=led
set system.usb_led2.name='USB'
set system.usb_led2.sysfs='ns-k330:green:usb2'
set system.usb_led2.trigger='usbdev'
set system.usb_led2.dev='1-2'
set system.usb_led2.interval='50'
commit system
EOF
}
if [ "${board}" == "ns-k330" ]; then
ns_k330_set_leds
fi

View file

@ -0,0 +1,25 @@
#!/bin/sh
#
# Copyright (C) 2010 OpenWrt.org
#
get_board_name() {
local hardware
local name
hardware=$(awk 'BEGIN{FS="[ \t]+:[ \t]"} /Hardware/ {print $2}' /proc/cpuinfo)
case "$hardware" in
*NSB3AST)
name="nsb3ast"
;;
"NS-K330 NAS")
name="ns-k330"
;;
*)
name="generic"
;;
esac
echo $name
}

View file

@ -0,0 +1,11 @@
#
# Copyright (C) 2010 OpenWrt.org
#
preinit_load_button_drivers() {
insmod input-core
insmod gpio_keys
insmod button-hotplug
}
boot_hook_add preinit_main preinit_load_button_drivers

View file

@ -0,0 +1,45 @@
#
# Copyright (C) 2010 OpenWrt.org
#
. /lib/cns21xx.sh
PART_NAME=firmware
RAMFS_COPY_DATA=/lib/cns21xx.sh
platform_check_image() {
local board=$(get_board_name)
local magic="$(get_magic_word "$1")"
[ "$ARGC" -gt 1 ] && return 1
case "$board" in
nsb3ast)
[ "$magic" != "0b1c" ] && {
echo "Invalid image type."
return 1
}
return 0
;;
ns-k330)
[ "$magic" != "0c1c" ] && {
echo "Invalid image type."
return 1
}
return 0
;;
esac
echo "Sysupgrade is not yet supported on $board."
return 1
}
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,130 @@
# CONFIG_AEABI is not set
CONFIG_ALIGNMENT_TRAP=y
CONFIG_ARCH_CNS21XX=y
CONFIG_ARCH_REQUIRE_GPIOLIB=y
# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
# CONFIG_ARCH_SUPPORTS_MSI is not set
CONFIG_ARCH_SUSPEND_POSSIBLE=y
# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
CONFIG_ARM=y
CONFIG_ARM_L1_CACHE_SHIFT=4
CONFIG_ARM_L1_CACHE_SHIFT_4=y
# CONFIG_ARPD is not set
CONFIG_ATA=m
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_CMDLINE="console=ttyS0,38400 rootfstype=squashfs,jffs2 noinitrd"
CONFIG_CNS21XX_DEV_GEC=y
CONFIG_CNS21XX_DEV_SPI_MASTER=y
CONFIG_CNS21XX_DEV_USB=y
CONFIG_CNS21XX_GEC=y
CONFIG_CPU_32v4=y
CONFIG_CPU_ABRT_EV4=y
# CONFIG_CPU_BPREDICT_DISABLE is not set
CONFIG_CPU_CACHE_FA=y
CONFIG_CPU_CACHE_VIVT=y
CONFIG_CPU_COPY_FA=y
CONFIG_CPU_CP15=y
CONFIG_CPU_CP15_MMU=y
# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
CONFIG_CPU_FA526=y
# CONFIG_CPU_ICACHE_DISABLE is not set
CONFIG_CPU_PABRT_LEGACY=y
CONFIG_CPU_TLB_FA=y
CONFIG_DEBUG_KERNEL=y
# CONFIG_DEBUG_USER is not set
CONFIG_DECOMPRESS_LZMA=y
CONFIG_DLCI=m
CONFIG_DLCI_MAX=8
CONFIG_DMADEVICES=y
CONFIG_DNOTIFY=y
CONFIG_EEPROM_AT25=y
CONFIG_ELF_CORE=y
CONFIG_FA_WATCHDOG=y
CONFIG_FORCE_MAX_ZONEORDER=11
# CONFIG_FPE_FASTFPE is not set
# CONFIG_FPE_NWFPE is not set
CONFIG_FRAME_POINTER=y
CONFIG_GENERIC_ATOMIC64=y
CONFIG_GENERIC_FIND_LAST_BIT=y
CONFIG_GENERIC_GPIO=y
CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_SYSFS=y
# CONFIG_HAMRADIO is not set
CONFIG_HARDIRQS_SW_RESEND=y
CONFIG_HAS_DMA=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAVE_AOUT=y
CONFIG_HAVE_ARCH_KGDB=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_HAVE_GENERIC_DMA_COHERENT=y
CONFIG_HAVE_IDE=y
CONFIG_HAVE_KERNEL_GZIP=y
CONFIG_HAVE_KERNEL_LZMA=y
CONFIG_HAVE_KERNEL_LZO=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
CONFIG_HAVE_MEMBLOCK=y
CONFIG_HAVE_OPROFILE=y
CONFIG_HAVE_PERF_EVENTS=y
CONFIG_HAVE_PROC_CPU=y
CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
CONFIG_HDLC=m
CONFIG_HDLC_CISCO=m
CONFIG_HDLC_FR=m
CONFIG_HDLC_PPP=m
CONFIG_HDLC_RAW=m
CONFIG_HWMON=y
# CONFIG_HWMON_DEBUG_CHIP is not set
CONFIG_HW_RANDOM=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_INOTIFY_USER=y
# CONFIG_IP_ADVANCED_ROUTER is not set
CONFIG_IP_PIMSM_V1=y
CONFIG_IP_PIMSM_V2=y
# CONFIG_LEDS_GPIO is not set
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
CONFIG_M25PXX_USE_FAST_READ=y
CONFIG_MACH_NSB3AST=y
CONFIG_MACH_NS_K330=y
# CONFIG_MTD_CFI is not set
CONFIG_MTD_M25P80=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NLS=m
CONFIG_PAGEFLAGS_EXTENDED=y
CONFIG_PAGE_OFFSET=0xC0000000
# CONFIG_PCI_SYSCALL is not set
CONFIG_PERF_USE_VMALLOC=y
CONFIG_PHYLIB=y
CONFIG_PLAT_FA=y
CONFIG_PLAT_FA_GPIO=y
CONFIG_PLAT_FA_TIME=y
CONFIG_SCSI=m
CONFIG_SCSI_MOD=m
# CONFIG_SCSI_MULTI_LUN is not set
CONFIG_SERIO=y
CONFIG_SERIO_LIBPS2=y
# CONFIG_SERIO_RAW is not set
CONFIG_SERIO_SERPORT=y
CONFIG_SPI=y
CONFIG_SPI_BITBANG=y
CONFIG_SPI_CNS21XX=y
CONFIG_SPI_DEBUG=y
# CONFIG_SPI_GPIO is not set
CONFIG_SPI_MASTER=y
CONFIG_SPLIT_PTLOCK_CPUS=999999
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
# CONFIG_TINY_RCU is not set
CONFIG_TREE_RCU=y
CONFIG_UID16=y
# CONFIG_USB_ARCH_HAS_EHCI is not set
# CONFIG_USB_ARCH_HAS_OHCI is not set
CONFIG_USB_SUPPORT=y
CONFIG_VECTORS_BASE=0xffff0000
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_WAN=y
CONFIG_ZBOOT_ROM_BSS=0x0
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZONE_DMA_FLAG=0

View file

@ -0,0 +1,147 @@
# CONFIG_AEABI is not set
CONFIG_ALIGNMENT_TRAP=y
CONFIG_ARCH_CNS21XX=y
# CONFIG_ARCH_CNS3XXX is not set
CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
# CONFIG_ARCH_NUC93X is not set
CONFIG_ARCH_REQUIRE_GPIOLIB=y
# CONFIG_ARCH_S5P6442 is not set
# CONFIG_ARCH_S5PC100 is not set
# CONFIG_ARCH_S5PV210 is not set
# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
# CONFIG_ARCH_SHMOBILE is not set
# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
# CONFIG_ARCH_SUPPORTS_MSI is not set
CONFIG_ARCH_SUSPEND_POSSIBLE=y
# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
# CONFIG_ARCH_VEXPRESS is not set
CONFIG_ARM=y
CONFIG_ARM_L1_CACHE_SHIFT=4
CONFIG_ARM_L1_CACHE_SHIFT_4=y
# CONFIG_ARPD is not set
CONFIG_ATA=m
CONFIG_BKL=y
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_CMDLINE="console=ttyS0,38400 rootfstype=squashfs,jffs2 noinitrd"
CONFIG_CNS21XX_DEV_GEC=y
CONFIG_CNS21XX_DEV_SPI_MASTER=y
CONFIG_CNS21XX_DEV_USB=y
CONFIG_CNS21XX_GEC=y
CONFIG_CPU_32v4=y
CONFIG_CPU_ABRT_EV4=y
# CONFIG_CPU_BPREDICT_DISABLE is not set
CONFIG_CPU_CACHE_FA=y
CONFIG_CPU_CACHE_VIVT=y
CONFIG_CPU_COPY_FA=y
CONFIG_CPU_CP15=y
CONFIG_CPU_CP15_MMU=y
# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
CONFIG_CPU_FA526=y
# CONFIG_CPU_ICACHE_DISABLE is not set
CONFIG_CPU_PABRT_LEGACY=y
CONFIG_CPU_TLB_FA=y
CONFIG_DEBUG_KERNEL=y
# CONFIG_DEBUG_USER is not set
CONFIG_DECOMPRESS_LZMA=y
CONFIG_DLCI=m
CONFIG_DLCI_MAX=8
CONFIG_DMADEVICES=y
# CONFIG_DMADEVICES_DEBUG is not set
CONFIG_DNOTIFY=y
CONFIG_EEPROM_AT25=y
CONFIG_ELF_CORE=y
CONFIG_FA_WATCHDOG=y
# CONFIG_FPE_FASTFPE is not set
# CONFIG_FPE_NWFPE is not set
CONFIG_FRAME_POINTER=y
CONFIG_GENERIC_ATOMIC64=y
CONFIG_GENERIC_FIND_LAST_BIT=y
CONFIG_GENERIC_GPIO=y
CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_SYSFS=y
# CONFIG_HAMRADIO is not set
CONFIG_HARDIRQS_SW_RESEND=y
CONFIG_HAS_DMA=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAVE_AOUT=y
CONFIG_HAVE_ARCH_KGDB=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_HAVE_GENERIC_DMA_COHERENT=y
# CONFIG_HAVE_GENERIC_HARDIRQS is not set
CONFIG_HAVE_IDE=y
CONFIG_HAVE_IRQ_WORK=y
CONFIG_HAVE_KERNEL_GZIP=y
CONFIG_HAVE_KERNEL_LZMA=y
CONFIG_HAVE_KERNEL_LZO=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
CONFIG_HAVE_MEMBLOCK=y
CONFIG_HAVE_OPROFILE=y
CONFIG_HAVE_PERF_EVENTS=y
CONFIG_HAVE_PROC_CPU=y
CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
CONFIG_HDLC=m
CONFIG_HDLC_CISCO=m
CONFIG_HDLC_FR=m
CONFIG_HDLC_PPP=m
CONFIG_HDLC_RAW=m
CONFIG_HWMON=y
# CONFIG_HWMON_DEBUG_CHIP is not set
CONFIG_HW_RANDOM=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_INOTIFY_USER=y
# CONFIG_IP_ADVANCED_ROUTER is not set
CONFIG_IP_PIMSM_V1=y
CONFIG_IP_PIMSM_V2=y
# CONFIG_LEDS_GPIO is not set
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
CONFIG_M25PXX_USE_FAST_READ=y
CONFIG_MACH_NO_WESTBRIDGE=y
CONFIG_MACH_NSB3AST=y
CONFIG_MACH_NS_K330=y
# CONFIG_MTD_CFI is not set
CONFIG_MTD_M25P80=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEED_PER_CPU_KM=y
CONFIG_NLS=m
CONFIG_PAGEFLAGS_EXTENDED=y
CONFIG_PAGE_OFFSET=0xC0000000
# CONFIG_PCI_SYSCALL is not set
CONFIG_PERF_USE_VMALLOC=y
CONFIG_PHYLIB=y
CONFIG_PLAT_FA=y
CONFIG_PLAT_FA_GPIO=y
CONFIG_PLAT_FA_TIME=y
# CONFIG_PLAT_SPEAR is not set
# CONFIG_PREEMPT_RCU is not set
# CONFIG_QUOTACTL is not set
CONFIG_SCSI=m
CONFIG_SCSI_MOD=m
# CONFIG_SCSI_MULTI_LUN is not set
CONFIG_SERIO=y
CONFIG_SERIO_LIBPS2=y
# CONFIG_SERIO_PS2MULT is not set
# CONFIG_SERIO_RAW is not set
CONFIG_SERIO_SERPORT=y
CONFIG_SPI=y
CONFIG_SPI_BITBANG=y
CONFIG_SPI_CNS21XX=y
CONFIG_SPI_DEBUG=y
# CONFIG_SPI_GPIO is not set
CONFIG_SPI_MASTER=y
CONFIG_SPLIT_PTLOCK_CPUS=999999
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
# CONFIG_TEST_LIST_SORT is not set
# CONFIG_TIMB_DMA is not set
CONFIG_UID16=y
CONFIG_USB_SUPPORT=y
CONFIG_VECTORS_BASE=0xffff0000
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_WAN=y
CONFIG_ZBOOT_ROM_BSS=0x0
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZONE_DMA_FLAG=0

View file

@ -0,0 +1,118 @@
#
# 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
JFFS2_BLOCKSIZE:=64k
include $(INCLUDE_DIR)/image.mk
INITRAMFS_SUFFIX:=
ifeq ($(CONFIG_TARGET_ROOTFS_INITRAMFS),y)
INITRAMFS_SUFFIX:=-initramfs
endif
define zimage_name
$(IMG_PREFIX)-$(1)-zImage$(INITRAMFS_SUFFIX)
endef
define uimage_name
$(IMG_PREFIX)-$(1)-uImage$(INITRAMFS_SUFFIX)
endef
define imgname
$(BIN_DIR)/$(IMG_PREFIX)-$(2)-$(patsubst jffs2-%,jffs2,$(patsubst squashfs-%,squashfs,$(1)))
endef
define rootfsname
$(BIN_DIR)/$(IMG_PREFIX)-$(2)-root.$(patsubst jffs2-%,jffs2,$(patsubst squashfs-%,squashfs,$(1)))
endef
define build_squashfs
dd if=$(KDIR)/root.squashfs of=$(KDIR)/root.squashfs-$(1) bs=$(1) conv=sync
$(call add_jffs2_mark,$(KDIR)/root.squashfs-$(1))
dd if=$(KDIR)/root.squashfs-$(1) of=$(BIN_DIR)/$(IMG_PREFIX)-root.squashfs-$(1) bs=$(1) conv=sync
endef
define prepare_zimage
echo -en "\x$(2)\x1c\xa0\xe3\x$(3)\x10\x81\xe3" > $(KDIR)/$(call zimage_name,$(1))
cat $(LINUX_DIR)/arch/arm/boot/zImage >> $(KDIR)/$(call zimage_name,$(1))
endef
define prepare_uimage
$(call prepare_zimage,$(1),$(2),$(3))
mkimage -A arm -O linux -T kernel -a 0x100000 -e 0x100000 -C none \
-n 'OpenWrt Linux-$(LINUX_VERSION)' \
-d $(KDIR)/$(call zimage_name,$(1)) \
$(KDIR)/$(call uimage_name,$(1))
endef
define Image/Prepare
# NSB3AST : mach id 2917 (0xb65)
$(call prepare_zimage,nsb3ast,0b,65)
# NS-K330 : mach id 3108 (0xc24)
$(call prepare_zimage,ns-k330,0c,24)
endef
define Image/BuildKernel
cat $(KDIR)/$(call zimage_name,nsb3ast) > $(BIN_DIR)/$(call zimage_name,nsb3ast)
cat $(KDIR)/$(call zimage_name,ns-k330) > $(BIN_DIR)/$(call zimage_name,ns-k330)
endef
define Image/Build/Generic
if [ `stat -c%s "$(KDIR)/$(call zimage_name,$(2))"` -gt 1048576 ]; then \
echo "Warning: $(KDIR)/$(call zimage_name,$(2)) is too big"; \
else if [ `stat -c%s $(KDIR)/root.$(1)` -gt $(3) ]; then \
echo "Warning: of=$(BIN_DIR)/$(IMG_PREFIX)-root.$(1) is too big"; \
else \
cat $(KDIR)/root.$(1) > $(call rootfsname,$(1),$(2)); \
( \
dd if=$(KDIR)/$(call zimage_name,$(2)) bs=1024k conv=sync; \
dd if=$(BIN_DIR)/$(IMG_PREFIX)-root.$(1) \
) > $(call imgname,$(1),$(2)).img; \
fi; fi
endef
define Image/Build/uImage
if [ `stat -c%s "$(KDIR)/$(call uimage_name,$(2))"` -gt 1048576 ]; then \
echo "Warning: $(KDIR)/$(call uimage_name,$(2)) is too big"; \
else if [ `stat -c%s $(KDIR)/root.$(1)` -gt $(3) ]; then \
echo "Warning: of=$(BIN_DIR)/$(IMG_PREFIX)-root.$(1) is too big"; \
else \
cat $(KDIR)/root.$(1) > $(call rootfsname,$(1),$(2)); \
( \
dd if=$(KDIR)/$(call uimage_name,$(2)) bs=1024k conv=sync; \
dd if=$(BIN_DIR)/$(IMG_PREFIX)-root.$(1) \
) > $(call imgname,$(1),$(2))-uImage.img; \
fi; fi
endef
define Image/Build/NSB3AST
$(call Image/Build/Generic,$(1),nsb3ast,7077888)
endef
define Image/Build/NSK330
$(call Image/Build/Generic,$(1),ns-k330,2686976)
endef
define Image/Build/squashfs
$(call prepare_generic_squashfs,$(KDIR)/root.squashfs)
$(call build_squashfs,64k)
$(call Image/Build/NSB3AST,squashfs-64k)
$(call Image/Build/NSK330,squashfs-64k)
endef
define Image/Build/jffs2-64k
dd if=$(KDIR)/root.$(1) of=$(BIN_DIR)/$(IMG_PREFIX)-root.$(1) bs=64k conv=sync
endef
define Image/Build
$(call Image/Build/$(1),$(1))
endef
$(eval $(call BuildImage))

View file

@ -0,0 +1,438 @@
From 248d9a5b63bba72bfc316b8a48c6163fce5acc22 Mon Sep 17 00:00:00 2001
From: Paulius Zaleckas <paulius.zaleckas@gmail.com>
Date: Thu, 18 Feb 2010 21:53:01 +0200
Subject: [PATCH] ARM: Use cache alignment from asm/cache.h
Make code more optimal for ARM variants with
different cache line size.
Signed-off-by: Paulius Zaleckas <paulius.zaleckas@gmail.com>
---
arch/arm/boot/compressed/head.S | 11 ++++++-----
arch/arm/include/asm/dma-mapping.h | 2 +-
arch/arm/kernel/entry-armv.S | 31 ++++++++++++++++---------------
arch/arm/kernel/entry-common.S | 7 ++++---
arch/arm/kernel/head.S | 3 ++-
arch/arm/kernel/vmlinux.lds.S | 5 +++--
arch/arm/lib/copy_page.S | 2 +-
arch/arm/lib/memchr.S | 3 ++-
arch/arm/lib/memset.S | 3 ++-
arch/arm/lib/memzero.S | 3 ++-
arch/arm/lib/strchr.S | 3 ++-
arch/arm/lib/strncpy_from_user.S | 3 ++-
arch/arm/lib/strnlen_user.S | 3 ++-
arch/arm/lib/strrchr.S | 3 ++-
arch/arm/mm/abort-ev4.S | 3 ++-
arch/arm/mm/abort-nommu.S | 3 ++-
16 files changed, 51 insertions(+), 37 deletions(-)
--- a/arch/arm/boot/compressed/head.S
+++ b/arch/arm/boot/compressed/head.S
@@ -9,6 +9,7 @@
* published by the Free Software Foundation.
*/
#include <linux/linkage.h>
+#include <asm/cache.h>
/*
* Debugging stuff
@@ -349,7 +350,7 @@ params: ldr r0, =0x10000100 @ params_p
* This routine must preserve:
* r4, r5, r6, r7, r8
*/
- .align 5
+ .align L1_CACHE_SHIFT
cache_on: mov r3, #8 @ cache_on function
b call_cache_fn
@@ -537,7 +538,7 @@ __common_mmu_cache_on:
mcr p15, 0, r3, c2, c0, 0 @ load page table pointer
mcr p15, 0, r1, c3, c0, 0 @ load domain access control
b 1f
- .align 5 @ cache line aligned
+ .align L1_CACHE_SHIFT @ cache line aligned
1: mcr p15, 0, r0, c1, c0, 0 @ load control register
mrc p15, 0, r0, c1, c0, 0 @ and read it back to
sub pc, lr, r0, lsr #32 @ properly flush pipeline
@@ -556,7 +557,7 @@ __common_mmu_cache_on:
* r8 = atags pointer
* r9-r12,r14 = corrupted
*/
- .align 5
+ .align L1_CACHE_SHIFT
reloc_start: add r9, r5, r0
sub r9, r9, #128 @ do not copy the stack
debug_reloc_start
@@ -786,7 +787,7 @@ proc_types:
* This routine must preserve:
* r4, r6, r7
*/
- .align 5
+ .align L1_CACHE_SHIFT
cache_off: mov r3, #12 @ cache_off function
b call_cache_fn
@@ -861,7 +862,7 @@ __armv3_mmu_cache_off:
* This routine must preserve:
* r0, r4, r5, r6, r7
*/
- .align 5
+ .align L1_CACHE_SHIFT
cache_clean_flush:
mov r3, #16
b call_cache_fn
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -23,6 +23,7 @@
#include <asm/unwind.h>
#include <asm/unistd.h>
#include <asm/tls.h>
+#include <asm/cache.h>
#include "entry-header.S"
@@ -165,7 +166,7 @@ ENDPROC(__und_invalid)
stmia r5, {r0 - r4}
.endm
- .align 5
+ .align L1_CACHE_SHIFT
__dabt_svc:
svc_entry
@@ -213,7 +214,7 @@ __dabt_svc:
UNWIND(.fnend )
ENDPROC(__dabt_svc)
- .align 5
+ .align L1_CACHE_SHIFT
__irq_svc:
svc_entry
@@ -257,7 +258,7 @@ svc_preempt:
b 1b
#endif
- .align 5
+ .align L1_CACHE_SHIFT
__und_svc:
#ifdef CONFIG_KPROBES
@ If a kprobe is about to simulate a "stmdb sp..." instruction,
@@ -303,7 +304,7 @@ __und_svc:
UNWIND(.fnend )
ENDPROC(__und_svc)
- .align 5
+ .align L1_CACHE_SHIFT
__pabt_svc:
svc_entry
@@ -339,7 +340,7 @@ __pabt_svc:
UNWIND(.fnend )
ENDPROC(__pabt_svc)
- .align 5
+ .align L1_CACHE_SHIFT
.LCcralign:
.word cr_alignment
#ifdef MULTI_DABORT
@@ -412,7 +413,7 @@ ENDPROC(__pabt_svc)
#endif
.endm
- .align 5
+ .align L1_CACHE_SHIFT
__dabt_usr:
usr_entry
kuser_cmpxchg_check
@@ -444,7 +445,7 @@ __dabt_usr:
UNWIND(.fnend )
ENDPROC(__dabt_usr)
- .align 5
+ .align L1_CACHE_SHIFT
__irq_usr:
usr_entry
kuser_cmpxchg_check
@@ -473,7 +474,7 @@ ENDPROC(__irq_usr)
.ltorg
- .align 5
+ .align L1_CACHE_SHIFT
__und_usr:
usr_entry
@@ -689,7 +690,7 @@ __und_usr_unknown:
b do_undefinstr
ENDPROC(__und_usr_unknown)
- .align 5
+ .align L1_CACHE_SHIFT
__pabt_usr:
usr_entry
@@ -803,7 +804,7 @@ ENDPROC(__switch_to)
#endif
.endm
- .align 5
+ .align L1_CACHE_SHIFT
.globl __kuser_helper_start
__kuser_helper_start:
@@ -843,7 +844,7 @@ __kuser_memory_barrier: @ 0xffff0fa0
smp_dmb
usr_ret lr
- .align 5
+ .align L1_CACHE_SHIFT
/*
* Reference prototype:
@@ -973,7 +974,7 @@ kuser_cmpxchg_fixup:
#endif
- .align 5
+ .align L1_CACHE_SHIFT
/*
* Reference prototype:
@@ -1051,7 +1052,7 @@ __kuser_helper_end:
* of which is copied into r0 for the mode specific abort handler.
*/
.macro vector_stub, name, mode, correction=0
- .align 5
+ .align L1_CACHE_SHIFT
vector_\name:
.if \correction
@@ -1182,7 +1183,7 @@ __stubs_start:
.long __und_invalid @ e
.long __und_invalid @ f
- .align 5
+ .align L1_CACHE_SHIFT
/*=============================================================================
* Undefined FIQs
@@ -1212,7 +1213,7 @@ vector_addrexcptn:
* We group all the following data together to optimise
* for CPUs with separate I & D caches.
*/
- .align 5
+ .align L1_CACHE_SHIFT
.LCvswi:
.word vector_swi
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -10,13 +10,14 @@
#include <asm/unistd.h>
#include <asm/ftrace.h>
+#include <asm/cache.h>
#include <mach/entry-macro.S>
#include <asm/unwind.h>
#include "entry-header.S"
- .align 5
+ .align L1_CACHE_SHIFT
/*
* This is the fast syscall return path. We do as little as
* possible here, and this includes saving r0 back into the SVC
@@ -221,7 +222,7 @@ ftrace_stub:
#define A710(code...)
#endif
- .align 5
+ .align L1_CACHE_SHIFT
ENTRY(vector_swi)
sub sp, sp, #S_FRAME_SIZE
stmia sp, {r0 - r12} @ Calling r0 - r12
@@ -354,7 +355,7 @@ __sys_trace_return:
bl syscall_trace
b ret_slow_syscall
- .align 5
+ .align L1_CACHE_SHIFT
#ifdef CONFIG_ALIGNMENT_TRAP
.type __cr_alignment, #object
__cr_alignment:
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -21,6 +21,7 @@
#include <asm/memory.h>
#include <asm/thread_info.h>
#include <asm/system.h>
+#include <asm/cache.h>
#if (PHYS_OFFSET & 0x001fffff)
#error "PHYS_OFFSET must be at an even 2MiB boundary!"
@@ -192,7 +193,7 @@ ENDPROC(__enable_mmu)
*
* other registers depend on the function called upon completion
*/
- .align 5
+ .align L1_CACHE_SHIFT
__turn_mmu_on:
mov r0, r0
mcr p15, 0, r0, c1, c0, 0 @ write control reg
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -7,6 +7,7 @@
#include <asm/thread_info.h>
#include <asm/memory.h>
#include <asm/page.h>
+#include <asm/cache.h>
OUTPUT_ARCH(arm)
ENTRY(stext)
--- a/arch/arm/lib/copy_page.S
+++ b/arch/arm/lib/copy_page.S
@@ -17,7 +17,7 @@
#define COPY_COUNT (PAGE_SZ / (2 * L1_CACHE_BYTES) PLD( -1 ))
.text
- .align 5
+ .align L1_CACHE_SHIFT
/*
* StrongARM optimised copy_page routine
* now 1.78bytes/cycle, was 1.60 bytes/cycle (50MHz bus -> 89MB/s)
--- a/arch/arm/lib/memchr.S
+++ b/arch/arm/lib/memchr.S
@@ -11,9 +11,10 @@
*/
#include <linux/linkage.h>
#include <asm/assembler.h>
+#include <asm/cache.h>
.text
- .align 5
+ .align L1_CACHE_SHIFT
ENTRY(memchr)
1: subs r2, r2, #1
bmi 2f
--- a/arch/arm/lib/memset.S
+++ b/arch/arm/lib/memset.S
@@ -11,9 +11,10 @@
*/
#include <linux/linkage.h>
#include <asm/assembler.h>
+#include <asm/cache.h>
.text
- .align 5
+ .align L1_CACHE_SHIFT
.word 0
1: subs r2, r2, #4 @ 1 do we have enough
--- a/arch/arm/lib/memzero.S
+++ b/arch/arm/lib/memzero.S
@@ -9,9 +9,10 @@
*/
#include <linux/linkage.h>
#include <asm/assembler.h>
+#include <asm/cache.h>
.text
- .align 5
+ .align L1_CACHE_SHIFT
.word 0
/*
* Align the pointer in r0. r3 contains the number of bytes that we are
--- a/arch/arm/lib/strchr.S
+++ b/arch/arm/lib/strchr.S
@@ -11,9 +11,10 @@
*/
#include <linux/linkage.h>
#include <asm/assembler.h>
+#include <asm/cache.h>
.text
- .align 5
+ .align L1_CACHE_SHIFT
ENTRY(strchr)
and r1, r1, #0xff
1: ldrb r2, [r0], #1
--- a/arch/arm/lib/strncpy_from_user.S
+++ b/arch/arm/lib/strncpy_from_user.S
@@ -10,9 +10,10 @@
#include <linux/linkage.h>
#include <asm/assembler.h>
#include <asm/errno.h>
+#include <asm/cache.h>
.text
- .align 5
+ .align L1_CACHE_SHIFT
/*
* Copy a string from user space to kernel space.
--- a/arch/arm/lib/strnlen_user.S
+++ b/arch/arm/lib/strnlen_user.S
@@ -10,9 +10,10 @@
#include <linux/linkage.h>
#include <asm/assembler.h>
#include <asm/errno.h>
+#include <asm/cache.h>
.text
- .align 5
+ .align L1_CACHE_SHIFT
/* Prototype: unsigned long __strnlen_user(const char *str, long n)
* Purpose : get length of a string in user memory
--- a/arch/arm/lib/strrchr.S
+++ b/arch/arm/lib/strrchr.S
@@ -11,9 +11,10 @@
*/
#include <linux/linkage.h>
#include <asm/assembler.h>
+#include <asm/cache.h>
.text
- .align 5
+ .align L1_CACHE_SHIFT
ENTRY(strrchr)
mov r3, #0
1: ldrb r2, [r0], #1
--- a/arch/arm/mm/abort-ev4.S
+++ b/arch/arm/mm/abort-ev4.S
@@ -1,5 +1,6 @@
#include <linux/linkage.h>
#include <asm/assembler.h>
+#include <asm/cache.h>
/*
* Function: v4_early_abort
*
@@ -17,7 +18,7 @@
* abort here if the I-TLB and D-TLB aren't seeing the same
* picture. Unfortunately, this does happen. We live with it.
*/
- .align 5
+ .align L1_CACHE_SHIFT
ENTRY(v4_early_abort)
mrc p15, 0, r1, c5, c0, 0 @ get FSR
mrc p15, 0, r0, c6, c0, 0 @ get FAR
--- a/arch/arm/mm/abort-nommu.S
+++ b/arch/arm/mm/abort-nommu.S
@@ -1,5 +1,6 @@
#include <linux/linkage.h>
#include <asm/assembler.h>
+#include <asm/cache.h>
/*
* Function: nommu_early_abort
*
@@ -12,7 +13,7 @@
* Note: There is no FSR/FAR on !CPU_CP15_MMU cores.
* Just fill zero into the registers.
*/
- .align 5
+ .align L1_CACHE_SHIFT
ENTRY(nommu_early_abort)
mov r0, #0 @ clear r0, r1 (no FSR/FAR)
mov r1, #0

View file

@ -0,0 +1,24 @@
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -48,6 +48,10 @@
#define for_each_console(con) \
for (con = console_drivers; con != NULL; con = con->next)
+#ifdef CONFIG_DEBUG_LL
+extern void printascii(char *);
+#endif /* CONFIG_DEBUG_LL */
+
/*
* Architectures can override it:
*/
@@ -760,6 +764,10 @@ asmlinkage int vprintk(const char *fmt,
}
}
+#ifdef CONFIG_DEBUG_LL
+ printascii(printk_buf);
+#endif
+
/*
* Copy the output into log_buf. If the caller didn't provide
* appropriate log level tags, we insert them here

View file

@ -0,0 +1,47 @@
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -954,10 +954,15 @@ source "arch/arm/mach-vexpress/Kconfig"
source "arch/arm/mach-w90x900/Kconfig"
+source "arch/arm/plat-fa/Kconfig"
+
# Definitions to make life easier
config ARCH_ACORN
bool
+config PLAT_FA
+ bool
+
config PLAT_IOP
bool
select GENERIC_CLOCKEVENTS
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -202,6 +202,7 @@ plat-$(CONFIG_ARCH_MXC) := mxc
plat-$(CONFIG_ARCH_OMAP) := omap
plat-$(CONFIG_ARCH_S3C64XX) := samsung
plat-$(CONFIG_ARCH_STMP3XXX) := stmp3xxx
+plat-$(CONFIG_PLAT_FA) := fa
plat-$(CONFIG_PLAT_IOP) := iop
plat-$(CONFIG_PLAT_NOMADIK) := nomadik
plat-$(CONFIG_PLAT_ORION) := orion
--- /dev/null
+++ b/arch/arm/plat-fa/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for the linux kernel.
+#
+
+obj-y :=
+
+obj-m :=
+obj-n :=
+obj- :=
+
--- /dev/null
+++ b/arch/arm/plat-fa/Kconfig
@@ -0,0 +1,3 @@
+if PLAT_FA
+
+endif

View file

@ -0,0 +1,143 @@
--- /dev/null
+++ b/arch/arm/plat-fa/include/plat/time.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _FA_TIME_H
+#define _FA_TIME_H
+
+#define FA_TIMER1 0
+#define FA_TIMER2 1
+#define FA_TIMER3 2
+
+int __init fa_timer_init(unsigned int mapbase, unsigned int irq,
+ unsigned int timer, unsigned int freq);
+
+#endif /* _FA_TIME_H */
--- /dev/null
+++ b/arch/arm/plat-fa/time.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2001-2006 Storlink, Corp.
+ * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+#include <asm/mach/time.h>
+#include <plat/time.h>
+
+/*
+ * Register definitions for the timers
+ */
+#define TIMER_COUNT(_base, _tmr) ((_base) + 0x00 + (_tmr) * 0x10)
+#define TIMER_LOAD(_base, _tmr) ((_base) + 0x04 + (_tmr) * 0x10)
+#define TIMER_MATCH1(_base, _tmr) ((_base) + 0x08 + (_tmr) * 0x10)
+#define TIMER_MATCH2(_base, _tmr) ((_base) + 0x0c + (_tmr) * 0x10)
+
+#define TIMER_CR(_base) ((_base) + 0x30)
+#define TIMER_STATUS(_base) ((_base) + 0x34)
+#define TIMER_MASK(_base) ((_base) + 0x38)
+
+#define TIMER_SIZE 0x3c
+
+#define TIMER_CR_ENABLE(x) (1 << ((x) * 3))
+#define TIMER_CR_CLOCK(x) (1 << ((x) * 3 + 1))
+#define TIMER_CR_INT(x) (1 << ((x) * 3 + 2))
+#define TIMER_CR_DOWN(x) (1 << ((x) * 3 + 9))
+
+#define TIMER_MASK_MATCH1(x) (1 << ((x) * 3))
+#define TIMER_MASK_MATCH2(x) (1 << ((x) * 3 + 1))
+#define TIMER_MASK_OF(x) (1 << ((x) * 3 + 2))
+
+#define TIMER_MASK_ALL 0x7ff
+
+/*
+ * IRQ handler for the timer
+ */
+static irqreturn_t fa_timer_interrupt(int irq, void *dev_id)
+{
+ timer_tick();
+ return IRQ_HANDLED;
+}
+
+static struct irqaction fa_timer_irq = {
+ .name = "Timer Tick",
+ .flags = IRQF_DISABLED | IRQF_TIMER,
+ .handler = fa_timer_interrupt,
+};
+
+int __init fa_timer_init(unsigned int mapbase, unsigned int irq,
+ unsigned int timer, unsigned int freq)
+{
+ void __iomem *base;
+
+ base = ioremap(mapbase, TIMER_SIZE);
+ if (!base)
+ return -ENOMEM;
+
+ /* disable timers, clear status and mask all interrupts */
+ __raw_writel(0, TIMER_CR(base));
+ __raw_writel(0, TIMER_STATUS(base));
+ __raw_writel(TIMER_MASK_ALL, TIMER_MASK(base));
+
+ /*
+ * Make irqs happen for the system timer
+ */
+ setup_irq(irq, &fa_timer_irq);
+
+ /* Setup the timer */
+ __raw_writel(freq / HZ, TIMER_COUNT(base, timer));
+ __raw_writel(freq / HZ, TIMER_LOAD(base, timer));
+ __raw_writel(0, TIMER_MATCH1(base, timer));
+ __raw_writel(0, TIMER_MATCH2(base, timer));
+
+ /* Enable interrupt and start the timer */
+ __raw_writel(TIMER_MASK_ALL & ~TIMER_MASK_OF(timer),
+ TIMER_MASK(base));
+
+ __raw_writel(TIMER_CR_ENABLE(timer) |
+ TIMER_CR_INT(timer) |
+ TIMER_CR_DOWN(timer),
+ TIMER_CR(base));
+
+ iounmap(base);
+
+ return 0;
+}
--- a/arch/arm/plat-fa/Kconfig
+++ b/arch/arm/plat-fa/Kconfig
@@ -1,3 +1,6 @@
if PLAT_FA
+config PLAT_FA_TIME
+ def_bool n
+
endif
--- a/arch/arm/plat-fa/Makefile
+++ b/arch/arm/plat-fa/Makefile
@@ -4,6 +4,8 @@
obj-y :=
+obj-$(CONFIG_PLAT_FA_TIME) += time.o
+
obj-m :=
obj-n :=
obj- :=

View file

@ -0,0 +1,335 @@
--- /dev/null
+++ b/arch/arm/plat-fa/gpio.c
@@ -0,0 +1,275 @@
+/*
+ * Gpiochip and interrupt routines for Faraday FA526 based SoCs
+ *
+ * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Based on plat-mxc/gpio.c:
+ * MXC GPIO supchip. (c) 2008 Daniel Mack <daniel@caiaq.de>
+ * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/spinlock.h>
+
+#include <plat/gpio.h>
+
+#define GPIO_DATA_OUT 0x0
+#define GPIO_DATA_IN 0x4
+#define GPIO_DIR 0x8
+#define GPIO_DATA_SET 0x10
+#define GPIO_DATA_CLR 0x14
+#define GPIO_PULL_EN 0x18
+#define GPIO_PULL_TYPE 0x1C
+#define GPIO_INT_EN 0x20
+#define GPIO_INT_STAT 0x24
+#define GPIO_INT_MASK 0x2C
+#define GPIO_INT_CLR 0x30
+#define GPIO_INT_TYPE 0x34
+#define GPIO_INT_BOTH_EDGE 0x38
+#define GPIO_INT_LEVEL 0x3C
+#define GPIO_DEBOUNCE_EN 0x40
+#define GPIO_DEBOUNCE_PRESCALE 0x44
+
+#define GPIO_REGS_SIZE 0x48
+
+static DEFINE_SPINLOCK(fa_gpio_lock);
+
+static inline struct fa_gpio_chip *to_fgc(struct gpio_chip *chip)
+{
+ return container_of(chip, struct fa_gpio_chip, gpio_chip);
+}
+
+static void _fa_gpio_irq_setenable(unsigned int irq, int enable)
+{
+ struct fa_gpio_chip *fgc = get_irq_chip_data(irq);
+ void __iomem *base = fgc->mem_base;
+ unsigned int gpio = irq - fgc->irq_base;
+ unsigned int reg;
+
+ reg = __raw_readl(base + GPIO_INT_EN);
+ reg = (reg & (~(1 << gpio))) | (!!enable << gpio);
+ __raw_writel(reg, base + GPIO_INT_EN);
+}
+
+static void fa_gpio_irq_ack(unsigned int irq)
+{
+ struct fa_gpio_chip *fgc = get_irq_chip_data(irq);
+ unsigned int gpio = irq - fgc->irq_base;
+
+ __raw_writel(1 << gpio, fgc->mem_base + GPIO_INT_CLR);
+}
+
+static void fa_gpio_irq_mask(unsigned int irq)
+{
+ _fa_gpio_irq_setenable(irq, 0);
+}
+
+static void fa_gpio_irq_unmask(unsigned int irq)
+{
+ _fa_gpio_irq_setenable(irq, 1);
+}
+
+static int fa_gpio_irq_set_type(unsigned int irq, unsigned int type)
+{
+ struct fa_gpio_chip *fgc = get_irq_chip_data(irq);
+ void __iomem *base = fgc->mem_base;
+ unsigned int gpio = irq - fgc->irq_base;
+ unsigned int gpio_mask = 1 << gpio;
+ unsigned int reg_both, reg_level, reg_type;
+
+ reg_type = __raw_readl(base + GPIO_INT_TYPE);
+ reg_level = __raw_readl(base + GPIO_INT_LEVEL);
+ reg_both = __raw_readl(base + GPIO_INT_BOTH_EDGE);
+
+ switch (type) {
+ case IRQ_TYPE_EDGE_BOTH:
+ reg_type &= ~gpio_mask;
+ reg_both |= gpio_mask;
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ reg_type &= ~gpio_mask;
+ reg_both &= ~gpio_mask;
+ reg_level &= ~gpio_mask;
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ reg_type &= ~gpio_mask;
+ reg_both &= ~gpio_mask;
+ reg_level |= gpio_mask;
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ reg_type |= gpio_mask;
+ reg_level &= ~gpio_mask;
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ reg_type |= gpio_mask;
+ reg_level |= gpio_mask;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ __raw_writel(reg_type, base + GPIO_INT_TYPE);
+ __raw_writel(reg_level, base + GPIO_INT_LEVEL);
+ __raw_writel(reg_both, base + GPIO_INT_BOTH_EDGE);
+
+ fa_gpio_irq_ack(irq);
+
+ return 0;
+}
+
+static void fa_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+ struct fa_gpio_data *data = get_irq_data(irq);
+ unsigned int chip;
+
+ for (chip = 0; chip < data->nchips; chip++) {
+ struct fa_gpio_chip *fgc = &data->chips[chip];
+ unsigned int status;
+ unsigned int i;
+
+ status = __raw_readl(fgc->mem_base + GPIO_INT_STAT);
+ for (i = fgc->irq_base; status != 0; status >>= 1, i++) {
+ if ((status & 1) == 0)
+ continue;
+
+ BUG_ON(!(irq_desc[i].handle_irq));
+ irq_desc[i].handle_irq(i, &irq_desc[i]);
+ }
+ }
+}
+
+static struct irq_chip fa_gpio_irq_chip = {
+ .name = "GPIO",
+ .ack = fa_gpio_irq_ack,
+ .mask = fa_gpio_irq_mask,
+ .unmask = fa_gpio_irq_unmask,
+ .set_type = fa_gpio_irq_set_type,
+};
+
+static void _fa_gpio_set_direction(struct fa_gpio_chip *fgc, unsigned offset,
+ int is_output)
+{
+ unsigned int reg;
+
+ reg = __raw_readl(fgc->mem_base + GPIO_DIR);
+ if (is_output)
+ reg |= 1 << offset;
+ else
+ reg &= ~(1 << offset);
+ __raw_writel(reg, fgc->mem_base + GPIO_DIR);
+}
+
+static void _fa_gpio_set(struct fa_gpio_chip *fgc, unsigned offset, int value)
+{
+ if (value)
+ __raw_writel(1 << offset, fgc->mem_base + GPIO_DATA_SET);
+ else
+ __raw_writel(1 << offset, fgc->mem_base + GPIO_DATA_CLR);
+}
+
+static void fa_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct fa_gpio_chip *fgc = to_fgc(chip);
+
+ _fa_gpio_set(fgc, offset, value);
+}
+
+static int fa_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct fa_gpio_chip *fgc = to_fgc(chip);
+
+ return (__raw_readl(fgc->mem_base + GPIO_DATA_IN) >> offset) & 1;
+}
+
+static int fa_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ struct fa_gpio_chip *fgc = to_fgc(chip);
+ unsigned long flags;
+
+ spin_lock_irqsave(&fa_gpio_lock, flags);
+
+ _fa_gpio_set_direction(fgc, offset, 0);
+
+ spin_unlock_irqrestore(&fa_gpio_lock, flags);
+
+ return 0;
+}
+
+static int fa_gpio_direction_output(struct gpio_chip *chip,
+ unsigned offset,
+ int value)
+{
+ struct fa_gpio_chip *fgc = to_fgc(chip);
+ unsigned long flags;
+
+ spin_lock_irqsave(&fa_gpio_lock, flags);
+
+ _fa_gpio_set(fgc, offset, value);
+ _fa_gpio_set_direction(fgc, offset, 1);
+
+ spin_unlock_irqrestore(&fa_gpio_lock, flags);
+
+ return 0;
+}
+
+static int fa_gpio_init_chip(struct fa_gpio_chip *fgc)
+{
+ void __iomem *mem_base;
+ unsigned int i;
+ int err;
+
+ mem_base = ioremap(fgc->map_base, GPIO_REGS_SIZE);
+ if (!mem_base)
+ return -ENXIO;
+
+ fgc->mem_base = mem_base;
+
+ fgc->gpio_chip.direction_input = fa_gpio_direction_input;
+ fgc->gpio_chip.direction_output = fa_gpio_direction_output;
+ fgc->gpio_chip.get = fa_gpio_get;
+ fgc->gpio_chip.set = fa_gpio_set;
+
+ /* disable, unmask and clear all interrupts */
+ __raw_writel(0x0, mem_base + GPIO_INT_EN);
+ __raw_writel(0x0, mem_base + GPIO_INT_MASK);
+ __raw_writel(~0x0, mem_base + GPIO_INT_CLR);
+
+ for (i = fgc->irq_base;
+ i < fgc->irq_base + fgc->gpio_chip.ngpio; i++) {
+ set_irq_chip(i, &fa_gpio_irq_chip);
+ set_irq_chip_data(i, fgc);
+ set_irq_handler(i, handle_edge_irq);
+ set_irq_flags(i, IRQF_VALID);
+ }
+
+ err = gpiochip_add(&fgc->gpio_chip);
+ if (err)
+ goto unmap;
+
+ return 0;
+
+ unmap:
+ iounmap(fgc->mem_base);
+ return err;
+}
+
+void __init fa_gpio_init(struct fa_gpio_data *data)
+{
+ unsigned int i;
+
+ for (i = 0; i < data->nchips; i++) {
+ int err;
+
+ err = fa_gpio_init_chip(&data->chips[i]);
+ if (WARN(err, "GPIO init failed\n"))
+ return;
+ }
+
+ set_irq_chained_handler(data->irq, fa_gpio_irq_handler);
+ set_irq_data(data->irq, data);
+}
--- /dev/null
+++ b/arch/arm/plat-fa/include/plat/gpio.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file 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 _FA_GPIO_H
+#define _FA_GPIO_H
+
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+struct fa_gpio_chip {
+ struct gpio_chip gpio_chip;
+ unsigned int map_base;
+ unsigned int irq_base;
+
+ void __iomem *mem_base;
+};
+
+struct fa_gpio_data {
+ struct fa_gpio_chip *chips;
+ unsigned int nchips;
+ unsigned int irq;
+};
+
+void __init fa_gpio_init(struct fa_gpio_data *data);
+
+#endif /* _FA_GPIO_H */
--- a/arch/arm/plat-fa/Kconfig
+++ b/arch/arm/plat-fa/Kconfig
@@ -1,5 +1,8 @@
if PLAT_FA
+config PLAT_FA_GPIO
+ def_bool n
+
config PLAT_FA_TIME
def_bool n
--- a/arch/arm/plat-fa/Makefile
+++ b/arch/arm/plat-fa/Makefile
@@ -4,6 +4,7 @@
obj-y :=
+obj-$(CONFIG_PLAT_FA_GPIO) += gpio.o
obj-$(CONFIG_PLAT_FA_TIME) += time.o
obj-m :=

View file

@ -0,0 +1,456 @@
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -331,6 +331,13 @@ config IMX2_WDT
To compile this driver as a module, choose M here: the
module will be called imx2_wdt.
+config FA_WATCHDOG
+ tristate "Faraday watchdog"
+ depends on ARCH_GEMINI
+ help
+ Say Y here if you want support for the built-in watchdog timer
+ found in some Faraday FA526 based SoCs.
+
# AVR32 Architecture
config AT32AP700X_WDT
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -49,6 +49,7 @@ obj-$(CONFIG_NUC900_WATCHDOG) += nuc900_
obj-$(CONFIG_ADX_WATCHDOG) += adx_wdt.o
obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o
obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o
+obj-$(CONFIG_FA_WATCHDOG) += fa_wdt.o
# AVR32 Architecture
obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
--- /dev/null
+++ b/drivers/watchdog/fa_wdt.c
@@ -0,0 +1,411 @@
+/*
+ * Watchdog driver for SoCs based on the Faraday FA526 core
+ *
+ * Copyright (C) 2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/fs.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/platform_device.h>
+#include <linux/watchdog.h>
+#include <linux/slab.h>
+#include <linux/fa_wdt.h>
+
+#define FA_WDCOUNTER 0x0
+#define FA_WDLOAD 0x4
+#define FA_WDRESTART 0x8
+
+#define WDRESTART_MAGIC 0x5AB9
+
+#define FA_WDCR 0xC
+
+#define WDCR_CLOCK_5MHZ (1 << 4)
+#define WDCR_SYS_RST (1 << 1)
+#define WDCR_ENABLE (1 << 0)
+
+#define WDT_DEFAULT_TIMEOUT 13
+
+/* status bits */
+#define WDT_ACTIVE 0
+#define WDT_OK_TO_CLOSE 1
+
+static unsigned int timeout = WDT_DEFAULT_TIMEOUT;
+static int nowayout = WATCHDOG_NOWAYOUT;
+
+static DEFINE_SPINLOCK(fa_wdt_lock);
+
+static struct platform_device *fa_wdt_dev;
+
+struct fa_wdt_struct {
+ struct resource *res;
+ struct device *dev;
+ void __iomem *base;
+ unsigned long status;
+ unsigned int clock;
+ unsigned int max_timeout;
+};
+
+static const struct watchdog_info fa_wdt_info = {
+ .identity = "Faraday watchdog",
+ .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING |
+ WDIOF_SETTIMEOUT,
+};
+
+/* Disable the watchdog. */
+static void fa_wdt_stop(struct fa_wdt_struct *fa_wdt)
+{
+ spin_lock(&fa_wdt_lock);
+
+ __raw_writel(0, fa_wdt->base + FA_WDCR);
+
+ clear_bit(WDT_ACTIVE, &fa_wdt->status);
+
+ spin_unlock(&fa_wdt_lock);
+}
+
+/* Service the watchdog */
+static void fa_wdt_service(struct fa_wdt_struct *fa_wdt)
+{
+ __raw_writel(WDRESTART_MAGIC, fa_wdt->base + FA_WDRESTART);
+}
+
+/* Enable and reset the watchdog. */
+static void fa_wdt_start(struct fa_wdt_struct *fa_wdt)
+{
+ spin_lock(&fa_wdt_lock);
+
+ __raw_writel(timeout * fa_wdt->clock,
+ fa_wdt->base + FA_WDLOAD);
+
+ fa_wdt_service(fa_wdt);
+
+ /* set clock before enabling */
+ __raw_writel(WDCR_CLOCK_5MHZ | WDCR_SYS_RST,
+ fa_wdt->base + FA_WDCR);
+
+ __raw_writel(WDCR_CLOCK_5MHZ | WDCR_SYS_RST | WDCR_ENABLE,
+ fa_wdt->base + FA_WDCR);
+
+ set_bit(WDT_ACTIVE, &fa_wdt->status);
+
+ spin_unlock(&fa_wdt_lock);
+}
+
+/* Watchdog device is opened, and watchdog starts running. */
+static int fa_wdt_open(struct inode *inode, struct file *file)
+{
+ struct fa_wdt_struct *fa_wdt = platform_get_drvdata(fa_wdt_dev);
+
+ if (test_bit(WDT_ACTIVE, &fa_wdt->status))
+ return -EBUSY;
+
+ file->private_data = fa_wdt;
+
+ fa_wdt_start(fa_wdt);
+
+ return nonseekable_open(inode, file);
+}
+
+/* Close the watchdog device. */
+static int fa_wdt_close(struct inode *inode, struct file *file)
+{
+ struct fa_wdt_struct *fa_wdt = file->private_data;
+
+ /* Disable the watchdog if possible */
+ if (test_bit(WDT_OK_TO_CLOSE, &fa_wdt->status))
+ fa_wdt_stop(fa_wdt);
+ else
+ dev_warn(fa_wdt->dev, "Device closed unexpectedly - timer will not stop\n");
+
+ return 0;
+}
+
+/* Handle commands from user-space. */
+static long fa_wdt_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct fa_wdt_struct *fa_wdt = file->private_data;
+
+ int value;
+
+ switch (cmd) {
+ case WDIOC_KEEPALIVE:
+ fa_wdt_service(fa_wdt);
+ return 0;
+
+ case WDIOC_GETSUPPORT:
+ return copy_to_user((struct watchdog_info *)arg, &fa_wdt_info,
+ sizeof(fa_wdt_info)) ? -EFAULT : 0;
+
+ case WDIOC_SETTIMEOUT:
+ if (get_user(value, (int *)arg))
+ return -EFAULT;
+
+ if ((value < 1) || (value > fa_wdt->max_timeout))
+ return -EINVAL;
+
+ timeout = value;
+
+ /* restart wdt to use new timeout */
+ fa_wdt_stop(fa_wdt);
+ fa_wdt_start(fa_wdt);
+
+ /* Fall through */
+ case WDIOC_GETTIMEOUT:
+ return put_user(timeout, (int *)arg);
+
+ case WDIOC_GETTIMELEFT:
+ value = __raw_readl(fa_wdt->base + FA_WDCOUNTER);
+ return put_user(value / fa_wdt->clock, (int *)arg);
+
+ default:
+ return -ENOTTY;
+ }
+}
+
+/* Refresh the watchdog whenever device is written to. */
+static ssize_t fa_wdt_write(struct file *file, const char *data,
+ size_t len, loff_t *ppos)
+{
+ struct fa_wdt_struct *fa_wdt = file->private_data;
+
+ if (len) {
+ if (!nowayout) {
+ size_t i;
+
+ clear_bit(WDT_OK_TO_CLOSE, &fa_wdt->status);
+ for (i = 0; i != len; i++) {
+ char c;
+
+ if (get_user(c, data + i))
+ return -EFAULT;
+ if (c == 'V')
+ set_bit(WDT_OK_TO_CLOSE,
+ &fa_wdt->status);
+ }
+ }
+ fa_wdt_service(fa_wdt);
+ }
+
+ return len;
+}
+
+static int fa_wdt_notify_sys(struct notifier_block *this,
+ unsigned long code, void *unused)
+{
+ struct fa_wdt_struct *fa_wdt = platform_get_drvdata(fa_wdt_dev);
+
+ if (code == SYS_DOWN || code == SYS_HALT)
+ fa_wdt_stop(fa_wdt);
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block fa_wdt_notifier = {
+ .notifier_call = fa_wdt_notify_sys,
+};
+
+static const struct file_operations fa_wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .unlocked_ioctl = fa_wdt_ioctl,
+ .open = fa_wdt_open,
+ .release = fa_wdt_close,
+ .write = fa_wdt_write,
+};
+
+static struct miscdevice fa_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &fa_wdt_fops,
+};
+
+static void fa_wdt_shutdown(struct platform_device *pdev)
+{
+ struct fa_wdt_struct *fa_wdt = platform_get_drvdata(pdev);
+
+ fa_wdt_stop(fa_wdt);
+}
+
+static int __devinit fa_wdt_probe(struct platform_device *pdev)
+{
+ int ret;
+ int res_size;
+ struct resource *res;
+ void __iomem *base;
+ struct fa_wdt_struct *fa_wdt;
+ struct fa_wdt_platform_data *pdata;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&pdev->dev, "no platform data specified\n");
+ return -EINVAL;
+ }
+
+ if (!pdata->clock) {
+ dev_err(&pdev->dev, "invalid clock value\n");
+ return -EINVAL;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "can't get device resources\n");
+ return -ENODEV;
+ }
+
+ res_size = resource_size(res);
+ if (!request_mem_region(res->start, res_size, res->name)) {
+ dev_err(&pdev->dev, "can't allocate %d bytes at %d address\n",
+ res_size, res->start);
+ return -ENOMEM;
+ }
+
+ base = ioremap(res->start, res_size);
+ if (!base) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ ret = -EIO;
+ goto fail0;
+ }
+
+ fa_wdt = kzalloc(sizeof(struct fa_wdt_struct), GFP_KERNEL);
+ if (!fa_wdt) {
+ dev_err(&pdev->dev, "can't allocate interface\n");
+ ret = -ENOMEM;
+ goto fail1;
+ }
+
+ /* Setup fa_wdt driver structure */
+ fa_wdt->base = base;
+ fa_wdt->res = res;
+ fa_wdt->dev = &pdev->dev;
+ fa_wdt->clock = pdata->clock;
+ fa_wdt->max_timeout = 0xffffffffU / pdata->clock;
+
+ /* Set up platform driver data */
+ platform_set_drvdata(pdev, fa_wdt);
+ fa_wdt_dev = pdev;
+
+ if (fa_wdt_miscdev.parent) {
+ ret = -EBUSY;
+ goto fail2;
+ }
+
+ ret = register_reboot_notifier(&fa_wdt_notifier);
+ if (ret)
+ goto fail2;
+
+ fa_wdt_miscdev.parent = &pdev->dev;
+
+ ret = misc_register(&fa_wdt_miscdev);
+ if (ret)
+ goto fail3;
+
+ return 0;
+
+fail3:
+ unregister_reboot_notifier(&fa_wdt_notifier);
+fail2:
+ platform_set_drvdata(pdev, NULL);
+ kfree(fa_wdt);
+fail1:
+ iounmap(base);
+fail0:
+ release_mem_region(res->start, res_size);
+
+ return ret;
+}
+
+static int __devexit fa_wdt_remove(struct platform_device *pdev)
+{
+ struct fa_wdt_struct *fa_wdt = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+ misc_deregister(&fa_wdt_miscdev);
+ unregister_reboot_notifier(&fa_wdt_notifier);
+ fa_wdt_dev = NULL;
+ iounmap(fa_wdt->base);
+ release_mem_region(fa_wdt->res->start, resource_size(fa_wdt->res));
+
+ kfree(fa_wdt);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int fa_wdt_suspend(struct platform_device *pdev, pm_message_t message)
+{
+ struct fa_wdt_struct *fa_wdt = platform_get_drvdata(pdev);
+ unsigned int reg;
+
+ reg = __raw_readw(fa_wdt->base + FA_WDCR);
+ reg &= ~(WDCR_WDENABLE);
+ __raw_writel(reg, fa_wdt->base + FA_WDCR);
+
+ return 0;
+}
+
+static int fa_wdt_resume(struct platform_device *pdev)
+{
+ struct fa_wdt_struct *fa_wdt = platform_get_drvdata(pdev);
+ unsigned int reg;
+
+ if (fa_wdt->status) {
+ reg = __raw_readw(fa_wdt->base + FA_WDCR);
+ reg |= WDCR_WDENABLE;
+ __raw_writel(reg, fa_wdt->base + FA_WDCR);
+ }
+
+ return 0;
+}
+#else
+#define fa_wdt_suspend NULL
+#define fa_wdt_resume NULL
+#endif
+
+static struct platform_driver fa_wdt_driver = {
+ .probe = fa_wdt_probe,
+ .remove = __devexit_p(fa_wdt_remove),
+ .shutdown = fa_wdt_shutdown,
+ .suspend = fa_wdt_suspend,
+ .resume = fa_wdt_resume,
+ .driver = {
+ .name = "fa-wdt",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init fa_wdt_init(void)
+{
+ return platform_driver_probe(&fa_wdt_driver, fa_wdt_probe);
+}
+
+static void __exit fa_wdt_exit(void)
+{
+ platform_driver_unregister(&fa_wdt_driver);
+}
+
+module_init(fa_wdt_init);
+module_exit(fa_wdt_exit);
+
+module_param(timeout, uint, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds");
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
+
+MODULE_AUTHOR("Paulius Zaleckas");
+MODULE_DESCRIPTION("Watchdog driver for Faraday FA526 based SoCs");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+MODULE_ALIAS("platform:fa-wdt");
--- /dev/null
+++ b/include/linux/fa_wdt.h
@@ -0,0 +1,13 @@
+/*
+ * Platform data definition for the Faraday watchdog driver
+ */
+
+#ifndef _FA_WDT_H
+#define _FA_WDT_H
+
+struct fa_wdt_platform_data {
+ unsigned int clock;
+};
+
+#endif /* _FA_WDT_H */
+

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,103 @@
--- a/arch/arm/mach-cns21xx/common.h
+++ b/arch/arm/mach-cns21xx/common.h
@@ -15,4 +15,7 @@ void __init cns21xx_init_irq(void);
extern struct sys_timer cns21xx_timer;
+int __init cns21xx_register_uart0(void);
+int __init cns21xx_register_uart1(void);
+
#endif /* _MACH_CNS21XX_COMMON_H */
--- /dev/null
+++ b/arch/arm/mach-cns21xx/devices.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2008 Cavium Networks
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/serial_8250.h>
+
+#include <mach/irqs.h>
+#include <mach/hardware.h>
+#include <mach/cns21xx.h>
+#include <mach/cns21xx_misc.h>
+
+#define CNS21XX_UART_CLOCK 24000000
+
+#define CNS21XX_UART_FLAGS (UPF_SKIP_TEST | UPF_FIXED_TYPE | UPF_NO_TXEN_TEST)
+
+static struct plat_serial8250_port cns21xx_uart0_data[] = {
+ {
+ .mapbase = CNS21XX_UART0_BASE,
+ .membase = (void *) CNS21XX_UART0_BASE_VIRT,
+ .irq = CNS21XX_IRQ_UART0,
+ .uartclk = CNS21XX_UART_CLOCK,
+ .regshift = 2,
+ .iotype = UPIO_MEM,
+ .type = PORT_16550A,
+ .flags = CNS21XX_UART_FLAGS,
+ }, {
+ /* terminating entry */
+ },
+};
+
+static struct platform_device cns21xx_uart0_device = {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM,
+ .dev = {
+ .platform_data = cns21xx_uart0_data,
+ },
+};
+
+int __init cns21xx_register_uart0(void)
+{
+ return platform_device_register(&cns21xx_uart0_device);
+}
+
+static struct plat_serial8250_port cns21xx_uart1_data[] = {
+ {
+ .mapbase = CNS21XX_UART1_BASE,
+ .membase = (void *) CNS21XX_UART1_BASE_VIRT,
+ .irq = CNS21XX_IRQ_UART1,
+ .uartclk = CNS21XX_UART_CLOCK,
+ .regshift = 2,
+ .iotype = UPIO_MEM,
+ .type = PORT_16550A,
+ .flags = CNS21XX_UART_FLAGS,
+ }, {
+ /* terminating entry */
+ },
+};
+
+static struct platform_device cns21xx_uart1_device = {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM1,
+ .dev = {
+ .platform_data = cns21xx_uart1_data,
+ },
+};
+
+int __init cns21xx_register_uart1(void)
+{
+ HAL_MISC_ENABLE_UART1_PINS();
+ return platform_device_register(&cns21xx_uart1_device);
+}
--- a/arch/arm/mach-cns21xx/Makefile
+++ b/arch/arm/mach-cns21xx/Makefile
@@ -4,7 +4,7 @@
# Object file lists.
-obj-y := core.o irq.o mm.o time.o
+obj-y := core.o devices.o irq.o mm.o time.o
# machine specific files

View file

@ -0,0 +1,113 @@
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -296,6 +296,8 @@ config ARCH_CNS21XX
select CPU_FA526
select PLAT_FA
select PLAT_FA_TIME
+ select PLAT_FA_GPIO
+ select ARCH_REQUIRE_GPIOLIB
select ARM_L1_CACHE_SHIFT_4
help
Support for Cavium Networks CNS21xx family.
--- a/arch/arm/mach-cns21xx/common.h
+++ b/arch/arm/mach-cns21xx/common.h
@@ -12,6 +12,7 @@
void __init cns21xx_map_io(void);
void __init cns21xx_init_irq(void);
+void __init cns21xx_gpio_init(void);
extern struct sys_timer cns21xx_timer;
--- /dev/null
+++ b/arch/arm/mach-cns21xx/gpio.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <plat/gpio.h>
+
+#include <mach/cns21xx.h>
+#include <mach/irqs.h>
+
+static struct fa_gpio_chip cns21xx_gpio_chips[] = {
+ {
+ .gpio_chip = {
+ .label = "GPIOA",
+ .base = 0,
+ .ngpio = 32,
+ },
+
+ .map_base = CNS21XX_GPIOA_BASE,
+ .irq_base = CNS21XX_GPIO_IRQ_BASE,
+ }, {
+ .gpio_chip = {
+ .label = "GPIOB",
+ .base = 32,
+ .ngpio = 32,
+ },
+
+ .map_base = CNS21XX_GPIOB_BASE,
+ .irq_base = CNS21XX_GPIO_IRQ_BASE + 32,
+ }
+};
+
+static struct fa_gpio_data cns21xx_gpio_data = {
+ .chips = cns21xx_gpio_chips,
+ .nchips = ARRAY_SIZE(cns21xx_gpio_chips),
+ .irq = CNS21XX_IRQ_GPIO,
+};
+
+void __init cns21xx_gpio_init(void)
+{
+ fa_gpio_init(&cns21xx_gpio_data);
+}
--- /dev/null
+++ b/arch/arm/mach-cns21xx/include/mach/gpio.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2008 Cavium Networks
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file 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 _CNS21XX_GPIO_H
+#define _CNS21XX_GPIO_H
+
+#include <asm-generic/gpio.h>
+#include <mach/irqs.h>
+
+#define gpio_get_value __gpio_get_value
+#define gpio_set_value __gpio_set_value
+#define gpio_cansleep __gpio_cansleep
+
+static inline int gpio_to_irq(unsigned gpio)
+{
+ return (CNS21XX_GPIO_IRQ_BASE + gpio);
+}
+
+static inline int irq_to_gpio(int irq)
+{
+ return (irq - CNS21XX_GPIO_IRQ_BASE);
+}
+
+#endif /* _CNS21XX_GPIO_H */
--- a/arch/arm/mach-cns21xx/Makefile
+++ b/arch/arm/mach-cns21xx/Makefile
@@ -4,7 +4,7 @@
# Object file lists.
-obj-y := core.o devices.o irq.o mm.o time.o
+obj-y := core.o devices.o gpio.o irq.o mm.o time.o
# machine specific files

View file

@ -0,0 +1,230 @@
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -583,7 +583,6 @@ static int ohci_run (struct ohci_hcd *oh
/* boot firmware should have set this up (5.1.1.3.1) */
if (first) {
-
val = ohci_readl (ohci, &ohci->regs->fminterval);
ohci->fminterval = val & 0x3fff;
if (ohci->fminterval != FI)
@@ -667,6 +666,9 @@ retry:
periodic_reinit (ohci);
+ if (ohci->flags & OHCI_QUIRK_INIT_FMINTERVAL)
+ ohci_writel (ohci, ohci->fminterval, &ohci->regs->fminterval);
+
/* some OHCI implementations are finicky about how they init.
* bogus values here mean not even enumeration could work.
*/
@@ -1061,6 +1063,11 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ohci_hcd_da8xx_driver
#endif
+#ifdef CONFIG_ARCH_CNS21XX
+#include "ohci-cns21xx.c"
+#define PLATFORM_DRIVER ohci_cns21xx_driver
+#endif
+
#if defined(CONFIG_CPU_SUBTYPE_SH7720) || \
defined(CONFIG_CPU_SUBTYPE_SH7721) || \
defined(CONFIG_CPU_SUBTYPE_SH7763) || \
--- /dev/null
+++ b/drivers/usb/host/ohci-cns21xx.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2008 Cavium Networks
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/platform_device.h>
+
+#include <mach/cns21xx.h>
+
+#define DRIVER_NAME "cns21xx-ohci"
+
+static int __devinit cns21xx_ohci_start(struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+ int ret;
+
+ ret = ohci_init(ohci);
+ if (ret)
+ return ret;
+
+ ret = ohci_run(ohci);
+ if (ret) {
+ err("can't start %s", ohci_to_hcd(ohci)->self.bus_name);
+ goto err;
+ }
+
+ return 0;
+
+err:
+ ohci_stop(hcd);
+ return ret;
+}
+
+static const struct hc_driver ohci_cns21xx_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "cns21xx-ohci",
+ .hcd_priv_size = sizeof(struct ohci_hcd),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ohci_irq,
+ .flags = HCD_USB11 | HCD_MEMORY,
+
+ /*
+ * basic lifecycle operations
+ */
+ .start = cns21xx_ohci_start,
+ .stop = ohci_stop,
+ .shutdown = ohci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = ohci_urb_enqueue,
+ .urb_dequeue = ohci_urb_dequeue,
+ .endpoint_disable = ohci_endpoint_disable,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = ohci_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
+ .start_port_reset = ohci_start_port_reset,
+};
+
+static void cns21xx_ohci_init_hc(void)
+{
+ __raw_writel(0x146, CNS21XX_OHCI_CONFIG_BASE_VIRT + 0x04);
+ __raw_writel(0x200, CNS21XX_OHCI_CONFIG_BASE_VIRT + 0x44);
+ msleep(100);
+}
+
+static int ohci_cns21xx_probe(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd;
+ struct resource *res;
+ struct ohci_hcd *ohci;
+ int irq;
+ int ret;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_dbg(&pdev->dev, "no IRQ specified for %s\n",
+ dev_name(&pdev->dev));
+ return -ENODEV;
+ }
+ irq = res->start;
+
+ hcd = usb_create_hcd(&ohci_cns21xx_hc_driver, &pdev->dev,
+ dev_name(&pdev->dev));
+ if (!hcd)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_dbg(&pdev->dev, "no base address specified for %s\n",
+ dev_name(&pdev->dev));
+ ret = -ENODEV;
+ goto err_put_hcd;
+ }
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = res->end - res->start + 1;
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ dev_dbg(&pdev->dev, "controller already in use\n");
+ ret = -EBUSY;
+ goto err_put_hcd;
+ }
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs) {
+ dev_dbg(&pdev->dev, "error mapping memory\n");
+ ret = -EFAULT;
+ goto err_release_region;
+ }
+
+ cns21xx_ohci_init_hc();
+
+ ohci = hcd_to_ohci(hcd);
+ ohci->flags |= OHCI_QUIRK_INIT_FMINTERVAL;
+ ohci_hcd_init(ohci);
+
+ ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
+ if (ret)
+ goto err_unmap;
+
+ platform_set_drvdata(pdev, hcd);
+ return 0;
+
+err_unmap:
+ iounmap(hcd->regs);
+err_release_region:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err_put_hcd:
+ usb_put_hcd(hcd);
+ return ret;
+}
+
+static int ohci_cns21xx_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+ usb_remove_hcd(hcd);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver ohci_cns21xx_driver = {
+ .probe = ohci_cns21xx_probe,
+ .remove = ohci_cns21xx_remove,
+ .shutdown = usb_hcd_platform_shutdown,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ },
+};
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -403,6 +403,7 @@ struct ohci_hcd {
#define OHCI_QUIRK_HUB_POWER 0x100 /* distrust firmware power/oc setup */
#define OHCI_QUIRK_AMD_ISO 0x200 /* ISO transfers*/
#define OHCI_QUIRK_AMD_PREFETCH 0x400 /* pre-fetch for ISO transfer */
+#define OHCI_QUIRK_INIT_FMINTERVAL 0x800 /* fminterval must be initialized */
// there are also chip quirks/bugs in init logic
struct work_struct nec_work; /* Worker for NEC quirk */
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -299,6 +299,7 @@ config ARCH_CNS21XX
select PLAT_FA_GPIO
select ARCH_REQUIRE_GPIOLIB
select ARM_L1_CACHE_SHIFT_4
+ select USB_ARCH_HAS_OHCI
help
Support for Cavium Networks CNS21xx family.

View file

@ -0,0 +1,211 @@
--- /dev/null
+++ b/drivers/usb/host/ehci-cns21xx.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2008 Cavium Networks
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+
+#include <mach/cns21xx.h>
+
+#define DRIVER_NAME "cns21xx-ehci"
+
+static int cns21xx_ehci_reset(struct usb_hcd *hcd)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ int ret;
+
+ ret = ehci_halt(ehci);
+ if (ret)
+ return ret;
+
+ ret = ehci_init(hcd);
+ if (ret)
+ return ret;
+
+ ehci_reset(ehci);
+ ehci_port_power(ehci, 0);
+
+ return 0;
+}
+
+static const struct hc_driver ehci_cns21xx_hc_driver = {
+ .description = hcd_name,
+ .product_desc = DRIVER_NAME,
+ .hcd_priv_size = sizeof(struct ehci_hcd),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ehci_irq,
+ .flags = HCD_MEMORY | HCD_USB2,
+
+ /*
+ * basic lifecycle operations
+ */
+ .reset = cns21xx_ehci_reset,
+ .start = ehci_run,
+ .stop = ehci_stop,
+ .shutdown = ehci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = ehci_urb_enqueue,
+ .urb_dequeue = ehci_urb_dequeue,
+ .endpoint_disable = ehci_endpoint_disable,
+ .endpoint_reset = ehci_endpoint_reset,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = ehci_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = ehci_hub_status_data,
+ .hub_control = ehci_hub_control,
+ .relinquish_port = ehci_relinquish_port,
+ .port_handed_over = ehci_port_handed_over,
+
+ .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
+};
+
+static void cns21xx_ehci_init_hc(void)
+{
+ __raw_writel(0x106, CNS21XX_EHCI_CONFIG_BASE_VIRT + 0x04);
+ __raw_writel((3 << 5) | 0x2000, CNS21XX_EHCI_CONFIG_BASE_VIRT + 0x40);
+ msleep(100);
+}
+
+static int ehci_cns21xx_probe(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd;
+ struct ehci_hcd *ehci;
+ struct resource *res;
+ int irq;
+ int ret;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_dbg(&pdev->dev, "no IRQ specified for %s\n",
+ dev_name(&pdev->dev));
+ return -ENODEV;
+ }
+ irq = res->start;
+
+ hcd = usb_create_hcd(&ehci_cns21xx_hc_driver, &pdev->dev,
+ dev_name(&pdev->dev));
+ if (!hcd)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_dbg(&pdev->dev, "no base address specified for %s\n",
+ dev_name(&pdev->dev));
+ ret = -ENODEV;
+ goto err_put_hcd;
+ }
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = res->end - res->start + 1;
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ dev_dbg(&pdev->dev, "controller already in use\n");
+ ret = -EBUSY;
+ goto err_put_hcd;
+ }
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs) {
+ dev_dbg(&pdev->dev, "error mapping memory\n");
+ ret = -EFAULT;
+ goto err_release_region;
+ }
+
+ cns21xx_ehci_init_hc();
+
+ ehci = hcd_to_ehci(hcd);
+
+ ehci->caps = hcd->regs;
+ ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
+ dbg_hcs_params(ehci, "reset");
+ dbg_hcc_params(ehci, "reset");
+
+ /* cache this readonly data; minimize chip reads */
+ ehci->hcs_params = readl(&ehci->caps->hcs_params);
+ ehci->sbrn = 0x20;
+
+ ret = usb_add_hcd(hcd, CNS21XX_IRQ_EHCI, IRQF_DISABLED);
+ if (ret)
+ goto err_unmap;
+
+ platform_set_drvdata(pdev, hcd);
+ return 0;
+
+err_unmap:
+ iounmap(hcd->regs);
+err_release_region:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err_put_hcd:
+ usb_put_hcd(hcd);
+ return ret;
+}
+
+static int ehci_cns21xx_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+ usb_remove_hcd(hcd);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver ehci_cns21xx_driver = {
+ .probe = ehci_cns21xx_probe,
+ .remove = ehci_cns21xx_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ },
+};
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1197,6 +1197,11 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ehci_atmel_driver
#endif
+#ifdef CONFIG_ARCH_CNS21XX
+#include "ehci-cns21xx.c"
+#define PLATFORM_DRIVER ehci_cns21xx_driver
+#endif
+
#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
!defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
!defined(XILINX_OF_PLATFORM_DRIVER)
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -300,6 +300,7 @@ config ARCH_CNS21XX
select ARCH_REQUIRE_GPIOLIB
select ARM_L1_CACHE_SHIFT_4
select USB_ARCH_HAS_OHCI
+ select USB_ARCH_HAS_EHCI
help
Support for Cavium Networks CNS21xx family.

View file

@ -0,0 +1,577 @@
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -442,6 +442,8 @@ struct spi_transfer {
u16 delay_usecs;
u32 speed_hz;
+ unsigned last_in_message_list;
+
struct list_head transfer_list;
};
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -152,6 +152,14 @@ config SPI_GPIO_OLD
If unsure, say N.
+config SPI_CNS21XX
+ tristate "Cavium Netowrks CNS21xx SPI master"
+ depends on ARCH_CNS21XX && EXPERIMENTAL
+ select SPI_BITBANG
+ help
+ This driver supports the buil-in SPI controller of the Cavium Networks
+ CNS21xx SoCs.
+
config SPI_IMX
tristate "Freescale i.MX SPI controllers"
depends on ARCH_MXC
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -48,6 +48,7 @@ obj-$(CONFIG_SPI_SH_SCI) += spi_sh_sci.
obj-$(CONFIG_SPI_SH_MSIOF) += spi_sh_msiof.o
obj-$(CONFIG_SPI_STMP3XXX) += spi_stmp.o
obj-$(CONFIG_SPI_NUC900) += spi_nuc900.o
+obj-$(CONFIG_SPI_CNS21XX) += spi_cns21xx.o
# special build for s3c24xx spi driver with fiq support
spi_s3c24xx_hw-y := spi_s3c24xx.o
--- a/drivers/spi/spi_bitbang.c
+++ b/drivers/spi/spi_bitbang.c
@@ -337,6 +337,13 @@ static void bitbang_work(struct work_str
*/
if (!m->is_dma_mapped)
t->rx_dma = t->tx_dma = 0;
+
+ if (t->transfer_list.next == &m->transfers) {
+ t->last_in_message_list = 1;
+ } else {
+ t->last_in_message_list = 0;
+ }
+
status = bitbang->txrx_bufs(spi, t);
}
if (status > 0)
--- /dev/null
+++ b/drivers/spi/spi_cns21xx.c
@@ -0,0 +1,520 @@
+/*
+ * Copyright (c) 2008 Cavium Networks
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+
+#include <mach/hardware.h>
+#include <mach/cns21xx.h>
+
+#define DRIVER_NAME "cns21xx-spi"
+
+#ifdef CONFIG_CNS21XX_SPI_DEBUG
+#define DBG(fmt, args...) pr_info("[CNS21XX_SPI_DEBUG]" fmt, ## args)
+#else
+#define DBG(fmt, args...) do {} while (0)
+#endif /* CNS21XX_SPI_DEBUG */
+
+#define SPI_REG_CFG 0x40
+#define SPI_REG_STAT 0x44
+#define SPI_REG_BIT_RATE 0x48
+#define SPI_REG_TX_CTRL 0x4c
+#define SPI_REG_TX_DATA 0x50
+#define SPI_REG_RX_CTRL 0x54
+#define SPI_REG_RX_DATA 0x58
+#define SPI_REG_FIFO_TX_CFG 0x5c
+#define SPI_REG_FIFO_TX_CTRL 0x60
+#define SPI_REG_FIFO_RX_CFG 0x64
+#define SPI_REG_INTR_STAT 0x68
+#define SPI_REG_INTR_ENA 0x6c
+
+#define CFG_SPI_EN BIT(31)
+#define CFG_SPI_CLKPOL BIT(14)
+#define CFG_SPI_CLKPHA BIT(13)
+#define CFG_SPI_MASTER_EN BIT(11)
+#define CFG_SPI_CHAR_LEN_M 0x3
+#define CFG_SPI_CHAR_LEN_8BITS 0
+#define CFG_SPI_CHAR_LEN_16BITS 1
+#define CFG_SPI_CHAR_LEN_24BITS 2
+#define CFG_SPI_CHAR_LEN_32BITS 3
+
+#define STAT_SPI_BUSY_STA BIT(1)
+
+#define BIT_RATE_DIV_1 0
+#define BIT_RATE_DIV_2 1
+#define BIT_RATE_DIV_4 2
+#define BIT_RATE_DIV_8 3
+#define BIT_RATE_DIV_16 4
+#define BIT_RATE_DIV_32 5
+#define BIT_RATE_DIV_64 6
+#define BIT_RATE_DIV_128 7
+
+#define TX_CTRL_SPI_TXDAT_EOF BIT(2)
+#define TX_CTRL_SPI_TXCH_NUM_M 0x3
+#define TX_CTRL_CLEAR_MASK (TX_CTRL_SPI_TXDAT_EOF | \
+ TX_CTRL_SPI_TXCH_NUM_M)
+
+#define RX_CTRL_SPI_RXDAT_EOF BIT(2)
+#define RX_CTRL_SPI_RXCH_NUM_M 0x3
+
+#define INTR_STAT_SPI_TXBF_UNRN_FG BIT(7)
+#define INTR_STAT_SPI_RXBF_OVRN_FG BIT(6)
+#define INTR_STAT_SPI_TXFF_UNRN_FG BIT(5)
+#define INTR_STAT_SPI_RXFF_OVRN_FG BIT(4)
+#define INTR_STAT_SPI_TXBUF_FG BIT(3)
+#define INTR_STAT_SPI_RXBUF_FG BIT(2)
+#define INTR_STAT_SPI_TXFF_FG BIT(1)
+#define INTR_STAT_SPI_RXFF_FG BIT(0)
+
+#define INTR_STAT_CLEAR_MASK (INTR_STAT_SPI_TXBF_UNRN_FG | \
+ INTR_STAT_SPI_RXBF_OVRN_FG | \
+ INTR_STAT_SPI_TXFF_UNRN_FG | \
+ INTR_STAT_SPI_RXFF_OVRN_FG)
+
+#define FIFO_TX_CFG_SPI_TXFF_THRED_M 0x3
+#define FIFO_TX_CFG_SPI_TXFF_THRED_S 4
+#define FIFO_TX_CFG_SPI_TXFF_THRED_2 0
+#define FIFO_TX_CFG_SPI_TXFF_THRED_4 1
+#define FIFO_TX_CFG_SPI_TXFF_THRED_6 0
+#define FIFO_TX_CFG_SPI_TXFF_STATUS_M 0xf
+
+#define FIFO_RX_CFG_SPI_RXFF_THRED_M 0x3
+#define FIFO_RX_CFG_SPI_RXFF_THRED_S 4
+#define FIFO_RX_CFG_SPI_RXFF_THRED_2 0
+#define FIFO_RX_CFG_SPI_RXFF_THRED_4 1
+#define FIFO_RX_CFG_SPI_RXFF_THRED_6 0
+#define FIFO_RX_CFG_SPI_RXFF_STATUS_M 0xf
+
+#define CNS21XX_SPI_NUM_BIT_RATES 8
+
+struct cns21xx_spi {
+ struct spi_bitbang bitbang;
+
+ struct spi_master *master;
+ struct device *dev;
+ void __iomem *base;
+ struct resource *region;
+
+ unsigned freq_max;
+ unsigned freq_min;
+
+};
+
+static inline struct cns21xx_spi *to_hw(struct spi_device *spi)
+{
+ return spi_master_get_devdata(spi->master);
+}
+
+static inline u32 cns21xx_spi_rr(struct cns21xx_spi *hw, unsigned int reg)
+{
+ return __raw_readl(hw->base + reg);
+}
+
+static inline void cns21xx_spi_wr(struct cns21xx_spi *hw, u32 val,
+ unsigned int reg)
+{
+ __raw_writel(val, hw->base + reg);
+}
+
+#define CNS21XX_SPI_RETRY_COUNT 100
+static inline int cns21xx_spi_wait(struct cns21xx_spi *hw, unsigned int reg,
+ u32 mask, u32 val)
+{
+ int retry_cnt = 0;
+
+ do {
+ if ((cns21xx_spi_rr(hw, reg) & mask) == val)
+ break;
+
+ if (++retry_cnt > CNS21XX_SPI_RETRY_COUNT) {
+ dev_err(hw->dev, "timeout waiting on register %02x\n",
+ reg);
+ return -EIO;
+ }
+ } while (1);
+
+ return 0;
+}
+
+static int cns21xx_spi_txrx_word(struct cns21xx_spi *hw, u8 tx_channel,
+ u8 tx_eof_flag, u32 tx_data, u32 *rx_data)
+{
+ unsigned int tx_ctrl;
+ u8 rx_channel;
+ u8 rx_eof_flag;
+ int err = 0;
+
+ err = cns21xx_spi_wait(hw, SPI_REG_STAT, STAT_SPI_BUSY_STA, 0);
+ if (err)
+ return err;
+
+ err = cns21xx_spi_wait(hw, SPI_REG_INTR_STAT, INTR_STAT_SPI_TXBUF_FG,
+ INTR_STAT_SPI_TXBUF_FG);
+ if (err)
+ return err;
+
+ tx_ctrl = cns21xx_spi_rr(hw, SPI_REG_TX_CTRL);
+ tx_ctrl &= ~(TX_CTRL_CLEAR_MASK);
+ tx_ctrl |= (tx_channel & TX_CTRL_SPI_TXCH_NUM_M);
+ tx_ctrl |= (tx_eof_flag) ? TX_CTRL_SPI_TXDAT_EOF : 0;
+ cns21xx_spi_wr(hw, tx_ctrl, SPI_REG_TX_CTRL);
+
+ cns21xx_spi_wr(hw, tx_data, SPI_REG_TX_DATA);
+
+ err = cns21xx_spi_wait(hw, SPI_REG_INTR_STAT, INTR_STAT_SPI_RXBUF_FG,
+ INTR_STAT_SPI_RXBUF_FG);
+ if (err)
+ return err;
+
+ rx_channel = cns21xx_spi_rr(hw, SPI_REG_RX_CTRL) &
+ RX_CTRL_SPI_RXCH_NUM_M;
+
+ rx_eof_flag = (cns21xx_spi_rr(hw, SPI_REG_RX_CTRL) &
+ RX_CTRL_SPI_RXDAT_EOF) ? 1 : 0;
+
+ *rx_data = cns21xx_spi_rr(hw, SPI_REG_RX_DATA);
+
+ if ((tx_channel != rx_channel) || (tx_eof_flag != rx_eof_flag))
+ return -EPROTO;
+
+ return 0;
+}
+
+static void cns21xx_spi_chipselect(struct spi_device *spi, int value)
+{
+ struct cns21xx_spi *hw = to_hw(spi);
+ unsigned int spi_config;
+ unsigned int tx_ctrl;
+
+ switch (value) {
+ case BITBANG_CS_INACTIVE:
+ break;
+
+ case BITBANG_CS_ACTIVE:
+ spi_config = cns21xx_spi_rr(hw, SPI_REG_CFG);
+
+ if (spi->mode & SPI_CPHA)
+ spi_config |= CFG_SPI_CLKPHA;
+ else
+ spi_config &= ~CFG_SPI_CLKPHA;
+
+ if (spi->mode & SPI_CPOL)
+ spi_config |= CFG_SPI_CLKPOL;
+ else
+ spi_config &= ~CFG_SPI_CLKPOL;
+
+ cns21xx_spi_wr(hw, spi_config, SPI_REG_CFG);
+
+ tx_ctrl = cns21xx_spi_rr(hw, SPI_REG_TX_CTRL);
+ tx_ctrl &= ~(TX_CTRL_CLEAR_MASK);
+ tx_ctrl |= (spi->chip_select & TX_CTRL_SPI_TXCH_NUM_M);
+ cns21xx_spi_wr(hw, tx_ctrl, SPI_REG_TX_CTRL);
+
+ break;
+ }
+}
+
+static int cns21xx_spi_setup(struct spi_device *spi)
+{
+ struct cns21xx_spi *hw = to_hw(spi);
+
+ if (spi->bits_per_word != 8) {
+ dev_err(&spi->dev, "%s: invalid bits_per_word=%u\n",
+ __func__, spi->bits_per_word);
+ return -EINVAL;
+ }
+
+ if (spi->max_speed_hz == 0)
+ spi->max_speed_hz = hw->freq_max;
+
+ if (spi->max_speed_hz > hw->freq_max ||
+ spi->max_speed_hz < hw->freq_min) {
+ dev_err(&spi->dev, "%s: max_speed_hz=%u out of range\n",
+ __func__, spi->max_speed_hz);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int cns21xx_spi_setup_transfer(struct spi_device *spi,
+ struct spi_transfer *t)
+{
+ struct cns21xx_spi *hw = to_hw(spi);
+ u8 bits_per_word;
+ u32 hz;
+ int i;
+
+ bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word;
+ hz = t ? t->speed_hz : spi->max_speed_hz;
+
+ if (!bits_per_word)
+ bits_per_word = spi->bits_per_word;
+
+ if (!hz)
+ hz = spi->max_speed_hz;
+
+ if (bits_per_word != 8) {
+ dev_err(&spi->dev, "%s: invalid bits_per_word=%u\n",
+ __func__, bits_per_word);
+ return -EINVAL;
+ }
+
+ if (hz > spi->max_speed_hz || hz > hw->freq_max || hz < hw->freq_min) {
+ dev_err(&spi->dev, "%s: max_speed_hz=%u out of range\n",
+ __func__, hz);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < CNS21XX_SPI_NUM_BIT_RATES; i++)
+ if (spi->max_speed_hz > (cns21xx_get_apb_freq() >> i))
+ break;
+
+ DBG("max_speed:%uHz, curr_speed:%luHz, rate_index=%d\n",
+ spi->max_speed_hz, cns21xx_get_apb_freq() / (1 << i), i);
+
+ cns21xx_spi_wr(hw, i, SPI_REG_BIT_RATE);
+
+ return 0;
+}
+
+static int cns21xx_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
+{
+ struct cns21xx_spi *hw = to_hw(spi);
+ const unsigned char *tx_buf;
+ unsigned char *rx_buf;
+ u32 rx_data;
+ int tx_eof;
+ int err = 0;
+ int i;
+
+ tx_buf = t->tx_buf;
+ rx_buf = t->rx_buf;
+ tx_eof = t->last_in_message_list;
+
+ DBG("txrx: tx %p, rx %p, len %d\n", tx_buf, rx_buf, t->len);
+
+ if (tx_buf) {
+ for (i = 0; i < t->len; i++)
+ DBG("tx_buf[%02d]: 0x%02x\n", i, tx_buf[i]);
+
+ for (i = 0; i < (t->len - 1); i++) {
+ err = cns21xx_spi_txrx_word(hw, spi->chip_select, 0,
+ tx_buf[i], &rx_data);
+ if (err)
+ goto done;
+
+ if (rx_buf) {
+ rx_buf[i] = rx_data;
+ DBG("rx_buf[%02d]:0x%02x\n", i, rx_buf[i]);
+ }
+ }
+
+ err = cns21xx_spi_txrx_word(hw, spi->chip_select, tx_eof,
+ tx_buf[i], &rx_data);
+ if (err)
+ goto done;
+
+ if ((tx_eof) && rx_buf) {
+ rx_buf[i] = rx_data;
+ DBG("rx_buf[%02d]:0x%02x\n", i, rx_buf[i]);
+ }
+ } else if (rx_buf) {
+ for (i = 0; i < (t->len - 1); i++) {
+ err = cns21xx_spi_txrx_word(hw, spi->chip_select, 0,
+ 0xff, &rx_data);
+ if (err)
+ goto done;
+
+ rx_buf[i] = rx_data;
+ DBG("rx_buf[%02d]:0x%02x\n", i, rx_buf[i]);
+ }
+
+ err = cns21xx_spi_txrx_word(hw, spi->chip_select, tx_eof,
+ 0xff, &rx_data);
+ if (err)
+ goto done;
+
+ rx_buf[i] = rx_data;
+ DBG("rx_buf[%02d]:0x%02x\n", i, rx_buf[i]);
+ }
+
+ done:
+ return (err) ? err : t->len;
+}
+
+static void __init cns21xx_spi_hw_init(struct cns21xx_spi *hw)
+{
+ u32 t;
+ u32 pclk;
+
+ /* Setup configuration register */
+ cns21xx_spi_wr(hw, CFG_SPI_MASTER_EN, SPI_REG_CFG);
+
+ /* Set default clock to PCLK/2 */
+ cns21xx_spi_wr(hw, BIT_RATE_DIV_2, SPI_REG_BIT_RATE);
+
+ /* Configure SPI's Tx channel */
+ cns21xx_spi_wr(hw, 0, SPI_REG_TX_CTRL);
+
+ /* Configure Tx FIFO Threshold */
+ t = cns21xx_spi_rr(hw, SPI_REG_FIFO_TX_CFG);
+ t &= ~(FIFO_TX_CFG_SPI_TXFF_THRED_M << FIFO_TX_CFG_SPI_TXFF_THRED_S);
+ t |= (FIFO_TX_CFG_SPI_TXFF_THRED_2 << FIFO_TX_CFG_SPI_TXFF_THRED_S);
+ cns21xx_spi_wr(hw, t, SPI_REG_FIFO_TX_CFG);
+
+ /* Configure Rx FIFO Threshold */
+ t = cns21xx_spi_rr(hw, SPI_REG_FIFO_RX_CFG);
+ t &= ~(FIFO_RX_CFG_SPI_RXFF_THRED_M << FIFO_RX_CFG_SPI_RXFF_THRED_S);
+ t |= (FIFO_RX_CFG_SPI_RXFF_THRED_2 << FIFO_RX_CFG_SPI_RXFF_THRED_S);
+ cns21xx_spi_wr(hw, t, SPI_REG_FIFO_RX_CFG);
+
+ /* Disable interrupts, and clear interrupt status */
+ cns21xx_spi_wr(hw, 0, SPI_REG_INTR_ENA);
+ cns21xx_spi_wr(hw, INTR_STAT_CLEAR_MASK, SPI_REG_INTR_STAT);
+
+ (void) cns21xx_spi_rr(hw, SPI_REG_RX_DATA);
+
+ /* Enable SPI */
+ t = cns21xx_spi_rr(hw, SPI_REG_CFG);
+ t |= CFG_SPI_EN;
+ cns21xx_spi_wr(hw, t, SPI_REG_CFG);
+
+ pclk = cns21xx_get_apb_freq();
+ hw->freq_max = pclk;
+ hw->freq_min = pclk / (1 << BIT_RATE_DIV_128);
+}
+
+static int __init cns21xx_spi_probe(struct platform_device *pdev)
+{
+ struct cns21xx_spi *hw;
+ struct spi_master *master;
+ struct resource *res;
+ int err = 0;
+
+ master = spi_alloc_master(&pdev->dev, sizeof(struct cns21xx_spi));
+ if (!master) {
+ dev_err(&pdev->dev, "No memory for spi_master\n");
+ return -ENOMEM;
+ }
+
+ hw = spi_master_get_devdata(master);
+
+ platform_set_drvdata(pdev, hw);
+ hw->master = spi_master_get(master);
+ hw->dev = &pdev->dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_dbg(&pdev->dev, "no MEM resource found\n");
+ err = -ENOENT;
+ goto err_put_master;
+ }
+
+ hw->region = request_mem_region(res->start, resource_size(res),
+ dev_name(&pdev->dev));
+ if (!hw->region) {
+ dev_err(&pdev->dev, "unable to reserve iomem region\n");
+ err = -ENXIO;
+ goto err_put_master;
+ }
+
+ hw->base = ioremap(res->start, resource_size(res));
+ if (!hw->base) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ err = -ENOENT;
+ goto err_release_region;
+ }
+
+ cns21xx_spi_hw_init(hw);
+
+ master->bus_num = pdev->id;
+ if (master->bus_num == -1)
+ master->bus_num = 0;
+
+ master->num_chipselect = 4;
+ master->setup = cns21xx_spi_setup;
+
+ hw->bitbang.master = hw->master;
+ hw->bitbang.chipselect = cns21xx_spi_chipselect;
+ hw->bitbang.txrx_bufs = cns21xx_spi_txrx;
+ hw->bitbang.setup_transfer = cns21xx_spi_setup_transfer;
+
+ err = spi_bitbang_start(&hw->bitbang);
+ if (err) {
+ dev_err(hw->dev, "unable to register SPI master\n");
+ goto err_unmap;
+ }
+
+ dev_info(hw->dev, "iomem at %08x\n", res->start);
+
+ return 0;
+
+ err_unmap:
+ iounmap(hw->base);
+
+ err_release_region:
+ release_resource(hw->region);
+ kfree(hw->region);
+
+ err_put_master:
+ spi_master_put(hw->bitbang.master);
+ platform_set_drvdata(pdev, NULL);
+
+ return err;
+}
+
+static int __devexit cns21xx_spi_remove(struct platform_device *pdev)
+{
+ struct cns21xx_spi *hw = platform_get_drvdata(pdev);
+
+ spi_bitbang_stop(&hw->bitbang);
+ iounmap(hw->base);
+ release_resource(hw->region);
+ kfree(hw->region);
+ spi_master_put(hw->bitbang.master);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver cns21xx_spi_driver = {
+ .remove = __devexit_p(cns21xx_spi_remove),
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init cns21xx_spi_init(void)
+{
+ return platform_driver_probe(&cns21xx_spi_driver, cns21xx_spi_probe);
+}
+
+static void __exit cns21xx_spi_exit(void)
+{
+ platform_driver_unregister(&cns21xx_spi_driver);
+}
+
+module_init(cns21xx_spi_init);
+module_exit(cns21xx_spi_exit);
+
+MODULE_DESCRIPTION("Cavium Networks CNS21xx SPI Controller driver");
+MODULE_AUTHOR("STAR Semi Corp.");
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,104 @@
--- /dev/null
+++ b/arch/arm/mach-cns21xx/dev-usb.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2008 Cavium Networks
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+
+#include <mach/cns21xx.h>
+
+static u64 cns21xx_usb_dmamask = DMA_BIT_MASK(32);
+
+static struct resource cns21xx_ohci_resources[] = {
+ [0] = {
+ .start = CNS21XX_OHCI_CTRL_BASE,
+ .end = CNS21XX_OHCI_CTRL_BASE + SZ_1M - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = CNS21XX_IRQ_OHCI,
+ .end = CNS21XX_IRQ_OHCI,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device cns21xx_ohci_device = {
+ .name = "cns21xx-ohci",
+ .id = -1,
+ .dev = {
+ .dma_mask = &cns21xx_usb_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ .resource = cns21xx_ohci_resources,
+ .num_resources = ARRAY_SIZE(cns21xx_ohci_resources),
+};
+
+static struct resource cns21xx_ehci_resources[] = {
+ [0] = {
+ .start = CNS21XX_EHCI_CTRL_BASE,
+ .end = CNS21XX_EHCI_CTRL_BASE + SZ_1M - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = CNS21XX_IRQ_EHCI,
+ .end = CNS21XX_IRQ_EHCI,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device cns21xx_ehci_device = {
+ .name = "cns21xx-ehci",
+ .id = -1,
+ .dev = {
+ .dma_mask = &cns21xx_usb_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ .resource = cns21xx_ehci_resources,
+ .num_resources = ARRAY_SIZE(cns21xx_ehci_resources),
+};
+
+void __init cns21xx_register_usb(void)
+{
+ platform_device_register(&cns21xx_ehci_device);
+ platform_device_register(&cns21xx_ohci_device);
+}
--- a/arch/arm/mach-cns21xx/Kconfig
+++ b/arch/arm/mach-cns21xx/Kconfig
@@ -3,4 +3,7 @@ if ARCH_CNS21XX
menu "Cavium Networks CNS21xx based machines"
endmenu
+config CNS21XX_DEV_USB
+ def_bool n
+
endif
--- a/arch/arm/mach-cns21xx/Makefile
+++ b/arch/arm/mach-cns21xx/Makefile
@@ -6,5 +6,8 @@
obj-y := core.o devices.o gpio.o irq.o mm.o time.o
+# devices
+obj-$(CONFIG_CNS21XX_DEV_USB) += dev-usb.o
+
# machine specific files
--- a/arch/arm/mach-cns21xx/common.h
+++ b/arch/arm/mach-cns21xx/common.h
@@ -18,5 +18,6 @@ extern struct sys_timer cns21xx_timer;
int __init cns21xx_register_uart0(void);
int __init cns21xx_register_uart1(void);
+int __init cns21xx_register_usb(void);
#endif /* _MACH_CNS21XX_COMMON_H */

View file

@ -0,0 +1,63 @@
--- a/arch/arm/mach-cns21xx/common.h
+++ b/arch/arm/mach-cns21xx/common.h
@@ -19,5 +19,6 @@ extern struct sys_timer cns21xx_timer;
int __init cns21xx_register_uart0(void);
int __init cns21xx_register_uart1(void);
int __init cns21xx_register_usb(void);
+int __init cns21xx_register_wdt(void);
#endif /* _MACH_CNS21XX_COMMON_H */
--- a/arch/arm/mach-cns21xx/devices.c
+++ b/arch/arm/mach-cns21xx/devices.c
@@ -11,6 +11,7 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/serial_8250.h>
+#include <linux/fa_wdt.h>
#include <mach/irqs.h>
#include <mach/hardware.h>
@@ -77,3 +78,32 @@ int __init cns21xx_register_uart1(void)
HAL_MISC_ENABLE_UART1_PINS();
return platform_device_register(&cns21xx_uart1_device);
}
+
+static struct resource cns21xx_wdt_resources[] = {
+ {
+ .start = CNS21XX_WDT_BASE,
+ .end = CNS21XX_WDT_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+#define CNS21XX_WDT_CLOCK 10 /* 10 Hz */
+
+static struct fa_wdt_platform_data cns21xx_wdt_data = {
+ .clock = CNS21XX_WDT_CLOCK,
+};
+
+static struct platform_device cns21xx_wdt_device = {
+ .name = "fa-wdt",
+ .id = -1,
+ .resource = cns21xx_wdt_resources,
+ .num_resources = ARRAY_SIZE(cns21xx_wdt_resources),
+ .dev = {
+ .platform_data = &cns21xx_wdt_data,
+ },
+};
+
+int __init cns21xx_register_wdt(void)
+{
+ return platform_device_register(&cns21xx_wdt_device);
+}
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -333,7 +333,7 @@ config IMX2_WDT
config FA_WATCHDOG
tristate "Faraday watchdog"
- depends on ARCH_GEMINI
+ depends on ARCH_GEMINI || ARCH_CNS21XX
help
Say Y here if you want support for the built-in watchdog timer
found in some Faraday FA526 based SoCs.

View file

@ -0,0 +1,117 @@
--- /dev/null
+++ b/arch/arm/mach-cns21xx/dev-spi-master.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/spi/spi.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+
+#include <mach/hardware.h>
+#include <mach/cns21xx.h>
+#include <mach/cns21xx_misc.h>
+#include <mach/cns21xx_powermgmt.h>
+#include <mach/irqs.h>
+
+#include "common.h"
+
+static u64 spi_dmamask = DMA_BIT_MASK(32);
+static struct resource cns21xx_spi_resources[] = {
+ [0] = {
+ .start = CNS21XX_SPI_BASE,
+ .end = CNS21XX_SPI_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = CNS21XX_IRQ_SPI,
+ .end = CNS21XX_IRQ_SPI,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device cns21xx_spi_master_device = {
+ .name = "cns21xx-spi",
+ .id = -1,
+ .dev = {
+ .dma_mask = &spi_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ .resource = cns21xx_spi_resources,
+ .num_resources = ARRAY_SIZE(cns21xx_spi_resources),
+};
+
+void __init cns21xx_register_spi_master(int id, struct spi_board_info *info,
+ unsigned int n)
+{
+ unsigned int i;
+
+ /* Enable SPI pins */
+ HAL_MISC_ENABLE_SPIDR_PINS();
+ HAL_MISC_ENABLE_SPICLK_PINS();
+ for (i = 0; i < n; i++) {
+ switch (info[i].chip_select) {
+ case 0:
+ HAL_MISC_ENABLE_SPICSN0_PINS();
+ break;
+ case 1:
+ HAL_MISC_ENABLE_SPICSN1_PINS();
+ break;
+ case 2:
+ HAL_MISC_ENABLE_SPICSN2_PINS();
+ break;
+ case 3:
+ HAL_MISC_ENABLE_SPICSN3_PINS();
+ break;
+ }
+ }
+
+ /* Disable SPI serial flash access through 0x30000000 region */
+ HAL_MISC_DISABLE_SPI_SERIAL_FLASH_BANK_ACCESS();
+
+ /* Enable SPI clock */
+ HAL_PWRMGT_ENABLE_SPI_CLOCK();
+
+ cns21xx_spi_master_device.id = id;
+
+ spi_register_board_info(info, n);
+ platform_device_register(&cns21xx_spi_master_device);
+}
--- a/arch/arm/mach-cns21xx/Kconfig
+++ b/arch/arm/mach-cns21xx/Kconfig
@@ -6,4 +6,7 @@ endmenu
config CNS21XX_DEV_USB
def_bool n
+config CNS21XX_DEV_SPI_MASTER
+ def_bool n
+
endif
--- a/arch/arm/mach-cns21xx/Makefile
+++ b/arch/arm/mach-cns21xx/Makefile
@@ -8,6 +8,7 @@ obj-y := core.o devices.o gpio.o irq.o
# devices
obj-$(CONFIG_CNS21XX_DEV_USB) += dev-usb.o
+obj-$(CONFIG_CNS21XX_DEV_SPI_MASTER) += dev-spi-master.o
# machine specific files
--- a/arch/arm/mach-cns21xx/common.h
+++ b/arch/arm/mach-cns21xx/common.h
@@ -21,4 +21,8 @@ int __init cns21xx_register_uart1(void);
int __init cns21xx_register_usb(void);
int __init cns21xx_register_wdt(void);
+struct spi_board_info;
+void __init cns21xx_register_spi_master(int id, struct spi_board_info *info,
+ unsigned int n);
+
#endif /* _MACH_CNS21XX_COMMON_H */

View file

@ -0,0 +1,178 @@
--- a/arch/arm/mach-cns21xx/Kconfig
+++ b/arch/arm/mach-cns21xx/Kconfig
@@ -3,6 +3,9 @@ if ARCH_CNS21XX
menu "Cavium Networks CNS21xx based machines"
endmenu
+config CNS21XX_DEV_GEC
+ def_bool n
+
config CNS21XX_DEV_USB
def_bool n
--- a/arch/arm/mach-cns21xx/Makefile
+++ b/arch/arm/mach-cns21xx/Makefile
@@ -7,6 +7,7 @@
obj-y := core.o devices.o gpio.o irq.o mm.o time.o
# devices
+obj-$(CONFIG_CNS21XX_DEV_GEC) += dev-gec.o
obj-$(CONFIG_CNS21XX_DEV_USB) += dev-usb.o
obj-$(CONFIG_CNS21XX_DEV_SPI_MASTER) += dev-spi-master.o
--- /dev/null
+++ b/arch/arm/mach-cns21xx/dev-gec.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/etherdevice.h>
+
+#include <asm/sizes.h>
+#include <mach/cns21xx.h>
+#include <mach/irqs.h>
+
+#include "dev-gec.h"
+
+static u8 cns21xx_ethaddr[ETH_ALEN];
+struct cns21xx_gec_plat_data cns21xx_gec_data;
+
+static struct resource cns21xx_gec_resources[] = {
+ {
+ .start = CNS21XX_NIC_BASE,
+ .end = CNS21XX_NIC_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .name = CNS21XX_GEC_STATUS_IRQ_NAME,
+ .start = CNS21XX_IRQ_NIC_STATUS,
+ .end = CNS21XX_IRQ_NIC_STATUS,
+ .flags = IORESOURCE_IRQ,
+ }, {
+ .name = CNS21XX_GEC_RXRC_IRQ_NAME,
+ .start = CNS21XX_IRQ_NIC_RXRC,
+ .end = CNS21XX_IRQ_NIC_RXRC,
+ .flags = IORESOURCE_IRQ,
+ }, {
+ .name = CNS21XX_GEC_RXQF_IRQ_NAME,
+ .start = CNS21XX_IRQ_NIC_RXQF,
+ .end = CNS21XX_IRQ_NIC_RXQF,
+ .flags = IORESOURCE_IRQ,
+ }, {
+ .name = CNS21XX_GEC_TXTC_IRQ_NAME,
+ .start = CNS21XX_IRQ_NIC_TXTC,
+ .end = CNS21XX_IRQ_NIC_TXTC,
+ .flags = IORESOURCE_IRQ,
+ }, {
+ .name = CNS21XX_GEC_TXQE_IRQ_NAME,
+ .start = CNS21XX_IRQ_NIC_TXQE,
+ .end = CNS21XX_IRQ_NIC_TXQE,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static u64 cns21xx_gec_dmamask = DMA_BIT_MASK(32);
+static struct platform_device cns21xx_gec_device = {
+ .name = "cns21xx-gec",
+ .id = -1,
+ .resource = cns21xx_gec_resources,
+ .num_resources = ARRAY_SIZE(cns21xx_gec_resources),
+ .dev = {
+ .dma_mask = &cns21xx_gec_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &cns21xx_gec_data,
+ },
+};
+
+static int __init cns21xx_ethaddr_setup(char *str)
+{
+ int t;
+
+ t = sscanf(str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
+ &cns21xx_ethaddr[0], &cns21xx_ethaddr[1],
+ &cns21xx_ethaddr[2], &cns21xx_ethaddr[3],
+ &cns21xx_ethaddr[4], &cns21xx_ethaddr[5]);
+
+ if (t != ETH_ALEN)
+ pr_err("cns21xx: failed to parse mac address \"%s\"\n", str);
+
+ return 1;
+}
+
+__setup("ethaddr=", cns21xx_ethaddr_setup);
+
+__init int cns21xx_register_gec(void)
+{
+ if (cns21xx_gec_data.mac_addr == NULL)
+ cns21xx_gec_data.mac_addr = cns21xx_ethaddr;
+
+ if (!is_valid_ether_addr(cns21xx_gec_data.mac_addr)) {
+ random_ether_addr(cns21xx_gec_data.mac_addr);
+ pr_debug("cns21xx: using random MAC address \"%s\"\n",
+ cns21xx_gec_data.mac_addr);
+ }
+
+ return platform_device_register(&cns21xx_gec_device);
+}
--- /dev/null
+++ b/arch/arm/mach-cns21xx/dev-gec.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file 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 _CNS21XX_DEV_GEC_H
+#define _CNS21XX_DEV_GEC_H
+
+#include <mach/cns21xx_gec_platform.h>
+
+extern struct cns21xx_gec_plat_data cns21xx_gec_data;
+
+__init int cns21xx_register_gec(void);
+
+#endif /* _CNS21XX_DEV_GEC_H */
--- /dev/null
+++ b/arch/arm/mach-cns21xx/include/mach/cns21xx_gec_platform.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file 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 _CNS21XX_GEC_PLATFORM_H
+#define _CNS21XX_GEC_PLATFORM_H
+
+#define CNS21XX_GEC_STATUS_IRQ_NAME "status"
+#define CNS21XX_GEC_RXRC_IRQ_NAME "rxrc"
+#define CNS21XX_GEC_RXQF_IRQ_NAME "rxqf"
+#define CNS21XX_GEC_TXTC_IRQ_NAME "txtc"
+#define CNS21XX_GEC_TXQE_IRQ_NAME "txqe"
+
+enum cns21xx_gec_phy_type {
+ CNS21XX_GEC_PHY_TYPE_INTERNAL = 0,
+ CNS21XX_GEC_PHY_TYPE_VSC8601,
+ CNS21XX_GEC_PHY_TYPE_IP101A,
+ CNS21XX_GEC_PHY_TYPE_IP1001,
+};
+
+struct cns21xx_gec_plat_data {
+ u8 *mac_addr;
+ enum cns21xx_gec_phy_type phy_type;
+ u8 phy_addr;
+};
+
+#endif /* _CNS21XX_GEC_PLATFORM_H */

View file

@ -0,0 +1,242 @@
--- a/arch/arm/mach-cns21xx/Kconfig
+++ b/arch/arm/mach-cns21xx/Kconfig
@@ -1,6 +1,16 @@
if ARCH_CNS21XX
menu "Cavium Networks CNS21xx based machines"
+
+config MACH_NS_K330
+ bool "NS-K330 NAS"
+ select CNS21XX_DEV_GEC
+ select CNS21XX_DEV_SPI_MASTER
+ select CNS21XX_DEV_USB
+ help
+ Say Y here if you intend to run this kernel on the
+ NS-K330 NAS board.
+
endmenu
config CNS21XX_DEV_GEC
--- /dev/null
+++ b/arch/arm/mach-cns21xx/mach-ns-k330.c
@@ -0,0 +1,212 @@
+/*
+ * NS-K330 NAS board support
+ *
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <mach/hardware.h>
+#include <mach/cns21xx.h>
+#include <mach/cns21xx_misc.h>
+
+#include "common.h"
+#include "dev-gec.h"
+
+#define NS_K330_GPIO_LED_LINK 1
+#define NS_K330_GPIO_LED_USB1 16
+#define NS_K330_GPIO_LED_USB2 17
+#define NS_K330_GPIO_LED_ETH_GREEN 22
+#define NS_K330_GPIO_LED_ETH_ORANGE 23
+
+#define NS_K330_GPIO_BTN_RESET 13
+#define NS_K330_GPIO_BTN_USB1 14
+#define NS_K330_GPIO_BTN_USB2 15
+
+#ifdef CONFIG_MTD_PARTITIONS
+static struct mtd_partition ns_k330_partitions[] = {
+ {
+ .name = "boot",
+ .offset = 0x0,
+ .size = 0x040000,
+ .mask_flags = MTD_WRITEABLE,
+ }, {
+ .name = "config",
+ .offset = 0x040000,
+ .size = 0x020000,
+ .mask_flags = MTD_WRITEABLE,
+ }, {
+ .name = "kernel",
+ .offset = 0x060000,
+ .size = 0x100000,
+ }, {
+ .name = "rootfs",
+ .offset = 0x160000,
+ .size = 0x290000,
+ }, {
+ .name = "firmware",
+ .offset = 0x060000,
+ .size = 0x390000,
+ },
+};
+#else
+#define ns_k330_partitions NULL
+#define ns_k330_num_partitions 0
+#endif /* CONFIG_MTD_PARTITIONS */
+
+static struct flash_platform_data ns_k330_flash_data = {
+ .parts = ns_k330_partitions,
+ .nr_parts = ARRAY_SIZE(ns_k330_partitions),
+};
+
+static struct spi_board_info ns_k330_spi_board_info[] = {
+ {
+ .bus_num = 0,
+ .chip_select = 0,
+ .max_speed_hz = 25000000,
+ .modalias = "m25p80",
+ .platform_data = &ns_k330_flash_data,
+ }
+};
+
+static struct gpio_led ns_k330_gpio_leds[] = {
+ {
+ .name = "ns-k330:red:link",
+ .gpio = NS_K330_GPIO_LED_LINK,
+ .active_low = 1,
+ }, {
+ .name = "ns-k330:green:usb1",
+ .gpio = NS_K330_GPIO_LED_USB1,
+ .active_low = 1,
+ }, {
+ .name = "ns-k330:green:usb2",
+ .gpio = NS_K330_GPIO_LED_USB2,
+ .active_low = 1,
+ }, {
+ .name = "ns-k330:green:eth",
+ .gpio = NS_K330_GPIO_LED_ETH_GREEN,
+ .active_low = 1,
+ }, {
+ .name = "ns-k330:orange:eth",
+ .gpio = NS_K330_GPIO_LED_ETH_ORANGE,
+ .active_low = 1,
+ }
+};
+
+static struct gpio_led_platform_data ns_k330_gpio_leds_data = {
+ .num_leds = ARRAY_SIZE(ns_k330_gpio_leds),
+ .leds = ns_k330_gpio_leds,
+};
+
+static struct platform_device ns_k330_gpio_leds_device = {
+ .name = "leds-gpio",
+ .id = -1,
+ .dev.platform_data = &ns_k330_gpio_leds_data,
+};
+
+static struct gpio_keys_button ns_k330_gpio_keys[] = {
+ {
+ .code = KEY_RESTART,
+ .gpio = NS_K330_GPIO_BTN_RESET,
+ .desc = "Reset Button",
+ .active_low = 1,
+ },
+ {
+ .code = BTN_0,
+ .gpio = NS_K330_GPIO_BTN_USB1,
+ .desc = "USB1 Button",
+ .active_low = 1,
+ },
+ {
+ .code = BTN_1,
+ .gpio = NS_K330_GPIO_BTN_USB2,
+ .desc = "USB2 Button",
+ .active_low = 0,
+ },
+};
+
+static struct gpio_keys_platform_data ns_k330_gpio_keys_data = {
+ .buttons = ns_k330_gpio_keys,
+ .nbuttons = ARRAY_SIZE(ns_k330_gpio_keys),
+};
+
+static struct platform_device ns_k330_gpio_keys_device = {
+ .name = "gpio-keys",
+ .id = -1,
+ .num_resources = 0,
+ .dev = {
+ .platform_data = &ns_k330_gpio_keys_data,
+ },
+};
+
+static void __init ns_k330_fixup(struct machine_desc *desc,
+ struct tag *tags, char **cmdline,
+ struct meminfo *mi)
+{
+ struct tag *t;
+
+ /* The board has 32MB of RAM mapped at 0. */
+ mi->nr_banks = 1;
+ mi->bank[0].start = 0;
+ mi->bank[0].size = SZ_32M;
+
+ for (t = tags; t->hdr.size; t = tag_next(t)) {
+ switch (t->hdr.tag) {
+ case ATAG_CORE:
+ if (t->u.core.rootdev == 255)
+ t->u.core.rootdev = 0;
+ break;
+ }
+ }
+}
+
+static void __init ns_k330_init(void)
+{
+ cns21xx_gpio_init();
+
+ HAL_MISC_DISABLE_LED012_PINS();
+ HAL_MISC_DISABLE_I2C_PINS();
+ HAL_MISC_DISABLE_I2S_PINS();
+
+ cns21xx_register_uart0();
+ cns21xx_register_wdt();
+ cns21xx_register_usb();
+ cns21xx_register_spi_master(-1, ns_k330_spi_board_info,
+ ARRAY_SIZE(ns_k330_spi_board_info));
+
+ cns21xx_gec_data.phy_type = CNS21XX_GEC_PHY_TYPE_INTERNAL;
+ cns21xx_register_gec();
+
+ platform_device_register(&ns_k330_gpio_leds_device);
+ platform_device_register(&ns_k330_gpio_keys_device);
+}
+
+MACHINE_START(NS_K330, "NS-K330 NAS")
+ .phys_io = CNS21XX_PHYS_IO,
+ .io_pg_offst = CNS21XX_IO_PAGE_OFFSET,
+ .boot_params = 0x100,
+ .fixup = ns_k330_fixup,
+ .map_io = cns21xx_map_io,
+ .init_irq = cns21xx_init_irq,
+ .timer = &cns21xx_timer,
+ .init_machine = ns_k330_init,
+MACHINE_END
--- a/arch/arm/mach-cns21xx/Makefile
+++ b/arch/arm/mach-cns21xx/Makefile
@@ -12,4 +12,4 @@ obj-$(CONFIG_CNS21XX_DEV_USB) += dev-us
obj-$(CONFIG_CNS21XX_DEV_SPI_MASTER) += dev-spi-master.o
# machine specific files
-
+obj-$(CONFIG_MACH_NS_K330) += mach-ns-k330.o

View file

@ -0,0 +1,209 @@
--- a/arch/arm/mach-cns21xx/Kconfig
+++ b/arch/arm/mach-cns21xx/Kconfig
@@ -2,6 +2,15 @@ if ARCH_CNS21XX
menu "Cavium Networks CNS21xx based machines"
+config MACH_NSB3AST
+ bool "AGESTAR NSB3AST support"
+ select CNS21XX_DEV_GEC
+ select CNS21XX_DEV_SPI_MASTER
+ select CNS21XX_DEV_USB
+ help
+ Say Y here if you intend to run this kernel on the
+ AGESTAR NSB3AST board.
+
config MACH_NS_K330
bool "NS-K330 NAS"
select CNS21XX_DEV_GEC
--- /dev/null
+++ b/arch/arm/mach-cns21xx/mach-nsb3ast.c
@@ -0,0 +1,181 @@
+/*
+ * AGESTAR NSB3AST board support
+ *
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <mach/hardware.h>
+#include <mach/cns21xx.h>
+#include <mach/cns21xx_misc.h>
+
+#include "common.h"
+#include "dev-gec.h"
+
+#ifdef CONFIG_MTD_PARTITIONS
+static struct mtd_partition nsb3ast_partitions[] = {
+ {
+ .name = "armboot",
+ .offset = 0x0,
+ .size = 0x040000,
+ .mask_flags = MTD_WRITEABLE,
+ }, {
+ .name = "kernel",
+ .offset = 0x040000,
+ .size = 0x100000,
+ }, {
+ .name = "rootfs",
+ .offset = 0x140000,
+ .size = 0x6c0000,
+ }, {
+ .name = "firmware",
+ .offset = 0x040000,
+ .size = 0x7c0000,
+ }, {
+ .name = "wholeflash",
+ .offset = 0x0,
+ .size = 0x800000,
+ .mask_flags = MTD_WRITEABLE,
+ },
+};
+#else
+#define nsb3ast_partitions NULL
+#define nsb3ast_num_partitions 0
+#endif /* CONFIG_MTD_PARTITIONS */
+
+static struct flash_platform_data nsb3ast_flash_data = {
+ .parts = nsb3ast_partitions,
+ .nr_parts = ARRAY_SIZE(nsb3ast_partitions),
+};
+
+static struct spi_board_info nsb3ast_spi_board_info[] = {
+ {
+ .bus_num = 0,
+ .chip_select = 0,
+ .max_speed_hz = 25000000,
+ .modalias = "m25p80",
+ .platform_data = &nsb3ast_flash_data,
+ }
+};
+
+static struct gpio_led nsb3ast_gpio_leds[] = {
+ {
+ .name = "nsb3ast:red:d1",
+ .gpio = 15,
+ .active_low = 1,
+ }, {
+ .name = "nsb3ast:amber:eth",
+ .gpio = 22,
+ .active_low = 1,
+ }
+};
+
+static struct gpio_led_platform_data nsb3ast_gpio_leds_data = {
+ .num_leds = ARRAY_SIZE(nsb3ast_gpio_leds),
+ .leds = nsb3ast_gpio_leds,
+};
+
+static struct platform_device nsb3ast_gpio_leds_device = {
+ .name = "leds-gpio",
+ .id = -1,
+ .dev.platform_data = &nsb3ast_gpio_leds_data,
+};
+
+static struct gpio_keys_button nsb3ast_gpio_keys[] = {
+ {
+ .code = KEY_RESTART,
+ .gpio = 0,
+ .desc = "Reset Button",
+ .active_low = 1,
+ },
+ {
+ .code = BTN_0,
+ .gpio = 2,
+ .desc = "USB Button",
+ .active_low = 0,
+ },
+};
+
+static struct gpio_keys_platform_data nsb3ast_gpio_keys_data = {
+ .buttons = nsb3ast_gpio_keys,
+ .nbuttons = ARRAY_SIZE(nsb3ast_gpio_keys),
+};
+
+static struct platform_device nsb3ast_gpio_keys_device = {
+ .name = "gpio-keys",
+ .id = -1,
+ .num_resources = 0,
+ .dev = {
+ .platform_data = &nsb3ast_gpio_keys_data,
+ },
+};
+
+static void __init nsb3ast_fixup(struct machine_desc *desc,
+ struct tag *tags, char **cmdline,
+ struct meminfo *mi)
+{
+ struct tag *t;
+
+ /* The board has 32MB of RAM mapped at 0. */
+ mi->nr_banks = 1;
+ mi->bank[0].start = 0;
+ mi->bank[0].size = SZ_32M;
+
+ for (t = tags; t->hdr.size; t = tag_next(t)) {
+ switch (t->hdr.tag) {
+ case ATAG_CORE:
+ if (t->u.core.rootdev == 255)
+ t->u.core.rootdev = 0;
+ break;
+ }
+ }
+}
+
+static void __init nsb3ast_init(void)
+{
+ cns21xx_gpio_init();
+ cns21xx_register_uart0();
+ cns21xx_register_uart1();
+ cns21xx_register_wdt();
+ cns21xx_register_usb();
+ cns21xx_register_spi_master(-1, nsb3ast_spi_board_info,
+ ARRAY_SIZE(nsb3ast_spi_board_info));
+
+ cns21xx_gec_data.phy_type = CNS21XX_GEC_PHY_TYPE_INTERNAL;
+ cns21xx_register_gec();
+
+ HAL_MISC_DISABLE_LED012_PINS();
+ platform_device_register(&nsb3ast_gpio_leds_device);
+ platform_device_register(&nsb3ast_gpio_keys_device);
+}
+
+MACHINE_START(NSB3AST, "AGESTAR NSB3AST")
+ .phys_io = CNS21XX_PHYS_IO,
+ .io_pg_offst = CNS21XX_IO_PAGE_OFFSET,
+ .boot_params = 0x100,
+ .fixup = nsb3ast_fixup,
+ .map_io = cns21xx_map_io,
+ .init_irq = cns21xx_init_irq,
+ .timer = &cns21xx_timer,
+ .init_machine = nsb3ast_init,
+MACHINE_END
--- a/arch/arm/mach-cns21xx/Makefile
+++ b/arch/arm/mach-cns21xx/Makefile
@@ -13,3 +13,4 @@ obj-$(CONFIG_CNS21XX_DEV_SPI_MASTER) +=
# machine specific files
obj-$(CONFIG_MACH_NS_K330) += mach-ns-k330.o
+obj-$(CONFIG_MACH_NSB3AST) += mach-nsb3ast.o

View file

@ -0,0 +1,438 @@
From 248d9a5b63bba72bfc316b8a48c6163fce5acc22 Mon Sep 17 00:00:00 2001
From: Paulius Zaleckas <paulius.zaleckas@gmail.com>
Date: Thu, 18 Feb 2010 21:53:01 +0200
Subject: [PATCH] ARM: Use cache alignment from asm/cache.h
Make code more optimal for ARM variants with
different cache line size.
Signed-off-by: Paulius Zaleckas <paulius.zaleckas@gmail.com>
---
arch/arm/boot/compressed/head.S | 11 ++++++-----
arch/arm/include/asm/dma-mapping.h | 2 +-
arch/arm/kernel/entry-armv.S | 31 ++++++++++++++++---------------
arch/arm/kernel/entry-common.S | 7 ++++---
arch/arm/kernel/head.S | 3 ++-
arch/arm/kernel/vmlinux.lds.S | 5 +++--
arch/arm/lib/copy_page.S | 2 +-
arch/arm/lib/memchr.S | 3 ++-
arch/arm/lib/memset.S | 3 ++-
arch/arm/lib/memzero.S | 3 ++-
arch/arm/lib/strchr.S | 3 ++-
arch/arm/lib/strncpy_from_user.S | 3 ++-
arch/arm/lib/strnlen_user.S | 3 ++-
arch/arm/lib/strrchr.S | 3 ++-
arch/arm/mm/abort-ev4.S | 3 ++-
arch/arm/mm/abort-nommu.S | 3 ++-
16 files changed, 51 insertions(+), 37 deletions(-)
--- a/arch/arm/boot/compressed/head.S
+++ b/arch/arm/boot/compressed/head.S
@@ -9,6 +9,7 @@
* published by the Free Software Foundation.
*/
#include <linux/linkage.h>
+#include <asm/cache.h>
/*
* Debugging stuff
@@ -355,7 +356,7 @@ params: ldr r0, =0x10000100 @ params_p
* This routine must preserve:
* r4, r5, r6, r7, r8
*/
- .align 5
+ .align L1_CACHE_SHIFT
cache_on: mov r3, #8 @ cache_on function
b call_cache_fn
@@ -544,7 +545,7 @@ __common_mmu_cache_on:
mcr p15, 0, r3, c2, c0, 0 @ load page table pointer
mcr p15, 0, r1, c3, c0, 0 @ load domain access control
b 1f
- .align 5 @ cache line aligned
+ .align L1_CACHE_SHIFT @ cache line aligned
1: mcr p15, 0, r0, c1, c0, 0 @ load control register
mrc p15, 0, r0, c1, c0, 0 @ and read it back to
sub pc, lr, r0, lsr #32 @ properly flush pipeline
@@ -563,7 +564,7 @@ __common_mmu_cache_on:
* r8 = atags pointer
* r9-r12,r14 = corrupted
*/
- .align 5
+ .align L1_CACHE_SHIFT
reloc_start: add r9, r5, r0
sub r9, r9, #128 @ do not copy the stack
debug_reloc_start
@@ -793,7 +794,7 @@ proc_types:
* This routine must preserve:
* r4, r6, r7
*/
- .align 5
+ .align L1_CACHE_SHIFT
cache_off: mov r3, #12 @ cache_off function
b call_cache_fn
@@ -868,7 +869,7 @@ __armv3_mmu_cache_off:
* This routine must preserve:
* r0, r4, r5, r6, r7
*/
- .align 5
+ .align L1_CACHE_SHIFT
cache_clean_flush:
mov r3, #16
b call_cache_fn
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -23,6 +23,7 @@
#include <asm/unwind.h>
#include <asm/unistd.h>
#include <asm/tls.h>
+#include <asm/cache.h>
#include "entry-header.S"
@@ -167,7 +168,7 @@ ENDPROC(__und_invalid)
stmia r5, {r0 - r4}
.endm
- .align 5
+ .align L1_CACHE_SHIFT
__dabt_svc:
svc_entry
@@ -215,7 +216,7 @@ __dabt_svc:
UNWIND(.fnend )
ENDPROC(__dabt_svc)
- .align 5
+ .align L1_CACHE_SHIFT
__irq_svc:
svc_entry
@@ -259,7 +260,7 @@ svc_preempt:
b 1b
#endif
- .align 5
+ .align L1_CACHE_SHIFT
__und_svc:
#ifdef CONFIG_KPROBES
@ If a kprobe is about to simulate a "stmdb sp..." instruction,
@@ -305,7 +306,7 @@ __und_svc:
UNWIND(.fnend )
ENDPROC(__und_svc)
- .align 5
+ .align L1_CACHE_SHIFT
__pabt_svc:
svc_entry
@@ -341,7 +342,7 @@ __pabt_svc:
UNWIND(.fnend )
ENDPROC(__pabt_svc)
- .align 5
+ .align L1_CACHE_SHIFT
.LCcralign:
.word cr_alignment
#ifdef MULTI_DABORT
@@ -414,7 +415,7 @@ ENDPROC(__pabt_svc)
#endif
.endm
- .align 5
+ .align L1_CACHE_SHIFT
__dabt_usr:
usr_entry
kuser_cmpxchg_check
@@ -446,7 +447,7 @@ __dabt_usr:
UNWIND(.fnend )
ENDPROC(__dabt_usr)
- .align 5
+ .align L1_CACHE_SHIFT
__irq_usr:
usr_entry
kuser_cmpxchg_check
@@ -475,7 +476,7 @@ ENDPROC(__irq_usr)
.ltorg
- .align 5
+ .align L1_CACHE_SHIFT
__und_usr:
usr_entry
@@ -691,7 +692,7 @@ __und_usr_unknown:
b do_undefinstr
ENDPROC(__und_usr_unknown)
- .align 5
+ .align L1_CACHE_SHIFT
__pabt_usr:
usr_entry
@@ -805,7 +806,7 @@ ENDPROC(__switch_to)
#endif
.endm
- .align 5
+ .align L1_CACHE_SHIFT
.globl __kuser_helper_start
__kuser_helper_start:
@@ -845,7 +846,7 @@ __kuser_memory_barrier: @ 0xffff0fa0
smp_dmb
usr_ret lr
- .align 5
+ .align L1_CACHE_SHIFT
/*
* Reference prototype:
@@ -972,7 +973,7 @@ kuser_cmpxchg_fixup:
#endif
- .align 5
+ .align L1_CACHE_SHIFT
/*
* Reference prototype:
@@ -1050,7 +1051,7 @@ __kuser_helper_end:
* of which is copied into r0 for the mode specific abort handler.
*/
.macro vector_stub, name, mode, correction=0
- .align 5
+ .align L1_CACHE_SHIFT
vector_\name:
.if \correction
@@ -1181,7 +1182,7 @@ __stubs_start:
.long __und_invalid @ e
.long __und_invalid @ f
- .align 5
+ .align L1_CACHE_SHIFT
/*=============================================================================
* Undefined FIQs
@@ -1211,7 +1212,7 @@ vector_addrexcptn:
* We group all the following data together to optimise
* for CPUs with separate I & D caches.
*/
- .align 5
+ .align L1_CACHE_SHIFT
.LCvswi:
.word vector_swi
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -10,13 +10,14 @@
#include <asm/unistd.h>
#include <asm/ftrace.h>
+#include <asm/cache.h>
#include <mach/entry-macro.S>
#include <asm/unwind.h>
#include "entry-header.S"
- .align 5
+ .align L1_CACHE_SHIFT
/*
* This is the fast syscall return path. We do as little as
* possible here, and this includes saving r0 back into the SVC
@@ -260,7 +261,7 @@ ENDPROC(ftrace_stub)
#define A710(code...)
#endif
- .align 5
+ .align L1_CACHE_SHIFT
ENTRY(vector_swi)
sub sp, sp, #S_FRAME_SIZE
stmia sp, {r0 - r12} @ Calling r0 - r12
@@ -404,7 +405,7 @@ __sys_trace_return:
bl syscall_trace
b ret_slow_syscall
- .align 5
+ .align L1_CACHE_SHIFT
#ifdef CONFIG_ALIGNMENT_TRAP
.type __cr_alignment, #object
__cr_alignment:
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -21,6 +21,7 @@
#include <asm/memory.h>
#include <asm/thread_info.h>
#include <asm/system.h>
+#include <asm/cache.h>
#ifdef CONFIG_DEBUG_LL
#include <mach/debug-macro.S>
@@ -373,7 +374,7 @@ ENDPROC(__enable_mmu)
*
* other registers depend on the function called upon completion
*/
- .align 5
+ .align L1_CACHE_SHIFT
__turn_mmu_on:
mov r0, r0
mcr p15, 0, r0, c1, c0, 0 @ write control reg
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -7,6 +7,7 @@
#include <asm/thread_info.h>
#include <asm/memory.h>
#include <asm/page.h>
+#include <asm/cache.h>
#define PROC_INFO \
VMLINUX_SYMBOL(__proc_info_begin) = .; \
--- a/arch/arm/lib/copy_page.S
+++ b/arch/arm/lib/copy_page.S
@@ -17,7 +17,7 @@
#define COPY_COUNT (PAGE_SZ / (2 * L1_CACHE_BYTES) PLD( -1 ))
.text
- .align 5
+ .align L1_CACHE_SHIFT
/*
* StrongARM optimised copy_page routine
* now 1.78bytes/cycle, was 1.60 bytes/cycle (50MHz bus -> 89MB/s)
--- a/arch/arm/lib/memchr.S
+++ b/arch/arm/lib/memchr.S
@@ -11,9 +11,10 @@
*/
#include <linux/linkage.h>
#include <asm/assembler.h>
+#include <asm/cache.h>
.text
- .align 5
+ .align L1_CACHE_SHIFT
ENTRY(memchr)
1: subs r2, r2, #1
bmi 2f
--- a/arch/arm/lib/memset.S
+++ b/arch/arm/lib/memset.S
@@ -11,9 +11,10 @@
*/
#include <linux/linkage.h>
#include <asm/assembler.h>
+#include <asm/cache.h>
.text
- .align 5
+ .align L1_CACHE_SHIFT
.word 0
1: subs r2, r2, #4 @ 1 do we have enough
--- a/arch/arm/lib/memzero.S
+++ b/arch/arm/lib/memzero.S
@@ -9,9 +9,10 @@
*/
#include <linux/linkage.h>
#include <asm/assembler.h>
+#include <asm/cache.h>
.text
- .align 5
+ .align L1_CACHE_SHIFT
.word 0
/*
* Align the pointer in r0. r3 contains the number of bytes that we are
--- a/arch/arm/lib/strchr.S
+++ b/arch/arm/lib/strchr.S
@@ -11,9 +11,10 @@
*/
#include <linux/linkage.h>
#include <asm/assembler.h>
+#include <asm/cache.h>
.text
- .align 5
+ .align L1_CACHE_SHIFT
ENTRY(strchr)
and r1, r1, #0xff
1: ldrb r2, [r0], #1
--- a/arch/arm/lib/strncpy_from_user.S
+++ b/arch/arm/lib/strncpy_from_user.S
@@ -10,9 +10,10 @@
#include <linux/linkage.h>
#include <asm/assembler.h>
#include <asm/errno.h>
+#include <asm/cache.h>
.text
- .align 5
+ .align L1_CACHE_SHIFT
/*
* Copy a string from user space to kernel space.
--- a/arch/arm/lib/strnlen_user.S
+++ b/arch/arm/lib/strnlen_user.S
@@ -10,9 +10,10 @@
#include <linux/linkage.h>
#include <asm/assembler.h>
#include <asm/errno.h>
+#include <asm/cache.h>
.text
- .align 5
+ .align L1_CACHE_SHIFT
/* Prototype: unsigned long __strnlen_user(const char *str, long n)
* Purpose : get length of a string in user memory
--- a/arch/arm/lib/strrchr.S
+++ b/arch/arm/lib/strrchr.S
@@ -11,9 +11,10 @@
*/
#include <linux/linkage.h>
#include <asm/assembler.h>
+#include <asm/cache.h>
.text
- .align 5
+ .align L1_CACHE_SHIFT
ENTRY(strrchr)
mov r3, #0
1: ldrb r2, [r0], #1
--- a/arch/arm/mm/abort-ev4.S
+++ b/arch/arm/mm/abort-ev4.S
@@ -1,5 +1,6 @@
#include <linux/linkage.h>
#include <asm/assembler.h>
+#include <asm/cache.h>
/*
* Function: v4_early_abort
*
@@ -17,7 +18,7 @@
* abort here if the I-TLB and D-TLB aren't seeing the same
* picture. Unfortunately, this does happen. We live with it.
*/
- .align 5
+ .align L1_CACHE_SHIFT
ENTRY(v4_early_abort)
mrc p15, 0, r1, c5, c0, 0 @ get FSR
mrc p15, 0, r0, c6, c0, 0 @ get FAR
--- a/arch/arm/mm/abort-nommu.S
+++ b/arch/arm/mm/abort-nommu.S
@@ -1,5 +1,6 @@
#include <linux/linkage.h>
#include <asm/assembler.h>
+#include <asm/cache.h>
/*
* Function: nommu_early_abort
*
@@ -12,7 +13,7 @@
* Note: There is no FSR/FAR on !CPU_CP15_MMU cores.
* Just fill zero into the registers.
*/
- .align 5
+ .align L1_CACHE_SHIFT
ENTRY(nommu_early_abort)
mov r0, #0 @ clear r0, r1 (no FSR/FAR)
mov r1, #0

View file

@ -0,0 +1,24 @@
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -48,6 +48,10 @@
#define for_each_console(con) \
for (con = console_drivers; con != NULL; con = con->next)
+#ifdef CONFIG_DEBUG_LL
+extern void printascii(char *);
+#endif /* CONFIG_DEBUG_LL */
+
/*
* Architectures can override it:
*/
@@ -780,6 +784,10 @@ asmlinkage int vprintk(const char *fmt,
}
}
+#ifdef CONFIG_DEBUG_LL
+ printascii(printk_buf);
+#endif
+
/*
* Copy the output into log_buf. If the caller didn't provide
* appropriate log level tags, we insert them here

View file

@ -0,0 +1,47 @@
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -975,10 +975,15 @@ source "arch/arm/mach-vexpress/Kconfig"
source "arch/arm/mach-w90x900/Kconfig"
+source "arch/arm/plat-fa/Kconfig"
+
# Definitions to make life easier
config ARCH_ACORN
bool
+config PLAT_FA
+ bool
+
config PLAT_IOP
bool
select GENERIC_CLOCKEVENTS
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -204,6 +204,7 @@ plat-$(CONFIG_ARCH_OMAP) := omap
plat-$(CONFIG_ARCH_S3C64XX) := samsung
plat-$(CONFIG_ARCH_STMP3XXX) := stmp3xxx
plat-$(CONFIG_ARCH_TCC_926) := tcc
+plat-$(CONFIG_PLAT_FA) := fa
plat-$(CONFIG_PLAT_IOP) := iop
plat-$(CONFIG_PLAT_NOMADIK) := nomadik
plat-$(CONFIG_PLAT_ORION) := orion
--- /dev/null
+++ b/arch/arm/plat-fa/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for the linux kernel.
+#
+
+obj-y :=
+
+obj-m :=
+obj-n :=
+obj- :=
+
--- /dev/null
+++ b/arch/arm/plat-fa/Kconfig
@@ -0,0 +1,3 @@
+if PLAT_FA
+
+endif

View file

@ -0,0 +1,143 @@
--- /dev/null
+++ b/arch/arm/plat-fa/include/plat/time.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _FA_TIME_H
+#define _FA_TIME_H
+
+#define FA_TIMER1 0
+#define FA_TIMER2 1
+#define FA_TIMER3 2
+
+int __init fa_timer_init(unsigned int mapbase, unsigned int irq,
+ unsigned int timer, unsigned int freq);
+
+#endif /* _FA_TIME_H */
--- /dev/null
+++ b/arch/arm/plat-fa/time.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2001-2006 Storlink, Corp.
+ * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+#include <asm/mach/time.h>
+#include <plat/time.h>
+
+/*
+ * Register definitions for the timers
+ */
+#define TIMER_COUNT(_base, _tmr) ((_base) + 0x00 + (_tmr) * 0x10)
+#define TIMER_LOAD(_base, _tmr) ((_base) + 0x04 + (_tmr) * 0x10)
+#define TIMER_MATCH1(_base, _tmr) ((_base) + 0x08 + (_tmr) * 0x10)
+#define TIMER_MATCH2(_base, _tmr) ((_base) + 0x0c + (_tmr) * 0x10)
+
+#define TIMER_CR(_base) ((_base) + 0x30)
+#define TIMER_STATUS(_base) ((_base) + 0x34)
+#define TIMER_MASK(_base) ((_base) + 0x38)
+
+#define TIMER_SIZE 0x3c
+
+#define TIMER_CR_ENABLE(x) (1 << ((x) * 3))
+#define TIMER_CR_CLOCK(x) (1 << ((x) * 3 + 1))
+#define TIMER_CR_INT(x) (1 << ((x) * 3 + 2))
+#define TIMER_CR_DOWN(x) (1 << ((x) * 3 + 9))
+
+#define TIMER_MASK_MATCH1(x) (1 << ((x) * 3))
+#define TIMER_MASK_MATCH2(x) (1 << ((x) * 3 + 1))
+#define TIMER_MASK_OF(x) (1 << ((x) * 3 + 2))
+
+#define TIMER_MASK_ALL 0x7ff
+
+/*
+ * IRQ handler for the timer
+ */
+static irqreturn_t fa_timer_interrupt(int irq, void *dev_id)
+{
+ timer_tick();
+ return IRQ_HANDLED;
+}
+
+static struct irqaction fa_timer_irq = {
+ .name = "Timer Tick",
+ .flags = IRQF_DISABLED | IRQF_TIMER,
+ .handler = fa_timer_interrupt,
+};
+
+int __init fa_timer_init(unsigned int mapbase, unsigned int irq,
+ unsigned int timer, unsigned int freq)
+{
+ void __iomem *base;
+
+ base = ioremap(mapbase, TIMER_SIZE);
+ if (!base)
+ return -ENOMEM;
+
+ /* disable timers, clear status and mask all interrupts */
+ __raw_writel(0, TIMER_CR(base));
+ __raw_writel(0, TIMER_STATUS(base));
+ __raw_writel(TIMER_MASK_ALL, TIMER_MASK(base));
+
+ /*
+ * Make irqs happen for the system timer
+ */
+ setup_irq(irq, &fa_timer_irq);
+
+ /* Setup the timer */
+ __raw_writel(freq / HZ, TIMER_COUNT(base, timer));
+ __raw_writel(freq / HZ, TIMER_LOAD(base, timer));
+ __raw_writel(0, TIMER_MATCH1(base, timer));
+ __raw_writel(0, TIMER_MATCH2(base, timer));
+
+ /* Enable interrupt and start the timer */
+ __raw_writel(TIMER_MASK_ALL & ~TIMER_MASK_OF(timer),
+ TIMER_MASK(base));
+
+ __raw_writel(TIMER_CR_ENABLE(timer) |
+ TIMER_CR_INT(timer) |
+ TIMER_CR_DOWN(timer),
+ TIMER_CR(base));
+
+ iounmap(base);
+
+ return 0;
+}
--- a/arch/arm/plat-fa/Kconfig
+++ b/arch/arm/plat-fa/Kconfig
@@ -1,3 +1,6 @@
if PLAT_FA
+config PLAT_FA_TIME
+ def_bool n
+
endif
--- a/arch/arm/plat-fa/Makefile
+++ b/arch/arm/plat-fa/Makefile
@@ -4,6 +4,8 @@
obj-y :=
+obj-$(CONFIG_PLAT_FA_TIME) += time.o
+
obj-m :=
obj-n :=
obj- :=

View file

@ -0,0 +1,335 @@
--- /dev/null
+++ b/arch/arm/plat-fa/gpio.c
@@ -0,0 +1,275 @@
+/*
+ * Gpiochip and interrupt routines for Faraday FA526 based SoCs
+ *
+ * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Based on plat-mxc/gpio.c:
+ * MXC GPIO supchip. (c) 2008 Daniel Mack <daniel@caiaq.de>
+ * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/spinlock.h>
+
+#include <plat/gpio.h>
+
+#define GPIO_DATA_OUT 0x0
+#define GPIO_DATA_IN 0x4
+#define GPIO_DIR 0x8
+#define GPIO_DATA_SET 0x10
+#define GPIO_DATA_CLR 0x14
+#define GPIO_PULL_EN 0x18
+#define GPIO_PULL_TYPE 0x1C
+#define GPIO_INT_EN 0x20
+#define GPIO_INT_STAT 0x24
+#define GPIO_INT_MASK 0x2C
+#define GPIO_INT_CLR 0x30
+#define GPIO_INT_TYPE 0x34
+#define GPIO_INT_BOTH_EDGE 0x38
+#define GPIO_INT_LEVEL 0x3C
+#define GPIO_DEBOUNCE_EN 0x40
+#define GPIO_DEBOUNCE_PRESCALE 0x44
+
+#define GPIO_REGS_SIZE 0x48
+
+static DEFINE_SPINLOCK(fa_gpio_lock);
+
+static inline struct fa_gpio_chip *to_fgc(struct gpio_chip *chip)
+{
+ return container_of(chip, struct fa_gpio_chip, gpio_chip);
+}
+
+static void _fa_gpio_irq_setenable(unsigned int irq, int enable)
+{
+ struct fa_gpio_chip *fgc = get_irq_chip_data(irq);
+ void __iomem *base = fgc->mem_base;
+ unsigned int gpio = irq - fgc->irq_base;
+ unsigned int reg;
+
+ reg = __raw_readl(base + GPIO_INT_EN);
+ reg = (reg & (~(1 << gpio))) | (!!enable << gpio);
+ __raw_writel(reg, base + GPIO_INT_EN);
+}
+
+static void fa_gpio_irq_ack(unsigned int irq)
+{
+ struct fa_gpio_chip *fgc = get_irq_chip_data(irq);
+ unsigned int gpio = irq - fgc->irq_base;
+
+ __raw_writel(1 << gpio, fgc->mem_base + GPIO_INT_CLR);
+}
+
+static void fa_gpio_irq_mask(unsigned int irq)
+{
+ _fa_gpio_irq_setenable(irq, 0);
+}
+
+static void fa_gpio_irq_unmask(unsigned int irq)
+{
+ _fa_gpio_irq_setenable(irq, 1);
+}
+
+static int fa_gpio_irq_set_type(unsigned int irq, unsigned int type)
+{
+ struct fa_gpio_chip *fgc = get_irq_chip_data(irq);
+ void __iomem *base = fgc->mem_base;
+ unsigned int gpio = irq - fgc->irq_base;
+ unsigned int gpio_mask = 1 << gpio;
+ unsigned int reg_both, reg_level, reg_type;
+
+ reg_type = __raw_readl(base + GPIO_INT_TYPE);
+ reg_level = __raw_readl(base + GPIO_INT_LEVEL);
+ reg_both = __raw_readl(base + GPIO_INT_BOTH_EDGE);
+
+ switch (type) {
+ case IRQ_TYPE_EDGE_BOTH:
+ reg_type &= ~gpio_mask;
+ reg_both |= gpio_mask;
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ reg_type &= ~gpio_mask;
+ reg_both &= ~gpio_mask;
+ reg_level &= ~gpio_mask;
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ reg_type &= ~gpio_mask;
+ reg_both &= ~gpio_mask;
+ reg_level |= gpio_mask;
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ reg_type |= gpio_mask;
+ reg_level &= ~gpio_mask;
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ reg_type |= gpio_mask;
+ reg_level |= gpio_mask;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ __raw_writel(reg_type, base + GPIO_INT_TYPE);
+ __raw_writel(reg_level, base + GPIO_INT_LEVEL);
+ __raw_writel(reg_both, base + GPIO_INT_BOTH_EDGE);
+
+ fa_gpio_irq_ack(irq);
+
+ return 0;
+}
+
+static void fa_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+ struct fa_gpio_data *data = get_irq_data(irq);
+ unsigned int chip;
+
+ for (chip = 0; chip < data->nchips; chip++) {
+ struct fa_gpio_chip *fgc = &data->chips[chip];
+ unsigned int status;
+ unsigned int i;
+
+ status = __raw_readl(fgc->mem_base + GPIO_INT_STAT);
+ for (i = fgc->irq_base; status != 0; status >>= 1, i++) {
+ if ((status & 1) == 0)
+ continue;
+
+ BUG_ON(!(irq_desc[i].handle_irq));
+ irq_desc[i].handle_irq(i, &irq_desc[i]);
+ }
+ }
+}
+
+static struct irq_chip fa_gpio_irq_chip = {
+ .name = "GPIO",
+ .ack = fa_gpio_irq_ack,
+ .mask = fa_gpio_irq_mask,
+ .unmask = fa_gpio_irq_unmask,
+ .set_type = fa_gpio_irq_set_type,
+};
+
+static void _fa_gpio_set_direction(struct fa_gpio_chip *fgc, unsigned offset,
+ int is_output)
+{
+ unsigned int reg;
+
+ reg = __raw_readl(fgc->mem_base + GPIO_DIR);
+ if (is_output)
+ reg |= 1 << offset;
+ else
+ reg &= ~(1 << offset);
+ __raw_writel(reg, fgc->mem_base + GPIO_DIR);
+}
+
+static void _fa_gpio_set(struct fa_gpio_chip *fgc, unsigned offset, int value)
+{
+ if (value)
+ __raw_writel(1 << offset, fgc->mem_base + GPIO_DATA_SET);
+ else
+ __raw_writel(1 << offset, fgc->mem_base + GPIO_DATA_CLR);
+}
+
+static void fa_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct fa_gpio_chip *fgc = to_fgc(chip);
+
+ _fa_gpio_set(fgc, offset, value);
+}
+
+static int fa_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct fa_gpio_chip *fgc = to_fgc(chip);
+
+ return (__raw_readl(fgc->mem_base + GPIO_DATA_IN) >> offset) & 1;
+}
+
+static int fa_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ struct fa_gpio_chip *fgc = to_fgc(chip);
+ unsigned long flags;
+
+ spin_lock_irqsave(&fa_gpio_lock, flags);
+
+ _fa_gpio_set_direction(fgc, offset, 0);
+
+ spin_unlock_irqrestore(&fa_gpio_lock, flags);
+
+ return 0;
+}
+
+static int fa_gpio_direction_output(struct gpio_chip *chip,
+ unsigned offset,
+ int value)
+{
+ struct fa_gpio_chip *fgc = to_fgc(chip);
+ unsigned long flags;
+
+ spin_lock_irqsave(&fa_gpio_lock, flags);
+
+ _fa_gpio_set(fgc, offset, value);
+ _fa_gpio_set_direction(fgc, offset, 1);
+
+ spin_unlock_irqrestore(&fa_gpio_lock, flags);
+
+ return 0;
+}
+
+static int fa_gpio_init_chip(struct fa_gpio_chip *fgc)
+{
+ void __iomem *mem_base;
+ unsigned int i;
+ int err;
+
+ mem_base = ioremap(fgc->map_base, GPIO_REGS_SIZE);
+ if (!mem_base)
+ return -ENXIO;
+
+ fgc->mem_base = mem_base;
+
+ fgc->gpio_chip.direction_input = fa_gpio_direction_input;
+ fgc->gpio_chip.direction_output = fa_gpio_direction_output;
+ fgc->gpio_chip.get = fa_gpio_get;
+ fgc->gpio_chip.set = fa_gpio_set;
+
+ /* disable, unmask and clear all interrupts */
+ __raw_writel(0x0, mem_base + GPIO_INT_EN);
+ __raw_writel(0x0, mem_base + GPIO_INT_MASK);
+ __raw_writel(~0x0, mem_base + GPIO_INT_CLR);
+
+ for (i = fgc->irq_base;
+ i < fgc->irq_base + fgc->gpio_chip.ngpio; i++) {
+ set_irq_chip(i, &fa_gpio_irq_chip);
+ set_irq_chip_data(i, fgc);
+ set_irq_handler(i, handle_edge_irq);
+ set_irq_flags(i, IRQF_VALID);
+ }
+
+ err = gpiochip_add(&fgc->gpio_chip);
+ if (err)
+ goto unmap;
+
+ return 0;
+
+ unmap:
+ iounmap(fgc->mem_base);
+ return err;
+}
+
+void __init fa_gpio_init(struct fa_gpio_data *data)
+{
+ unsigned int i;
+
+ for (i = 0; i < data->nchips; i++) {
+ int err;
+
+ err = fa_gpio_init_chip(&data->chips[i]);
+ if (WARN(err, "GPIO init failed\n"))
+ return;
+ }
+
+ set_irq_chained_handler(data->irq, fa_gpio_irq_handler);
+ set_irq_data(data->irq, data);
+}
--- /dev/null
+++ b/arch/arm/plat-fa/include/plat/gpio.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file 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 _FA_GPIO_H
+#define _FA_GPIO_H
+
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+struct fa_gpio_chip {
+ struct gpio_chip gpio_chip;
+ unsigned int map_base;
+ unsigned int irq_base;
+
+ void __iomem *mem_base;
+};
+
+struct fa_gpio_data {
+ struct fa_gpio_chip *chips;
+ unsigned int nchips;
+ unsigned int irq;
+};
+
+void __init fa_gpio_init(struct fa_gpio_data *data);
+
+#endif /* _FA_GPIO_H */
--- a/arch/arm/plat-fa/Kconfig
+++ b/arch/arm/plat-fa/Kconfig
@@ -1,5 +1,8 @@
if PLAT_FA
+config PLAT_FA_GPIO
+ def_bool n
+
config PLAT_FA_TIME
def_bool n
--- a/arch/arm/plat-fa/Makefile
+++ b/arch/arm/plat-fa/Makefile
@@ -4,6 +4,7 @@
obj-y :=
+obj-$(CONFIG_PLAT_FA_GPIO) += gpio.o
obj-$(CONFIG_PLAT_FA_TIME) += time.o
obj-m :=

View file

@ -0,0 +1,456 @@
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -331,6 +331,13 @@ config IMX2_WDT
To compile this driver as a module, choose M here: the
module will be called imx2_wdt.
+config FA_WATCHDOG
+ tristate "Faraday watchdog"
+ depends on ARCH_GEMINI
+ help
+ Say Y here if you want support for the built-in watchdog timer
+ found in some Faraday FA526 based SoCs.
+
# AVR32 Architecture
config AT32AP700X_WDT
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -49,6 +49,7 @@ obj-$(CONFIG_NUC900_WATCHDOG) += nuc900_
obj-$(CONFIG_ADX_WATCHDOG) += adx_wdt.o
obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o
obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o
+obj-$(CONFIG_FA_WATCHDOG) += fa_wdt.o
# AVR32 Architecture
obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
--- /dev/null
+++ b/drivers/watchdog/fa_wdt.c
@@ -0,0 +1,411 @@
+/*
+ * Watchdog driver for SoCs based on the Faraday FA526 core
+ *
+ * Copyright (C) 2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/fs.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/platform_device.h>
+#include <linux/watchdog.h>
+#include <linux/slab.h>
+#include <linux/fa_wdt.h>
+
+#define FA_WDCOUNTER 0x0
+#define FA_WDLOAD 0x4
+#define FA_WDRESTART 0x8
+
+#define WDRESTART_MAGIC 0x5AB9
+
+#define FA_WDCR 0xC
+
+#define WDCR_CLOCK_5MHZ (1 << 4)
+#define WDCR_SYS_RST (1 << 1)
+#define WDCR_ENABLE (1 << 0)
+
+#define WDT_DEFAULT_TIMEOUT 13
+
+/* status bits */
+#define WDT_ACTIVE 0
+#define WDT_OK_TO_CLOSE 1
+
+static unsigned int timeout = WDT_DEFAULT_TIMEOUT;
+static int nowayout = WATCHDOG_NOWAYOUT;
+
+static DEFINE_SPINLOCK(fa_wdt_lock);
+
+static struct platform_device *fa_wdt_dev;
+
+struct fa_wdt_struct {
+ struct resource *res;
+ struct device *dev;
+ void __iomem *base;
+ unsigned long status;
+ unsigned int clock;
+ unsigned int max_timeout;
+};
+
+static const struct watchdog_info fa_wdt_info = {
+ .identity = "Faraday watchdog",
+ .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING |
+ WDIOF_SETTIMEOUT,
+};
+
+/* Disable the watchdog. */
+static void fa_wdt_stop(struct fa_wdt_struct *fa_wdt)
+{
+ spin_lock(&fa_wdt_lock);
+
+ __raw_writel(0, fa_wdt->base + FA_WDCR);
+
+ clear_bit(WDT_ACTIVE, &fa_wdt->status);
+
+ spin_unlock(&fa_wdt_lock);
+}
+
+/* Service the watchdog */
+static void fa_wdt_service(struct fa_wdt_struct *fa_wdt)
+{
+ __raw_writel(WDRESTART_MAGIC, fa_wdt->base + FA_WDRESTART);
+}
+
+/* Enable and reset the watchdog. */
+static void fa_wdt_start(struct fa_wdt_struct *fa_wdt)
+{
+ spin_lock(&fa_wdt_lock);
+
+ __raw_writel(timeout * fa_wdt->clock,
+ fa_wdt->base + FA_WDLOAD);
+
+ fa_wdt_service(fa_wdt);
+
+ /* set clock before enabling */
+ __raw_writel(WDCR_CLOCK_5MHZ | WDCR_SYS_RST,
+ fa_wdt->base + FA_WDCR);
+
+ __raw_writel(WDCR_CLOCK_5MHZ | WDCR_SYS_RST | WDCR_ENABLE,
+ fa_wdt->base + FA_WDCR);
+
+ set_bit(WDT_ACTIVE, &fa_wdt->status);
+
+ spin_unlock(&fa_wdt_lock);
+}
+
+/* Watchdog device is opened, and watchdog starts running. */
+static int fa_wdt_open(struct inode *inode, struct file *file)
+{
+ struct fa_wdt_struct *fa_wdt = platform_get_drvdata(fa_wdt_dev);
+
+ if (test_bit(WDT_ACTIVE, &fa_wdt->status))
+ return -EBUSY;
+
+ file->private_data = fa_wdt;
+
+ fa_wdt_start(fa_wdt);
+
+ return nonseekable_open(inode, file);
+}
+
+/* Close the watchdog device. */
+static int fa_wdt_close(struct inode *inode, struct file *file)
+{
+ struct fa_wdt_struct *fa_wdt = file->private_data;
+
+ /* Disable the watchdog if possible */
+ if (test_bit(WDT_OK_TO_CLOSE, &fa_wdt->status))
+ fa_wdt_stop(fa_wdt);
+ else
+ dev_warn(fa_wdt->dev, "Device closed unexpectedly - timer will not stop\n");
+
+ return 0;
+}
+
+/* Handle commands from user-space. */
+static long fa_wdt_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct fa_wdt_struct *fa_wdt = file->private_data;
+
+ int value;
+
+ switch (cmd) {
+ case WDIOC_KEEPALIVE:
+ fa_wdt_service(fa_wdt);
+ return 0;
+
+ case WDIOC_GETSUPPORT:
+ return copy_to_user((struct watchdog_info *)arg, &fa_wdt_info,
+ sizeof(fa_wdt_info)) ? -EFAULT : 0;
+
+ case WDIOC_SETTIMEOUT:
+ if (get_user(value, (int *)arg))
+ return -EFAULT;
+
+ if ((value < 1) || (value > fa_wdt->max_timeout))
+ return -EINVAL;
+
+ timeout = value;
+
+ /* restart wdt to use new timeout */
+ fa_wdt_stop(fa_wdt);
+ fa_wdt_start(fa_wdt);
+
+ /* Fall through */
+ case WDIOC_GETTIMEOUT:
+ return put_user(timeout, (int *)arg);
+
+ case WDIOC_GETTIMELEFT:
+ value = __raw_readl(fa_wdt->base + FA_WDCOUNTER);
+ return put_user(value / fa_wdt->clock, (int *)arg);
+
+ default:
+ return -ENOTTY;
+ }
+}
+
+/* Refresh the watchdog whenever device is written to. */
+static ssize_t fa_wdt_write(struct file *file, const char *data,
+ size_t len, loff_t *ppos)
+{
+ struct fa_wdt_struct *fa_wdt = file->private_data;
+
+ if (len) {
+ if (!nowayout) {
+ size_t i;
+
+ clear_bit(WDT_OK_TO_CLOSE, &fa_wdt->status);
+ for (i = 0; i != len; i++) {
+ char c;
+
+ if (get_user(c, data + i))
+ return -EFAULT;
+ if (c == 'V')
+ set_bit(WDT_OK_TO_CLOSE,
+ &fa_wdt->status);
+ }
+ }
+ fa_wdt_service(fa_wdt);
+ }
+
+ return len;
+}
+
+static int fa_wdt_notify_sys(struct notifier_block *this,
+ unsigned long code, void *unused)
+{
+ struct fa_wdt_struct *fa_wdt = platform_get_drvdata(fa_wdt_dev);
+
+ if (code == SYS_DOWN || code == SYS_HALT)
+ fa_wdt_stop(fa_wdt);
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block fa_wdt_notifier = {
+ .notifier_call = fa_wdt_notify_sys,
+};
+
+static const struct file_operations fa_wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .unlocked_ioctl = fa_wdt_ioctl,
+ .open = fa_wdt_open,
+ .release = fa_wdt_close,
+ .write = fa_wdt_write,
+};
+
+static struct miscdevice fa_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &fa_wdt_fops,
+};
+
+static void fa_wdt_shutdown(struct platform_device *pdev)
+{
+ struct fa_wdt_struct *fa_wdt = platform_get_drvdata(pdev);
+
+ fa_wdt_stop(fa_wdt);
+}
+
+static int __devinit fa_wdt_probe(struct platform_device *pdev)
+{
+ int ret;
+ int res_size;
+ struct resource *res;
+ void __iomem *base;
+ struct fa_wdt_struct *fa_wdt;
+ struct fa_wdt_platform_data *pdata;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&pdev->dev, "no platform data specified\n");
+ return -EINVAL;
+ }
+
+ if (!pdata->clock) {
+ dev_err(&pdev->dev, "invalid clock value\n");
+ return -EINVAL;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "can't get device resources\n");
+ return -ENODEV;
+ }
+
+ res_size = resource_size(res);
+ if (!request_mem_region(res->start, res_size, res->name)) {
+ dev_err(&pdev->dev, "can't allocate %d bytes at %d address\n",
+ res_size, res->start);
+ return -ENOMEM;
+ }
+
+ base = ioremap(res->start, res_size);
+ if (!base) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ ret = -EIO;
+ goto fail0;
+ }
+
+ fa_wdt = kzalloc(sizeof(struct fa_wdt_struct), GFP_KERNEL);
+ if (!fa_wdt) {
+ dev_err(&pdev->dev, "can't allocate interface\n");
+ ret = -ENOMEM;
+ goto fail1;
+ }
+
+ /* Setup fa_wdt driver structure */
+ fa_wdt->base = base;
+ fa_wdt->res = res;
+ fa_wdt->dev = &pdev->dev;
+ fa_wdt->clock = pdata->clock;
+ fa_wdt->max_timeout = 0xffffffffU / pdata->clock;
+
+ /* Set up platform driver data */
+ platform_set_drvdata(pdev, fa_wdt);
+ fa_wdt_dev = pdev;
+
+ if (fa_wdt_miscdev.parent) {
+ ret = -EBUSY;
+ goto fail2;
+ }
+
+ ret = register_reboot_notifier(&fa_wdt_notifier);
+ if (ret)
+ goto fail2;
+
+ fa_wdt_miscdev.parent = &pdev->dev;
+
+ ret = misc_register(&fa_wdt_miscdev);
+ if (ret)
+ goto fail3;
+
+ return 0;
+
+fail3:
+ unregister_reboot_notifier(&fa_wdt_notifier);
+fail2:
+ platform_set_drvdata(pdev, NULL);
+ kfree(fa_wdt);
+fail1:
+ iounmap(base);
+fail0:
+ release_mem_region(res->start, res_size);
+
+ return ret;
+}
+
+static int __devexit fa_wdt_remove(struct platform_device *pdev)
+{
+ struct fa_wdt_struct *fa_wdt = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+ misc_deregister(&fa_wdt_miscdev);
+ unregister_reboot_notifier(&fa_wdt_notifier);
+ fa_wdt_dev = NULL;
+ iounmap(fa_wdt->base);
+ release_mem_region(fa_wdt->res->start, resource_size(fa_wdt->res));
+
+ kfree(fa_wdt);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int fa_wdt_suspend(struct platform_device *pdev, pm_message_t message)
+{
+ struct fa_wdt_struct *fa_wdt = platform_get_drvdata(pdev);
+ unsigned int reg;
+
+ reg = __raw_readw(fa_wdt->base + FA_WDCR);
+ reg &= ~(WDCR_WDENABLE);
+ __raw_writel(reg, fa_wdt->base + FA_WDCR);
+
+ return 0;
+}
+
+static int fa_wdt_resume(struct platform_device *pdev)
+{
+ struct fa_wdt_struct *fa_wdt = platform_get_drvdata(pdev);
+ unsigned int reg;
+
+ if (fa_wdt->status) {
+ reg = __raw_readw(fa_wdt->base + FA_WDCR);
+ reg |= WDCR_WDENABLE;
+ __raw_writel(reg, fa_wdt->base + FA_WDCR);
+ }
+
+ return 0;
+}
+#else
+#define fa_wdt_suspend NULL
+#define fa_wdt_resume NULL
+#endif
+
+static struct platform_driver fa_wdt_driver = {
+ .probe = fa_wdt_probe,
+ .remove = __devexit_p(fa_wdt_remove),
+ .shutdown = fa_wdt_shutdown,
+ .suspend = fa_wdt_suspend,
+ .resume = fa_wdt_resume,
+ .driver = {
+ .name = "fa-wdt",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init fa_wdt_init(void)
+{
+ return platform_driver_probe(&fa_wdt_driver, fa_wdt_probe);
+}
+
+static void __exit fa_wdt_exit(void)
+{
+ platform_driver_unregister(&fa_wdt_driver);
+}
+
+module_init(fa_wdt_init);
+module_exit(fa_wdt_exit);
+
+module_param(timeout, uint, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds");
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
+
+MODULE_AUTHOR("Paulius Zaleckas");
+MODULE_DESCRIPTION("Watchdog driver for Faraday FA526 based SoCs");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+MODULE_ALIAS("platform:fa-wdt");
--- /dev/null
+++ b/include/linux/fa_wdt.h
@@ -0,0 +1,13 @@
+/*
+ * Platform data definition for the Faraday watchdog driver
+ */
+
+#ifndef _FA_WDT_H
+#define _FA_WDT_H
+
+struct fa_wdt_platform_data {
+ unsigned int clock;
+};
+
+#endif /* _FA_WDT_H */
+

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,103 @@
--- a/arch/arm/mach-cns21xx/common.h
+++ b/arch/arm/mach-cns21xx/common.h
@@ -15,4 +15,7 @@ void __init cns21xx_init_irq(void);
extern struct sys_timer cns21xx_timer;
+int __init cns21xx_register_uart0(void);
+int __init cns21xx_register_uart1(void);
+
#endif /* _MACH_CNS21XX_COMMON_H */
--- /dev/null
+++ b/arch/arm/mach-cns21xx/devices.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2008 Cavium Networks
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/serial_8250.h>
+
+#include <mach/irqs.h>
+#include <mach/hardware.h>
+#include <mach/cns21xx.h>
+#include <mach/cns21xx_misc.h>
+
+#define CNS21XX_UART_CLOCK 24000000
+
+#define CNS21XX_UART_FLAGS (UPF_SKIP_TEST | UPF_FIXED_TYPE | UPF_NO_TXEN_TEST)
+
+static struct plat_serial8250_port cns21xx_uart0_data[] = {
+ {
+ .mapbase = CNS21XX_UART0_BASE,
+ .membase = (void *) CNS21XX_UART0_BASE_VIRT,
+ .irq = CNS21XX_IRQ_UART0,
+ .uartclk = CNS21XX_UART_CLOCK,
+ .regshift = 2,
+ .iotype = UPIO_MEM,
+ .type = PORT_16550A,
+ .flags = CNS21XX_UART_FLAGS,
+ }, {
+ /* terminating entry */
+ },
+};
+
+static struct platform_device cns21xx_uart0_device = {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM,
+ .dev = {
+ .platform_data = cns21xx_uart0_data,
+ },
+};
+
+int __init cns21xx_register_uart0(void)
+{
+ return platform_device_register(&cns21xx_uart0_device);
+}
+
+static struct plat_serial8250_port cns21xx_uart1_data[] = {
+ {
+ .mapbase = CNS21XX_UART1_BASE,
+ .membase = (void *) CNS21XX_UART1_BASE_VIRT,
+ .irq = CNS21XX_IRQ_UART1,
+ .uartclk = CNS21XX_UART_CLOCK,
+ .regshift = 2,
+ .iotype = UPIO_MEM,
+ .type = PORT_16550A,
+ .flags = CNS21XX_UART_FLAGS,
+ }, {
+ /* terminating entry */
+ },
+};
+
+static struct platform_device cns21xx_uart1_device = {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM1,
+ .dev = {
+ .platform_data = cns21xx_uart1_data,
+ },
+};
+
+int __init cns21xx_register_uart1(void)
+{
+ HAL_MISC_ENABLE_UART1_PINS();
+ return platform_device_register(&cns21xx_uart1_device);
+}
--- a/arch/arm/mach-cns21xx/Makefile
+++ b/arch/arm/mach-cns21xx/Makefile
@@ -4,7 +4,7 @@
# Object file lists.
-obj-y := core.o irq.o mm.o time.o
+obj-y := core.o devices.o irq.o mm.o time.o
# machine specific files

View file

@ -0,0 +1,113 @@
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -296,6 +296,8 @@ config ARCH_CNS21XX
select CPU_FA526
select PLAT_FA
select PLAT_FA_TIME
+ select PLAT_FA_GPIO
+ select ARCH_REQUIRE_GPIOLIB
select ARM_L1_CACHE_SHIFT_4
help
Support for Cavium Networks CNS21xx family.
--- a/arch/arm/mach-cns21xx/common.h
+++ b/arch/arm/mach-cns21xx/common.h
@@ -12,6 +12,7 @@
void __init cns21xx_map_io(void);
void __init cns21xx_init_irq(void);
+void __init cns21xx_gpio_init(void);
extern struct sys_timer cns21xx_timer;
--- /dev/null
+++ b/arch/arm/mach-cns21xx/gpio.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <plat/gpio.h>
+
+#include <mach/cns21xx.h>
+#include <mach/irqs.h>
+
+static struct fa_gpio_chip cns21xx_gpio_chips[] = {
+ {
+ .gpio_chip = {
+ .label = "GPIOA",
+ .base = 0,
+ .ngpio = 32,
+ },
+
+ .map_base = CNS21XX_GPIOA_BASE,
+ .irq_base = CNS21XX_GPIO_IRQ_BASE,
+ }, {
+ .gpio_chip = {
+ .label = "GPIOB",
+ .base = 32,
+ .ngpio = 32,
+ },
+
+ .map_base = CNS21XX_GPIOB_BASE,
+ .irq_base = CNS21XX_GPIO_IRQ_BASE + 32,
+ }
+};
+
+static struct fa_gpio_data cns21xx_gpio_data = {
+ .chips = cns21xx_gpio_chips,
+ .nchips = ARRAY_SIZE(cns21xx_gpio_chips),
+ .irq = CNS21XX_IRQ_GPIO,
+};
+
+void __init cns21xx_gpio_init(void)
+{
+ fa_gpio_init(&cns21xx_gpio_data);
+}
--- /dev/null
+++ b/arch/arm/mach-cns21xx/include/mach/gpio.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2008 Cavium Networks
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file 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 _CNS21XX_GPIO_H
+#define _CNS21XX_GPIO_H
+
+#include <asm-generic/gpio.h>
+#include <mach/irqs.h>
+
+#define gpio_get_value __gpio_get_value
+#define gpio_set_value __gpio_set_value
+#define gpio_cansleep __gpio_cansleep
+
+static inline int gpio_to_irq(unsigned gpio)
+{
+ return (CNS21XX_GPIO_IRQ_BASE + gpio);
+}
+
+static inline int irq_to_gpio(int irq)
+{
+ return (irq - CNS21XX_GPIO_IRQ_BASE);
+}
+
+#endif /* _CNS21XX_GPIO_H */
--- a/arch/arm/mach-cns21xx/Makefile
+++ b/arch/arm/mach-cns21xx/Makefile
@@ -4,7 +4,7 @@
# Object file lists.
-obj-y := core.o devices.o irq.o mm.o time.o
+obj-y := core.o devices.o gpio.o irq.o mm.o time.o
# machine specific files

View file

@ -0,0 +1,230 @@
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -589,7 +589,6 @@ static int ohci_run (struct ohci_hcd *oh
/* boot firmware should have set this up (5.1.1.3.1) */
if (first) {
-
val = ohci_readl (ohci, &ohci->regs->fminterval);
ohci->fminterval = val & 0x3fff;
if (ohci->fminterval != FI)
@@ -673,6 +672,9 @@ retry:
periodic_reinit (ohci);
+ if (ohci->flags & OHCI_QUIRK_INIT_FMINTERVAL)
+ ohci_writel (ohci, ohci->fminterval, &ohci->regs->fminterval);
+
/* some OHCI implementations are finicky about how they init.
* bogus values here mean not even enumeration could work.
*/
@@ -1067,6 +1069,11 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ohci_hcd_da8xx_driver
#endif
+#ifdef CONFIG_ARCH_CNS21XX
+#include "ohci-cns21xx.c"
+#define PLATFORM_DRIVER ohci_cns21xx_driver
+#endif
+
#if defined(CONFIG_CPU_SUBTYPE_SH7720) || \
defined(CONFIG_CPU_SUBTYPE_SH7721) || \
defined(CONFIG_CPU_SUBTYPE_SH7763) || \
--- /dev/null
+++ b/drivers/usb/host/ohci-cns21xx.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2008 Cavium Networks
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/platform_device.h>
+
+#include <mach/cns21xx.h>
+
+#define DRIVER_NAME "cns21xx-ohci"
+
+static int __devinit cns21xx_ohci_start(struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+ int ret;
+
+ ret = ohci_init(ohci);
+ if (ret)
+ return ret;
+
+ ret = ohci_run(ohci);
+ if (ret) {
+ err("can't start %s", ohci_to_hcd(ohci)->self.bus_name);
+ goto err;
+ }
+
+ return 0;
+
+err:
+ ohci_stop(hcd);
+ return ret;
+}
+
+static const struct hc_driver ohci_cns21xx_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "cns21xx-ohci",
+ .hcd_priv_size = sizeof(struct ohci_hcd),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ohci_irq,
+ .flags = HCD_USB11 | HCD_MEMORY,
+
+ /*
+ * basic lifecycle operations
+ */
+ .start = cns21xx_ohci_start,
+ .stop = ohci_stop,
+ .shutdown = ohci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = ohci_urb_enqueue,
+ .urb_dequeue = ohci_urb_dequeue,
+ .endpoint_disable = ohci_endpoint_disable,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = ohci_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
+ .start_port_reset = ohci_start_port_reset,
+};
+
+static void cns21xx_ohci_init_hc(void)
+{
+ __raw_writel(0x146, CNS21XX_OHCI_CONFIG_BASE_VIRT + 0x04);
+ __raw_writel(0x200, CNS21XX_OHCI_CONFIG_BASE_VIRT + 0x44);
+ msleep(100);
+}
+
+static int ohci_cns21xx_probe(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd;
+ struct resource *res;
+ struct ohci_hcd *ohci;
+ int irq;
+ int ret;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_dbg(&pdev->dev, "no IRQ specified for %s\n",
+ dev_name(&pdev->dev));
+ return -ENODEV;
+ }
+ irq = res->start;
+
+ hcd = usb_create_hcd(&ohci_cns21xx_hc_driver, &pdev->dev,
+ dev_name(&pdev->dev));
+ if (!hcd)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_dbg(&pdev->dev, "no base address specified for %s\n",
+ dev_name(&pdev->dev));
+ ret = -ENODEV;
+ goto err_put_hcd;
+ }
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = res->end - res->start + 1;
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ dev_dbg(&pdev->dev, "controller already in use\n");
+ ret = -EBUSY;
+ goto err_put_hcd;
+ }
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs) {
+ dev_dbg(&pdev->dev, "error mapping memory\n");
+ ret = -EFAULT;
+ goto err_release_region;
+ }
+
+ cns21xx_ohci_init_hc();
+
+ ohci = hcd_to_ohci(hcd);
+ ohci->flags |= OHCI_QUIRK_INIT_FMINTERVAL;
+ ohci_hcd_init(ohci);
+
+ ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
+ if (ret)
+ goto err_unmap;
+
+ platform_set_drvdata(pdev, hcd);
+ return 0;
+
+err_unmap:
+ iounmap(hcd->regs);
+err_release_region:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err_put_hcd:
+ usb_put_hcd(hcd);
+ return ret;
+}
+
+static int ohci_cns21xx_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+ usb_remove_hcd(hcd);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver ohci_cns21xx_driver = {
+ .probe = ohci_cns21xx_probe,
+ .remove = ohci_cns21xx_remove,
+ .shutdown = usb_hcd_platform_shutdown,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ },
+};
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -404,6 +404,7 @@ struct ohci_hcd {
#define OHCI_QUIRK_AMD_ISO 0x200 /* ISO transfers*/
#define OHCI_QUIRK_AMD_PREFETCH 0x400 /* pre-fetch for ISO transfer */
#define OHCI_QUIRK_SHUTDOWN 0x800 /* nVidia power bug */
+#define OHCI_QUIRK_INIT_FMINTERVAL 0x1000 /* fminterval must be initialized */
// there are also chip quirks/bugs in init logic
struct work_struct nec_work; /* Worker for NEC quirk */
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -299,6 +299,7 @@ config ARCH_CNS21XX
select PLAT_FA_GPIO
select ARCH_REQUIRE_GPIOLIB
select ARM_L1_CACHE_SHIFT_4
+ select USB_ARCH_HAS_OHCI
help
Support for Cavium Networks CNS21xx family.

View file

@ -0,0 +1,212 @@
--- /dev/null
+++ b/drivers/usb/host/ehci-cns21xx.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2008 Cavium Networks
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+
+#include <mach/cns21xx.h>
+
+#define DRIVER_NAME "cns21xx-ehci"
+
+static int cns21xx_ehci_reset(struct usb_hcd *hcd)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ int ret;
+
+ ret = ehci_halt(ehci);
+ if (ret)
+ return ret;
+
+ ret = ehci_init(hcd);
+ if (ret)
+ return ret;
+
+ ehci_reset(ehci);
+ ehci_port_power(ehci, 0);
+
+ return 0;
+}
+
+static const struct hc_driver ehci_cns21xx_hc_driver = {
+ .description = hcd_name,
+ .product_desc = DRIVER_NAME,
+ .hcd_priv_size = sizeof(struct ehci_hcd),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ehci_irq,
+ .flags = HCD_MEMORY | HCD_USB2,
+
+ /*
+ * basic lifecycle operations
+ */
+ .reset = cns21xx_ehci_reset,
+ .start = ehci_run,
+ .stop = ehci_stop,
+ .shutdown = ehci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = ehci_urb_enqueue,
+ .urb_dequeue = ehci_urb_dequeue,
+ .endpoint_disable = ehci_endpoint_disable,
+ .endpoint_reset = ehci_endpoint_reset,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = ehci_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = ehci_hub_status_data,
+ .hub_control = ehci_hub_control,
+ .relinquish_port = ehci_relinquish_port,
+ .port_handed_over = ehci_port_handed_over,
+
+ .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
+};
+
+static void cns21xx_ehci_init_hc(void)
+{
+ __raw_writel(0x106, CNS21XX_EHCI_CONFIG_BASE_VIRT + 0x04);
+ __raw_writel((3 << 5) | 0x2000, CNS21XX_EHCI_CONFIG_BASE_VIRT + 0x40);
+ msleep(100);
+}
+
+static int ehci_cns21xx_probe(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd;
+ struct ehci_hcd *ehci;
+ struct resource *res;
+ int irq;
+ int ret;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_dbg(&pdev->dev, "no IRQ specified for %s\n",
+ dev_name(&pdev->dev));
+ return -ENODEV;
+ }
+ irq = res->start;
+
+ hcd = usb_create_hcd(&ehci_cns21xx_hc_driver, &pdev->dev,
+ dev_name(&pdev->dev));
+ if (!hcd)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_dbg(&pdev->dev, "no base address specified for %s\n",
+ dev_name(&pdev->dev));
+ ret = -ENODEV;
+ goto err_put_hcd;
+ }
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = res->end - res->start + 1;
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ dev_dbg(&pdev->dev, "controller already in use\n");
+ ret = -EBUSY;
+ goto err_put_hcd;
+ }
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs) {
+ dev_dbg(&pdev->dev, "error mapping memory\n");
+ ret = -EFAULT;
+ goto err_release_region;
+ }
+
+ cns21xx_ehci_init_hc();
+
+ ehci = hcd_to_ehci(hcd);
+
+ ehci->caps = hcd->regs;
+ ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
+ dbg_hcs_params(ehci, "reset");
+ dbg_hcc_params(ehci, "reset");
+
+ /* cache this readonly data; minimize chip reads */
+ ehci->hcs_params = readl(&ehci->caps->hcs_params);
+ ehci->sbrn = 0x20;
+
+ ret = usb_add_hcd(hcd, CNS21XX_IRQ_EHCI, IRQF_DISABLED);
+ if (ret)
+ goto err_unmap;
+
+ platform_set_drvdata(pdev, hcd);
+ return 0;
+
+err_unmap:
+ iounmap(hcd->regs);
+err_release_region:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err_put_hcd:
+ usb_put_hcd(hcd);
+ return ret;
+}
+
+static int ehci_cns21xx_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+ usb_remove_hcd(hcd);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver ehci_cns21xx_driver = {
+ .probe = ehci_cns21xx_probe,
+ .remove = ehci_cns21xx_remove,
+ .shutdown = usb_hcd_platform_shutdown,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ },
+};
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1216,6 +1216,11 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ehci_octeon_driver
#endif
+#ifdef CONFIG_ARCH_CNS21XX
+#include "ehci-cns21xx.c"
+#define PLATFORM_DRIVER ehci_cns21xx_driver
+#endif
+
#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
!defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
!defined(XILINX_OF_PLATFORM_DRIVER)
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -300,6 +300,7 @@ config ARCH_CNS21XX
select ARCH_REQUIRE_GPIOLIB
select ARM_L1_CACHE_SHIFT_4
select USB_ARCH_HAS_OHCI
+ select USB_ARCH_HAS_EHCI
help
Support for Cavium Networks CNS21xx family.

View file

@ -0,0 +1,577 @@
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -445,6 +445,8 @@ struct spi_transfer {
u16 delay_usecs;
u32 speed_hz;
+ unsigned last_in_message_list;
+
struct list_head transfer_list;
};
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -167,6 +167,14 @@ config SPI_GPIO_OLD
If unsure, say N.
+config SPI_CNS21XX
+ tristate "Cavium Netowrks CNS21xx SPI master"
+ depends on ARCH_CNS21XX && EXPERIMENTAL
+ select SPI_BITBANG
+ help
+ This driver supports the buil-in SPI controller of the Cavium Networks
+ CNS21xx SoCs.
+
config SPI_IMX
tristate "Freescale i.MX SPI controllers"
depends on ARCH_MXC
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_SPI_SH_SCI) += spi_sh_sci.
obj-$(CONFIG_SPI_SH_MSIOF) += spi_sh_msiof.o
obj-$(CONFIG_SPI_STMP3XXX) += spi_stmp.o
obj-$(CONFIG_SPI_NUC900) += spi_nuc900.o
+obj-$(CONFIG_SPI_CNS21XX) += spi_cns21xx.o
# special build for s3c24xx spi driver with fiq support
spi_s3c24xx_hw-y := spi_s3c24xx.o
--- a/drivers/spi/spi_bitbang.c
+++ b/drivers/spi/spi_bitbang.c
@@ -337,6 +337,13 @@ static void bitbang_work(struct work_str
*/
if (!m->is_dma_mapped)
t->rx_dma = t->tx_dma = 0;
+
+ if (t->transfer_list.next == &m->transfers) {
+ t->last_in_message_list = 1;
+ } else {
+ t->last_in_message_list = 0;
+ }
+
status = bitbang->txrx_bufs(spi, t);
}
if (status > 0)
--- /dev/null
+++ b/drivers/spi/spi_cns21xx.c
@@ -0,0 +1,520 @@
+/*
+ * Copyright (c) 2008 Cavium Networks
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+
+#include <mach/hardware.h>
+#include <mach/cns21xx.h>
+
+#define DRIVER_NAME "cns21xx-spi"
+
+#ifdef CONFIG_CNS21XX_SPI_DEBUG
+#define DBG(fmt, args...) pr_info("[CNS21XX_SPI_DEBUG]" fmt, ## args)
+#else
+#define DBG(fmt, args...) do {} while (0)
+#endif /* CNS21XX_SPI_DEBUG */
+
+#define SPI_REG_CFG 0x40
+#define SPI_REG_STAT 0x44
+#define SPI_REG_BIT_RATE 0x48
+#define SPI_REG_TX_CTRL 0x4c
+#define SPI_REG_TX_DATA 0x50
+#define SPI_REG_RX_CTRL 0x54
+#define SPI_REG_RX_DATA 0x58
+#define SPI_REG_FIFO_TX_CFG 0x5c
+#define SPI_REG_FIFO_TX_CTRL 0x60
+#define SPI_REG_FIFO_RX_CFG 0x64
+#define SPI_REG_INTR_STAT 0x68
+#define SPI_REG_INTR_ENA 0x6c
+
+#define CFG_SPI_EN BIT(31)
+#define CFG_SPI_CLKPOL BIT(14)
+#define CFG_SPI_CLKPHA BIT(13)
+#define CFG_SPI_MASTER_EN BIT(11)
+#define CFG_SPI_CHAR_LEN_M 0x3
+#define CFG_SPI_CHAR_LEN_8BITS 0
+#define CFG_SPI_CHAR_LEN_16BITS 1
+#define CFG_SPI_CHAR_LEN_24BITS 2
+#define CFG_SPI_CHAR_LEN_32BITS 3
+
+#define STAT_SPI_BUSY_STA BIT(1)
+
+#define BIT_RATE_DIV_1 0
+#define BIT_RATE_DIV_2 1
+#define BIT_RATE_DIV_4 2
+#define BIT_RATE_DIV_8 3
+#define BIT_RATE_DIV_16 4
+#define BIT_RATE_DIV_32 5
+#define BIT_RATE_DIV_64 6
+#define BIT_RATE_DIV_128 7
+
+#define TX_CTRL_SPI_TXDAT_EOF BIT(2)
+#define TX_CTRL_SPI_TXCH_NUM_M 0x3
+#define TX_CTRL_CLEAR_MASK (TX_CTRL_SPI_TXDAT_EOF | \
+ TX_CTRL_SPI_TXCH_NUM_M)
+
+#define RX_CTRL_SPI_RXDAT_EOF BIT(2)
+#define RX_CTRL_SPI_RXCH_NUM_M 0x3
+
+#define INTR_STAT_SPI_TXBF_UNRN_FG BIT(7)
+#define INTR_STAT_SPI_RXBF_OVRN_FG BIT(6)
+#define INTR_STAT_SPI_TXFF_UNRN_FG BIT(5)
+#define INTR_STAT_SPI_RXFF_OVRN_FG BIT(4)
+#define INTR_STAT_SPI_TXBUF_FG BIT(3)
+#define INTR_STAT_SPI_RXBUF_FG BIT(2)
+#define INTR_STAT_SPI_TXFF_FG BIT(1)
+#define INTR_STAT_SPI_RXFF_FG BIT(0)
+
+#define INTR_STAT_CLEAR_MASK (INTR_STAT_SPI_TXBF_UNRN_FG | \
+ INTR_STAT_SPI_RXBF_OVRN_FG | \
+ INTR_STAT_SPI_TXFF_UNRN_FG | \
+ INTR_STAT_SPI_RXFF_OVRN_FG)
+
+#define FIFO_TX_CFG_SPI_TXFF_THRED_M 0x3
+#define FIFO_TX_CFG_SPI_TXFF_THRED_S 4
+#define FIFO_TX_CFG_SPI_TXFF_THRED_2 0
+#define FIFO_TX_CFG_SPI_TXFF_THRED_4 1
+#define FIFO_TX_CFG_SPI_TXFF_THRED_6 0
+#define FIFO_TX_CFG_SPI_TXFF_STATUS_M 0xf
+
+#define FIFO_RX_CFG_SPI_RXFF_THRED_M 0x3
+#define FIFO_RX_CFG_SPI_RXFF_THRED_S 4
+#define FIFO_RX_CFG_SPI_RXFF_THRED_2 0
+#define FIFO_RX_CFG_SPI_RXFF_THRED_4 1
+#define FIFO_RX_CFG_SPI_RXFF_THRED_6 0
+#define FIFO_RX_CFG_SPI_RXFF_STATUS_M 0xf
+
+#define CNS21XX_SPI_NUM_BIT_RATES 8
+
+struct cns21xx_spi {
+ struct spi_bitbang bitbang;
+
+ struct spi_master *master;
+ struct device *dev;
+ void __iomem *base;
+ struct resource *region;
+
+ unsigned freq_max;
+ unsigned freq_min;
+
+};
+
+static inline struct cns21xx_spi *to_hw(struct spi_device *spi)
+{
+ return spi_master_get_devdata(spi->master);
+}
+
+static inline u32 cns21xx_spi_rr(struct cns21xx_spi *hw, unsigned int reg)
+{
+ return __raw_readl(hw->base + reg);
+}
+
+static inline void cns21xx_spi_wr(struct cns21xx_spi *hw, u32 val,
+ unsigned int reg)
+{
+ __raw_writel(val, hw->base + reg);
+}
+
+#define CNS21XX_SPI_RETRY_COUNT 100
+static inline int cns21xx_spi_wait(struct cns21xx_spi *hw, unsigned int reg,
+ u32 mask, u32 val)
+{
+ int retry_cnt = 0;
+
+ do {
+ if ((cns21xx_spi_rr(hw, reg) & mask) == val)
+ break;
+
+ if (++retry_cnt > CNS21XX_SPI_RETRY_COUNT) {
+ dev_err(hw->dev, "timeout waiting on register %02x\n",
+ reg);
+ return -EIO;
+ }
+ } while (1);
+
+ return 0;
+}
+
+static int cns21xx_spi_txrx_word(struct cns21xx_spi *hw, u8 tx_channel,
+ u8 tx_eof_flag, u32 tx_data, u32 *rx_data)
+{
+ unsigned int tx_ctrl;
+ u8 rx_channel;
+ u8 rx_eof_flag;
+ int err = 0;
+
+ err = cns21xx_spi_wait(hw, SPI_REG_STAT, STAT_SPI_BUSY_STA, 0);
+ if (err)
+ return err;
+
+ err = cns21xx_spi_wait(hw, SPI_REG_INTR_STAT, INTR_STAT_SPI_TXBUF_FG,
+ INTR_STAT_SPI_TXBUF_FG);
+ if (err)
+ return err;
+
+ tx_ctrl = cns21xx_spi_rr(hw, SPI_REG_TX_CTRL);
+ tx_ctrl &= ~(TX_CTRL_CLEAR_MASK);
+ tx_ctrl |= (tx_channel & TX_CTRL_SPI_TXCH_NUM_M);
+ tx_ctrl |= (tx_eof_flag) ? TX_CTRL_SPI_TXDAT_EOF : 0;
+ cns21xx_spi_wr(hw, tx_ctrl, SPI_REG_TX_CTRL);
+
+ cns21xx_spi_wr(hw, tx_data, SPI_REG_TX_DATA);
+
+ err = cns21xx_spi_wait(hw, SPI_REG_INTR_STAT, INTR_STAT_SPI_RXBUF_FG,
+ INTR_STAT_SPI_RXBUF_FG);
+ if (err)
+ return err;
+
+ rx_channel = cns21xx_spi_rr(hw, SPI_REG_RX_CTRL) &
+ RX_CTRL_SPI_RXCH_NUM_M;
+
+ rx_eof_flag = (cns21xx_spi_rr(hw, SPI_REG_RX_CTRL) &
+ RX_CTRL_SPI_RXDAT_EOF) ? 1 : 0;
+
+ *rx_data = cns21xx_spi_rr(hw, SPI_REG_RX_DATA);
+
+ if ((tx_channel != rx_channel) || (tx_eof_flag != rx_eof_flag))
+ return -EPROTO;
+
+ return 0;
+}
+
+static void cns21xx_spi_chipselect(struct spi_device *spi, int value)
+{
+ struct cns21xx_spi *hw = to_hw(spi);
+ unsigned int spi_config;
+ unsigned int tx_ctrl;
+
+ switch (value) {
+ case BITBANG_CS_INACTIVE:
+ break;
+
+ case BITBANG_CS_ACTIVE:
+ spi_config = cns21xx_spi_rr(hw, SPI_REG_CFG);
+
+ if (spi->mode & SPI_CPHA)
+ spi_config |= CFG_SPI_CLKPHA;
+ else
+ spi_config &= ~CFG_SPI_CLKPHA;
+
+ if (spi->mode & SPI_CPOL)
+ spi_config |= CFG_SPI_CLKPOL;
+ else
+ spi_config &= ~CFG_SPI_CLKPOL;
+
+ cns21xx_spi_wr(hw, spi_config, SPI_REG_CFG);
+
+ tx_ctrl = cns21xx_spi_rr(hw, SPI_REG_TX_CTRL);
+ tx_ctrl &= ~(TX_CTRL_CLEAR_MASK);
+ tx_ctrl |= (spi->chip_select & TX_CTRL_SPI_TXCH_NUM_M);
+ cns21xx_spi_wr(hw, tx_ctrl, SPI_REG_TX_CTRL);
+
+ break;
+ }
+}
+
+static int cns21xx_spi_setup(struct spi_device *spi)
+{
+ struct cns21xx_spi *hw = to_hw(spi);
+
+ if (spi->bits_per_word != 8) {
+ dev_err(&spi->dev, "%s: invalid bits_per_word=%u\n",
+ __func__, spi->bits_per_word);
+ return -EINVAL;
+ }
+
+ if (spi->max_speed_hz == 0)
+ spi->max_speed_hz = hw->freq_max;
+
+ if (spi->max_speed_hz > hw->freq_max ||
+ spi->max_speed_hz < hw->freq_min) {
+ dev_err(&spi->dev, "%s: max_speed_hz=%u out of range\n",
+ __func__, spi->max_speed_hz);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int cns21xx_spi_setup_transfer(struct spi_device *spi,
+ struct spi_transfer *t)
+{
+ struct cns21xx_spi *hw = to_hw(spi);
+ u8 bits_per_word;
+ u32 hz;
+ int i;
+
+ bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word;
+ hz = t ? t->speed_hz : spi->max_speed_hz;
+
+ if (!bits_per_word)
+ bits_per_word = spi->bits_per_word;
+
+ if (!hz)
+ hz = spi->max_speed_hz;
+
+ if (bits_per_word != 8) {
+ dev_err(&spi->dev, "%s: invalid bits_per_word=%u\n",
+ __func__, bits_per_word);
+ return -EINVAL;
+ }
+
+ if (hz > spi->max_speed_hz || hz > hw->freq_max || hz < hw->freq_min) {
+ dev_err(&spi->dev, "%s: max_speed_hz=%u out of range\n",
+ __func__, hz);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < CNS21XX_SPI_NUM_BIT_RATES; i++)
+ if (spi->max_speed_hz > (cns21xx_get_apb_freq() >> i))
+ break;
+
+ DBG("max_speed:%uHz, curr_speed:%luHz, rate_index=%d\n",
+ spi->max_speed_hz, cns21xx_get_apb_freq() / (1 << i), i);
+
+ cns21xx_spi_wr(hw, i, SPI_REG_BIT_RATE);
+
+ return 0;
+}
+
+static int cns21xx_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
+{
+ struct cns21xx_spi *hw = to_hw(spi);
+ const unsigned char *tx_buf;
+ unsigned char *rx_buf;
+ u32 rx_data;
+ int tx_eof;
+ int err = 0;
+ int i;
+
+ tx_buf = t->tx_buf;
+ rx_buf = t->rx_buf;
+ tx_eof = t->last_in_message_list;
+
+ DBG("txrx: tx %p, rx %p, len %d\n", tx_buf, rx_buf, t->len);
+
+ if (tx_buf) {
+ for (i = 0; i < t->len; i++)
+ DBG("tx_buf[%02d]: 0x%02x\n", i, tx_buf[i]);
+
+ for (i = 0; i < (t->len - 1); i++) {
+ err = cns21xx_spi_txrx_word(hw, spi->chip_select, 0,
+ tx_buf[i], &rx_data);
+ if (err)
+ goto done;
+
+ if (rx_buf) {
+ rx_buf[i] = rx_data;
+ DBG("rx_buf[%02d]:0x%02x\n", i, rx_buf[i]);
+ }
+ }
+
+ err = cns21xx_spi_txrx_word(hw, spi->chip_select, tx_eof,
+ tx_buf[i], &rx_data);
+ if (err)
+ goto done;
+
+ if ((tx_eof) && rx_buf) {
+ rx_buf[i] = rx_data;
+ DBG("rx_buf[%02d]:0x%02x\n", i, rx_buf[i]);
+ }
+ } else if (rx_buf) {
+ for (i = 0; i < (t->len - 1); i++) {
+ err = cns21xx_spi_txrx_word(hw, spi->chip_select, 0,
+ 0xff, &rx_data);
+ if (err)
+ goto done;
+
+ rx_buf[i] = rx_data;
+ DBG("rx_buf[%02d]:0x%02x\n", i, rx_buf[i]);
+ }
+
+ err = cns21xx_spi_txrx_word(hw, spi->chip_select, tx_eof,
+ 0xff, &rx_data);
+ if (err)
+ goto done;
+
+ rx_buf[i] = rx_data;
+ DBG("rx_buf[%02d]:0x%02x\n", i, rx_buf[i]);
+ }
+
+ done:
+ return (err) ? err : t->len;
+}
+
+static void __init cns21xx_spi_hw_init(struct cns21xx_spi *hw)
+{
+ u32 t;
+ u32 pclk;
+
+ /* Setup configuration register */
+ cns21xx_spi_wr(hw, CFG_SPI_MASTER_EN, SPI_REG_CFG);
+
+ /* Set default clock to PCLK/2 */
+ cns21xx_spi_wr(hw, BIT_RATE_DIV_2, SPI_REG_BIT_RATE);
+
+ /* Configure SPI's Tx channel */
+ cns21xx_spi_wr(hw, 0, SPI_REG_TX_CTRL);
+
+ /* Configure Tx FIFO Threshold */
+ t = cns21xx_spi_rr(hw, SPI_REG_FIFO_TX_CFG);
+ t &= ~(FIFO_TX_CFG_SPI_TXFF_THRED_M << FIFO_TX_CFG_SPI_TXFF_THRED_S);
+ t |= (FIFO_TX_CFG_SPI_TXFF_THRED_2 << FIFO_TX_CFG_SPI_TXFF_THRED_S);
+ cns21xx_spi_wr(hw, t, SPI_REG_FIFO_TX_CFG);
+
+ /* Configure Rx FIFO Threshold */
+ t = cns21xx_spi_rr(hw, SPI_REG_FIFO_RX_CFG);
+ t &= ~(FIFO_RX_CFG_SPI_RXFF_THRED_M << FIFO_RX_CFG_SPI_RXFF_THRED_S);
+ t |= (FIFO_RX_CFG_SPI_RXFF_THRED_2 << FIFO_RX_CFG_SPI_RXFF_THRED_S);
+ cns21xx_spi_wr(hw, t, SPI_REG_FIFO_RX_CFG);
+
+ /* Disable interrupts, and clear interrupt status */
+ cns21xx_spi_wr(hw, 0, SPI_REG_INTR_ENA);
+ cns21xx_spi_wr(hw, INTR_STAT_CLEAR_MASK, SPI_REG_INTR_STAT);
+
+ (void) cns21xx_spi_rr(hw, SPI_REG_RX_DATA);
+
+ /* Enable SPI */
+ t = cns21xx_spi_rr(hw, SPI_REG_CFG);
+ t |= CFG_SPI_EN;
+ cns21xx_spi_wr(hw, t, SPI_REG_CFG);
+
+ pclk = cns21xx_get_apb_freq();
+ hw->freq_max = pclk;
+ hw->freq_min = pclk / (1 << BIT_RATE_DIV_128);
+}
+
+static int __init cns21xx_spi_probe(struct platform_device *pdev)
+{
+ struct cns21xx_spi *hw;
+ struct spi_master *master;
+ struct resource *res;
+ int err = 0;
+
+ master = spi_alloc_master(&pdev->dev, sizeof(struct cns21xx_spi));
+ if (!master) {
+ dev_err(&pdev->dev, "No memory for spi_master\n");
+ return -ENOMEM;
+ }
+
+ hw = spi_master_get_devdata(master);
+
+ platform_set_drvdata(pdev, hw);
+ hw->master = spi_master_get(master);
+ hw->dev = &pdev->dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_dbg(&pdev->dev, "no MEM resource found\n");
+ err = -ENOENT;
+ goto err_put_master;
+ }
+
+ hw->region = request_mem_region(res->start, resource_size(res),
+ dev_name(&pdev->dev));
+ if (!hw->region) {
+ dev_err(&pdev->dev, "unable to reserve iomem region\n");
+ err = -ENXIO;
+ goto err_put_master;
+ }
+
+ hw->base = ioremap(res->start, resource_size(res));
+ if (!hw->base) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ err = -ENOENT;
+ goto err_release_region;
+ }
+
+ cns21xx_spi_hw_init(hw);
+
+ master->bus_num = pdev->id;
+ if (master->bus_num == -1)
+ master->bus_num = 0;
+
+ master->num_chipselect = 4;
+ master->setup = cns21xx_spi_setup;
+
+ hw->bitbang.master = hw->master;
+ hw->bitbang.chipselect = cns21xx_spi_chipselect;
+ hw->bitbang.txrx_bufs = cns21xx_spi_txrx;
+ hw->bitbang.setup_transfer = cns21xx_spi_setup_transfer;
+
+ err = spi_bitbang_start(&hw->bitbang);
+ if (err) {
+ dev_err(hw->dev, "unable to register SPI master\n");
+ goto err_unmap;
+ }
+
+ dev_info(hw->dev, "iomem at %08x\n", res->start);
+
+ return 0;
+
+ err_unmap:
+ iounmap(hw->base);
+
+ err_release_region:
+ release_resource(hw->region);
+ kfree(hw->region);
+
+ err_put_master:
+ spi_master_put(hw->bitbang.master);
+ platform_set_drvdata(pdev, NULL);
+
+ return err;
+}
+
+static int __devexit cns21xx_spi_remove(struct platform_device *pdev)
+{
+ struct cns21xx_spi *hw = platform_get_drvdata(pdev);
+
+ spi_bitbang_stop(&hw->bitbang);
+ iounmap(hw->base);
+ release_resource(hw->region);
+ kfree(hw->region);
+ spi_master_put(hw->bitbang.master);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver cns21xx_spi_driver = {
+ .remove = __devexit_p(cns21xx_spi_remove),
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init cns21xx_spi_init(void)
+{
+ return platform_driver_probe(&cns21xx_spi_driver, cns21xx_spi_probe);
+}
+
+static void __exit cns21xx_spi_exit(void)
+{
+ platform_driver_unregister(&cns21xx_spi_driver);
+}
+
+module_init(cns21xx_spi_init);
+module_exit(cns21xx_spi_exit);
+
+MODULE_DESCRIPTION("Cavium Networks CNS21xx SPI Controller driver");
+MODULE_AUTHOR("STAR Semi Corp.");
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,104 @@
--- /dev/null
+++ b/arch/arm/mach-cns21xx/dev-usb.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2008 Cavium Networks
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+
+#include <mach/cns21xx.h>
+
+static u64 cns21xx_usb_dmamask = DMA_BIT_MASK(32);
+
+static struct resource cns21xx_ohci_resources[] = {
+ [0] = {
+ .start = CNS21XX_OHCI_CTRL_BASE,
+ .end = CNS21XX_OHCI_CTRL_BASE + SZ_1M - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = CNS21XX_IRQ_OHCI,
+ .end = CNS21XX_IRQ_OHCI,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device cns21xx_ohci_device = {
+ .name = "cns21xx-ohci",
+ .id = -1,
+ .dev = {
+ .dma_mask = &cns21xx_usb_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ .resource = cns21xx_ohci_resources,
+ .num_resources = ARRAY_SIZE(cns21xx_ohci_resources),
+};
+
+static struct resource cns21xx_ehci_resources[] = {
+ [0] = {
+ .start = CNS21XX_EHCI_CTRL_BASE,
+ .end = CNS21XX_EHCI_CTRL_BASE + SZ_1M - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = CNS21XX_IRQ_EHCI,
+ .end = CNS21XX_IRQ_EHCI,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device cns21xx_ehci_device = {
+ .name = "cns21xx-ehci",
+ .id = -1,
+ .dev = {
+ .dma_mask = &cns21xx_usb_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ .resource = cns21xx_ehci_resources,
+ .num_resources = ARRAY_SIZE(cns21xx_ehci_resources),
+};
+
+void __init cns21xx_register_usb(void)
+{
+ platform_device_register(&cns21xx_ehci_device);
+ platform_device_register(&cns21xx_ohci_device);
+}
--- a/arch/arm/mach-cns21xx/Kconfig
+++ b/arch/arm/mach-cns21xx/Kconfig
@@ -3,4 +3,7 @@ if ARCH_CNS21XX
menu "Cavium Networks CNS21xx based machines"
endmenu
+config CNS21XX_DEV_USB
+ def_bool n
+
endif
--- a/arch/arm/mach-cns21xx/Makefile
+++ b/arch/arm/mach-cns21xx/Makefile
@@ -6,5 +6,8 @@
obj-y := core.o devices.o gpio.o irq.o mm.o time.o
+# devices
+obj-$(CONFIG_CNS21XX_DEV_USB) += dev-usb.o
+
# machine specific files
--- a/arch/arm/mach-cns21xx/common.h
+++ b/arch/arm/mach-cns21xx/common.h
@@ -18,5 +18,6 @@ extern struct sys_timer cns21xx_timer;
int __init cns21xx_register_uart0(void);
int __init cns21xx_register_uart1(void);
+int __init cns21xx_register_usb(void);
#endif /* _MACH_CNS21XX_COMMON_H */

View file

@ -0,0 +1,63 @@
--- a/arch/arm/mach-cns21xx/common.h
+++ b/arch/arm/mach-cns21xx/common.h
@@ -19,5 +19,6 @@ extern struct sys_timer cns21xx_timer;
int __init cns21xx_register_uart0(void);
int __init cns21xx_register_uart1(void);
int __init cns21xx_register_usb(void);
+int __init cns21xx_register_wdt(void);
#endif /* _MACH_CNS21XX_COMMON_H */
--- a/arch/arm/mach-cns21xx/devices.c
+++ b/arch/arm/mach-cns21xx/devices.c
@@ -11,6 +11,7 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/serial_8250.h>
+#include <linux/fa_wdt.h>
#include <mach/irqs.h>
#include <mach/hardware.h>
@@ -77,3 +78,32 @@ int __init cns21xx_register_uart1(void)
HAL_MISC_ENABLE_UART1_PINS();
return platform_device_register(&cns21xx_uart1_device);
}
+
+static struct resource cns21xx_wdt_resources[] = {
+ {
+ .start = CNS21XX_WDT_BASE,
+ .end = CNS21XX_WDT_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+#define CNS21XX_WDT_CLOCK 10 /* 10 Hz */
+
+static struct fa_wdt_platform_data cns21xx_wdt_data = {
+ .clock = CNS21XX_WDT_CLOCK,
+};
+
+static struct platform_device cns21xx_wdt_device = {
+ .name = "fa-wdt",
+ .id = -1,
+ .resource = cns21xx_wdt_resources,
+ .num_resources = ARRAY_SIZE(cns21xx_wdt_resources),
+ .dev = {
+ .platform_data = &cns21xx_wdt_data,
+ },
+};
+
+int __init cns21xx_register_wdt(void)
+{
+ return platform_device_register(&cns21xx_wdt_device);
+}
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -333,7 +333,7 @@ config IMX2_WDT
config FA_WATCHDOG
tristate "Faraday watchdog"
- depends on ARCH_GEMINI
+ depends on ARCH_GEMINI || ARCH_CNS21XX
help
Say Y here if you want support for the built-in watchdog timer
found in some Faraday FA526 based SoCs.

View file

@ -0,0 +1,117 @@
--- /dev/null
+++ b/arch/arm/mach-cns21xx/dev-spi-master.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/spi/spi.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+
+#include <mach/hardware.h>
+#include <mach/cns21xx.h>
+#include <mach/cns21xx_misc.h>
+#include <mach/cns21xx_powermgmt.h>
+#include <mach/irqs.h>
+
+#include "common.h"
+
+static u64 spi_dmamask = DMA_BIT_MASK(32);
+static struct resource cns21xx_spi_resources[] = {
+ [0] = {
+ .start = CNS21XX_SPI_BASE,
+ .end = CNS21XX_SPI_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = CNS21XX_IRQ_SPI,
+ .end = CNS21XX_IRQ_SPI,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device cns21xx_spi_master_device = {
+ .name = "cns21xx-spi",
+ .id = -1,
+ .dev = {
+ .dma_mask = &spi_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ .resource = cns21xx_spi_resources,
+ .num_resources = ARRAY_SIZE(cns21xx_spi_resources),
+};
+
+void __init cns21xx_register_spi_master(int id, struct spi_board_info *info,
+ unsigned int n)
+{
+ unsigned int i;
+
+ /* Enable SPI pins */
+ HAL_MISC_ENABLE_SPIDR_PINS();
+ HAL_MISC_ENABLE_SPICLK_PINS();
+ for (i = 0; i < n; i++) {
+ switch (info[i].chip_select) {
+ case 0:
+ HAL_MISC_ENABLE_SPICSN0_PINS();
+ break;
+ case 1:
+ HAL_MISC_ENABLE_SPICSN1_PINS();
+ break;
+ case 2:
+ HAL_MISC_ENABLE_SPICSN2_PINS();
+ break;
+ case 3:
+ HAL_MISC_ENABLE_SPICSN3_PINS();
+ break;
+ }
+ }
+
+ /* Disable SPI serial flash access through 0x30000000 region */
+ HAL_MISC_DISABLE_SPI_SERIAL_FLASH_BANK_ACCESS();
+
+ /* Enable SPI clock */
+ HAL_PWRMGT_ENABLE_SPI_CLOCK();
+
+ cns21xx_spi_master_device.id = id;
+
+ spi_register_board_info(info, n);
+ platform_device_register(&cns21xx_spi_master_device);
+}
--- a/arch/arm/mach-cns21xx/Kconfig
+++ b/arch/arm/mach-cns21xx/Kconfig
@@ -6,4 +6,7 @@ endmenu
config CNS21XX_DEV_USB
def_bool n
+config CNS21XX_DEV_SPI_MASTER
+ def_bool n
+
endif
--- a/arch/arm/mach-cns21xx/Makefile
+++ b/arch/arm/mach-cns21xx/Makefile
@@ -8,6 +8,7 @@ obj-y := core.o devices.o gpio.o irq.o
# devices
obj-$(CONFIG_CNS21XX_DEV_USB) += dev-usb.o
+obj-$(CONFIG_CNS21XX_DEV_SPI_MASTER) += dev-spi-master.o
# machine specific files
--- a/arch/arm/mach-cns21xx/common.h
+++ b/arch/arm/mach-cns21xx/common.h
@@ -21,4 +21,8 @@ int __init cns21xx_register_uart1(void);
int __init cns21xx_register_usb(void);
int __init cns21xx_register_wdt(void);
+struct spi_board_info;
+void __init cns21xx_register_spi_master(int id, struct spi_board_info *info,
+ unsigned int n);
+
#endif /* _MACH_CNS21XX_COMMON_H */

View file

@ -0,0 +1,178 @@
--- a/arch/arm/mach-cns21xx/Kconfig
+++ b/arch/arm/mach-cns21xx/Kconfig
@@ -3,6 +3,9 @@ if ARCH_CNS21XX
menu "Cavium Networks CNS21xx based machines"
endmenu
+config CNS21XX_DEV_GEC
+ def_bool n
+
config CNS21XX_DEV_USB
def_bool n
--- a/arch/arm/mach-cns21xx/Makefile
+++ b/arch/arm/mach-cns21xx/Makefile
@@ -7,6 +7,7 @@
obj-y := core.o devices.o gpio.o irq.o mm.o time.o
# devices
+obj-$(CONFIG_CNS21XX_DEV_GEC) += dev-gec.o
obj-$(CONFIG_CNS21XX_DEV_USB) += dev-usb.o
obj-$(CONFIG_CNS21XX_DEV_SPI_MASTER) += dev-spi-master.o
--- /dev/null
+++ b/arch/arm/mach-cns21xx/dev-gec.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/etherdevice.h>
+
+#include <asm/sizes.h>
+#include <mach/cns21xx.h>
+#include <mach/irqs.h>
+
+#include "dev-gec.h"
+
+static u8 cns21xx_ethaddr[ETH_ALEN];
+struct cns21xx_gec_plat_data cns21xx_gec_data;
+
+static struct resource cns21xx_gec_resources[] = {
+ {
+ .start = CNS21XX_NIC_BASE,
+ .end = CNS21XX_NIC_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .name = CNS21XX_GEC_STATUS_IRQ_NAME,
+ .start = CNS21XX_IRQ_NIC_STATUS,
+ .end = CNS21XX_IRQ_NIC_STATUS,
+ .flags = IORESOURCE_IRQ,
+ }, {
+ .name = CNS21XX_GEC_RXRC_IRQ_NAME,
+ .start = CNS21XX_IRQ_NIC_RXRC,
+ .end = CNS21XX_IRQ_NIC_RXRC,
+ .flags = IORESOURCE_IRQ,
+ }, {
+ .name = CNS21XX_GEC_RXQF_IRQ_NAME,
+ .start = CNS21XX_IRQ_NIC_RXQF,
+ .end = CNS21XX_IRQ_NIC_RXQF,
+ .flags = IORESOURCE_IRQ,
+ }, {
+ .name = CNS21XX_GEC_TXTC_IRQ_NAME,
+ .start = CNS21XX_IRQ_NIC_TXTC,
+ .end = CNS21XX_IRQ_NIC_TXTC,
+ .flags = IORESOURCE_IRQ,
+ }, {
+ .name = CNS21XX_GEC_TXQE_IRQ_NAME,
+ .start = CNS21XX_IRQ_NIC_TXQE,
+ .end = CNS21XX_IRQ_NIC_TXQE,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static u64 cns21xx_gec_dmamask = DMA_BIT_MASK(32);
+static struct platform_device cns21xx_gec_device = {
+ .name = "cns21xx-gec",
+ .id = -1,
+ .resource = cns21xx_gec_resources,
+ .num_resources = ARRAY_SIZE(cns21xx_gec_resources),
+ .dev = {
+ .dma_mask = &cns21xx_gec_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &cns21xx_gec_data,
+ },
+};
+
+static int __init cns21xx_ethaddr_setup(char *str)
+{
+ int t;
+
+ t = sscanf(str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
+ &cns21xx_ethaddr[0], &cns21xx_ethaddr[1],
+ &cns21xx_ethaddr[2], &cns21xx_ethaddr[3],
+ &cns21xx_ethaddr[4], &cns21xx_ethaddr[5]);
+
+ if (t != ETH_ALEN)
+ pr_err("cns21xx: failed to parse mac address \"%s\"\n", str);
+
+ return 1;
+}
+
+__setup("ethaddr=", cns21xx_ethaddr_setup);
+
+__init int cns21xx_register_gec(void)
+{
+ if (cns21xx_gec_data.mac_addr == NULL)
+ cns21xx_gec_data.mac_addr = cns21xx_ethaddr;
+
+ if (!is_valid_ether_addr(cns21xx_gec_data.mac_addr)) {
+ random_ether_addr(cns21xx_gec_data.mac_addr);
+ pr_debug("cns21xx: using random MAC address \"%s\"\n",
+ cns21xx_gec_data.mac_addr);
+ }
+
+ return platform_device_register(&cns21xx_gec_device);
+}
--- /dev/null
+++ b/arch/arm/mach-cns21xx/dev-gec.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file 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 _CNS21XX_DEV_GEC_H
+#define _CNS21XX_DEV_GEC_H
+
+#include <mach/cns21xx_gec_platform.h>
+
+extern struct cns21xx_gec_plat_data cns21xx_gec_data;
+
+__init int cns21xx_register_gec(void);
+
+#endif /* _CNS21XX_DEV_GEC_H */
--- /dev/null
+++ b/arch/arm/mach-cns21xx/include/mach/cns21xx_gec_platform.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file 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 _CNS21XX_GEC_PLATFORM_H
+#define _CNS21XX_GEC_PLATFORM_H
+
+#define CNS21XX_GEC_STATUS_IRQ_NAME "status"
+#define CNS21XX_GEC_RXRC_IRQ_NAME "rxrc"
+#define CNS21XX_GEC_RXQF_IRQ_NAME "rxqf"
+#define CNS21XX_GEC_TXTC_IRQ_NAME "txtc"
+#define CNS21XX_GEC_TXQE_IRQ_NAME "txqe"
+
+enum cns21xx_gec_phy_type {
+ CNS21XX_GEC_PHY_TYPE_INTERNAL = 0,
+ CNS21XX_GEC_PHY_TYPE_VSC8601,
+ CNS21XX_GEC_PHY_TYPE_IP101A,
+ CNS21XX_GEC_PHY_TYPE_IP1001,
+};
+
+struct cns21xx_gec_plat_data {
+ u8 *mac_addr;
+ enum cns21xx_gec_phy_type phy_type;
+ u8 phy_addr;
+};
+
+#endif /* _CNS21XX_GEC_PLATFORM_H */

View file

@ -0,0 +1,240 @@
--- a/arch/arm/mach-cns21xx/Kconfig
+++ b/arch/arm/mach-cns21xx/Kconfig
@@ -1,6 +1,16 @@
if ARCH_CNS21XX
menu "Cavium Networks CNS21xx based machines"
+
+config MACH_NS_K330
+ bool "NS-K330 NAS"
+ select CNS21XX_DEV_GEC
+ select CNS21XX_DEV_SPI_MASTER
+ select CNS21XX_DEV_USB
+ help
+ Say Y here if you intend to run this kernel on the
+ NS-K330 NAS board.
+
endmenu
config CNS21XX_DEV_GEC
--- /dev/null
+++ b/arch/arm/mach-cns21xx/mach-ns-k330.c
@@ -0,0 +1,210 @@
+/*
+ * NS-K330 NAS board support
+ *
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <mach/hardware.h>
+#include <mach/cns21xx.h>
+#include <mach/cns21xx_misc.h>
+
+#include "common.h"
+#include "dev-gec.h"
+
+#define NS_K330_GPIO_LED_LINK 1
+#define NS_K330_GPIO_LED_USB1 16
+#define NS_K330_GPIO_LED_USB2 17
+#define NS_K330_GPIO_LED_ETH_GREEN 22
+#define NS_K330_GPIO_LED_ETH_ORANGE 23
+
+#define NS_K330_GPIO_BTN_RESET 13
+#define NS_K330_GPIO_BTN_USB1 14
+#define NS_K330_GPIO_BTN_USB2 15
+
+#ifdef CONFIG_MTD_PARTITIONS
+static struct mtd_partition ns_k330_partitions[] = {
+ {
+ .name = "boot",
+ .offset = 0x0,
+ .size = 0x040000,
+ .mask_flags = MTD_WRITEABLE,
+ }, {
+ .name = "config",
+ .offset = 0x040000,
+ .size = 0x020000,
+ .mask_flags = MTD_WRITEABLE,
+ }, {
+ .name = "kernel",
+ .offset = 0x060000,
+ .size = 0x100000,
+ }, {
+ .name = "rootfs",
+ .offset = 0x160000,
+ .size = 0x290000,
+ }, {
+ .name = "firmware",
+ .offset = 0x060000,
+ .size = 0x390000,
+ },
+};
+#else
+#define ns_k330_partitions NULL
+#define ns_k330_num_partitions 0
+#endif /* CONFIG_MTD_PARTITIONS */
+
+static struct flash_platform_data ns_k330_flash_data = {
+ .parts = ns_k330_partitions,
+ .nr_parts = ARRAY_SIZE(ns_k330_partitions),
+};
+
+static struct spi_board_info ns_k330_spi_board_info[] = {
+ {
+ .bus_num = 0,
+ .chip_select = 0,
+ .max_speed_hz = 25000000,
+ .modalias = "m25p80",
+ .platform_data = &ns_k330_flash_data,
+ }
+};
+
+static struct gpio_led ns_k330_gpio_leds[] = {
+ {
+ .name = "ns-k330:red:link",
+ .gpio = NS_K330_GPIO_LED_LINK,
+ .active_low = 1,
+ }, {
+ .name = "ns-k330:green:usb1",
+ .gpio = NS_K330_GPIO_LED_USB1,
+ .active_low = 1,
+ }, {
+ .name = "ns-k330:green:usb2",
+ .gpio = NS_K330_GPIO_LED_USB2,
+ .active_low = 1,
+ }, {
+ .name = "ns-k330:green:eth",
+ .gpio = NS_K330_GPIO_LED_ETH_GREEN,
+ .active_low = 1,
+ }, {
+ .name = "ns-k330:orange:eth",
+ .gpio = NS_K330_GPIO_LED_ETH_ORANGE,
+ .active_low = 1,
+ }
+};
+
+static struct gpio_led_platform_data ns_k330_gpio_leds_data = {
+ .num_leds = ARRAY_SIZE(ns_k330_gpio_leds),
+ .leds = ns_k330_gpio_leds,
+};
+
+static struct platform_device ns_k330_gpio_leds_device = {
+ .name = "leds-gpio",
+ .id = -1,
+ .dev.platform_data = &ns_k330_gpio_leds_data,
+};
+
+static struct gpio_keys_button ns_k330_gpio_keys[] = {
+ {
+ .code = KEY_RESTART,
+ .gpio = NS_K330_GPIO_BTN_RESET,
+ .desc = "Reset Button",
+ .active_low = 1,
+ },
+ {
+ .code = BTN_0,
+ .gpio = NS_K330_GPIO_BTN_USB1,
+ .desc = "USB1 Button",
+ .active_low = 1,
+ },
+ {
+ .code = BTN_1,
+ .gpio = NS_K330_GPIO_BTN_USB2,
+ .desc = "USB2 Button",
+ .active_low = 0,
+ },
+};
+
+static struct gpio_keys_platform_data ns_k330_gpio_keys_data = {
+ .buttons = ns_k330_gpio_keys,
+ .nbuttons = ARRAY_SIZE(ns_k330_gpio_keys),
+};
+
+static struct platform_device ns_k330_gpio_keys_device = {
+ .name = "gpio-keys",
+ .id = -1,
+ .num_resources = 0,
+ .dev = {
+ .platform_data = &ns_k330_gpio_keys_data,
+ },
+};
+
+static void __init ns_k330_fixup(struct machine_desc *desc,
+ struct tag *tags, char **cmdline,
+ struct meminfo *mi)
+{
+ struct tag *t;
+
+ /* The board has 32MB of RAM mapped at 0. */
+ mi->nr_banks = 1;
+ mi->bank[0].start = 0;
+ mi->bank[0].size = SZ_32M;
+
+ for (t = tags; t->hdr.size; t = tag_next(t)) {
+ switch (t->hdr.tag) {
+ case ATAG_CORE:
+ if (t->u.core.rootdev == 255)
+ t->u.core.rootdev = 0;
+ break;
+ }
+ }
+}
+
+static void __init ns_k330_init(void)
+{
+ cns21xx_gpio_init();
+
+ HAL_MISC_DISABLE_LED012_PINS();
+ HAL_MISC_DISABLE_I2C_PINS();
+ HAL_MISC_DISABLE_I2S_PINS();
+
+ cns21xx_register_uart0();
+ cns21xx_register_wdt();
+ cns21xx_register_usb();
+ cns21xx_register_spi_master(-1, ns_k330_spi_board_info,
+ ARRAY_SIZE(ns_k330_spi_board_info));
+
+ cns21xx_gec_data.phy_type = CNS21XX_GEC_PHY_TYPE_INTERNAL;
+ cns21xx_register_gec();
+
+ platform_device_register(&ns_k330_gpio_leds_device);
+ platform_device_register(&ns_k330_gpio_keys_device);
+}
+
+MACHINE_START(NS_K330, "NS-K330 NAS")
+ .boot_params = 0x100,
+ .fixup = ns_k330_fixup,
+ .map_io = cns21xx_map_io,
+ .init_irq = cns21xx_init_irq,
+ .timer = &cns21xx_timer,
+ .init_machine = ns_k330_init,
+MACHINE_END
--- a/arch/arm/mach-cns21xx/Makefile
+++ b/arch/arm/mach-cns21xx/Makefile
@@ -12,4 +12,4 @@ obj-$(CONFIG_CNS21XX_DEV_USB) += dev-us
obj-$(CONFIG_CNS21XX_DEV_SPI_MASTER) += dev-spi-master.o
# machine specific files
-
+obj-$(CONFIG_MACH_NS_K330) += mach-ns-k330.o

View file

@ -0,0 +1,207 @@
--- a/arch/arm/mach-cns21xx/Kconfig
+++ b/arch/arm/mach-cns21xx/Kconfig
@@ -2,6 +2,15 @@ if ARCH_CNS21XX
menu "Cavium Networks CNS21xx based machines"
+config MACH_NSB3AST
+ bool "AGESTAR NSB3AST support"
+ select CNS21XX_DEV_GEC
+ select CNS21XX_DEV_SPI_MASTER
+ select CNS21XX_DEV_USB
+ help
+ Say Y here if you intend to run this kernel on the
+ AGESTAR NSB3AST board.
+
config MACH_NS_K330
bool "NS-K330 NAS"
select CNS21XX_DEV_GEC
--- /dev/null
+++ b/arch/arm/mach-cns21xx/mach-nsb3ast.c
@@ -0,0 +1,179 @@
+/*
+ * AGESTAR NSB3AST board support
+ *
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <mach/hardware.h>
+#include <mach/cns21xx.h>
+#include <mach/cns21xx_misc.h>
+
+#include "common.h"
+#include "dev-gec.h"
+
+#ifdef CONFIG_MTD_PARTITIONS
+static struct mtd_partition nsb3ast_partitions[] = {
+ {
+ .name = "armboot",
+ .offset = 0x0,
+ .size = 0x040000,
+ .mask_flags = MTD_WRITEABLE,
+ }, {
+ .name = "kernel",
+ .offset = 0x040000,
+ .size = 0x100000,
+ }, {
+ .name = "rootfs",
+ .offset = 0x140000,
+ .size = 0x6c0000,
+ }, {
+ .name = "firmware",
+ .offset = 0x040000,
+ .size = 0x7c0000,
+ }, {
+ .name = "wholeflash",
+ .offset = 0x0,
+ .size = 0x800000,
+ .mask_flags = MTD_WRITEABLE,
+ },
+};
+#else
+#define nsb3ast_partitions NULL
+#define nsb3ast_num_partitions 0
+#endif /* CONFIG_MTD_PARTITIONS */
+
+static struct flash_platform_data nsb3ast_flash_data = {
+ .parts = nsb3ast_partitions,
+ .nr_parts = ARRAY_SIZE(nsb3ast_partitions),
+};
+
+static struct spi_board_info nsb3ast_spi_board_info[] = {
+ {
+ .bus_num = 0,
+ .chip_select = 0,
+ .max_speed_hz = 25000000,
+ .modalias = "m25p80",
+ .platform_data = &nsb3ast_flash_data,
+ }
+};
+
+static struct gpio_led nsb3ast_gpio_leds[] = {
+ {
+ .name = "nsb3ast:red:d1",
+ .gpio = 15,
+ .active_low = 1,
+ }, {
+ .name = "nsb3ast:amber:eth",
+ .gpio = 22,
+ .active_low = 1,
+ }
+};
+
+static struct gpio_led_platform_data nsb3ast_gpio_leds_data = {
+ .num_leds = ARRAY_SIZE(nsb3ast_gpio_leds),
+ .leds = nsb3ast_gpio_leds,
+};
+
+static struct platform_device nsb3ast_gpio_leds_device = {
+ .name = "leds-gpio",
+ .id = -1,
+ .dev.platform_data = &nsb3ast_gpio_leds_data,
+};
+
+static struct gpio_keys_button nsb3ast_gpio_keys[] = {
+ {
+ .code = KEY_RESTART,
+ .gpio = 0,
+ .desc = "Reset Button",
+ .active_low = 1,
+ },
+ {
+ .code = BTN_0,
+ .gpio = 2,
+ .desc = "USB Button",
+ .active_low = 0,
+ },
+};
+
+static struct gpio_keys_platform_data nsb3ast_gpio_keys_data = {
+ .buttons = nsb3ast_gpio_keys,
+ .nbuttons = ARRAY_SIZE(nsb3ast_gpio_keys),
+};
+
+static struct platform_device nsb3ast_gpio_keys_device = {
+ .name = "gpio-keys",
+ .id = -1,
+ .num_resources = 0,
+ .dev = {
+ .platform_data = &nsb3ast_gpio_keys_data,
+ },
+};
+
+static void __init nsb3ast_fixup(struct machine_desc *desc,
+ struct tag *tags, char **cmdline,
+ struct meminfo *mi)
+{
+ struct tag *t;
+
+ /* The board has 32MB of RAM mapped at 0. */
+ mi->nr_banks = 1;
+ mi->bank[0].start = 0;
+ mi->bank[0].size = SZ_32M;
+
+ for (t = tags; t->hdr.size; t = tag_next(t)) {
+ switch (t->hdr.tag) {
+ case ATAG_CORE:
+ if (t->u.core.rootdev == 255)
+ t->u.core.rootdev = 0;
+ break;
+ }
+ }
+}
+
+static void __init nsb3ast_init(void)
+{
+ cns21xx_gpio_init();
+ cns21xx_register_uart0();
+ cns21xx_register_uart1();
+ cns21xx_register_wdt();
+ cns21xx_register_usb();
+ cns21xx_register_spi_master(-1, nsb3ast_spi_board_info,
+ ARRAY_SIZE(nsb3ast_spi_board_info));
+
+ cns21xx_gec_data.phy_type = CNS21XX_GEC_PHY_TYPE_INTERNAL;
+ cns21xx_register_gec();
+
+ HAL_MISC_DISABLE_LED012_PINS();
+ platform_device_register(&nsb3ast_gpio_leds_device);
+ platform_device_register(&nsb3ast_gpio_keys_device);
+}
+
+MACHINE_START(NSB3AST, "AGESTAR NSB3AST")
+ .boot_params = 0x100,
+ .fixup = nsb3ast_fixup,
+ .map_io = cns21xx_map_io,
+ .init_irq = cns21xx_init_irq,
+ .timer = &cns21xx_timer,
+ .init_machine = nsb3ast_init,
+MACHINE_END
--- a/arch/arm/mach-cns21xx/Makefile
+++ b/arch/arm/mach-cns21xx/Makefile
@@ -13,3 +13,4 @@ obj-$(CONFIG_CNS21XX_DEV_SPI_MASTER) +=
# machine specific files
obj-$(CONFIG_MACH_NS_K330) += mach-ns-k330.o
+obj-$(CONFIG_MACH_NSB3AST) += mach-nsb3ast.o

View file

@ -0,0 +1,17 @@
#
# Copyright (C) 2010 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
define Profile/Default
NAME:=Default Profile (all drivers)
PACKAGES:= \
kmod-usb-core kmod-usb-ohci kmod-usb2 kmod-ledtrig-usbdev
endef
define Profile/Default/Description
Default package set compatible with most boards.
endef
$(eval $(call Profile,Default))

View file

@ -91,6 +91,7 @@ config EABI_SUPPORT
depends arm||armeb
prompt "Enable EABI support" if TOOLCHAINOPTS
default n if TARGET_gemini
default n if TARGET_cns21xx
default y
help
Enable ARM EABI support

View file

@ -3,8 +3,8 @@
choice
prompt "GCC compiler Version" if TOOLCHAINOPTS
default GCC_VERSION_4_3_5 if (avr32 || powerpc64)
default GCC_VERSION_4_3_5 if (TARGET_coldfire || TARGET_etrax || TARGET_gemini)
default GCC_VERSION_4_3_3_CS if (arm || armeb) && !(TARGET_gemini || TARGET_omap35xx)
default GCC_VERSION_4_3_5 if (TARGET_coldfire || TARGET_etrax || TARGET_gemini || TARGET_cns21xx)
default GCC_VERSION_4_3_3_CS if (arm || armeb) && !(TARGET_gemini || TARGET_cns21xx || TARGET_omap35xx)
default GCC_VERSION_4_3_3_CS if (mips || mipsel) && !(TARGET_octeon || TARGET_sibyte)
default GCC_VERSION_4_4_5 if (powerpc || ubicom32)
default GCC_VERSION_4_4_5 if (TARGET_omap35xx || TARGET_octeon || TARGET_sibyte)

View file

@ -47,7 +47,7 @@ if !TOOLCHAINOPTS
config GCC_VERSION_4_3_3_CS
default y if (mips || mipsel) && !(TARGET_octeon || TARGET_sibyte)
default y if (arm || armeb) && !(TARGET_gemini || TARGET_omap35xx)
default y if (arm || armeb) && !(TARGET_gemini || TARGET_cns21xx || TARGET_omap35xx)
config GCC_VERSION_4_3_5
default y if avr32
@ -55,6 +55,7 @@ if !TOOLCHAINOPTS
default y if TARGET_etrax
default y if TARGET_coldfire
default y if TARGET_gemini
default y if TARGET_cns21xx
config GCC_VERSION_4_4_5
default y if (TARGET_octeon || TARGET_sibyte || TARGET_omap35xx)

View file

@ -0,0 +1,26 @@
ARCH_ANY_ENDIAN=y
ARCH_LITTLE_ENDIAN=y
ARCH_WANTS_LITTLE_ENDIAN=y
# CONFIG_ARM10T is not set
# CONFIG_ARM1136JF_S is not set
# CONFIG_ARM1176JZF_S is not set
# CONFIG_ARM1176JZ_S is not set
# CONFIG_ARM610 is not set
# CONFIG_ARM710 is not set
# CONFIG_ARM720T is not set
# CONFIG_ARM7TDMI is not set
CONFIG_ARM920T=y
# CONFIG_ARM922T is not set
# CONFIG_ARM926T is not set
# CONFIG_ARM_CORTEX_M1 is not set
# CONFIG_ARM_CORTEX_M3 is not set
# CONFIG_ARM_EABI is not set
# CONFIG_ARM_IWMMXT is not set
CONFIG_ARM_OABI=y
# CONFIG_ARM_SA110 is not set
# CONFIG_ARM_SA1100 is not set
# CONFIG_ARM_XSCALE is not set
# CONFIG_GENERIC_ARM is not set
TARGET_ARCH="arm"
TARGET_arm=y
# USE_BX is not set

View file

@ -0,0 +1,26 @@
ARCH_ANY_ENDIAN=y
ARCH_LITTLE_ENDIAN=y
ARCH_WANTS_LITTLE_ENDIAN=y
# CONFIG_ARM10T is not set
# CONFIG_ARM1136JF_S is not set
# CONFIG_ARM1176JZF_S is not set
# CONFIG_ARM1176JZ_S is not set
# CONFIG_ARM610 is not set
# CONFIG_ARM710 is not set
# CONFIG_ARM720T is not set
# CONFIG_ARM7TDMI is not set
CONFIG_ARM920T=y
# CONFIG_ARM922T is not set
# CONFIG_ARM926T is not set
# CONFIG_ARM_CORTEX_M1 is not set
# CONFIG_ARM_CORTEX_M3 is not set
# CONFIG_ARM_EABI is not set
# CONFIG_ARM_IWMMXT is not set
CONFIG_ARM_OABI=y
# CONFIG_ARM_SA110 is not set
# CONFIG_ARM_SA1100 is not set
# CONFIG_ARM_XSCALE is not set
# CONFIG_GENERIC_ARM is not set
TARGET_ARCH="arm"
TARGET_arm=y
# USE_BX is not set

View file

@ -0,0 +1,26 @@
ARCH_ANY_ENDIAN=y
ARCH_LITTLE_ENDIAN=y
ARCH_WANTS_LITTLE_ENDIAN=y
# CONFIG_ARM10T is not set
# CONFIG_ARM1136JF_S is not set
# CONFIG_ARM1176JZF_S is not set
# CONFIG_ARM1176JZ_S is not set
# CONFIG_ARM610 is not set
# CONFIG_ARM710 is not set
# CONFIG_ARM720T is not set
# CONFIG_ARM7TDMI is not set
CONFIG_ARM920T=y
# CONFIG_ARM922T is not set
# CONFIG_ARM926T is not set
# CONFIG_ARM_CORTEX_M1 is not set
# CONFIG_ARM_CORTEX_M3 is not set
# CONFIG_ARM_EABI is not set
# CONFIG_ARM_IWMMXT is not set
CONFIG_ARM_OABI=y
# CONFIG_ARM_SA110 is not set
# CONFIG_ARM_SA1100 is not set
# CONFIG_ARM_XSCALE is not set
# CONFIG_GENERIC_ARM is not set
TARGET_ARCH="arm"
TARGET_arm=y
# USE_BX is not set