add Moschip MSC814x support

This target currently only supports Moschip's MCS8140 SoC, but support
for other chips in the same family (MCS8142, MCS8144) will be easy to add.

Target support is entirely using Device Tree for probing peripherals.
Drivers support include:
- PCI
- USB 1 & 2
- watchdog
- random number generator
- UART
- timer
- internal Ethernet PHY
- Ethernet MAC core

Support for the following boards is included using Device Tree
- Devolo dLAN USB Extender
- Tigal RBT-832

SVN-Revision: 32462
v19.07.3_mercusys_ac12_duma
Florian Fainelli 12 years ago
parent 7c87391c55
commit f4afa00862

@ -0,0 +1,29 @@
#
# Copyright (C) 2012 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:=mcs814x
BOARDNAME:=Moschip MCS814x
FEATURES:=pci usb
CFLAGS=-Os -pipe -march=armv5te -mtune=arm926ej-s -fno-caller-saves
MAINTAINER:=Florian Fainelli <florian@openwrt.org>
LINUX_VERSION:=3.3.8
include $(INCLUDE_DIR)/target.mk
DEFAULT_PACKAGES := $(filter-out ppp%,$(DEFAULT_PACKAGES)) \
kmod-usb-core kmod-usb2 kmod-usb-ohci \
kmod-usb-storage kmod-fs-vfat \
kmod-nls-cp437 kmod-nls-iso8859-1 kmod-nls-iso8859-15 \
kmod-nls-utf8 \
kmod-mcs814x-wdt
KERNELNAME:="zImage dtbs"
$(eval $(call BuildTarget))

@ -0,0 +1,45 @@
#!/bin/sh
#
# Copyright (C) 2012 OpenWrt.org
#
COMMIT_SYSTEM=0
set_led_usbdev() {
local cfg="led_$1"
local name=$2
local sysfs=$3
local dev=$4
uci -q get system.$cfg && return 0
uci batch <<EOF
set system.$cfg='led'
set system.$cfg.name='$name'
set system.$cfg.sysfs='$sysfs'
set system.$cfg.trigger='usbdev'
set system.$cfg.dev='$dev'
set system.$cfg.interval='50'
EOF
COMMIT_SYSTEM=1
}
. /lib/mcs814x.sh
board=$(mcs814x_board_name)
case "$board" in
dlan-usb-extender)
set_led_usbdev "usb" "USB" "dlan-usb-extender:green:usb" "1-1"
;;
rbt-832)
set_led_usbdev "usb" "USB" "rbt-832:red:usb0" "1-1"
set_led_usbdev "usb" "USB" "rbt-832:red:usb1" "1-2"
set_led_usbdev "usb" "USB" "rbt-832:red:usb2" "1-3"
set_led_usbdev "usb" "USB" "rbt-832:red:usb3" "1-4"
;;
esac
[ "$COMMIT_SYSTEM" == "1" ] && uci commit system
exit 0

@ -0,0 +1,42 @@
#!/bin/sh
#
# Copyright (C) 2012 OpenWrt.org
#
MCS814X_BOARD_NAME=
MCS814X_MODEL=
mcs814x_board_detect() {
local machine
local name
machine=$(cat /proc/device-tree/model)
case "$machine" in
*"Devolo dLAN USB Extender")
name="dlan-usb-extender"
;;
*"Tigal RBT-832")
name="rbt-832"
;;
esac
[ -z "$name" ] && name="unknown"
[ -z "$MCS814X_BOARD_NAME" ] && MCS814X_BOARD_NAME="$name"
[ -z "$MCS814X_MODEL" ] && MCS814X_MODEL="$machine"
[ -e "/tmp/sysinfo/" ] || mkdir -p "/tmp/sysinfo/"
echo "$MCS814X_BOARD_NAME" > /tmp/sysinfo/board_name
echo "$MCS814X_MODEL" > /tmp/sysinfo/model
}
mcs814x_board_name() {
local name
[ -f /tmp/sysinfo/board_name ] && name=$(cat /tmp/sysinfo/board_name)
[ -z "$name" ] && name="unknown"
echo "$name"
}

@ -0,0 +1,9 @@
#!/bin/sh
do_mcs814x() {
. /lib/mcs814x.sh
mcs814x_board_detect
}
boot_hook_add preinit_main do_mcs814x

@ -0,0 +1,248 @@
CONFIG_ALIGNMENT_TRAP=y
CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
CONFIG_ARCH_MCS814X=y
CONFIG_ARCH_NR_GPIO=0
CONFIG_ARCH_REQUIRE_GPIOLIB=y
# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_ARCH_USES_GETTIMEOFFSET=y
CONFIG_ARM=y
CONFIG_ARM_APPENDED_DTB=y
# CONFIG_ARM_ATAG_DTB_COMPAT is not set
# CONFIG_ARM_CPU_SUSPEND is not set
CONFIG_ARM_L1_CACHE_SHIFT=5
CONFIG_ARM_NR_BANKS=8
# CONFIG_ARM_THUMB is not set
# CONFIG_ARPD is not set
CONFIG_BCMA_POSSIBLE=y
CONFIG_BINFMT_MISC=y
# CONFIG_BLK_DEV is not set
# CONFIG_BRIDGE is not set
CONFIG_BSD_PROCESS_ACCT=y
# CONFIG_CACHE_L2X0 is not set
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_CLKDEV_LOOKUP=y
CONFIG_CMDLINE="earlyprintk"
CONFIG_CMDLINE_EXTEND=y
CONFIG_CPU_32v5=y
CONFIG_CPU_ABRT_EV5TJ=y
CONFIG_CPU_ARM926T=y
# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
CONFIG_CPU_CACHE_VIVT=y
CONFIG_CPU_COPY_V4WB=y
CONFIG_CPU_CP15=y
CONFIG_CPU_CP15_MMU=y
# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
# CONFIG_CPU_ICACHE_DISABLE is not set
CONFIG_CPU_PABRT_LEGACY=y
CONFIG_CPU_TLB_V4WBI=y
CONFIG_CPU_USE_DOMAINS=y
CONFIG_CRC_CCITT=y
CONFIG_CRC_ITU_T=y
CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_ALGAPI2=y
CONFIG_CRYPTO_CRC32C=y
CONFIG_CRYPTO_HASH=y
CONFIG_CRYPTO_HASH2=y
CONFIG_DEBUG_LL=y
CONFIG_DEBUG_LL_UART_NONE=y
# CONFIG_DEBUG_USER is not set
CONFIG_DECOMPRESS_LZMA=y
# CONFIG_DEFAULT_BIC is not set
CONFIG_DEFAULT_CFQ=y
CONFIG_DEFAULT_CUBIC=y
# CONFIG_DEFAULT_DEADLINE is not set
# CONFIG_DEFAULT_HTCP is not set
CONFIG_DEFAULT_IOSCHED="cfq"
CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_DEFAULT_WESTWOOD is not set
CONFIG_DTC=y
CONFIG_EARLY_PRINTK=y
CONFIG_ELF_CORE=y
# CONFIG_ENABLE_WARN_DEPRECATED is not set
# CONFIG_FILE_LOCKING is not set
CONFIG_FIQ=y
# CONFIG_FPE_FASTFPE is not set
CONFIG_FPE_NWFPE=y
# CONFIG_FPE_NWFPE_XP is not set
CONFIG_FRAME_POINTER=y
CONFIG_GENERIC_ATOMIC64=y
CONFIG_GENERIC_BUG=y
CONFIG_GENERIC_GPIO=y
CONFIG_GENERIC_IRQ_CHIP=y
CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_GENERIC_PCI_IOMAP=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_MCS814X=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_ARCH_PFN_VALID=y
CONFIG_HAVE_CLK=y
CONFIG_HAVE_C_RECORDMCOUNT=y
CONFIG_HAVE_DMA_API_DEBUG=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_HAVE_GENERIC_DMA_COHERENT=y
CONFIG_HAVE_GENERIC_HARDIRQS=y
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_KERNEL_XZ=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_HAVE_SPARSE_IRQ=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_MCS814X=y
CONFIG_INET_DIAG=y
CONFIG_INET_TCP_DIAG=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_INPUT=y
CONFIG_IOSCHED_CFQ=y
# CONFIG_IP_ADVANCED_ROUTER is not set
# CONFIG_IP_MULTICAST is not set
CONFIG_IP_PNP=y
# CONFIG_IP_PNP_BOOTP is not set
# CONFIG_IP_PNP_DHCP is not set
# CONFIG_IP_PNP_RARP is not set
CONFIG_IRQ_DOMAIN=y
# CONFIG_ISDN is not set
CONFIG_JFFS2_LZO=y
CONFIG_JFFS2_RUBIN=y
# CONFIG_JFFS2_SUMMARY is not set
CONFIG_JFFS2_ZLIB=y
CONFIG_KALLSYMS=y
CONFIG_KERNEL_GZIP=y
# CONFIG_KERNEL_XZ is not set
CONFIG_KTIME_SCALAR=y
CONFIG_LEDS_GPIO=y
# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
# CONFIG_LEDS_TRIGGER_NETDEV is not set
# CONFIG_LEDS_TRIGGER_TIMER is not set
CONFIG_LIBCRC32C=y
CONFIG_LZO_COMPRESS=y
CONFIG_LZO_DECOMPRESS=y
CONFIG_MACH_DLAN_USB_EXT=y
CONFIG_MACH_RBT_832=y
CONFIG_MCS8140=y
CONFIG_MCS814X_PHY=y
# CONFIG_MCS814X_WATCHDOG is not set
CONFIG_MDIO_BOARDINFO=y
# CONFIG_MFD_T7L66XB is not set
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
# CONFIG_MTD_IMPA7 is not set
CONFIG_MTD_JEDECPROBE=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_PHYSMAP=y
CONFIG_MTD_PHYSMAP_OF=y
CONFIG_MULTI_IRQ_HANDLER=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEED_MACH_MEMORY_H=y
CONFIG_NEED_PER_CPU_KM=y
CONFIG_NET_KEY=y
# CONFIG_NET_SCHED is not set
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_NET_VENDOR_ADAPTEC is not set
# CONFIG_NET_VENDOR_ALTEON is not set
# CONFIG_NET_VENDOR_AMD is not set
# CONFIG_NET_VENDOR_ATHEROS is not set
# CONFIG_NET_VENDOR_BROADCOM is not set
# CONFIG_NET_VENDOR_BROCADE is not set
# CONFIG_NET_VENDOR_CHELSIO is not set
# CONFIG_NET_VENDOR_CISCO is not set
# CONFIG_NET_VENDOR_DEC is not set
# CONFIG_NET_VENDOR_DLINK is not set
# CONFIG_NET_VENDOR_EMULEX is not set
# CONFIG_NET_VENDOR_EXAR is not set
# CONFIG_NET_VENDOR_FARADAY is not set
# CONFIG_NET_VENDOR_HP is not set
# CONFIG_NET_VENDOR_INTEL is not set
# CONFIG_NET_VENDOR_MARVELL is not set
# CONFIG_NET_VENDOR_MELLANOX is not set
# CONFIG_NET_VENDOR_MICREL is not set
# CONFIG_NET_VENDOR_MYRI is not set
# CONFIG_NET_VENDOR_NATSEMI is not set
# CONFIG_NET_VENDOR_NVIDIA is not set
# CONFIG_NET_VENDOR_OKI is not set
# CONFIG_NET_VENDOR_QLOGIC is not set
# CONFIG_NET_VENDOR_RDC is not set
# CONFIG_NET_VENDOR_REALTEK is not set
# CONFIG_NET_VENDOR_SEEQ is not set
# CONFIG_NET_VENDOR_SILAN is not set
# CONFIG_NET_VENDOR_SIS is not set
# CONFIG_NET_VENDOR_SMSC is not set
# CONFIG_NET_VENDOR_STMICRO is not set
# CONFIG_NET_VENDOR_SUN is not set
# CONFIG_NET_VENDOR_TEHUTI is not set
# CONFIG_NET_VENDOR_TI is not set
# CONFIG_NET_VENDOR_VIA is not set
CONFIG_NLS=y
CONFIG_NLS_DEFAULT="iso8859-15"
CONFIG_NUPORT_ETHERNET_DRIVER=y
CONFIG_OABI_COMPAT=y
CONFIG_OF=y
CONFIG_OF_ADDRESS=y
CONFIG_OF_DEVICE=y
CONFIG_OF_EARLY_FLATTREE=y
CONFIG_OF_FLATTREE=y
CONFIG_OF_GPIO=y
CONFIG_OF_IRQ=y
CONFIG_OF_MDIO=y
CONFIG_OF_NET=y
CONFIG_OF_PCI=y
CONFIG_OF_PCI_IRQ=y
CONFIG_PAGEFLAGS_EXTENDED=y
CONFIG_PAGE_OFFSET=0xC0000000
# CONFIG_PARTITION_ADVANCED is not set
CONFIG_PCI=y
CONFIG_PCI_DEBUG=y
CONFIG_PCI_DISABLE_COMMON_QUIRKS=y
CONFIG_PERF_USE_VMALLOC=y
CONFIG_PHYLIB=y
# CONFIG_PREEMPT_RCU is not set
# CONFIG_PREVENT_FIRMWARE_BUILD is not set
CONFIG_PRINTK_TIME=y
CONFIG_PROC_DEVICETREE=y
CONFIG_SCHED_DEBUG=y
# CONFIG_SCSI_DMA is not set
CONFIG_SERIAL_OF_PLATFORM=y
CONFIG_SPLIT_PTLOCK_CPUS=999999
# CONFIG_SWAP is not set
# CONFIG_SYN_COOKIES is not set
CONFIG_SYSCTL_SYSCALL=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
CONFIG_TCP_CONG_BIC=y
CONFIG_TCP_CONG_CUBIC=y
CONFIG_TCP_CONG_HTCP=y
CONFIG_UID16=y
CONFIG_USB_ARCH_HAS_XHCI=y
CONFIG_USB_SUPPORT=y
CONFIG_USE_OF=y
CONFIG_VECTORS_BASE=0xffff0000
# CONFIG_VFP is not set
# CONFIG_VLAN_8021Q is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_WATCHDOG_CORE=y
CONFIG_WATCHDOG_NOWAYOUT=y
# CONFIG_WEXT_PRIV is not set
# CONFIG_WEXT_SPY is not set
# CONFIG_WIRELESS_EXT is not set
CONFIG_XZ_DEC=y
CONFIG_ZBOOT_ROM_BSS=0
CONFIG_ZBOOT_ROM_TEXT=0
CONFIG_ZONE_DMA_FLAG=0

@ -0,0 +1,68 @@
/*
* dlan-usb-extender.dts - Device Tree file for Devolo dLAN USB Extender
*
* Copyright (C) 2012, Florian Fainelli <florian@openwrt.org>
*
* Licensed under GPLv2
*/
/dts-v1/;
/include/ "mcs8140.dtsi"
/ {
model = "Devolo dLAN USB Extender";
compatible = "devolo,dlan-usb-extender", "moschip,mcs8140", "moschip,mcs814x";
chosen {
bootargs = "mem=16M console=ttyS0,57600 earlyprintk";
};
ahb {
vci {
adc {
sdram: memory@0,0 {
reg = <0 0 0x1000000>;
};
nor: flash@7,0 {
partition@0 {
label = "ArmBoot";
reg = <0 0x30000>;
};
partition@30000 {
label = "Config1";
reg = <0x30000 0x10000>;
};
partition@40000 {
label = "Config2";
reg = <0x40000 0x10000>;
};
partition@50000 {
label = "bZimage";
reg = <0x50000 0x100000>;
};
partition@150000 {
label = "UserFS";
reg = <0x150000 0x3C0000>;
};
partition@50000 {
label = "Combined";
reg = <0x50000 0x4C0000>;
};
};
};
leds {
compatible = "gpio-leds";
usb {
label = "dlan-usb-extender:green:usb";
gpios = <&gpio 19 0>; // gpio 19 active high
};
};
};
};
};

@ -0,0 +1,198 @@
/*
* mcs8140.dtsi - Device Tree Include file for Moschip MCS8140 family SoC
*
* Copyright (C) 2012, Florian Fainelli <florian@openwrt.org>
*
* Licensed under GPLv2.
*/
/include/ "skeleton.dtsi"
/ {
model = "Moschip MCS8140 family SoC";
compatible = "moschip,mcs8140";
interrupt-parent = <&intc>;
aliases {
serial0 = &uart0;
eth0 = &eth0;
};
cpus {
cpu@0 {
compatible = "arm,arm926ejs";
};
};
ahb {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
ranges;
vci {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
ranges;
eth0: ethernet@40084000 {
//compatible = "moschip,mcs814x-eth";
compatible = "moschip,nuport-mac";
reg = <0x40084000 0xd8 // mac
0x40080000 0x58>; // dma channels
interrupts = <4 5 29>; /* tx, rx, link */
};
tso@40088000 {
reg = <0x40088000 0x1c>;
};
i2s@4008c000 {
compatible = "moschip,mcs814x-i2s";
reg = <0x4008c000 0x18>;
};
ipsec@40094000 {
compatible = "moschip,mcs814x-ipsec";
reg = <0x40094000 0x1d8>;
};
rng@4009c000 {
compatible = "moschip,mcs814x-rng";
reg = <0x4009c000 0x8>;
};
memc@400a8000 {
reg = <0x400a8000 0x58>;
};
list-proc@400ac0c0 {
reg = <0x400ac0c0 0x38>;
};
pci@400b0000 {
reg = <0x400b0000 0x44 // PCI master
0x400d8000 0xe4>; // EEPROM emulator
interrupts = <25>; // abort interrupt
status = "disabled";
#address-cells = <3>;
#size-cells = <2>;
ranges = <0x01000000 0 0x80000000 0x80000000 0 0x04000000 // IO
0x42000000 0 0x90000000 0x90000000 0 0x20000000 // non-prefetch
0x02000000 0 0xb0000000 0xb0000000 0 0x10000000>; // prefecth
#interrupt-cells = <1>;
interrupt-map-mask = <>;
interrupt-map = <0 0 0 1 &intc 22 0
0 0 0 2 &intc 23 0
0 0 0 3 &intc 24 0
0 0 0 4 &intc 26 0>;
};
gpio: gpio@400d0000 {
compatible = "moschip,mcs814x-gpio";
reg = <0x400d0000 0x670>;
#gpio-cells = <2>;
gpio-controller;
num-gpios = <20>;
};
eepio: gpio@400d4000 {
compatible = "moschip,mcs814x-gpio";
reg = <0x400d4000 0x470>;
#gpio-cells = <2>;
gpio-controller;
num-gpios = <4>;
};
uart0: serial@400dc000 {
compatible = "ns16550";
reg = <0x400dc000 0x20>;
clock-frequency = <50000000>;
reg-shift = <2>;
interrupts = <21>;
status = "okay";
};
intc: interrupt-controller@400e4000 {
#interrupt-cells = <1>;
compatible = "moschip,mcs814x-intc";
interrupt-controller;
interrupt-parent;
reg = <0x400e4000 0x48>;
};
m2m@400e8000 {
reg = <0x400e8000 0x24>;
};
eth-filters@400ec000 {
reg = <0x400ec000 0x80>;
};
timer: timer@400f800c {
compatible = "moschip,mcs814x-timer";
interrupts = <0>;
reg = <0x400f800c 0x8>;
};
watchdog@400f8014 {
compatible = "moschip,mcs814x-wdt";
reg = <0x400f8014 0x8>;
};
adc {
compatible = "simple-bus";
#address-cells = <2>;
#size-cells = <1>;
// 8 64MB chip-selects
ranges = <0 0 0x00000000 0x4000000 // sdram
1 0 0x04000000 0x4000000 // sdram
2 0 0x08000000 0x4000000 // reserved
3 0 0x0c000000 0x4000000 // flash/localbus
4 0 0x10000000 0x4000000 // flash/localbus
5 0 0x14000000 0x4000000 // flash/localbus
6 0 0x18000000 0x4000000 // flash/localbus
7 0 0x1c000000 0x4000000>; // flash/localbus
sdram: memory@0,0 {
reg = <0 0 0>;
};
nor: flash@7,0 {
reg = <7 0 0x4000000>;
compatible = "cfi-flash";
bank-width = <1>; // 8-bit external flash
#address-cells = <1>;
#size-cells = <1>;
};
};
usb0: ehci@400fc000 {
compatible = "moschip,mcs814x-ehci", "usb-ehci";
reg = <0x400fc000 0x74>;
interrupts = <2>;
};
usb1: ohci@400fd000 {
compatible = "moschip,mcs814x-ohci", "ohci-le";
reg = <0x400fd000 0x74>;
interrupts = <11>;
};
usb2: ohci@400fe000 {
compatible = "moschip,mcs814x-ohci", "ohci-le";
reg = <0x400fe000 0x74>;
interrupts = <12>;
};
usb3: otg@400ff000 {
compatible = "moschip,msc814x-otg", "usb-otg";
reg = <0x400ff000 0x1000>;
};
};
};
};

@ -0,0 +1,80 @@
/*
* rbt-832.dts - Device Tree file for Tigal RBT-832
*
* Copyright (C) 2012, Florian Fainelli <florian@openwrt.org>
*
* Licensed under GPLv2
*/
/dts-v1/;
/include/ "mcs8140.dtsi"
/ {
model = "Tigal RBT-832";
compatible = "tigal,rbt-832", "moschip,mcs8140", "moschip,mcs814x";
chosen {
bootargs = "mem=32M console=ttyS0,115200 earlyprintk";
};
ahb {
vci {
adc {
sdram: memory@0,0 {
reg = <0 0 0x2000000>;
};
nor: flash@7,0 {
partition@0 {
label = "ArmBoot";
reg = <0 0x40000>;
};
partition@30000 {
label = "Enviroment";
reg = <0x40000 0x20000>;
};
partition@50000 {
label = "bZimage";
reg = <0x60000 0x1a0000>;
};
partition@150000 {
label = "UserFS";
reg = <0x200000 0x600000>;
};
};
};
leds {
compatible = "gpio-leds";
ethernet {
label = "rbt-832:red:ethernet";
gpios = <&gpio 0 0>; // gpio 0 active high
};
usb0 {
label = "rbt-832:red:usb0";
gpios = <&gpio 4 0>; // gpio 4 active high
};
usb1 {
label = "rbt-832:red:usb1";
gpios = <&gpio 3 0>; // gpio 3 active high
};
usb2 {
label = "rbt-832:red:usb2";
gpios = <&gpio 2 0>; // gpio 2 active high
};
usb3 {
label = "rbt-832:red:usb3";
gpios = <&gpio 1 0>; // gpio 1 active high
};
};
};
};
};

@ -0,0 +1,28 @@
if ARCH_MCS814X
config MCS8140
bool
menu "Moschip MCS8140 boards"
config MACH_DLAN_USB_EXT
bool "Devolo dLAN USB Extender"
select MCS8140
select NEW_LEDS
select LEDS_CLASS
select LEDS_GPIO
help
Machine support for the Devolo dLAN USB Extender
config MACH_RBT_832
bool "Tigal RBT-832"
select MCS8140
select NEW_LEDS
select LEDS_CLASS
select LEDS_GPIO
help
Machine support for the Tigal RBT-832 board
endmenu
endif

@ -0,0 +1,6 @@
obj-y += clock.o
obj-y += common.o
obj-y += irq.o
obj-y += timer.o
obj-y += board-mcs8140-dt.o
obj-$(CONFIG_PCI) += pci.o

@ -0,0 +1,6 @@
zreladdr-y := 0x00008000
params_phys-y := 0x00000008
initrd_phys-y := 0x00400000
dtb-$(CONFIG_MACH_DLAN_USB_EXT) += dlan-usb-extender.dtb
dtb-$(CONFIG_MACH_RBT_832) += rbt-832.dtb

@ -0,0 +1,48 @@
/*
* Setup code for Moschip MCS8140-based board using Device Tree
*
* Copyright (C) 2012, Florian Fainelli <florian@openwrt.org>
*
* Licensed under GPLv2.
*/
#include <linux/types.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/irqdomain.h>
#include <linux/of_platform.h>
#include <mach/hardware.h>
#include "common.h"
#include <asm/setup.h>
#include <asm/irq.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
static void __init mcs814x_dt_device_init(void)
{
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
mcs814x_init_machine();
}
static const char *mcs8140_dt_board_compat[] __initdata = {
"devolo,dlan-usb-extender",
"tigal,rbt-832",
"moschip,mcs8140",
NULL, /* sentinel */
};
DT_MACHINE_START(mcs8140_dt, "Moschip MCS8140 board")
/* Maintainer: Florian Fainelli <florian@openwrt.org> */
.timer = &mcs814x_timer,
.map_io = mcs814x_map_io,
.init_early = mcs814x_clk_init,
.init_irq = mcs814x_of_irq_init,
.init_machine = mcs814x_dt_device_init,
.handle_irq = mcs814x_handle_irq,
.restart = mcs814x_restart,
.dt_compat = mcs8140_dt_board_compat,
MACHINE_END

@ -0,0 +1,280 @@
/*
* Moschip MCS814x clock routines
*
* Copyright (C) 2012, Florian Fainelli <florian@openwrt.org>
*
* Licensed under GPLv2
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/export.h>
#include <linux/spinlock.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/clkdev.h>
#include <linux/clk.h>
#include <mach/hardware.h>
/* System configuration registers offsets */
#define SYSDBG_BS1 0x00
#define SYSDBG_SYSCTL 0x08
#define SYSCTL_EMAC (1 << 0)
#define SYSCTL_CIPHER (1 << 16)
#define SYSDBG_PLL_CTL 0x3C
#define CPU_FREQ_SHIFT 27
#define CPU_FREQ_MASK 0x0F
#define SDRAM_FREQ_BIT (1 << 22)
#define KHZ 1000
#define MHZ (KHZ * KHZ)
struct clk_ops {
unsigned long (*get_rate)(struct clk *clk);
int (*set_rate)(struct clk *clk, unsigned long rate);
struct clk *(*get_parent)(struct clk *clk);
int (*enable)(struct clk *clk, int enable);
};
struct clk {
struct clk *parent; /* parent clk */
unsigned long rate; /* clock rate in Hz */
unsigned long divider; /* clock divider */
u32 usecount; /* reference count */
struct clk_ops *ops; /* clock operation */
void __iomem *enable_reg; /* clock enable register */
u32 enable_mask; /* clock enable mask */
};
static unsigned long clk_divide_parent(struct clk *clk)
{
if (clk->parent && clk->divider)
return clk_get_rate(clk->parent) / clk->divider;
else
return 0;
}
static int clk_local_onoff_enable(struct clk *clk, int enable)
{
u32 tmp;
/* no enable_reg means the clock is always enabled */
if (!clk->enable_reg)
return 0;
tmp = __raw_readl(clk->enable_reg);
if (!enable)
tmp &= ~clk->enable_mask;
else
tmp |= clk->enable_mask;
__raw_writel(tmp, clk->enable_reg);
return 0;
}
static struct clk_ops default_clk_ops = {
.get_rate = clk_divide_parent,
.enable = clk_local_onoff_enable,
};
static DEFINE_SPINLOCK(clocks_lock);
static const unsigned long cpu_freq_table[] = {
175000,
300000,
125000,
137500,
212500,
250000,
162500,
187500,
162500,
150000,
225000,
237500,
200000,
262500,
275000,
287500
};
static struct clk clk_cpu;
/* System clock is fixed at 50Mhz */
static struct clk clk_sys = {
.rate = 50 * MHZ,
};
static struct clk clk_sdram;
static struct clk clk_timer0 = {
.parent = &clk_sdram,
.divider = 2,
.ops = &default_clk_ops,
};
static struct clk clk_timer1_2 = {
.parent = &clk_sys,
};
/* Watchdog clock is system clock / 128 */
static struct clk clk_wdt = {
.parent = &clk_sys,
.divider = 128,
.ops = &default_clk_ops,
};
static struct clk clk_emac = {
.ops = &default_clk_ops,
.enable_reg = (void __iomem *)(_CONFADDR_SYSDBG + SYSDBG_SYSCTL),
.enable_mask = SYSCTL_EMAC,
};
static struct clk clk_ephy = {
.ops = &default_clk_ops,
.enable_reg = (void __iomem *)(_CONFADDR_SYSDBG + SYSDBG_PLL_CTL),
.enable_mask = ~(1 << 0),
};
static struct clk clk_cipher = {
.ops = &default_clk_ops,
.enable_reg = (void __iomem *)(_CONFADDR_SYSDBG + SYSDBG_SYSCTL),
.enable_mask = SYSCTL_CIPHER,
};
#define CLK(_dev, _con, _clk) \
{ .dev_id = (_dev), .con_id = (_con), .clk = (_clk) },
static struct clk_lookup mcs814x_chip_clks[] = {
CLK("cpu", NULL, &clk_cpu)
CLK("sys", NULL, &clk_sys)
CLK("sdram", NULL, &clk_sdram)
/* 32-bits timer0 */
CLK("timer0", NULL, &clk_timer0)
/* 16-bits timer1 */
CLK("timer1", NULL, &clk_timer1_2)
/* 64-bits timer2, same as timer 1 */
CLK("timer2", NULL, &clk_timer1_2)
CLK(NULL, "wdt", &clk_wdt)
CLK(NULL, "emac", &clk_emac)
CLK(NULL, "ephy", &clk_ephy)
CLK(NULL, "cipher", &clk_cipher)
};
static void local_clk_disable(struct clk *clk)
{
WARN_ON(!clk->usecount);
if (clk->usecount > 0) {
clk->usecount--;
if ((clk->usecount == 0) && (clk->ops->enable))
clk->ops->enable(clk, 0);
if (clk->parent)
local_clk_disable(clk->parent);
}
}
static int local_clk_enable(struct clk *clk)
{
int ret = 0;
if (clk->parent)
ret = local_clk_enable(clk->parent);
if (ret)
return ret;
if ((clk->usecount == 0) && (clk->ops->enable))
ret = clk->ops->enable(clk, 1);
if (!ret)
clk->usecount++;
else if (clk->parent && clk->parent->ops->enable)
local_clk_disable(clk->parent);
return ret;
}
int clk_enable(struct clk *clk)
{
int ret;
unsigned long flags;
spin_lock_irqsave(&clocks_lock, flags);
ret = local_clk_enable(clk);
spin_unlock_irqrestore(&clocks_lock, flags);
return ret;
}
EXPORT_SYMBOL(clk_enable);
void clk_disable(struct clk *clk)
{
unsigned long flags;
spin_lock_irqsave(&clocks_lock, flags);
local_clk_disable(clk);
spin_unlock_irqrestore(&clocks_lock, flags);
}
EXPORT_SYMBOL(clk_disable);
unsigned long clk_get_rate(struct clk *clk)
{
if (unlikely(IS_ERR_OR_NULL(clk)))
return 0;
if (clk->rate)
return clk->rate;
if (clk->ops && clk->ops->get_rate)
return clk->ops->get_rate(clk);
return clk_get_rate(clk->parent);
}
EXPORT_SYMBOL(clk_get_rate);
struct clk *clk_get_parent(struct clk *clk)
{
unsigned long flags;
if (unlikely(IS_ERR_OR_NULL(clk)))
return NULL;
if (!clk->ops || !clk->ops->get_parent)
return clk->parent;
spin_lock_irqsave(&clocks_lock, flags);
clk->parent = clk->ops->get_parent(clk);
spin_unlock_irqrestore(&clocks_lock, flags);
return clk->parent;
}
EXPORT_SYMBOL(clk_get_parent);
void __init mcs814x_clk_init(void)
{
u32 bs1;
u8 cpu_freq;
clkdev_add_table(mcs814x_chip_clks, ARRAY_SIZE(mcs814x_chip_clks));
/* read the bootstrap registers to know the exact clocking scheme */
bs1 = __raw_readl(_CONFADDR_SYSDBG + SYSDBG_BS1);
cpu_freq = (bs1 >> CPU_FREQ_SHIFT) & CPU_FREQ_MASK;
pr_info("CPU frequency: %lu (kHz)\n", cpu_freq_table[cpu_freq]);
clk_cpu.rate = cpu_freq * KHZ;
/* read SDRAM frequency */
if (bs1 & SDRAM_FREQ_BIT)
clk_sdram.rate = 100 * MHZ;
else
clk_sdram.rate = 133 * MHZ;
pr_info("SDRAM frequency: %lu (MHz)\n", clk_sdram.rate / MHZ);
}

@ -0,0 +1,92 @@
/*
* arch/arm/mach-mcs814x/common.c
*
* Core functions for Moschip MCS814x SoCs
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <asm/setup.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <mach/hardware.h>
#include <mach/cpu.h>
#include <asm/pgtable.h>
#include <asm/mach/map.h>
static struct map_desc mcs814x_io_desc[] __initdata = {
{
.virtual = MCS814X_IO_BASE,
.pfn = __phys_to_pfn(MCS814X_IO_START),
.length = MCS814X_IO_SIZE,
.type = MT_DEVICE
},
};
#define SYSDBG_BS2 0x04
#define CPU_MODE_SHIFT 23
#define CPU_MODE_MASK 0x03
struct cpu_mode {
const char *name;
int gpio_start;
int gpio_end;
};
static const struct cpu_mode cpu_modes[] = {
{
.name = "I2S",
.gpio_start = 4,
.gpio_end = 8,
},
{
.name = "UART",
.gpio_start = 4,
.gpio_end = 9,
},
{
.name = "External MII",
.gpio_start = 0,
.gpio_end = 16,
},
{
.name = "Normal",
.gpio_start = -1,
.gpio_end = -1,
},
};
void __init mcs814x_init_machine(void)
{
u32 bs2, cpu_mode;
int gpio;
bs2 = __raw_readl(_CONFADDR_SYSDBG + SYSDBG_BS2);
cpu_mode = (bs2 >> CPU_MODE_SHIFT) & CPU_MODE_MASK;
pr_info("CPU mode: %s\n", cpu_modes[cpu_mode].name);
/* request the gpios since the pins are muxed for functionnality */
for (gpio = cpu_modes[cpu_mode].gpio_start;
gpio == cpu_modes[cpu_mode].gpio_end; gpio++) {
if (gpio != -1)
gpio_request(gpio, cpu_modes[cpu_mode].name);
}
}
void __init mcs814x_map_io(void)
{
iotable_init(mcs814x_io_desc, ARRAY_SIZE(mcs814x_io_desc));
}
void mcs814x_restart(char mode, const char *cmd)
{
__raw_writel(~(1 << 31), _CONFADDR_SYSDBG);
}

@ -0,0 +1,14 @@
#ifndef __ARCH_MCS814X_COMMON_H
#define __ARCH_MCS814X_COMMON_H
#include <asm/mach/time.h>
void mcs814x_map_io(void);
void mcs814x_clk_init(void);
void mcs814x_of_irq_init(void);
void mcs814x_init_machine(void);
void mcs814x_handle_irq(struct pt_regs *regs);
void mcs814x_restart(char mode, const char *cmd);
extern struct sys_timer mcs814x_timer;
#endif /* __ARCH_MCS814X_COMMON_H */

@ -0,0 +1,16 @@
#ifndef __ASM_ARCH_CPU_H__
#define __ASM_ARCH_CPU_H__
#include <asm/cputype.h>
#define MCS8140_ID 0x41069260 /* ARM926EJ-S */
#define MCS814X_MASK 0xff0ffff0
#ifdef CONFIG_MCS8140
/* Moschip MCS8140 is based on an ARM926EJ-S core */
#define soc_is_mcs8140() ((read_cpuid_id() & MCS814X_MASK) == MCS8140_ID)
#else
#define soc_is_mcs8140() (0)
#endif /* !CONFIG_MCS8140 */
#endif /* __ASM_ARCH_CPU_H__ */

@ -0,0 +1,11 @@
#include <mach/hardware.h>
.macro addruart, rp, rv, tmp
ldr \rp, =_PHYS_CONFADDR
ldr \rv, =_VIRT_CONFADDR
orr \rp, \rp, #_CONFOFFSET_UART
orr \rv, \rv, #_CONFOFFSET_UART
.endm
#define UART_SHIFT 2
#include <asm/hardware/debug-8250.S>

@ -0,0 +1,6 @@
#include <mach/hardware.h>
.macro disable_fiq
.endm
.macro arch_ret_to_user, tmp1, tmp2
.endm

@ -0,0 +1,21 @@
#ifndef __ASM_ARCH_GPIO_H
#define __ASM_ARCH_GPIO_H
/* new generic GPIO API */
#include <asm-generic/gpio.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 -EINVAL;
}
static inline int irq_to_gpio(unsigned irq)
{
return -EINVAL;
}
#endif

@ -0,0 +1,28 @@
/*
* Copyright (C) 2003 Artec Design Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#ifndef __ASM_ARCH_HARDWARE_H
#define __ASM_ARCH_HARDWARE_H
#define MCS814X_IO_BASE 0xF0000000
#define MCS814X_IO_START 0x40000000
#define MCS814X_IO_SIZE 0x00100000
#define _PHYS_CONFADDR 0x40000000
#define _VIRT_CONFADDR MCS814X_IO_BASE
#define _CONFOFFSET_UART 0x000DC000
#define _CONFOFFSET_DBGLED 0x000EC000
#define _CONFOFFSET_SYSDBG 0x000F8000
#define _CONFADDR_DBGLED (_VIRT_CONFADDR + _CONFOFFSET_DBGLED)
#define _CONFADDR_SYSDBG (_VIRT_CONFADDR + _CONFOFFSET_SYSDBG)
#endif

@ -0,0 +1,27 @@
/*
* Copyright (C) 2003 Artec Design Ltd.
* Copyright (C) 2012, Florian Fainelli <florian@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.
*
*/
#ifndef __ASM_ARM_ARCH_IO_H
#define __ASM_ARM_ARCH_IO_H
#define IO_SPACE_LIMIT 0xffffffff
/*
* We don't support ins[lb]/outs[lb]. Make them fault.
*/
#define __raw_readsb(p, d, l) do { *(int *)0 = 0; } while (0)
#define __raw_readsl(p, d, l) do { *(int *)0 = 0; } while (0)
#define __raw_writesb(p, d, l) do { *(int *)0 = 0; } while (0)
#define __raw_writesl(p, d, l) do { *(int *)0 = 0; } while (0)
#define __io(a) __typesafe_io(a)
#define __mem_pci(a) (a)
#endif

@ -0,0 +1,22 @@
/*
* Copyright (C) 2003 Artec Design Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#ifndef __ASM_ARCH_IRQS_H
#define __ASM_ARCH_IRQS_H
#define FIQ_START 0
#define NR_IRQS 32
#define IRQ_PCI_INTA 22
#define IRQ_PCI_INTB 23
#define IRQ_PCI_INTC 24
#define IRQ_PCI_INTD 26
#endif

@ -0,0 +1,16 @@
/*
* Copyright (C) 2003 Artec Design Ltd.
* Copyright (C) 2012, Florian Fainelli <florian@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.
*
*/
#ifndef __ASM_ARCH_MEMORY_H
#define __ASM_ARCH_MEMORY_H
#define PLAT_PHYS_OFFSET UL(0x00000000)
#endif

@ -0,0 +1,15 @@
/*
* Copyright (C) 2003 Artec Design Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#ifndef __ASM_ARCH_PARAM_H
#define __ASM_ARCH_PARAM_H
#define HZ 100
#endif

@ -0,0 +1,18 @@
/*
* Copyright (C) 2003 Artec Design Ltd.
* Copyright (C) 2012 Florian Fainelli <florian@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.
*
*/
#ifndef __ASM_ARCH_SYSTEM_H
#define __ASM_ARCH_SYSTEM_H
static inline void arch_idle(void)
{
cpu_do_idle();
}
#endif

@ -0,0 +1,18 @@
/*
* Copyright (C) 2003 Artec Design Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#ifndef __ASM_ARCH_TIMEX_H
#define __ASM_ARCH_TIMEX_H
/*
* Timex specification for MCS814X
*/
#define CLOCK_TICK_RATE 100
#endif

@ -0,0 +1,40 @@
/*
* Copyright (C) 2012, Florian Fainelli <florian@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.
*/
#ifndef __ASM_ARCH_UNCOMPRESS_H
#define __ASM_ARCH_UNCOMPRESS_H
#include <linux/serial_reg.h>
#include <asm/io.h>
#include <mach/hardware.h>
#include <mach/cpu.h>
#define UART_SHIFT (2)
/* cannot be static because the code will be inlined */
void __iomem *uart_base;
static inline void putc(int c)
{
while (!(__raw_readb(uart_base + (UART_LSR << UART_SHIFT)) & UART_LSR_TEMT));
__raw_writeb(c, uart_base + (UART_TX << UART_SHIFT));
}
static inline void flush(void)
{
}
static inline void arch_decomp_setup(void)
{
if (soc_is_mcs8140())
uart_base = (void __iomem *)(_PHYS_CONFADDR + _CONFOFFSET_UART);
}
#define arch_decomp_wdog()
#endif

@ -0,0 +1,93 @@
/*
* Moschip MCS814x generic interrupt controller routines
*
* Copyright (C) 2012, Florian Fainelli <florian@openwrt.org>
*
* Licensed under the GPLv2
*/
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/irqdomain.h>
#include <asm/exception.h>
#include <asm/mach/irq.h>
#define MCS814X_IRQ_ICR 0x00
#define MCS814X_IRQ_ISR 0x04
#define MCS814X_IRQ_MASK 0x20
#define MCS814X_IRQ_STS0 0x40
static void __iomem *mcs814x_intc_base;
static void __init mcs814x_alloc_gc(void __iomem *base, unsigned int irq_start,
unsigned int num)
{
struct irq_chip_generic *gc;
struct irq_chip_type *ct;
gc = irq_alloc_generic_chip("mcs814x-intc", 1,
irq_start, base, handle_level_irq);
if (!gc)
panic("unable to allocate generic irq chip");
ct = gc->chip_types;
ct->chip.irq_ack = irq_gc_unmask_enable_reg;
ct->chip.irq_mask = irq_gc_mask_clr_bit;
ct->chip.irq_unmask = irq_gc_mask_set_bit;
ct->regs.mask = MCS814X_IRQ_MASK;
ct->regs.enable = MCS814X_IRQ_ICR;
irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE,
IRQ_NOREQUEST, 0);
/* Clear all interrupts */
__raw_writel(0xffffffff, base + MCS814X_IRQ_ICR);
}
asmlinkage void __exception_irq_entry mcs814x_handle_irq(struct pt_regs *regs)
{
u32 status, irq;
do {
/* read the status register */
status = __raw_readl(mcs814x_intc_base + MCS814X_IRQ_STS0);
if (!status)
break;
irq = ffs(status) - 1;
status |= (1 << irq);
/* clear the interrupt */
__raw_writel(status, mcs814x_intc_base + MCS814X_IRQ_ICR);
/* call the generic handler */
handle_IRQ(irq, regs);
} while (1);
}
static const struct of_device_id mcs814x_intc_ids[] = {
{ .compatible = "moschip,mcs814x-intc" },
{ /* sentinel */ },
};
void __init mcs814x_of_irq_init(void)
{
struct device_node *np;
np = of_find_matching_node(NULL, mcs814x_intc_ids);
if (!np)
panic("unable to find compatible intc node in dtb\n");
mcs814x_intc_base = of_iomap(np, 0);
if (!mcs814x_intc_base)
panic("unable to map intc cpu registers\n");
irq_domain_add_simple(np, 0);
of_node_put(np);
mcs814x_alloc_gc(mcs814x_intc_base, 0, 32);
}

@ -0,0 +1,453 @@
/*
* Moschip MCS8140 PCI support
*
* Copyright (C) 2003 Moschip Semiconductors Ltd.
* Copyright (C) 2003 Artec Design Ltd.
* Copyright (C) 2012 Florian Fainelli <florian@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/pci.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/io.h>
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/mach/pci.h>
#include <asm/mach/map.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
#define MCS8140_PCI_CONFIG_SIZE SZ_64M
#define MCS8140_PCI_IOMISC_SIZE SZ_64M
#define MCS8140_PCI_HOST_BASE 0x80000000
#define MCS8140_PCI_IOMISC_BASE 0x00000000
#define MCS8140_PCI_PRE_BASE 0x10000000
#define MCS8140_PCI_NONPRE_BASE 0x30000000
#define MCS8140_PCI_CFG_BASE (MCS8140_PCI_HOST_BASE + 0x04000000)
#define MCS8140_PCI_IO_BASE (MCS8140_PCI_HOST_BASE)
#define MCS8140_PCI_IO_VIRT_BASE (MCS814X_IO_BASE - MCS8140_PCI_CONFIG_SIZE - \
MCS8140_PCI_IOMISC_SIZE)
#define MCS8140_PCI_CFG_VIRT_BASE (MCS814X_IO_BASE - MCS8140_PCI_CONFIG_SIZE)
#define PCI_FATAL_ERROR 1
#define EXTERNAL_ABORT_NON_LINE_FETCH 8
#define EPRM_DONE 0x80
#define EPRM_SDRAM_FUNC0 0xAC
#define PCI_INTD 4
#define MCS8140_PCI_DEVICE_ID 0xA0009710
#define MCS8140_PCI_CLASS_ID 0x02000011 /* Host-Class id :0x0600 */
#define PCI_IF_CONFIG 0x200
static void __iomem *mcs8140_pci_master_base;
static void __iomem *mcs8140_eeprom_emu_base;
static unsigned long __pci_addr(struct pci_bus *bus,
unsigned int devfn, int offset)
{
unsigned int busnr = bus->number;
unsigned int slot;
/* we only support bus 0 */
if (busnr != 0)
return 0;
/*
* Trap out illegal values
*/
BUG_ON(devfn > 255 || busnr > 255 || devfn > 255);
/* Scan 3 slots */
slot = PCI_SLOT(devfn);
switch (slot) {
case 1:
case 2:
case 3:
if (PCI_FUNC(devfn) >= 4)
return 0;
return MCS8140_PCI_CFG_VIRT_BASE | (PCI_SLOT(devfn) << 11) |
(PCI_FUNC(devfn) << 8) | offset;
default:
pr_warn("Ignoring: PCI Slot is %x\n", PCI_SLOT(devfn));
return 0;
}
}
static int mcs8140_pci_host_status(void)
{
u32 host_status;
host_status = __raw_readl(mcs8140_pci_master_base + PCI_IF_CONFIG);
if (host_status & PCI_FATAL_ERROR) {
__raw_writel(host_status & 0xfffffff0,
mcs8140_pci_master_base + PCI_IF_CONFIG);
/* flush write */
host_status =
__raw_readl(mcs8140_pci_master_base + PCI_IF_CONFIG);
return 1;
}
return 0;
}
static int mcs8140_pci_read_config(struct pci_bus *bus,
unsigned int devfn, int where,
int size, u32 *val)
{
unsigned long v = 0xFFFFFFFF;
unsigned long addr = __pci_addr(bus, devfn, where);
if (addr != 0) {
switch (size) {
case 1:
v = __raw_readb(addr);
break;
case 2:
addr &= ~1;
v = __raw_readw(addr);
break;
default:
addr &= ~3;
v = __raw_readl(addr);
break;
}
} else
v = 0xffffffff;
if (mcs8140_pci_host_status())
v = 0xffffffff;
*val = v;
return PCIBIOS_SUCCESSFUL;
}
static void mcs8140_eeprom_emu_init(void)
{
__raw_writel(0x0000000F, mcs8140_eeprom_emu_base + EPRM_SDRAM_FUNC0);
__raw_writel(0x08000000, MCS8140_PCI_CFG_VIRT_BASE + 0x10);
/* Set the DONE bit of the EEPROM emulator */
__raw_writel(0x01, mcs8140_eeprom_emu_base + EPRM_DONE);
}
static int mcs8140_pci_write_config(struct pci_bus *bus,
unsigned int devfn, int where,
int size, u32 val)
{
unsigned long addr = __pci_addr(bus, devfn, where);
if (addr != 0) {
switch (size) {
case 1:
__raw_writeb((u8)val, addr);
break;
case 2:
__raw_writew((u16)val, addr);
break;
case 4:
__raw_writel(val, addr);
break;
}
}
return PCIBIOS_SUCCESSFUL;
}
static struct pci_ops pci_mcs8140_ops = {
.read = mcs8140_pci_read_config,
.write = mcs8140_pci_write_config,
};
static struct resource io_mem = {
.name = "PCI I/O space",
.start = MCS8140_PCI_HOST_BASE + MCS8140_PCI_IOMISC_BASE,
.end = MCS8140_PCI_HOST_BASE + MCS8140_PCI_IOMISC_BASE + SZ_64M,
.flags = IORESOURCE_IO,
};
static struct resource pre_mem = {
.name = "PCI prefetchable",
.start = MCS8140_PCI_HOST_BASE + MCS8140_PCI_PRE_BASE,
.end = MCS8140_PCI_HOST_BASE + MCS8140_PCI_PRE_BASE + SZ_512M,
.flags = IORESOURCE_MEM | IORESOURCE_PREFETCH,
};
static struct resource non_mem = {
.name = "PCI non-prefetchable",
.start = MCS8140_PCI_HOST_BASE + MCS8140_PCI_NONPRE_BASE,
.end = MCS8140_PCI_HOST_BASE + MCS8140_PCI_NONPRE_BASE + SZ_256M,
.flags = IORESOURCE_MEM,
};
int __init pci_mcs8140_setup_resources(struct pci_sys_data *sys)
{
int ret = 0;
ret = request_resource(&iomem_resource, &io_mem);
if (ret) {
pr_err("PCI: unable to allocate I/O "
"memory region (%d)\n", ret);
goto out;
}
ret = request_resource(&iomem_resource, &non_mem);
if (ret) {
pr_err("PCI: unable to allocate non-prefetchable "
"memory region (%d)\n", ret);
goto release_io_mem;
}
ret = request_resource(&iomem_resource, &pre_mem);
if (ret) {
pr_err("PCI: unable to allocate prefetchable "
"memory region (%d)\n", ret);
goto release_non_mem;
}
mcs8140_eeprom_emu_init();
pci_add_resource(&sys->resources, &io_mem);
pci_add_resource(&sys->resources, &non_mem);
pci_add_resource(&sys->resources, &pre_mem);
return ret;
release_non_mem:
release_resource(&non_mem);
release_io_mem:
release_resource(&io_mem);
out:
return ret;
}
struct pci_bus *pci_mcs8140_scan_bus(int nr, struct pci_sys_data *sys)
{
return pci_scan_bus(sys->busnr, &pci_mcs8140_ops, sys);
}
int __init pci_mcs8140_setup(int nr, struct pci_sys_data *sys)
{
int ret = 0;
u32 val;
if (nr > 0)
return 0;
sys->mem_offset = MCS8140_PCI_IO_VIRT_BASE - MCS8140_PCI_IO_BASE;
sys->io_offset = 0;
ret = pci_mcs8140_setup_resources(sys);
if (ret < 0) {
pr_err("unable to setup mcs8140 resources\n");
goto out;
}
val = __raw_readl(MCS8140_PCI_CFG_VIRT_BASE);
if (val != MCS8140_PCI_DEVICE_ID) {
pr_err("cannot find MCS8140 PCI Core: %08x\n", val);
ret = -EIO;
goto out;
}
pr_info("MCS8140 PCI core found\n");
val = __raw_readl(MCS8140_PCI_CFG_VIRT_BASE + PCI_COMMAND);
/* Added to support wireless cards */
__raw_writel(0, MCS8140_PCI_CFG_VIRT_BASE + 0x40);
__raw_writel(val | 0x147, MCS8140_PCI_CFG_VIRT_BASE + PCI_COMMAND);
val = __raw_readl(MCS8140_PCI_CFG_VIRT_BASE + PCI_COMMAND);
ret = 1;
out:
return ret;
}
static int __init mcs8140_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
int line = IRQ_PCI_INTA;
if (pin != 0) {
/* IRQ_PCIA - 22 */
if (pin == PCI_INTD)
line = IRQ_PCI_INTA + pin; /* IRQ_PCIA - 22 */
else
line = IRQ_PCI_INTA + pin - 1; /* IRQ_PCIA - 22 */
}
pr_info("PCI: Map interrupt slot 0x%02x pin 0x%02x line 0x%02x\n",
slot, pin, line);
return line;
}
static irqreturn_t mcs8140_pci_abort_interrupt(int irq, void *dummy)
{
u32 word;
word = __raw_readl(mcs8140_pci_master_base + PCI_IF_CONFIG);
if (!(word & (1 << 24)))
return IRQ_NONE;
__raw_writel(word & 0xfffffff0,
mcs8140_pci_master_base + PCI_IF_CONFIG);
/* flush write */
word = __raw_readl(mcs8140_pci_master_base + PCI_IF_CONFIG);
return IRQ_HANDLED;
}
static int mcs8140_pci_abort_irq_init(int irq)
{
u32 word;
/* Enable Interrupt in PCI Master Core */
word = __raw_readl(mcs8140_pci_master_base + PCI_IF_CONFIG);
word |= (1 << 24);
__raw_writel(word, mcs8140_pci_master_base + PCI_IF_CONFIG);
/* flush write */
word = __raw_readl(mcs8140_pci_master_base + PCI_IF_CONFIG);
return request_irq(irq, mcs8140_pci_abort_interrupt, 0,
"PCI abort", NULL);
}
static int mcs8140_pci_host_abort(unsigned long addr,
unsigned int fsr, struct pt_regs *regs)
{
pr_warn("PCI Data abort: address = 0x%08lx fsr = 0x%03x"
"PC = 0x%08lx LR = 0x%08lx\n",
addr, fsr, regs->ARM_pc, regs->ARM_lr);
/*
* If it was an imprecise abort, then we need to correct the
* return address to be _after_ the instruction.
*/
if (fsr & (1 << 10) || mcs8140_pci_host_status())
regs->ARM_pc += 4;
return 0;
}
static void mcs8140_data_abort_init(void)
{
hook_fault_code(EXTERNAL_ABORT_NON_LINE_FETCH,
mcs8140_pci_host_abort, SIGBUS,
0, "external abort on non-line fetch");
}
static struct hw_pci mcs8140_pci __initdata = {
.map_irq = mcs8140_map_irq,
.nr_controllers = 1,
.setup = pci_mcs8140_setup,
.scan = pci_mcs8140_scan_bus,
};
static struct map_desc mcs8140_pci_io_desc[] __initdata = {
{
.virtual = MCS8140_PCI_CFG_VIRT_BASE,
.pfn = __phys_to_pfn(MCS8140_PCI_CFG_BASE),
.length = MCS8140_PCI_CONFIG_SIZE,
.type = MT_DEVICE
},
{
.virtual = MCS8140_PCI_IO_VIRT_BASE,
.pfn = __phys_to_pfn(MCS8140_PCI_IO_BASE),
.length = MCS8140_PCI_IOMISC_SIZE,
.type = MT_DEVICE
},
};
static int __devinit mcs8140_pci_probe(struct platform_device *pdev)
{
struct resource *res;
int ret, irq;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "failed to get mem resource 0\n");
return -ENODEV;
}
mcs8140_pci_master_base = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
if (!mcs8140_pci_master_base) {
dev_err(&pdev->dev, "failed to remap PCI master regs\n");
return -ENODEV;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!res) {
dev_err(&pdev->dev, "failed to get mem resource 1\n");
return -ENOMEM;
}
mcs8140_eeprom_emu_base = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
if (!mcs8140_eeprom_emu_base) {
dev_err(&pdev->dev, "failed to remap EEPROM regs\n");
return -ENOMEM;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "failed to get pci abort irq\n");
return -ENODEV;
}
/* Setup static mappins for PCI CFG space */
iotable_init(mcs8140_pci_io_desc, ARRAY_SIZE(mcs8140_pci_io_desc));
pcibios_min_io = MCS8140_PCI_HOST_BASE;
pcibios_min_mem = MCS8140_PCI_HOST_BASE + MCS8140_PCI_PRE_BASE;
mcs8140_data_abort_init();
ret = mcs8140_pci_abort_irq_init(irq);
if (ret) {
dev_err(&pdev->dev, "failed to setup abort irq\n");
return ret;
}
pci_common_init(&mcs8140_pci);
return 0;
}
static struct of_device_id mcs8140_of_ids[] __devinitdata = {
{ .compatible = "moschip,mcs8140-pci" },
{ .compatible = "moschip,mcs814x-pci" },
{ /* sentinel */ },
};
static struct platform_driver mcs8140_pci_driver = {
.driver = {
.name = "mcs8140-pci",
.of_match_table = mcs8140_of_ids,
},
.probe = mcs8140_pci_probe,
};
static int __init mcs8140_pci_init(void)
{
return platform_driver_register(&mcs8140_pci_driver);
}
subsys_initcall(mcs8140_pci_init);

@ -0,0 +1,133 @@
/*
* Moschip MCS814x timer routines
*
* Copyright (C) 2012, Florian Fainelli <florian@openwrt.org>
*
* Licensed under GPLv2
*/
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/time.h>
#include <linux/timex.h>
#include <linux/irq.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <asm/mach/time.h>
#include <mach/hardware.h>
/* Timer block registers */
#define TIMER_VAL 0x00
#define TIMER_CTL 0x04
static u32 last_reload;
static u32 timer_correct;
static u32 clock_rate;
static u32 timer_reload_value;
static void __iomem *mcs814x_timer_base;
static inline unsigned long ticks2usecs(u32 x)
{
return x / (clock_rate / 1000000);
}
/*
* Returns number of ms since last clock interrupt. Note that interrupts
* will have been disabled by do_gettimeoffset()
*/
static unsigned long mcs814x_gettimeoffset(void)
{
u32 ticks = __raw_readl(mcs814x_timer_base + TIMER_VAL);
if (ticks < last_reload)
return ticks2usecs(ticks + (u32)(0xffffffff - last_reload));
else
return ticks2usecs(ticks - last_reload);
}
static irqreturn_t mcs814x_timer_interrupt(int irq, void *dev_id)
{
u32 count = __raw_readl(mcs814x_timer_base + TIMER_VAL);
/* take into account delay up to this moment */
last_reload = count + timer_correct + timer_reload_value;
if (last_reload < timer_reload_value) {
last_reload = timer_reload_value;
} else {
if (timer_correct == 0)
timer_correct = __raw_readl(mcs814x_timer_base + TIMER_VAL) - count;
}
__raw_writel(last_reload, mcs814x_timer_base + TIMER_VAL);
timer_tick();
return IRQ_HANDLED;
}
static struct irqaction mcs814x_timer_irq = {
.name = "mcs814x-timer",
.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = mcs814x_timer_interrupt,
};
static struct of_device_id mcs814x_timer_ids[] = {
{ .compatible = "moschip,mcs814x-timer" },
{ /* sentinel */ },
};
static void __init mcs814x_of_timer_init(void)
{
struct device_node *np;
const unsigned int *intspec;
np = of_find_matching_node(NULL, mcs814x_timer_ids);
if (!np)
panic("unable to find compatible timer node in dtb");
mcs814x_timer_base = of_iomap(np, 0);
if (!mcs814x_timer_base)
panic("unable to remap timer cpu registers");
intspec = of_get_property(np, "interrupts", NULL);
if (!intspec)
panic("no interrupts property for timer");
mcs814x_timer_irq.irq = be32_to_cpup(intspec);
}
static void __init mcs814x_timer_init(void)
{
struct clk *clk;
clk = clk_get_sys("timer0", NULL);
if (IS_ERR_OR_NULL(clk))
panic("unable to get timer0 clock");
clock_rate = clk_get_rate(clk);
clk_put(clk);
mcs814x_of_timer_init();
pr_info("Timer frequency: %d (kHz)\n", clock_rate / 1000);
timer_reload_value = 0xffffffff - (clock_rate / HZ);
/* disable timer */
__raw_writel(0, mcs814x_timer_base + TIMER_CTL);
__raw_writel(timer_reload_value, mcs814x_timer_base + TIMER_VAL);
last_reload = timer_reload_value;
setup_irq(mcs814x_timer_irq.irq, &mcs814x_timer_irq);
/* enable timer, stop timer in debug mode */
__raw_writel(0x03, mcs814x_timer_base + TIMER_CTL);
}
struct sys_timer mcs814x_timer = {
.init = mcs814x_timer_init,
.offset = mcs814x_gettimeoffset,
};

@ -0,0 +1,128 @@
/*
* RNG driver for Moschip MCS814x SoC
*
* Copyright 2012 (C), Florian Fainelli <florian@openwrt.org>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/platform_device.h>
#include <linux/hw_random.h>
#include <linux/io.h>
#include <linux/of.h>
#define STAT 0x00
#define RND 0x04
struct mcs814x_rng_priv {
void __iomem *regs;
};
static int mcs814x_rng_data_read(struct hwrng *rng, u32 *buffer)
{
struct mcs814x_rng_priv *priv = (struct mcs814x_rng_priv *)rng->priv;
*buffer = __raw_readl(priv->regs + RND);
return 4;
}
static int mcs814x_rng_probe(struct platform_device *pdev)
{
struct resource *res;
struct mcs814x_rng_priv *priv;
struct hwrng *rng;
int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
ret = -ENOMEM;
goto out;
}
rng = kzalloc(sizeof(*rng), GFP_KERNEL);
if (!rng) {
ret = -ENOMEM;
goto out_priv;
}
platform_set_drvdata(pdev, rng);
rng->priv = (unsigned long)priv;
rng->name = pdev->name;
rng->data_read = mcs814x_rng_data_read;
if (!devm_request_mem_region(&pdev->dev,
res->start, resource_size(res),
pdev->name)) {
ret = -EBUSY;
goto out_rng;
}
priv->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
if (!priv->regs) {
ret = -ENOMEM;
goto out_rng;
}
ret = hwrng_register(rng);
if (ret) {
dev_err(&pdev->dev, "failed to register hwrng driver\n");
goto out;
}
dev_info(&pdev->dev, "registered\n");
return ret;
out_rng:
platform_set_drvdata(pdev, NULL);
kfree(rng);
out_priv:
kfree(priv);
out:
return ret;
}
static int mcs814x_rng_remove(struct platform_device *pdev)
{
struct hwrng *rng = platform_get_drvdata(pdev);
struct mcs814x_rng_priv *priv = (struct mcs814x_rng_priv *)rng->priv;
hwrng_unregister(rng);
kfree(priv);
kfree(rng);
platform_set_drvdata(pdev, NULL);
return 0;
}
static const struct of_device_id mcs814x_rng_ids[] = {
{ .compatible = "moschip,mcs814x-rng", },
{ /* sentinel */ },
};
static struct platform_driver mcs814x_rng_driver = {
.driver = {
.name = "mcs814x-rng",
.owner = THIS_MODULE,
.of_match_table = mcs814x_rng_ids,
},
.probe = mcs814x_rng_probe,
.remove = __devexit_p(mcs814x_rng_remove),
};
module_platform_driver(mcs814x_rng_driver);
MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
MODULE_DESCRIPTION("H/W Random Number Generator (RNG) for Moschip MCS814x");
MODULE_LICENSE("GPL");

@ -0,0 +1,148 @@
/*
* Moschip MCS814x GPIO support
*
* Copyright (C) 2012, Florian Fainelli <florian@openwrt.org>
*
* Licensed under the GPLv2
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
struct mcs814x_gpio_chip {
void __iomem *regs;
struct gpio_chip chip;
};
#define GPIO_PIN 0x00
#define GPIO_DIR 0x04
#define to_mcs814x_gpio_chip(x) container_of(x, struct mcs814x_gpio_chip, chip)
static int mcs814x_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct mcs814x_gpio_chip *mcs814x = to_mcs814x_gpio_chip(chip);
return __raw_readl(mcs814x->regs + GPIO_PIN) & (1 << offset);
}
static void mcs814x_gpio_set(struct gpio_chip *chip,
unsigned offset, int value)
{
struct mcs814x_gpio_chip *mcs814x = to_mcs814x_gpio_chip(chip);
u32 mask;
mask = __raw_readl(mcs814x->regs + GPIO_PIN);
if (value)
mask |= (1 << offset);
else
mask &= ~(1 << offset);
__raw_writel(mask, mcs814x->regs + GPIO_PIN);
}
static int mcs814x_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int value)
{
struct mcs814x_gpio_chip *mcs814x = to_mcs814x_gpio_chip(chip);
u32 mask;
mask = __raw_readl(mcs814x->regs + GPIO_DIR);
mask &= ~(1 << offset);
__raw_writel(mask, mcs814x->regs + GPIO_DIR);
return 0;
}
static int mcs814x_gpio_direction_input(struct gpio_chip *chip,
unsigned offset)
{
struct mcs814x_gpio_chip *mcs814x = to_mcs814x_gpio_chip(chip);
u32 mask;
mask = __raw_readl(mcs814x->regs + GPIO_DIR);
mask |= (1 << offset);
__raw_writel(mask, mcs814x->regs + GPIO_DIR);
return 0;
}
static int __devinit mcs814x_gpio_probe(struct platform_device *pdev)
{
struct resource *res;
struct mcs814x_gpio_chip *mcs814x_chip;
int ret;
const unsigned int *num_gpios;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
num_gpios = of_get_property(pdev->dev.of_node, "num-gpios", NULL);
if (!num_gpios)
dev_err(&pdev->dev, "FIXME: no num-gpios property\n");
mcs814x_chip = kzalloc(sizeof(*mcs814x_chip), GFP_KERNEL);
if (!mcs814x_chip)
return -ENOMEM;
mcs814x_chip->regs = devm_request_and_ioremap(&pdev->dev, res);
if (!mcs814x_chip->regs) {
ret = -ENOMEM;
goto out;
}
platform_set_drvdata(pdev, mcs814x_chip);
#ifdef CONFIG_OF_GPIO
mcs814x_chip->chip.of_node = pdev->dev.of_node;
#endif
mcs814x_chip->chip.label = pdev->name;
mcs814x_chip->chip.get = mcs814x_gpio_get;
mcs814x_chip->chip.set = mcs814x_gpio_set;
mcs814x_chip->chip.direction_input = mcs814x_gpio_direction_input;
mcs814x_chip->chip.direction_output = mcs814x_gpio_direction_output;
mcs814x_chip->chip.ngpio = be32_to_cpup(num_gpios);
/* we want dynamic base allocation */
mcs814x_chip->chip.base = -1;
ret = gpiochip_add(&mcs814x_chip->chip);
if (ret) {
dev_err(&pdev->dev, "failed to register gpiochip\n");
goto out;
}
return 0;
out:
platform_set_drvdata(pdev, NULL);
kfree(mcs814x_chip);
return ret;
}
static struct of_device_id mcs814x_gpio_ids[] __devinitdata = {
{ .compatible = "moschip,mcs814x-gpio" },
{ /* sentinel */ },
};
static struct platform_driver mcs814x_gpio_driver = {
.driver = {
.name = "mcs814x-gpio",
.owner = THIS_MODULE,
.of_match_table = mcs814x_gpio_ids,
},
.probe = mcs814x_gpio_probe,
};
int __init mcs814x_gpio_init(void)
{
return platform_driver_register(&mcs814x_gpio_driver);
}
postcore_initcall(mcs814x_gpio_init);

@ -0,0 +1,4 @@
config NUPORT_ETHERNET_DRIVER
tristate "MCS8140 Ethernet driver"
depends on ETHERNET && ARCH_MCS814X
help

@ -0,0 +1,3 @@
obj-$(CONFIG_NUPORT_ETHERNET_DRIVER) += mcs8140.o
mcs8140-objs := nuport_mac.o

@ -0,0 +1,64 @@
/*
* Driver for Moschip MCS814x internal PHY
*
* Copyright (c) 2012 Florian Fainelli <florian@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/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/unistd.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/phy.h>
MODULE_DESCRIPTION("Moschip MCS814x PHY driver");
MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
MODULE_LICENSE("GPL");
/* Nothing special about this PHY but its OUI (O) */
static struct phy_driver mcs8140_driver = {
.phy_id = 0,
.name = "Moschip MCS8140",
.phy_id_mask = 0x02,
.features = PHY_BASIC_FEATURES,
.config_aneg = &genphy_config_aneg,
.read_status = &genphy_read_status,
.suspend = genphy_suspend,
.resume = genphy_resume,
.driver = { .owner = THIS_MODULE,},
};
static int __init mcs814x_phy_init(void)
{
return phy_driver_register(&mcs8140_driver);
}
static void __exit mcs814x_phy_exit(void)
{
phy_driver_unregister(&mcs8140_driver);
}
module_init(mcs814x_phy_init);
module_exit(mcs814x_phy_exit);
static struct mdio_device_id __maybe_unused mcs814x_phy_tbl[] = {
{ 0x0, 0x0ffffff0 },
{ }
};
MODULE_DEVICE_TABLE(mdio, mcs814x_phy_tbl);

@ -0,0 +1,165 @@
/*
* MCS814X EHCI Host Controller Driver
*
* Based on "ehci-fsl.c" by Randy Vinson <rvinson@mvista.com>
*
* 2007 (c) MontaVista Software, Inc. This file is licensed under
* the terms of the GNU General Public License version 2. This program
* is licensed "as is" without any warranty of any kind, whether express
* or implied.
*/
#include <linux/platform_device.h>
#include <linux/of.h>
#define MCS814X_EHCI_CAPS_OFFSET 0x68
static int mcs814x_ehci_init(struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
int retval = 0;
ehci->caps = hcd->regs + MCS814X_EHCI_CAPS_OFFSET;
ehci->regs = hcd->regs
+ HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
ehci_reset(ehci);
retval = ehci_init(hcd);
if (retval) {
pr_err("ehci_init failed\n");
return retval;
}
ehci_port_power(ehci, 0);
return retval;
}
static const struct hc_driver mcs814x_ehci_hc_driver = {
.description = hcd_name,
.product_desc = "MCS814X EHCI Host Controller",
.hcd_priv_size = sizeof(struct ehci_hcd),
.irq = ehci_irq,
.flags = HCD_MEMORY | HCD_USB2,
.reset = mcs814x_ehci_init,
.start = ehci_run,
.stop = ehci_stop,
.shutdown = ehci_shutdown,
.urb_enqueue = ehci_urb_enqueue,
.urb_dequeue = ehci_urb_dequeue,
.endpoint_disable = ehci_endpoint_disable,
.get_frame_number = ehci_get_frame,
.hub_status_data = ehci_hub_status_data,
.hub_control = ehci_hub_control,
#if defined(CONFIG_PM)
.bus_suspend = ehci_bus_suspend,
.bus_resume = ehci_bus_resume,
#endif
.relinquish_port = ehci_relinquish_port,
.port_handed_over = ehci_port_handed_over,
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
};
static int mcs814x_ehci_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd;
const struct hc_driver *driver = &mcs814x_ehci_hc_driver;
struct resource *res;
int irq;
int retval;
if (usb_disabled())
return -ENODEV;
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
dev_err(&pdev->dev,
"Found HC with no IRQ. Check %s setup!\n",
dev_name(&pdev->dev));
return -ENODEV;
}
irq = res->start;
pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
if (!hcd) {
retval = -ENOMEM;
goto fail_create_hcd;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev,
"Found HC with no register addr. Check %s setup!\n",
dev_name(&pdev->dev));
retval = -ENODEV;
goto fail_request_resource;
}
hcd->rsrc_start = res->start;
hcd->rsrc_len = resource_size(res);
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
driver->description)) {
dev_dbg(&pdev->dev, "controller already in use\n");
retval = -EBUSY;
goto fail_request_resource;
}
hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
if (hcd->regs == NULL) {
dev_dbg(&pdev->dev, "error mapping memory\n");
retval = -EFAULT;
goto fail_ioremap;
}
retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (retval)
goto fail_add_hcd;
dev_info(&pdev->dev, "added MCS814X EHCI driver\n");
return retval;
fail_add_hcd:
iounmap(hcd->regs);
fail_ioremap:
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
fail_request_resource:
usb_put_hcd(hcd);
fail_create_hcd:
dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), retval);
return retval;
}
static int mcs814x_ehci_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);
return 0;
}
MODULE_ALIAS("platform:mcs814x-ehci");
static const struct of_device_id mcs814x_ehci_id[] = {
{ .compatible = "moschip,mcs814x-ehci" },
{ .compatible = "usb-ehci" },
{ /* sentinel */ },
};
static struct platform_driver mcs814x_ehci_driver = {
.probe = mcs814x_ehci_probe,
.remove = mcs814x_ehci_remove,
.driver = {
.name = "mcs814x-ehci",
.of_match_table = mcs814x_ehci_id,
},
};

@ -0,0 +1,202 @@
/*
* OHCI HCD (Host Controller Driver) for USB.
*
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
* (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
* (C) Copyright 2002 Hewlett-Packard Company
*
* Bus Glue for Moschip MCS814x.
*
* Written by Christopher Hoover <ch@hpl.hp.com>
* Based on fragments of previous driver by Russell King et al.
*
* Modified for LH7A404 from ohci-sa1111.c
* by Durgesh Pattamatta <pattamattad@sharpsec.com>
*
* Modified for pxa27x from ohci-lh7a404.c
* by Nick Bane <nick@cecomputing.co.uk> 26-8-2004
*
* Modified for mcs814x from ohci-mcs814x.c
* by Lennert Buytenhek <buytenh@wantstofly.org> 28-2-2006
* Based on an earlier driver by Ray Lehtiniemi
*
* This file is licenced under the GPL.
*/
#include <linux/device.h>
#include <linux/signal.h>
#include <linux/platform_device.h>
#include <linux/of.h>
static int usb_hcd_mcs814x_probe(const struct hc_driver *driver,
struct platform_device *pdev)
{
int retval;
struct usb_hcd *hcd;
if (pdev->resource[1].flags != IORESOURCE_IRQ) {
pr_debug("resource[1] is not IORESOURCE_IRQ");
return -ENOMEM;
}
pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
hcd = usb_create_hcd(driver, &pdev->dev, "mcs814x");
if (hcd == NULL)
return -ENOMEM;
hcd->rsrc_start = pdev->resource[0].start;
hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
usb_put_hcd(hcd);
retval = -EBUSY;
goto err1;
}
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
if (hcd->regs == NULL) {
pr_debug("ioremap failed");
retval = -ENOMEM;
goto err2;
}
ohci_hcd_init(hcd_to_ohci(hcd));
retval = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_DISABLED);
if (retval == 0)
return retval;
iounmap(hcd->regs);
err2:
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
err1:
usb_put_hcd(hcd);
return retval;
}
static void usb_hcd_mcs814x_remove(struct usb_hcd *hcd,
struct platform_device *pdev)
{
usb_remove_hcd(hcd);
iounmap(hcd->regs);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
}
static int __devinit ohci_mcs814x_start(struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
int ret;
ret = ohci_init(ohci);
if (ret < 0)
return ret;
ret = ohci_run(ohci);
if (ret < 0) {
err("can't start %s", hcd->self.bus_name);
ohci_stop(hcd);
return ret;
}
return 0;
}
static struct hc_driver ohci_mcs814x_hc_driver = {
.description = hcd_name,
.product_desc = "MCS814X OHCI",
.hcd_priv_size = sizeof(struct ohci_hcd),
.irq = ohci_irq,
.flags = HCD_USB11 | HCD_MEMORY,
.start = ohci_mcs814x_start,
.stop = ohci_stop,
.shutdown = ohci_shutdown,
.urb_enqueue = ohci_urb_enqueue,
.urb_dequeue = ohci_urb_dequeue,
.endpoint_disable = ohci_endpoint_disable,
.get_frame_number = ohci_get_frame,
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
#endif
.start_port_reset = ohci_start_port_reset,
};
extern int usb_disabled(void);
static int ohci_hcd_mcs814x_drv_probe(struct platform_device *pdev)
{
int ret;
ret = -ENODEV;
if (!usb_disabled())
ret = usb_hcd_mcs814x_probe(&ohci_mcs814x_hc_driver, pdev);
return ret;
}
static int ohci_hcd_mcs814x_drv_remove(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
usb_hcd_mcs814x_remove(hcd, pdev);
return 0;
}
#ifdef CONFIG_PM
static int ohci_hcd_mcs814x_drv_suspend(struct platform_device *pdev, pm_message_t state)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
if (time_before(jiffies, ohci->next_statechange))
msleep(5);
ohci->next_statechange = jiffies;
hcd->state = HC_STATE_SUSPENDED;
return 0;
}
static int ohci_hcd_mcs814x_drv_resume(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
int status;
if (time_before(jiffies, ohci->next_statechange))
msleep(5);
ohci->next_statechange = jiffies;
ohci_finish_controller_resume(hcd);
return 0;
}
#endif
static const struct of_device_id mcs814x_ohci_id[] = {
{ .compatible = "moschip,mcs814x-ohci" },
{ .compatible = "ohci-le" },
{ /* sentinel */ },
};
static struct platform_driver ohci_hcd_mcs814x_driver = {
.probe = ohci_hcd_mcs814x_drv_probe,
.remove = ohci_hcd_mcs814x_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
#ifdef CONFIG_PM
.suspend = ohci_hcd_mcs814x_drv_suspend,
.resume = ohci_hcd_mcs814x_drv_resume,
#endif
.driver = {
.name = "mcs814x-ohci",
.owner = THIS_MODULE,
.of_match_table = mcs814x_ohci_id,
},
};
MODULE_ALIAS("platform:mcs814x-ohci");

@ -0,0 +1,207 @@
/*
* Moschip MCS814x Watchdog driver
*
* Copyright (C) 2012, Florian Fainelli <florian@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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/io.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/of.h>
#define WDT_COUNT 0x00
#define WDT_CTRL 0x04
#define WDT_CTRL_EN 0x1
/* watchdog frequency */
#define WDT_MAX_VALUE (0xffffffff)
struct mcs814x_wdt {
void __iomem *regs;
spinlock_t lock;
struct watchdog_device wdt_dev;
struct clk *clk;
};
static int mcs814x_wdt_start(struct watchdog_device *dev)
{
struct mcs814x_wdt *wdt = watchdog_get_drvdata(dev);
u32 reg;
spin_lock(&wdt->lock);
reg = __raw_readl(wdt->regs + WDT_CTRL);
reg |= WDT_CTRL_EN;
__raw_writel(reg, wdt->regs + WDT_CTRL);
spin_unlock(&wdt->lock);
return 0;
}
static int mcs814x_wdt_stop(struct watchdog_device *dev)
{
struct mcs814x_wdt *wdt = watchdog_get_drvdata(dev);
u32 reg;
spin_lock(&wdt->lock);
reg = __raw_readl(wdt->regs + WDT_CTRL);
reg &= ~WDT_CTRL_EN;
__raw_writel(reg, wdt->regs + WDT_CTRL);
spin_unlock(&wdt->lock);
return 0;
}
static int mcs814x_wdt_set_timeout(struct watchdog_device *dev,
unsigned int new_timeout)
{
struct mcs814x_wdt *wdt = watchdog_get_drvdata(dev);
spin_lock(&wdt->lock);
/* watchdog counts upward and rollover (0xfffffff -> 0)
* triggers the reboot
*/
__raw_writel(WDT_MAX_VALUE - (new_timeout * clk_get_rate(wdt->clk)),
wdt->regs + WDT_COUNT);
spin_unlock(&wdt->lock);
return 0;
}
static int mcs814x_wdt_ping(struct watchdog_device *dev)
{
/* restart the watchdog */
mcs814x_wdt_stop(dev);
mcs814x_wdt_set_timeout(dev, dev->timeout);
mcs814x_wdt_start(dev);
return 0;
}
static const struct watchdog_info mcs814x_wdt_ident = {
.options = WDIOF_CARDRESET | WDIOF_SETTIMEOUT |
WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
.identity = "MCS814x Watchdog",
};
static struct watchdog_ops mcs814x_wdt_ops = {
.owner = THIS_MODULE,
.start = mcs814x_wdt_start,
.stop = mcs814x_wdt_stop,
.set_timeout = mcs814x_wdt_set_timeout,
.ping = mcs814x_wdt_ping,
};
static int __devinit mcs814x_wdt_probe(struct platform_device *pdev)
{
struct resource *res;
struct mcs814x_wdt *wdt;
int ret;
struct clk *clk;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
clk = clk_get(NULL, "wdt");
if (IS_ERR_OR_NULL(clk)) {
dev_err(&pdev->dev, "failed to get watchdog clock\n");
return PTR_ERR(clk);
}
wdt = kzalloc(sizeof(*wdt), GFP_KERNEL);
if (!wdt) {
ret = -ENOMEM;
goto out_clk;
}
spin_lock_init(&wdt->lock);
wdt->clk = clk;
wdt->wdt_dev.info = &mcs814x_wdt_ident;
wdt->wdt_dev.ops = &mcs814x_wdt_ops;
wdt->wdt_dev.min_timeout = 1;
/* approximately 10995 secs */
wdt->wdt_dev.max_timeout = (WDT_MAX_VALUE / clk_get_rate(clk));
platform_set_drvdata(pdev, wdt);
/* only ioremap registers, because the register is shared */
wdt->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
if (!wdt->regs) {
ret = -ENOMEM;
goto out;
}
watchdog_set_drvdata(&wdt->wdt_dev, wdt);
ret = watchdog_register_device(&wdt->wdt_dev);
if (ret) {
dev_err(&pdev->dev, "cannot register watchdog: %d\n", ret);
goto out;
}
dev_info(&pdev->dev, "registered\n");
return 0;
out:
platform_set_drvdata(pdev, NULL);
kfree(wdt);
out_clk:
clk_put(clk);
return ret;
}
static int __devexit mcs814x_wdt_remove(struct platform_device *pdev)
{
struct mcs814x_wdt *wdt = platform_get_drvdata(pdev);
clk_put(wdt->clk);
watchdog_unregister_device(&wdt->wdt_dev);
watchdog_set_drvdata(&wdt->wdt_dev, NULL);
kfree(wdt);
platform_set_drvdata(pdev, NULL);
return 0;
}
static const struct of_device_id mcs814x_wdt_ids[] = {
{ .compatible = "moschip,mcs814x-wdt", },
{ /* sentinel */ },
};
static struct platform_driver mcs814x_wdt_driver = {
.driver = {
.name = "mcs814x-wdt",
.owner = THIS_MODULE,
.of_match_table = mcs814x_wdt_ids,
},
.probe = mcs814x_wdt_probe,
.remove = __devexit_p(mcs814x_wdt_remove),
};
module_platform_driver(mcs814x_wdt_driver);
MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
MODULE_DESCRIPTION("Moschip MCS814x Watchdog driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
MODULE_ALIAS("platform:mcs814x-wdt");

@ -0,0 +1,48 @@
#
# Copyright (C) 2012 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/image.mk
TARGET_DTBS := rbt-832 dlan-usb-extender
LOADADDR:=0x00008000
define Image/Build/MkuImage
mkimage -A arm -O linux -T kernel -a $(LOADADDR) -C none -e $(LOADADDR) \
-n 'ARM OpenWrt Linux-$(LINUX_VERSION)' -d $(1) $(2);
endef
define Image/Prepare
cp $(LINUX_DIR)/arch/$(ARCH)/boot/zImage $(KDIR)/zImage
endef
define Image/BuildKernel
$(foreach dtb,$(TARGET_DTBS),cp $(KDIR)/zImage $(KDIR)/zImage-$(dtb);)
$(foreach dtb,$(TARGET_DTBS),cat $(LINUX_DIR)/arch/$(ARCH)/boot/$(dtb).dtb >> $(KDIR)/zImage-$(dtb);)
$(foreach dtb,$(TARGET_DTBS),$(call Image/Build/MkuImage,$(KDIR)/zImage-$(dtb),$(KDIR)/uImage-$(dtb)))
$(call Image/Build/Initramfs)
endef
define Image/Build/squashfs
$(call prepare_generic_squashfs,$(KDIR)/root.squashfs)
endef
define Image/Build/ext2
cp $(KDIR)/root.$(1) $(BIN_DIR)/$(IMG_PREFIX)-ext2.img
endef
ifneq ($(CONFIG_TARGET_ROOTFS_INITRAMFS),)
define Image/Build/Initramfs
$(foreach dtb,$(TARGET_DTBS),cp $(KDIR)/uImage-$(dtb) $(BIN_DIR)/uImage-$(IMG_PREFIX)-$(dtb)-initramfs;)
endef
endif
define Image/Build
$(call Image/Build/$(1),$(1))
endef
$(eval $(call BuildImage))

@ -0,0 +1,20 @@
#
# Copyright (C) 2012 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
define KernelPackage/mcs814x-wdt
SUBMENU:=$(OTHER_MENU)
DEPENDS:=@TARGET_mcs814x
TITLE:=MCS814x watchdog driver
KCONFIG:=CONFIG_MCS814X_WATCHDOG
FILES:=$(LINUX_DIR)/drivers/$(WATCHDOG_DIR)/mcs814x_wdt.ko
AUTOLOAD:=$(call AutoLoad,50,mcs814x_wdt)
endef
define KernelPackage/mcs814x-wdt/description
Kernel module for the Moschip MCS814x watchdog timer.
endef
$(eval $(call KernelPackage,mcs814x-wdt))

@ -0,0 +1,43 @@
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -869,6 +869,21 @@ config ARCH_EXYNOS
help
Support for SAMSUNG's EXYNOS SoCs (EXYNOS4/5)
+config ARCH_MCS814X
+ bool "Moschip MCS814x"
+ select CPU_ARM926T
+ select PCI
+ select FIQ
+ select GENERIC_IRQ_CHIP
+ select GENERIC_GPIO
+ select ARCH_REQUIRE_GPIOLIB
+ select CLKDEV_LOOKUP
+ select ARCH_USES_GETTIMEOFFSET
+ select NEED_MACH_MEMORY_H
+ select MULTI_IRQ_HANDLER
+ help
+ Support for Moschip MCS814x SoCs (MCS8140).
+
config ARCH_SHARK
bool "Shark"
select CPU_SA110
@@ -1065,6 +1080,8 @@ source "arch/arm/plat-samsung/Kconfig"
source "arch/arm/plat-s3c24xx/Kconfig"
source "arch/arm/plat-s5p/Kconfig"
+source "arch/arm/mach-mcs814x/Kconfig"
+
source "arch/arm/plat-spear/Kconfig"
if ARCH_S3C2410
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -179,6 +179,7 @@ machine-$(CONFIG_ARCH_S3C64XX) := s3c64
machine-$(CONFIG_ARCH_S5P64X0) := s5p64x0
machine-$(CONFIG_ARCH_S5PC100) := s5pc100
machine-$(CONFIG_ARCH_S5PV210) := s5pv210
+machine-$(CONFIG_ARCH_MCS814X) := mcs814x
machine-$(CONFIG_ARCH_EXYNOS4) := exynos
machine-$(CONFIG_ARCH_SA1100) := sa1100
machine-$(CONFIG_ARCH_SHARK) := shark

@ -0,0 +1,16 @@
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -176,4 +176,6 @@ source "drivers/net/ethernet/via/Kconfig
source "drivers/net/ethernet/xilinx/Kconfig"
source "drivers/net/ethernet/xircom/Kconfig"
+source "drivers/net/ethernet/mcs8140/Kconfig"
+
endif # ETHERNET
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -74,3 +74,4 @@ obj-$(CONFIG_NET_VENDOR_TUNDRA) += tundr
obj-$(CONFIG_NET_VENDOR_VIA) += via/
obj-$(CONFIG_NET_VENDOR_XILINX) += xilinx/
obj-$(CONFIG_NET_VENDOR_XIRCOM) += xircom/
+obj-$(CONFIG_NUPORT_ETHERNET_DRIVER) += mcs8140/

@ -0,0 +1,29 @@
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1381,6 +1381,11 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ehci_mv_driver
#endif
+#ifdef CONFIG_ARCH_MCS814X
+#include "ehci-mcs814x.c"
+#define PLATFORM_DRIVER mcs814x_ehci_driver
+#endif
+
#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
!defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
!defined(XILINX_OF_PLATFORM_DRIVER)
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -1121,6 +1121,12 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ohci_xls_driver
#endif
+#ifdef CONFIG_ARCH_MCS814X
+#include "ohci-mcs814x.c"
+#define PLATFORM_DRIVER ohci_hcd_mcs814x_driver
+#endif
+
+
#if !defined(PCI_DRIVER) && \
!defined(PLATFORM_DRIVER) && \
!defined(OMAP1_PLATFORM_DRIVER) && \

@ -0,0 +1,31 @@
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -188,6 +188,18 @@ config HW_RANDOM_TX4939
If unsure, say Y.
+config HW_RANDOM_MCS814X
+ tristate "Moschip MCS814x Random Number Generator"
+ depends on HW_RANDOM && ARCH_MCS814X
+ ---help---
+ This driver provides kernel-side support for the Random Number
+ Generator hardware found on Moschip MCS814x processors.
+
+ To compile this driver as a module, choose M here: the
+ module will be called mcs814x-rng.
+
+ If unusure, say Y.
+
config HW_RANDOM_MXC_RNGA
tristate "Freescale i.MX RNGA Random Number Generator"
depends on HW_RANDOM && ARCH_HAS_RNGA
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng
obj-$(CONFIG_HW_RANDOM_PASEMI) += pasemi-rng.o
obj-$(CONFIG_HW_RANDOM_VIRTIO) += virtio-rng.o
obj-$(CONFIG_HW_RANDOM_TX4939) += tx4939-rng.o
+obj-$(CONFIG_HW_RANDOM_MCS814X) += mcs814x-rng.o
obj-$(CONFIG_HW_RANDOM_MXC_RNGA) += mxc-rnga.o
obj-$(CONFIG_HW_RANDOM_OCTEON) += octeon-rng.o
obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o

@ -0,0 +1,25 @@
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -343,6 +343,12 @@ config IMX2_WDT
To compile this driver as a module, choose M here: the
module will be called imx2_wdt.
+config MCS814X_WATCHDOG
+ tristate "Moschip MCS814x watchdog"
+ depends on WATCHDOG_CORE && ARCH_MCS814X
+ help
+ Support for the Moschip MCS814x SoCs on-chip watchdog timer.
+
# AVR32 Architecture
config AT32AP700X_WDT
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -53,6 +53,7 @@ obj-$(CONFIG_STMP3XXX_WATCHDOG) += stmp3
obj-$(CONFIG_NUC900_WATCHDOG) += nuc900_wdt.o
obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o
obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o
+obj-$(CONFIG_MCS814X_WATCHDOG) += mcs814x_wdt.o
# AVR32 Architecture
obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o

@ -0,0 +1,25 @@
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -450,6 +450,12 @@ config GPIO_MC33880
SPI driver for Freescale MC33880 high-side/low-side switch.
This provides GPIO interface supporting inputs and outputs.
+config GPIO_MCS814X
+ tristate "Moschip MCS814x GPIO support"
+ depends on ARCH_MCS814X
+ help
+ GPIO driver for Moschip MCS814x SoC gpio controllers.
+
config GPIO_74X164
tristate "74x164 serial-in/parallel-out 8-bits shift register"
depends on SPI_MASTER
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_GPIO_MAX7300) += gpio-max73
obj-$(CONFIG_GPIO_MAX7301) += gpio-max7301.o
obj-$(CONFIG_GPIO_MAX732X) += gpio-max732x.o
obj-$(CONFIG_GPIO_MC33880) += gpio-mc33880.o
+obj-$(CONFIG_GPIO_MCS814X) += gpio-mcs814x.o
obj-$(CONFIG_GPIO_MCP23S08) += gpio-mcp23s08.o
obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o
obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o

@ -0,0 +1,140 @@
The old logic assumes CMDLINE_FROM_BOOTLOADER vs. CMDLINE_FORCE and
ignores CMDLINE_EXTEND. Here's the old logic:
- CONFIG_CMDLINE_FORCE=true
CONFIG_CMDLINE
- dt bootargs=non-empty:
dt bootargs
- dt bootargs=empty, @data is non-empty string
@data is left unchanged
- dt bootargs=empty, @data is empty string
CONFIG_CMDLINE (or "" if that's not defined)
The new logic is now documented in of_fdt.h and is copied here for
reference:
- CONFIG_CMDLINE_FORCE=true
CONFIG_CMDLINE
- CONFIG_CMDLINE_EXTEND=true, @data is non-empty string
@data + dt bootargs (even if dt bootargs are empty)
- CONFIG_CMDLINE_EXTEND=true, @data is empty string
CONFIG_CMDLINE + dt bootargs (even if dt bootargs are empty)
- CMDLINE_FROM_BOOTLOADER=true, dt bootargs=non-empty:
dt bootargs
- CMDLINE_FROM_BOOTLOADER=true, dt bootargs=empty, @data is non-empty string
@data is left unchanged
- CMDLINE_FROM_BOOTLOADER=true, dt bootargs=empty, @data is empty string
CONFIG_CMDLINE (or "" if that's not defined)
Signed-off-by: Doug Anderson <diand...@chromium.org>
CC: devicetree-discuss@lists.ozlabs.org
CC: Grant Likely <grant.lik...@secretlab.ca>
CC: Benjamin Herrenschmidt <b...@kernel.crashing.org>
CC: Rob Herring <rob.herr...@calxeda.com>
---
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -663,6 +663,29 @@ int __init early_init_dt_scan_memory(uns
return 0;
}
+/*
+ * Convert configs to something easy to use in C code
+ */
+#if defined(CONFIG_CMDLINE_FORCE)
+static const int overwrite_incoming_cmdline = 1;
+static const int read_dt_cmdline;
+static const int concat_cmdline;
+#elif defined(CONFIG_CMDLINE_EXTEND)
+static const int overwrite_incoming_cmdline;
+static const int read_dt_cmdline = 1;
+static const int concat_cmdline = 1;
+#else /* CMDLINE_FROM_BOOTLOADER */
+static const int overwrite_incoming_cmdline;
+static const int read_dt_cmdline = 1;
+static const int concat_cmdline;
+#endif
+
+#ifdef CONFIG_CMDLINE
+static const char *config_cmdline = CONFIG_CMDLINE;
+#else
+static const char *config_cmdline = "";
+#endif
+
int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
int depth, void *data)
{
@@ -677,22 +700,26 @@ int __init early_init_dt_scan_chosen(uns
early_init_dt_check_for_initrd(node);
- /* Retrieve command line */
- p = of_get_flat_dt_prop(node, "bootargs", &l);
- if (p != NULL && l > 0)
- strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE));
-
- /*
- * CONFIG_CMDLINE is meant to be a default in case nothing else
- * managed to set the command line, unless CONFIG_CMDLINE_FORCE
- * is set in which case we override whatever was found earlier.
- */
-#ifdef CONFIG_CMDLINE
-#ifndef CONFIG_CMDLINE_FORCE
- if (!((char *)data)[0])
-#endif
- strlcpy(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
-#endif /* CONFIG_CMDLINE */
+ /* Put CONFIG_CMDLINE in if forced or if data had nothing in it to start */
+ if (overwrite_incoming_cmdline || !((char *)data)[0])
+ strlcpy(data, config_cmdline, COMMAND_LINE_SIZE);
+
+ /* Retrieve command line unless forcing */
+ if (read_dt_cmdline) {
+ p = of_get_flat_dt_prop(node, "bootargs", &l);
+ if (p != NULL && l > 0) {
+ if (concat_cmdline) {
+ strlcat(data, " ", COMMAND_LINE_SIZE);
+ strlcat(data, p, min_t(int, (int)l,
+ COMMAND_LINE_SIZE));
+ } else
+ strlcpy(data, p, min_t(int, (int)l,
+ COMMAND_LINE_SIZE));
+ }
+ }
+
+ pr_debug("Command line is: %s\n", (char*)data);
+
pr_debug("Command line is: %s\n", (char*)data);
--- a/include/linux/of_fdt.h
+++ b/include/linux/of_fdt.h
@@ -91,6 +91,27 @@ extern int of_flat_dt_is_compatible(unsi
extern int of_flat_dt_match(unsigned long node, const char *const *matches);
extern unsigned long of_get_flat_dt_root(void);
+/*
+ * early_init_dt_scan_chosen - scan the device tree for ramdisk and bootargs
+ *
+ * The boot arguments will be placed into the memory pointed to by @data.
+ * That memory should be COMMAND_LINE_SIZE big and initialized to be a valid
+ * (possibly empty) string. Logic for what will be in @data after this
+ * function finishes:
+ *
+ * - CONFIG_CMDLINE_FORCE=true
+ * CONFIG_CMDLINE
+ * - CONFIG_CMDLINE_EXTEND=true, @data is non-empty string
+ * @data + dt bootargs (even if dt bootargs are empty)
+ * - CONFIG_CMDLINE_EXTEND=true, @data is empty string
+ * CONFIG_CMDLINE + dt bootargs (even if dt bootargs are empty)
+ * - CMDLINE_FROM_BOOTLOADER=true, dt bootargs=non-empty:
+ * dt bootargs
+ * - CMDLINE_FROM_BOOTLOADER=true, dt bootargs=empty, @data is non-empty string
+ * @data is left unchanged
+ * - CMDLINE_FROM_BOOTLOADER=true, dt bootargs=empty, @data is empty string
+ * CONFIG_CMDLINE (or "" if that's not defined)
+ */
extern int early_init_dt_scan_chosen(unsigned long node, const char *uname,
int depth, void *data);
extern void early_init_dt_check_for_initrd(unsigned long node);

@ -0,0 +1,20 @@
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -135,6 +135,10 @@ config MICREL_PHY
---help---
Currently has a driver for the KSZ8041
+config MCS814X_PHY
+ tristate "Driver for the Moschip MCS814x internal PHY"
+ depends on ARCH_MCS814X
+
config FIXED_PHY
bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
depends on PHYLIB=y
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -38,3 +38,4 @@ obj-$(CONFIG_STE10XP) += ste10Xp.o
obj-$(CONFIG_MICREL_PHY) += micrel.o
obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o
obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o
+obj-$(CONFIG_MCS814X_PHY) += mcs814x.o
Loading…
Cancel
Save