mcs814x: add support for 3.18

Signed-off-by: Florian Fainelli <florian@openwrt.org>

SVN-Revision: 45273
owl
Florian Fainelli 2015-04-04 18:01:07 +00:00
parent c31df6e995
commit b1ba4c5096
43 changed files with 4004 additions and 0 deletions

View File

@ -0,0 +1,230 @@
CONFIG_ALIGNMENT_TRAP=y
CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
# CONFIG_ARCH_HAS_SG_CHAIN is not set
CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
CONFIG_ARCH_MCS814X=y
CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=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_SUPPORTS_ATOMIC_RMW=y
CONFIG_ARCH_SUPPORTS_UPROBES=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_ARCH_USES_GETTIMEOFFSET=y
CONFIG_ARCH_USE_BUILTIN_BSWAP=y
CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
CONFIG_ARCH_WANT_IPC_PARSE_VERSION=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_THUMB is not set
CONFIG_BINFMT_MISC=y
# CONFIG_BRIDGE is not set
# CONFIG_CACHE_L2X0 is not set
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_CLKDEV_LOOKUP=y
CONFIG_CLONE_BACKWARDS=y
CONFIG_CMDLINE="earlyprintk"
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_CRC32C=y
CONFIG_CRYPTO_HASH=y
CONFIG_CRYPTO_HASH2=y
CONFIG_DEBUG_LL=y
CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S"
CONFIG_DEBUG_LL_UART_NONE=y
# CONFIG_DEBUG_UART_8250 is not set
# CONFIG_DEBUG_UART_PL01X is not set
# CONFIG_DEBUG_USER is not set
CONFIG_DTC=y
CONFIG_EARLY_PRINTK=y
# CONFIG_ENABLE_WARN_DEPRECATED is not set
CONFIG_FIQ=y
CONFIG_FRAME_POINTER=y
CONFIG_GENERIC_ALLOCATOR=y
CONFIG_GENERIC_ATOMIC64=y
CONFIG_GENERIC_BUG=y
CONFIG_GENERIC_IDLE_POLL_SETUP=y
CONFIG_GENERIC_IO=y
CONFIG_GENERIC_IRQ_CHIP=y
CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_GENERIC_PCI_IOMAP=y
CONFIG_GENERIC_SCHED_CLOCK=y
CONFIG_GENERIC_SMP_IDLE_THREAD=y
CONFIG_GENERIC_STRNCPY_FROM_USER=y
CONFIG_GENERIC_STRNLEN_USER=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_DEVRES=y
CONFIG_GPIO_MCS814X=y
CONFIG_GPIO_SYSFS=y
CONFIG_HANDLE_DOMAIN_IRQ=y
CONFIG_HARDIRQS_SW_RESEND=y
CONFIG_HAS_DMA=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT_MAP=y
# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
CONFIG_HAVE_ARCH_AUDITSYSCALL=y
CONFIG_HAVE_ARCH_JUMP_LABEL=y
CONFIG_HAVE_ARCH_KGDB=y
CONFIG_HAVE_ARCH_PFN_VALID=y
CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
CONFIG_HAVE_BPF_JIT=y
CONFIG_HAVE_CC_STACKPROTECTOR=y
CONFIG_HAVE_CLK=y
CONFIG_HAVE_CONTEXT_TRACKING=y
CONFIG_HAVE_C_RECORDMCOUNT=y
CONFIG_HAVE_DEBUG_KMEMLEAK=y
CONFIG_HAVE_DMA_API_DEBUG=y
CONFIG_HAVE_DMA_ATTRS=y
CONFIG_HAVE_DMA_CONTIGUOUS=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_IRQ_TIME_ACCOUNTING=y
CONFIG_HAVE_KERNEL_GZIP=y
CONFIG_HAVE_KERNEL_LZ4=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_NET_DSA=y
CONFIG_HAVE_OPROFILE=y
CONFIG_HAVE_PERF_EVENTS=y
CONFIG_HAVE_PERF_REGS=y
CONFIG_HAVE_PERF_USER_STACK_DUMP=y
CONFIG_HAVE_PROC_CPU=y
CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
CONFIG_HAVE_UID16=y
CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_MCS814X=y
CONFIG_HZ_FIXED=0
CONFIG_INITRAMFS_SOURCE=""
CONFIG_IOMMU_HELPER=y
CONFIG_IRQCHIP=y
CONFIG_IRQ_DOMAIN=y
CONFIG_IRQ_FORCED_THREADING=y
CONFIG_IRQ_WORK=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_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_LIBFDT=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_MODULES_USE_ELF_REL=y
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
# CONFIG_MTD_IMPA7 is not set
CONFIG_MTD_JEDECPROBE=y
CONFIG_MTD_PHYSMAP=y
CONFIG_MULTI_IRQ_HANDLER=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEED_KUSER_HELPERS=y
CONFIG_NEED_MACH_MEMORY_H=y
CONFIG_NEED_PER_CPU_KM=y
CONFIG_NET_KEY=y
# CONFIG_NET_VENDOR_BROADCOM is not set
# CONFIG_NET_VENDOR_FARADAY is not set
# CONFIG_NET_VENDOR_INTEL is not set
# CONFIG_NET_VENDOR_MARVELL is not set
# CONFIG_NET_VENDOR_MICREL is not set
# CONFIG_NET_VENDOR_NATSEMI is not set
# CONFIG_NET_VENDOR_SEEQ is not set
# CONFIG_NET_VENDOR_SMSC is not set
# CONFIG_NET_VENDOR_STMICRO is not set
CONFIG_NLS=y
CONFIG_NLS_DEFAULT="iso8859-15"
CONFIG_NO_BOOTMEM=y
CONFIG_NUPORT_ETHERNET_DRIVER=y
CONFIG_OF=y
CONFIG_OF_ADDRESS=y
CONFIG_OF_EARLY_FLATTREE=y
CONFIG_OF_FLATTREE=y
CONFIG_OF_GPIO=y
CONFIG_OF_IRQ=y
CONFIG_OF_MDIO=y
CONFIG_OF_MTD=y
CONFIG_OF_NET=y
CONFIG_OF_RESERVED_MEM=y
CONFIG_OLD_SIGACTION=y
CONFIG_OLD_SIGSUSPEND3=y
CONFIG_PAGEFLAGS_EXTENDED=y
CONFIG_PAGE_OFFSET=0xC0000000
# CONFIG_PARTITION_ADVANCED is not set
# CONFIG_PCI_SYSCALL is not set
CONFIG_PERF_USE_VMALLOC=y
CONFIG_PHYLIB=y
CONFIG_PHYS_OFFSET=0x00000000
# CONFIG_PREEMPT_RCU is not set
# CONFIG_PREVENT_FIRMWARE_BUILD is not set
# CONFIG_RCU_STALL_COMMON is not set
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
# CONFIG_SCHED_HRTICK is not set
# CONFIG_SCSI_DMA is not set
CONFIG_SERIAL_OF_PLATFORM=y
CONFIG_SPLIT_PTLOCK_CPUS=999999
# CONFIG_SWAP is not set
CONFIG_SWIOTLB=y
# CONFIG_SYN_COOKIES is not set
CONFIG_SYSCTL_SYSCALL=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
CONFIG_TICK_CPU_ACCOUNTING=y
CONFIG_UID16=y
CONFIG_UNCOMPRESS_INCLUDE="mach/uncompress.h"
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_XFRM_ALGO=y
CONFIG_XZ_DEC_ARM=y
CONFIG_XZ_DEC_BCJ=y
CONFIG_ZBOOT_ROM_BSS=0
CONFIG_ZBOOT_ROM_TEXT=0
CONFIG_ZLIB_DEFLATE=y
CONFIG_ZLIB_INFLATE=y
CONFIG_ZONE_DMA_FLAG=0

View File

@ -0,0 +1,76 @@
/*
* 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 {
eth0: ethernet@40084000 {
phy = <&phy0>;
phy-mode = "mii";
phy0: ethernet-phy@0 {
reg = <8>;
};
};
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 = "kernel";
reg = <0x50000 0x100000>;
};
partition@150000 {
label = "rootfs";
reg = <0x150000 0x3C0000>;
};
partition@50001 {
label = "linux";
reg = <0x50000 0x4C0000>;
};
};
};
leds {
compatible = "gpio-leds";
usb {
label = "dlan-usb-extender:green:usb";
gpios = <&gpio 19 0>; // gpio 19 active high
};
};
};
};
};

View File

@ -0,0 +1,189 @@
/*
* 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 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "moschip,nuport-mac";
reg = <0x40084000 0xd8 // mac
0x40080000 0x58>; // dma channels
interrupts = <4 5 29>; /* tx, rx, link */
nuport-mac,buffer-shifting;
nuport-mac,link-activity = <0>;
};
tso@40088000 {
reg = <0x40088000 0x1c>;
interrupts = <7>;
};
i2s@4008c000 {
compatible = "moschip,mcs814x-i2s";
reg = <0x4008c000 0x18>;
interrupts = <8>;
};
ipsec@40094000 {
compatible = "moschip,mcs814x-ipsec";
reg = <0x40094000 0x1d8>;
interrupts = <16>;
};
rng@4009c000 {
compatible = "moschip,mcs814x-rng";
reg = <0x4009c000 0x8>;
};
memc@400a8000 {
reg = <0x400a8000 0x58>;
};
list-proc@400ac0c0 {
reg = <0x400ac0c0 0x38>;
interrupts = <19 27>; // done, error
};
gpio: gpio@400d0000 {
compatible = "moschip,mcs814x-gpio";
reg = <0x400d0000 0x670>;
interrupts = <10>;
#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>;
interrupts = <17>;
};
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>;
interrupts = <13>;
};
};
};
};

View File

@ -0,0 +1,89 @@
/*
* 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 {
eth0: ethernet@40084000 {
nuport-mac,link-activity = <0x01>;
phy = <&phy0>;
phy-mode = "mii";
phy0: ethernet-phy@0 {
reg = <1>;
};
};
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
};
};
};
};
};

View File

@ -0,0 +1,29 @@
if ARCH_MCS814X
config MCS8140
bool
select CPU_ARM926T
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

View File

@ -0,0 +1,5 @@
obj-y += clock.o
obj-y += common.o
obj-y += irq.o
obj-y += timer.o
obj-y += board-mcs8140-dt.o

View File

@ -0,0 +1,4 @@
zreladdr-y := 0x00008000
dtb-$(CONFIG_MACH_DLAN_USB_EXT) += dlan-usb-extender.dtb
dtb-$(CONFIG_MACH_RBT_832) += rbt-832.dtb

View File

@ -0,0 +1,45 @@
/*
* 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 "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 = {
"moschip,mcs8140",
NULL, /* sentinel */
};
DT_MACHINE_START(mcs8140_dt, "Moschip MCS8140 board")
/* Maintainer: Florian Fainelli <florian@openwrt.org> */
.map_io = mcs814x_map_io,
.init_early = mcs814x_clk_init,
.init_irq = mcs814x_of_irq_init,
.init_time = mcs814x_timer_init,
.init_machine = mcs814x_dt_device_init,
.restart = mcs814x_restart,
.dt_compat = mcs8140_dt_board_compat,
.handle_irq = mcs814x_handle_irq,
MACHINE_END

View File

@ -0,0 +1,271 @@
/*
* 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/mcs814x.h>
#include "common.h"
#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 */
u32 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 = readl_relaxed(mcs814x_sysdbg_base + clk->enable_reg);
if (!enable)
tmp &= ~clk->enable_mask;
else
tmp |= clk->enable_mask;
writel_relaxed(tmp, mcs814x_sysdbg_base + 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 = SYSDBG_SYSCTL,
.enable_mask = SYSCTL_EMAC,
};
static struct clk clk_ephy = {
.ops = &default_clk_ops,
.enable_reg = SYSDBG_PLL_CTL,
.enable_mask = ~SYSCTL_EPHY, /* active low */
};
static struct clk clk_cipher = {
.ops = &default_clk_ops,
.enable_reg = 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 = readl_relaxed(mcs814x_sysdbg_base + 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);
}

View File

@ -0,0 +1,166 @@
/*
* 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 <linux/of.h>
#include <linux/of_address.h>
#include <linux/reboot.h>
#include <asm/setup.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <mach/mcs814x.h>
#include <mach/cpu.h>
#include <asm/pgtable.h>
#include <asm/mach/map.h>
void __iomem *mcs814x_sysdbg_base;
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
},
};
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,
},
};
static void mcs814x_eth_hardware_filter_set(u8 value)
{
u32 reg;
reg = readl_relaxed(MCS814X_VIRT_BASE + MCS814X_DBGLED);
if (value)
reg |= 0x80;
else
reg &= ~0x80;
writel_relaxed(reg, MCS814X_VIRT_BASE + MCS814X_DBGLED);
}
static void mcs814x_eth_led_cfg_set(u8 cfg)
{
u32 reg;
reg = readl_relaxed(mcs814x_sysdbg_base + SYSDBG_BS2);
reg &= ~LED_CFG_MASK;
reg |= cfg;
writel_relaxed(reg, mcs814x_sysdbg_base + SYSDBG_BS2);
}
static void mcs814x_eth_buffer_shifting_set(u8 value)
{
u8 reg;
reg = readb_relaxed(mcs814x_sysdbg_base + SYSDBG_SYSCTL_MAC);
if (value)
reg |= BUF_SHIFT_BIT;
else
reg &= ~BUF_SHIFT_BIT;
writeb_relaxed(reg, mcs814x_sysdbg_base + SYSDBG_SYSCTL_MAC);
}
static struct of_device_id mcs814x_eth_ids[] __initdata = {
{ .compatible = "moschip,nuport-mac", },
{ /* sentinel */ },
};
/* Configure platform specific knobs based on ethernet device node
* properties */
static void mcs814x_eth_init(void)
{
struct device_node *np;
const unsigned int *intspec;
np = of_find_matching_node(NULL, mcs814x_eth_ids);
if (!np)
return;
/* hardware filter must always be enabled */
mcs814x_eth_hardware_filter_set(1);
intspec = of_get_property(np, "nuport-mac,buffer-shifting", NULL);
if (!intspec)
mcs814x_eth_buffer_shifting_set(0);
else
mcs814x_eth_buffer_shifting_set(1);
intspec = of_get_property(np, "nuport-mac,link-activity", NULL);
if (intspec)
mcs814x_eth_led_cfg_set(be32_to_cpup(intspec));
of_node_put(np);
}
void __init mcs814x_init_machine(void)
{
u32 bs2, cpu_mode;
int gpio;
bs2 = readl_relaxed(mcs814x_sysdbg_base + 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);
}
mcs814x_eth_init();
}
void __init mcs814x_map_io(void)
{
iotable_init(mcs814x_io_desc, ARRAY_SIZE(mcs814x_io_desc));
mcs814x_sysdbg_base = ioremap(MCS814X_IO_START + MCS814X_SYSDBG,
MCS814X_SYSDBG_SIZE);
if (!mcs814x_sysdbg_base)
panic("unable to remap sysdbg base");
}
void mcs814x_restart(enum reboot_mode mode, const char *cmd)
{
writel_relaxed(~(1 << 31), mcs814x_sysdbg_base);
}

View File

@ -0,0 +1,16 @@
#ifndef __ARCH_MCS814X_COMMON_H
#define __ARCH_MCS814X_COMMON_H
#include <linux/reboot.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(enum reboot_mode mode, const char *cmd);
void mcs814x_timer_init(void);
extern void __iomem *mcs814x_sysdbg_base;
#endif /* __ARCH_MCS814X_COMMON_H */

View File

@ -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__ */

View File

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

View File

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

View File

@ -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

View File

@ -0,0 +1,16 @@
/*
* 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
#include "mcs814x.h"
#endif

View File

@ -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

View File

@ -0,0 +1,17 @@
/*
* 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
#endif

View File

@ -0,0 +1,53 @@
/*
* 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_MCS814X_H
#define __ASM_ARCH_MCS814X_H
#define MCS814X_IO_BASE 0xF0000000
#define MCS814X_IO_START 0x40000000
#define MCS814X_IO_SIZE 0x00100000
/* IRQ controller register offset */
#define MCS814X_IRQ_ICR 0x00
#define MCS814X_IRQ_ISR 0x04
#define MCS814X_IRQ_MASK 0x20
#define MCS814X_IRQ_STS0 0x40
#define MCS814X_PHYS_BASE 0x40000000
#define MCS814X_VIRT_BASE MCS814X_IO_BASE
#define MCS814X_UART 0x000DC000
#define MCS814X_DBGLED 0x000EC000
#define MCS814X_SYSDBG 0x000F8000
#define MCS814X_SYSDBG_SIZE 0x50
/* System configuration and bootstrap registers */
#define SYSDBG_BS1 0x00
#define CPU_FREQ_SHIFT 27
#define CPU_FREQ_MASK 0x0F
#define SDRAM_FREQ_BIT (1 << 22)
#define SYSDBG_BS2 0x04
#define LED_CFG_MASK 0x03
#define CPU_MODE_SHIFT 23
#define CPU_MODE_MASK 0x03
#define SYSDBG_SYSCTL_MAC 0x1d
#define BUF_SHIFT_BIT (1 << 0)
#define SYSDBG_SYSCTL 0x08
#define SYSCTL_EMAC (1 << 0)
#define SYSCTL_EPHY (1 << 0) /* active low */
#define SYSCTL_CIPHER (1 << 16)
#define SYSDBG_PLL_CTL 0x3C
#endif /* __ASM_ARCH_MCS814X_H */

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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/mcs814x.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 *)(MCS814X_PHYS_BASE +MCS814X_UART);
}
#define arch_decomp_wdog()
#endif

View File

@ -0,0 +1,89 @@
/*
* 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>
#include <mach/mcs814x.h>
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 */
writel_relaxed(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_STS0);
/* 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, 32, 0, &irq_generic_chip_ops, NULL);
of_node_put(np);
mcs814x_alloc_gc(mcs814x_intc_base, 0, 32);
}

View File

@ -0,0 +1,132 @@
/*
* 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/mcs814x.h>
/* Timer block registers */
#define TIMER_VAL 0x00
#define TIMER_CTL 0x04
#define TIMER_CTL_EN 0x01
#define TIMER_CTL_DBG 0x02
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 u32 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 u32 mcs814x_gettimeoffset(void)
{
u32 ticks = readl_relaxed(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 = readl_relaxed(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 = readl_relaxed(mcs814x_timer_base + TIMER_VAL) - count;
}
writel_relaxed(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);
}
void __init mcs814x_timer_init(void)
{
struct clk *clk;
arch_gettimeoffset = mcs814x_gettimeoffset;
clk = clk_get_sys("timer0", NULL);
if (IS_ERR_OR_NULL(clk))
panic("unable to get timer0 clock");
clock_rate = clk_get_rate(clk);
mcs814x_of_timer_init();
pr_info("Timer frequency: %d (kHz)\n", clock_rate / 1000);
timer_reload_value = 0xffffffff - (clock_rate / HZ);
/* disable timer */
writel_relaxed(~TIMER_CTL_EN, mcs814x_timer_base + TIMER_CTL);
writel_relaxed(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 */
writel_relaxed(TIMER_CTL_EN | TIMER_CTL_DBG,
mcs814x_timer_base + TIMER_CTL);
}

View File

@ -0,0 +1,121 @@
/*
* 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 = readl_relaxed(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;
priv->regs = devm_ioremap_resource(&pdev->dev, 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 = 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");

View File

@ -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 readl_relaxed(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 = readl_relaxed(mcs814x->regs + GPIO_PIN);
if (value)
mask |= (1 << offset);
else
mask &= ~(1 << offset);
writel_relaxed(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 = readl_relaxed(mcs814x->regs + GPIO_DIR);
mask &= ~(1 << offset);
writel_relaxed(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 = readl_relaxed(mcs814x->regs + GPIO_DIR);
mask |= (1 << offset);
writel_relaxed(mask, mcs814x->regs + GPIO_DIR);
return 0;
}
static int 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_ioremap_resource(&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[] = {
{ .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);

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -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);

View File

@ -0,0 +1,163 @@
/*
* 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;
}
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,
},
};

View File

@ -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 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) {
ohci_err(ohci, "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");

View File

@ -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 = readl_relaxed(wdt->regs + WDT_CTRL);
reg |= WDT_CTRL_EN;
writel_relaxed(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 = readl_relaxed(wdt->regs + WDT_CTRL);
reg &= ~WDT_CTRL_EN;
writel_relaxed(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
*/
writel_relaxed(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 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 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 = 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");

View File

@ -0,0 +1,64 @@
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -267,7 +267,8 @@ config PHYS_OFFSET
ARCH_INTEGRATOR || \
ARCH_IOP13XX || \
ARCH_KS8695 || \
- (ARCH_REALVIEW && !REALVIEW_HIGH_PHYS_OFFSET)
+ (ARCH_REALVIEW && !REALVIEW_HIGH_PHYS_OFFSET) || \
+ ARCH_MCS814X
default 0x10000000 if ARCH_OMAP1 || ARCH_RPC
default 0x20000000 if ARCH_S5PV210
default 0x70000000 if REALVIEW_HIGH_PHYS_OFFSET
@@ -786,6 +787,21 @@ config ARCH_OMAP1
help
Support for older TI OMAP1 (omap7xx, omap15xx or omap16xx)
+config ARCH_MCS814X
+ bool "Moschip MCS814x"
+ select FIQ
+ select GENERIC_IRQ_CHIP
+ select GENERIC_GPIO
+ select ARCH_REQUIRE_GPIOLIB
+ select CLKDEV_LOOKUP
+ select ARCH_USES_GETTIMEOFFSET
+ select USB_ARCH_HAS_OHCI
+ select USB_ARCH_HAS_EHCI
+ select MULTI_IRQ_HANDLER
+ help
+ Support for Moschip MCS814x SoCs (MCS8140).
+
+
endchoice
menu "Multiple platform selection"
@@ -927,6 +944,8 @@ source "arch/arm/mach-picoxcell/Kconfig"
source "arch/arm/mach-pxa/Kconfig"
source "arch/arm/plat-pxa/Kconfig"
+source "arch/arm/mach-mcs814x/Kconfig"
+
source "arch/arm/mach-mmp/Kconfig"
source "arch/arm/mach-qcom/Kconfig"
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -172,6 +172,7 @@ machine-$(CONFIG_ARCH_IXP4XX) += ixp4xx
machine-$(CONFIG_ARCH_KEYSTONE) += keystone
machine-$(CONFIG_ARCH_KS8695) += ks8695
machine-$(CONFIG_ARCH_LPC32XX) += lpc32xx
+machine-$(CONFIG_ARCH_MCS814X) += mcs814x
machine-$(CONFIG_ARCH_MESON) += meson
machine-$(CONFIG_ARCH_MMP) += mmp
machine-$(CONFIG_ARCH_MOXART) += moxart
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -163,6 +163,8 @@ dtb-$(CONFIG_MACH_KIRKWOOD) += kirkwood-
kirkwood-ts419-6282.dtb
dtb-$(CONFIG_ARCH_LPC32XX) += ea3250.dtb phy3250.dtb
dtb-$(CONFIG_ARCH_MARCO) += marco-evb.dtb
+dtb-$(CONFIG_ARCH_MCS814X) += dlan-usb-extender.dtb \
+ rbt-832.dtb
dtb-$(CONFIG_MACH_MESON6) += meson6-atv1200.dtb
dtb-$(CONFIG_ARCH_MOXART) += moxart-uc7112lx.dtb
dtb-$(CONFIG_ARCH_MXC) += \

View File

@ -0,0 +1,16 @@
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -186,4 +186,6 @@ source "drivers/net/ethernet/wiznet/Kcon
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
@@ -84,3 +84,4 @@ obj-$(CONFIG_NET_VENDOR_VIA) += via/
obj-$(CONFIG_NET_VENDOR_WIZNET) += wiznet/
obj-$(CONFIG_NET_VENDOR_XILINX) += xilinx/
obj-$(CONFIG_NET_VENDOR_XIRCOM) += xircom/
+obj-$(CONFIG_NUPORT_ETHERNET_DRIVER) += mcs8140/

View File

@ -0,0 +1,28 @@
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1298,6 +1298,11 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ehci_hcd_sead3_driver
#endif
+#ifdef CONFIG_ARCH_MCS814X
+#include "ehci-mcs814x.c"
+#define PLATFORM_DRIVER mcs814x_ehci_driver
+#endif
+
static int __init ehci_hcd_init(void)
{
int retval = 0;
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -1259,6 +1259,11 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ohci_hcd_tilegx_driver
#endif
+#ifdef CONFIG_ARCH_MCS814X
+#include "ohci-mcs814x.c"
+#define PLATFORM_DRIVER ohci_hcd_mcs814x_driver
+#endif
+
static int __init ohci_hcd_mod_init(void)
{
int retval = 0;

View File

@ -0,0 +1,31 @@
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -229,6 +229,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 ARCH_HAS_RNGA
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_HW_RANDOM_OMAP3_ROM) += oma
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

View File

@ -0,0 +1,25 @@
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -505,6 +505,12 @@ config MESON_WATCHDOG
To compile this driver as a module, choose M here: the
module will be called meson_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
@@ -63,6 +63,7 @@ obj-$(CONFIG_QCOM_WDT) += qcom-wdt.o
obj-$(CONFIG_BCM_KONA_WDT) += bcm_kona_wdt.o
obj-$(CONFIG_TEGRA_WATCHDOG) += tegra_wdt.o
obj-$(CONFIG_MESON_WATCHDOG) += meson_wdt.o
+obj-$(CONFIG_MCS814X_WATCHDOG) += mcs814x_wdt.o
# AVR32 Architecture
obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o

View File

@ -0,0 +1,25 @@
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -819,6 +819,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 && OF
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -49,6 +49,7 @@ obj-$(CONFIG_GPIO_MAX732X) += gpio-max73
obj-$(CONFIG_GPIO_MC33880) += gpio-mc33880.o
obj-$(CONFIG_GPIO_MC9S08DZ60) += gpio-mc9s08dz60.o
obj-$(CONFIG_GPIO_MCP23S08) += gpio-mcp23s08.o
+obj-$(CONFIG_GPIO_MCS814X) += gpio-mcs814x.o
obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o
obj-$(CONFIG_GPIO_MM_LANTIQ) += gpio-mm-lantiq.o
obj-$(CONFIG_GPIO_MOXART) += gpio-moxart.o

View File

@ -0,0 +1,20 @@
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -164,6 +164,10 @@ config RTL8306_PHY
tristate "Driver for Realtek RTL8306S switches"
select SWCONFIG
+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
@@ -51,3 +51,4 @@ obj-$(CONFIG_MDIO_SUN4I) += mdio-sun4i.o
obj-$(CONFIG_MDIO_MOXART) += mdio-moxart.o
obj-$(CONFIG_AMD_XGBE_PHY) += amd-xgbe-phy.o
obj-$(CONFIG_MDIO_BCM_UNIMAC) += mdio-bcm-unimac.o
+obj-$(CONFIG_MCS814X_PHY) += mcs814x.o

View File

@ -0,0 +1,14 @@
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -40,9 +40,9 @@
#include <linux/mtd/xip.h>
#define AMD_BOOTLOC_BUG
-#define FORCE_WORD_WRITE 0
+#define FORCE_WORD_WRITE 1
-#define MAX_WORD_RETRIES 3
+#define MAX_WORD_RETRIES 10
#define SST49LF004B 0x0060
#define SST49LF040B 0x0050

View File

@ -0,0 +1,64 @@
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -122,7 +122,7 @@ struct td {
/* PSW is only for ISO. Only 1 PSW entry is used, but on
* big-endian PPC hardware that's the second entry.
*/
-#define MAXPSW 2
+#define MAXPSW 8
__hc16 hwPSW [MAXPSW];
/* rest are purely for the driver's use */
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -441,6 +441,7 @@ static int ohci_init (struct ohci_hcd *o
{
int ret;
struct usb_hcd *hcd = ohci_to_hcd(ohci);
+ u32 hcca_area;
/* Accept arbitrarily long scatter-gather lists */
hcd->self.sg_tablesize = ~0;
@@ -501,11 +502,13 @@ static int ohci_init (struct ohci_hcd *o
(unsigned long) ohci);
set_timer_slack(&ohci->io_watchdog, msecs_to_jiffies(20));
- ohci->hcca = dma_alloc_coherent (hcd->self.controller,
- sizeof(*ohci->hcca), &ohci->hcca_dma, GFP_KERNEL);
+ hcca_area = ohci_readl(ohci, &ohci->regs->hcca);
+ ohci->hcca = ioremap_nocache(hcca_area, sizeof *ohci->hcca);
if (!ohci->hcca)
return -ENOMEM;
+ ohci->hcca_dma = hcca_area;
+
if ((ret = ohci_mem_init (ohci)) < 0)
ohci_stop (hcd);
else {
@@ -523,6 +526,7 @@ static int ohci_init (struct ohci_hcd *o
*/
static int ohci_run (struct ohci_hcd *ohci)
{
+ int i = 0;
u32 mask, val;
int first = ohci->fminterval == 0;
struct usb_hcd *hcd = ohci_to_hcd(ohci);
@@ -573,6 +577,8 @@ static int ohci_run (struct ohci_hcd *oh
msleep(val);
memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
+ for (i = 0; i < NUM_INTS; i++)
+ ohci->hcca->int_table[i] = 0;
/* 2msec timelimit here means no irqs/preempt */
spin_lock_irq (&ohci->lock);
@@ -984,9 +990,6 @@ static void ohci_stop (struct usb_hcd *h
remove_debug_files (ohci);
ohci_mem_cleanup (ohci);
if (ohci->hcca) {
- dma_free_coherent (hcd->self.controller,
- sizeof *ohci->hcca,
- ohci->hcca, ohci->hcca_dma);
ohci->hcca = NULL;
ohci->hcca_dma = 0;
}