diff options
author | juhosg <juhosg@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2013-02-21 20:45:24 +0000 |
---|---|---|
committer | juhosg <juhosg@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2013-02-21 20:45:24 +0000 |
commit | 14aca56112cac8d89ef8ea472dc74736419c594f (patch) | |
tree | 937042c1547638c462f20c49d1b07f54a5a7e956 /target/linux | |
parent | 6f8f9a35d5414ee8080ef40821d8b22aaf5262e2 (diff) |
cns21xx: add support for 3.8
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@35737 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux')
19 files changed, 7843 insertions, 0 deletions
diff --git a/target/linux/cns21xx/config-3.8 b/target/linux/cns21xx/config-3.8 new file mode 100644 index 0000000000..7b7d7cb365 --- /dev/null +++ b/target/linux/cns21xx/config-3.8 @@ -0,0 +1,160 @@ +CONFIG_ALIGNMENT_TRAP=y +CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y +CONFIG_ARCH_CNS21XX=y +CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y +CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y +# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set +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_VT8500_SINGLE is not set +CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y +CONFIG_ARM=y +# CONFIG_ARM_CPU_SUSPEND is not set +CONFIG_ARM_L1_CACHE_SHIFT=4 +CONFIG_ARM_L1_CACHE_SHIFT_4=y +CONFIG_ARM_NR_BANKS=8 +# CONFIG_ARPD is not set +CONFIG_ATA=m +CONFIG_ATAGS=y +# CONFIG_CACHE_L2X0 is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_CMDLINE="console=ttyS0,38400 rootfstype=squashfs,jffs2 noinitrd" +CONFIG_CMDLINE_FROM_BOOTLOADER=y +CONFIG_CNS21XX_DEV_GEC=y +CONFIG_CNS21XX_DEV_SPI_MASTER=y +CONFIG_CNS21XX_DEV_USB=y +CONFIG_CNS21XX_GEC=y +CONFIG_CPU_32v4=y +CONFIG_CPU_ABRT_EV4=y +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_CPU_CACHE_FA=y +CONFIG_CPU_CACHE_VIVT=y +CONFIG_CPU_COPY_FA=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y +# CONFIG_CPU_DCACHE_WRITETHROUGH is not set +CONFIG_CPU_FA526=y +# CONFIG_CPU_ICACHE_DISABLE is not set +CONFIG_CPU_PABRT_LEGACY=y +CONFIG_CPU_TLB_FA=y +CONFIG_CPU_USE_DOMAINS=y +CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S" +# CONFIG_DEBUG_USER is not set +CONFIG_DECOMPRESS_LZMA=y +CONFIG_DLCI=m +CONFIG_DLCI_MAX=8 +CONFIG_DMADEVICES=y +CONFIG_DNOTIFY=y +CONFIG_EEPROM_AT25=y +CONFIG_FA_WATCHDOG=y +CONFIG_FRAME_POINTER=y +CONFIG_GENERIC_ATOMIC64=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_GPIO=y +CONFIG_GENERIC_IO=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GPIOLIB=y +CONFIG_GPIO_SYSFS=y +# CONFIG_HAMRADIO is not set +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAVE_AOUT=y +CONFIG_HAVE_ARCH_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_BPF_JIT=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_GENERIC_HARDIRQS=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_NET_DSA=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_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_UID16=y +CONFIG_HDLC=m +CONFIG_HDLC_CISCO=m +CONFIG_HDLC_FR=m +CONFIG_HDLC_PPP=m +CONFIG_HDLC_RAW=m +CONFIG_HWMON=y +CONFIG_HW_RANDOM=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +CONFIG_KTIME_SCALAR=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_M25PXX_USE_FAST_READ=y +CONFIG_MACH_NSB3AST=y +CONFIG_MACH_NS_K330=y +CONFIG_MDIO_BOARDINFO=y +CONFIG_MODULES_USE_ELF_REL=y +# CONFIG_MTD_CFI is not set +CONFIG_MTD_M25P80=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_NEED_PER_CPU_KM=y +CONFIG_NLS=m +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_PAGE_OFFSET=0xC0000000 +# CONFIG_PCI_SYSCALL is not set +CONFIG_PERCPU_RWSEM=y +CONFIG_PERF_USE_VMALLOC=y +CONFIG_PHYLIB=y +CONFIG_PHYS_OFFSET=0x00000000 +CONFIG_PLAT_FA=y +CONFIG_PLAT_FA_GPIO=y +CONFIG_PLAT_FA_TIME=y +# CONFIG_PREEMPT_RCU is not set +CONFIG_SCSI=m +CONFIG_SCSI_MOD=m +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SERIO=y +CONFIG_SERIO_LIBPS2=y +CONFIG_SERIO_SERPORT=y +CONFIG_SPI=y +CONFIG_SPI_BITBANG=y +CONFIG_SPI_CNS21XX=y +CONFIG_SPI_DEBUG=y +CONFIG_SPI_MASTER=y +CONFIG_SPLIT_PTLOCK_CPUS=999999 +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_TICK_CPU_ACCOUNTING=y +CONFIG_UID16=y +CONFIG_UIDGID_CONVERTED=y +# CONFIG_USB_ARCH_HAS_XHCI is not set +CONFIG_USB_SUPPORT=y +CONFIG_VECTORS_BASE=0xffff0000 +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_WAN=y +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZONE_DMA_FLAG=0 diff --git a/target/linux/cns21xx/patches-3.8/002-arm-debugll-printk.patch b/target/linux/cns21xx/patches-3.8/002-arm-debugll-printk.patch new file mode 100644 index 0000000000..e14509ef3c --- /dev/null +++ b/target/linux/cns21xx/patches-3.8/002-arm-debugll-printk.patch @@ -0,0 +1,24 @@ +--- a/kernel/printk.c ++++ b/kernel/printk.c +@@ -48,6 +48,10 @@ + #define CREATE_TRACE_POINTS + #include <trace/events/printk.h> + ++#ifdef CONFIG_DEBUG_LL ++extern void printascii(char *); ++#endif /* CONFIG_DEBUG_LL */ ++ + /* + * Architectures can override it: + */ +@@ -473,6 +477,10 @@ static ssize_t devkmsg_read(struct file + ts_usec = msg->ts_nsec; + do_div(ts_usec, 1000); + ++#ifdef CONFIG_DEBUG_LL ++ printascii(printk_buf); ++#endif ++ + /* + * If we couldn't merge continuation line fragments during the print, + * export the stored flags to allow an optional external merge of the diff --git a/target/linux/cns21xx/patches-3.8/003-arm-introduce-fa-platform.patch b/target/linux/cns21xx/patches-3.8/003-arm-introduce-fa-platform.patch new file mode 100644 index 0000000000..5f7907c049 --- /dev/null +++ b/target/linux/cns21xx/patches-3.8/003-arm-introduce-fa-platform.patch @@ -0,0 +1,56 @@ +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -1133,10 +1133,15 @@ source "arch/arm/mach-w90x900/Kconfig" + + source "arch/arm/mach-zynq/Kconfig" + ++source "arch/arm/plat-fa/Kconfig" ++ + # Definitions to make life easier + config ARCH_ACORN + bool + ++config PLAT_FA ++ bool ++ + config PLAT_IOP + bool + select GENERIC_CLOCKEVENTS +--- a/arch/arm/Makefile ++++ b/arch/arm/Makefile +@@ -202,6 +202,7 @@ machine-$(CONFIG_ARCH_SUNXI) += sunxi + plat-$(CONFIG_ARCH_OMAP) += omap + plat-$(CONFIG_ARCH_S3C64XX) += samsung + plat-$(CONFIG_PLAT_IOP) += iop ++plat-$(CONFIG_PLAT_FA) += fa + plat-$(CONFIG_PLAT_ORION) += orion + plat-$(CONFIG_PLAT_PXA) += pxa + plat-$(CONFIG_PLAT_S3C24XX) += s3c24xx samsung +@@ -311,7 +312,7 @@ define archhelp + echo ' Image - Uncompressed kernel image (arch/$(ARCH)/boot/Image)' + echo '* xipImage - XIP kernel image, if configured (arch/$(ARCH)/boot/xipImage)' + echo ' uImage - U-Boot wrapped zImage' +- echo ' bootpImage - Combined zImage and initial RAM disk' ++ echo ' bootpImage - Combined zImage and initial RAM disk' + echo ' (supply initrd image via make variable INITRD=<path>)' + echo '* dtbs - Build device tree blobs for enabled boards' + echo ' install - Install uncompressed kernel' +--- /dev/null ++++ b/arch/arm/plat-fa/Makefile +@@ -0,0 +1,10 @@ ++# ++# Makefile for the linux kernel. ++# ++ ++obj-y := ++ ++obj-m := ++obj-n := ++obj- := ++ +--- /dev/null ++++ b/arch/arm/plat-fa/Kconfig +@@ -0,0 +1,3 @@ ++if PLAT_FA ++ ++endif diff --git a/target/linux/cns21xx/patches-3.8/004-arm-add-fa-time.patch b/target/linux/cns21xx/patches-3.8/004-arm-add-fa-time.patch new file mode 100644 index 0000000000..460e7cb69d --- /dev/null +++ b/target/linux/cns21xx/patches-3.8/004-arm-add-fa-time.patch @@ -0,0 +1,143 @@ +--- /dev/null ++++ b/arch/arm/plat-fa/include/plat/time.h +@@ -0,0 +1,20 @@ ++/* ++ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#ifndef _FA_TIME_H ++#define _FA_TIME_H ++ ++#define FA_TIMER1 0 ++#define FA_TIMER2 1 ++#define FA_TIMER3 2 ++ ++int __init fa_timer_init(unsigned int mapbase, unsigned int irq, ++ unsigned int timer, unsigned int freq); ++ ++#endif /* _FA_TIME_H */ +--- /dev/null ++++ b/arch/arm/plat-fa/time.c +@@ -0,0 +1,97 @@ ++/* ++ * Copyright (C) 2001-2006 Storlink, Corp. ++ * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> ++ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include <linux/init.h> ++#include <linux/interrupt.h> ++#include <linux/irq.h> ++#include <linux/io.h> ++ ++#include <asm/mach/time.h> ++#include <plat/time.h> ++ ++/* ++ * Register definitions for the timers ++ */ ++#define TIMER_COUNT(_base, _tmr) ((_base) + 0x00 + (_tmr) * 0x10) ++#define TIMER_LOAD(_base, _tmr) ((_base) + 0x04 + (_tmr) * 0x10) ++#define TIMER_MATCH1(_base, _tmr) ((_base) + 0x08 + (_tmr) * 0x10) ++#define TIMER_MATCH2(_base, _tmr) ((_base) + 0x0c + (_tmr) * 0x10) ++ ++#define TIMER_CR(_base) ((_base) + 0x30) ++#define TIMER_STATUS(_base) ((_base) + 0x34) ++#define TIMER_MASK(_base) ((_base) + 0x38) ++ ++#define TIMER_SIZE 0x3c ++ ++#define TIMER_CR_ENABLE(x) (1 << ((x) * 3)) ++#define TIMER_CR_CLOCK(x) (1 << ((x) * 3 + 1)) ++#define TIMER_CR_INT(x) (1 << ((x) * 3 + 2)) ++#define TIMER_CR_DOWN(x) (1 << ((x) * 3 + 9)) ++ ++#define TIMER_MASK_MATCH1(x) (1 << ((x) * 3)) ++#define TIMER_MASK_MATCH2(x) (1 << ((x) * 3 + 1)) ++#define TIMER_MASK_OF(x) (1 << ((x) * 3 + 2)) ++ ++#define TIMER_MASK_ALL 0x7ff ++ ++/* ++ * IRQ handler for the timer ++ */ ++static irqreturn_t fa_timer_interrupt(int irq, void *dev_id) ++{ ++ timer_tick(); ++ return IRQ_HANDLED; ++} ++ ++static struct irqaction fa_timer_irq = { ++ .name = "Timer Tick", ++ .flags = IRQF_DISABLED | IRQF_TIMER, ++ .handler = fa_timer_interrupt, ++}; ++ ++int __init fa_timer_init(unsigned int mapbase, unsigned int irq, ++ unsigned int timer, unsigned int freq) ++{ ++ void __iomem *base; ++ ++ base = ioremap(mapbase, TIMER_SIZE); ++ if (!base) ++ return -ENOMEM; ++ ++ /* disable timers, clear status and mask all interrupts */ ++ __raw_writel(0, TIMER_CR(base)); ++ __raw_writel(0, TIMER_STATUS(base)); ++ __raw_writel(TIMER_MASK_ALL, TIMER_MASK(base)); ++ ++ /* ++ * Make irqs happen for the system timer ++ */ ++ setup_irq(irq, &fa_timer_irq); ++ ++ /* Setup the timer */ ++ __raw_writel(freq / HZ, TIMER_COUNT(base, timer)); ++ __raw_writel(freq / HZ, TIMER_LOAD(base, timer)); ++ __raw_writel(0, TIMER_MATCH1(base, timer)); ++ __raw_writel(0, TIMER_MATCH2(base, timer)); ++ ++ /* Enable interrupt and start the timer */ ++ __raw_writel(TIMER_MASK_ALL & ~TIMER_MASK_OF(timer), ++ TIMER_MASK(base)); ++ ++ __raw_writel(TIMER_CR_ENABLE(timer) | ++ TIMER_CR_INT(timer) | ++ TIMER_CR_DOWN(timer), ++ TIMER_CR(base)); ++ ++ iounmap(base); ++ ++ return 0; ++} +--- a/arch/arm/plat-fa/Kconfig ++++ b/arch/arm/plat-fa/Kconfig +@@ -1,3 +1,6 @@ + if PLAT_FA + ++config PLAT_FA_TIME ++ def_bool n ++ + endif +--- a/arch/arm/plat-fa/Makefile ++++ b/arch/arm/plat-fa/Makefile +@@ -4,6 +4,8 @@ + + obj-y := + ++obj-$(CONFIG_PLAT_FA_TIME) += time.o ++ + obj-m := + obj-n := + obj- := diff --git a/target/linux/cns21xx/patches-3.8/005-arm-add-fa-gpio-driver.patch b/target/linux/cns21xx/patches-3.8/005-arm-add-fa-gpio-driver.patch new file mode 100644 index 0000000000..d7e8e88cc9 --- /dev/null +++ b/target/linux/cns21xx/patches-3.8/005-arm-add-fa-gpio-driver.patch @@ -0,0 +1,343 @@ +--- /dev/null ++++ b/arch/arm/plat-fa/gpio.c +@@ -0,0 +1,283 @@ ++/* ++ * Gpiochip and interrupt routines for Faraday FA526 based SoCs ++ * ++ * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> ++ * Copyright (C) 2010-2012 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * Based on plat-mxc/gpio.c: ++ * MXC GPIO supchip. (c) 2008 Daniel Mack <daniel@caiaq.de> ++ * Copyright 2008 Juergen Beisert, kernel@pengutronix.de ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include <linux/spinlock.h> ++ ++#include <plat/gpio.h> ++ ++#define GPIO_DATA_OUT 0x0 ++#define GPIO_DATA_IN 0x4 ++#define GPIO_DIR 0x8 ++#define GPIO_DATA_SET 0x10 ++#define GPIO_DATA_CLR 0x14 ++#define GPIO_PULL_EN 0x18 ++#define GPIO_PULL_TYPE 0x1C ++#define GPIO_INT_EN 0x20 ++#define GPIO_INT_STAT 0x24 ++#define GPIO_INT_MASK 0x2C ++#define GPIO_INT_CLR 0x30 ++#define GPIO_INT_TYPE 0x34 ++#define GPIO_INT_BOTH_EDGE 0x38 ++#define GPIO_INT_LEVEL 0x3C ++#define GPIO_DEBOUNCE_EN 0x40 ++#define GPIO_DEBOUNCE_PRESCALE 0x44 ++ ++#define GPIO_REGS_SIZE 0x48 ++ ++static DEFINE_SPINLOCK(fa_gpio_lock); ++ ++static inline struct fa_gpio_chip *to_fgc(struct gpio_chip *chip) ++{ ++ return container_of(chip, struct fa_gpio_chip, gpio_chip); ++} ++ ++static void _fa_gpio_irq_setenable(struct irq_data *d, int enable) ++{ ++ struct fa_gpio_chip *fgc = irq_get_chip_data(d->irq); ++ void __iomem *base = fgc->mem_base; ++ unsigned int gpio = d->irq - fgc->irq_base; ++ unsigned int reg; ++ ++ reg = __raw_readl(base + GPIO_INT_EN); ++ reg = (reg & (~(1 << gpio))) | (!!enable << gpio); ++ __raw_writel(reg, base + GPIO_INT_EN); ++} ++ ++static void fa_gpio_irq_ack(struct irq_data *d) ++{ ++ struct fa_gpio_chip *fgc = irq_get_chip_data(d->irq); ++ unsigned int gpio = d->irq - fgc->irq_base; ++ ++ __raw_writel(1 << gpio, fgc->mem_base + GPIO_INT_CLR); ++} ++ ++static void fa_gpio_irq_mask(struct irq_data *d) ++{ ++ _fa_gpio_irq_setenable(d, 0); ++} ++ ++static void fa_gpio_irq_unmask(struct irq_data *d) ++{ ++ _fa_gpio_irq_setenable(d, 1); ++} ++ ++static int fa_gpio_irq_set_type(struct irq_data *d, unsigned int type) ++{ ++ struct fa_gpio_chip *fgc = irq_get_chip_data(d->irq); ++ void __iomem *base = fgc->mem_base; ++ unsigned int gpio = d->irq - fgc->irq_base; ++ unsigned int gpio_mask = 1 << gpio; ++ unsigned int reg_both, reg_level, reg_type; ++ ++ reg_type = __raw_readl(base + GPIO_INT_TYPE); ++ reg_level = __raw_readl(base + GPIO_INT_LEVEL); ++ reg_both = __raw_readl(base + GPIO_INT_BOTH_EDGE); ++ ++ switch (type) { ++ case IRQ_TYPE_EDGE_BOTH: ++ reg_type &= ~gpio_mask; ++ reg_both |= gpio_mask; ++ break; ++ case IRQ_TYPE_EDGE_RISING: ++ reg_type &= ~gpio_mask; ++ reg_both &= ~gpio_mask; ++ reg_level &= ~gpio_mask; ++ break; ++ case IRQ_TYPE_EDGE_FALLING: ++ reg_type &= ~gpio_mask; ++ reg_both &= ~gpio_mask; ++ reg_level |= gpio_mask; ++ break; ++ case IRQ_TYPE_LEVEL_HIGH: ++ reg_type |= gpio_mask; ++ reg_level &= ~gpio_mask; ++ break; ++ case IRQ_TYPE_LEVEL_LOW: ++ reg_type |= gpio_mask; ++ reg_level |= gpio_mask; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ __raw_writel(reg_type, base + GPIO_INT_TYPE); ++ __raw_writel(reg_level, base + GPIO_INT_LEVEL); ++ __raw_writel(reg_both, base + GPIO_INT_BOTH_EDGE); ++ ++ fa_gpio_irq_ack(d); ++ ++ return 0; ++} ++ ++static void fa_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) ++{ ++ struct fa_gpio_data *data = irq_get_handler_data(irq); ++ unsigned int chip; ++ ++ for (chip = 0; chip < data->nchips; chip++) { ++ struct fa_gpio_chip *fgc = &data->chips[chip]; ++ unsigned int status; ++ unsigned int i; ++ ++ status = __raw_readl(fgc->mem_base + GPIO_INT_STAT); ++ for (i = fgc->irq_base; status != 0; status >>= 1, i++) { ++ if ((status & 1) == 0) ++ continue; ++ ++ BUG_ON(!(irq_desc[i].handle_irq)); ++ irq_desc[i].handle_irq(i, &irq_desc[i]); ++ } ++ } ++} ++ ++static struct irq_chip fa_gpio_irq_chip = { ++ .name = "GPIO", ++ .irq_ack = fa_gpio_irq_ack, ++ .irq_mask = fa_gpio_irq_mask, ++ .irq_unmask = fa_gpio_irq_unmask, ++ .irq_set_type = fa_gpio_irq_set_type, ++}; ++ ++static void _fa_gpio_set_direction(struct fa_gpio_chip *fgc, unsigned offset, ++ int is_output) ++{ ++ unsigned int reg; ++ ++ reg = __raw_readl(fgc->mem_base + GPIO_DIR); ++ if (is_output) ++ reg |= 1 << offset; ++ else ++ reg &= ~(1 << offset); ++ __raw_writel(reg, fgc->mem_base + GPIO_DIR); ++} ++ ++static void _fa_gpio_set(struct fa_gpio_chip *fgc, unsigned offset, int value) ++{ ++ if (value) ++ __raw_writel(1 << offset, fgc->mem_base + GPIO_DATA_SET); ++ else ++ __raw_writel(1 << offset, fgc->mem_base + GPIO_DATA_CLR); ++} ++ ++static void fa_gpio_set(struct gpio_chip *chip, unsigned offset, int value) ++{ ++ struct fa_gpio_chip *fgc = to_fgc(chip); ++ ++ _fa_gpio_set(fgc, offset, value); ++} ++ ++static int fa_gpio_get(struct gpio_chip *chip, unsigned offset) ++{ ++ struct fa_gpio_chip *fgc = to_fgc(chip); ++ ++ return (__raw_readl(fgc->mem_base + GPIO_DATA_IN) >> offset) & 1; ++} ++ ++static int fa_gpio_to_irq(struct gpio_chip *chip, unsigned offset) ++{ ++ struct fa_gpio_chip *fgc = to_fgc(chip); ++ ++ return fgc->irq_base + offset; ++} ++ ++static int fa_gpio_direction_input(struct gpio_chip *chip, unsigned offset) ++{ ++ struct fa_gpio_chip *fgc = to_fgc(chip); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&fa_gpio_lock, flags); ++ ++ _fa_gpio_set_direction(fgc, offset, 0); ++ ++ spin_unlock_irqrestore(&fa_gpio_lock, flags); ++ ++ return 0; ++} ++ ++static int fa_gpio_direction_output(struct gpio_chip *chip, ++ unsigned offset, ++ int value) ++{ ++ struct fa_gpio_chip *fgc = to_fgc(chip); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&fa_gpio_lock, flags); ++ ++ _fa_gpio_set(fgc, offset, value); ++ _fa_gpio_set_direction(fgc, offset, 1); ++ ++ spin_unlock_irqrestore(&fa_gpio_lock, flags); ++ ++ return 0; ++} ++ ++static int fa_gpio_init_chip(struct fa_gpio_chip *fgc) ++{ ++ void __iomem *mem_base; ++ unsigned int i; ++ int err; ++ ++ mem_base = ioremap(fgc->map_base, GPIO_REGS_SIZE); ++ if (!mem_base) ++ return -ENXIO; ++ ++ fgc->mem_base = mem_base; ++ ++ fgc->gpio_chip.direction_input = fa_gpio_direction_input; ++ fgc->gpio_chip.direction_output = fa_gpio_direction_output; ++ fgc->gpio_chip.get = fa_gpio_get; ++ fgc->gpio_chip.set = fa_gpio_set; ++ fgc->gpio_chip.to_irq = fa_gpio_to_irq; ++ ++ /* disable, unmask and clear all interrupts */ ++ __raw_writel(0x0, mem_base + GPIO_INT_EN); ++ __raw_writel(0x0, mem_base + GPIO_INT_MASK); ++ __raw_writel(~0x0, mem_base + GPIO_INT_CLR); ++ ++ for (i = fgc->irq_base; ++ i < fgc->irq_base + fgc->gpio_chip.ngpio; i++) { ++ irq_set_chip(i, &fa_gpio_irq_chip); ++ irq_set_chip_data(i, fgc); ++ irq_set_handler(i, handle_edge_irq); ++ set_irq_flags(i, IRQF_VALID); ++ } ++ ++ err = gpiochip_add(&fgc->gpio_chip); ++ if (err) ++ goto unmap; ++ ++ return 0; ++ ++ unmap: ++ iounmap(fgc->mem_base); ++ return err; ++} ++ ++void __init fa_gpio_init(struct fa_gpio_data *data) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < data->nchips; i++) { ++ int err; ++ ++ err = fa_gpio_init_chip(&data->chips[i]); ++ if (WARN(err, "GPIO init failed\n")) ++ return; ++ } ++ ++ irq_set_chained_handler(data->irq, fa_gpio_irq_handler); ++ irq_set_handler_data(data->irq, data); ++} +--- /dev/null ++++ b/arch/arm/plat-fa/include/plat/gpio.h +@@ -0,0 +1,33 @@ ++/* ++ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License, Version 2, as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef _FA_GPIO_H ++#define _FA_GPIO_H ++ ++#include <linux/init.h> ++#include <linux/gpio.h> ++#include <linux/irq.h> ++#include <linux/io.h> ++ ++struct fa_gpio_chip { ++ struct gpio_chip gpio_chip; ++ unsigned int map_base; ++ unsigned int irq_base; ++ ++ void __iomem *mem_base; ++}; ++ ++struct fa_gpio_data { ++ struct fa_gpio_chip *chips; ++ unsigned int nchips; ++ unsigned int irq; ++}; ++ ++void __init fa_gpio_init(struct fa_gpio_data *data); ++ ++#endif /* _FA_GPIO_H */ +--- a/arch/arm/plat-fa/Kconfig ++++ b/arch/arm/plat-fa/Kconfig +@@ -1,5 +1,8 @@ + if PLAT_FA + ++config PLAT_FA_GPIO ++ def_bool n ++ + config PLAT_FA_TIME + def_bool n + +--- a/arch/arm/plat-fa/Makefile ++++ b/arch/arm/plat-fa/Makefile +@@ -4,6 +4,7 @@ + + obj-y := + ++obj-$(CONFIG_PLAT_FA_GPIO) += gpio.o + obj-$(CONFIG_PLAT_FA_TIME) += time.o + + obj-m := diff --git a/target/linux/cns21xx/patches-3.8/006-arm-add-fa-watchdog-driver.patch b/target/linux/cns21xx/patches-3.8/006-arm-add-fa-watchdog-driver.patch new file mode 100644 index 0000000000..a485529184 --- /dev/null +++ b/target/linux/cns21xx/patches-3.8/006-arm-add-fa-watchdog-driver.patch @@ -0,0 +1,458 @@ +--- a/drivers/watchdog/Kconfig ++++ b/drivers/watchdog/Kconfig +@@ -364,6 +364,13 @@ config IMX2_WDT + To compile this driver as a module, choose M here: the + module will be called imx2_wdt. + ++config FA_WATCHDOG ++ tristate "Faraday watchdog" ++ depends on ARCH_GEMINI ++ help ++ Say Y here if you want support for the built-in watchdog timer ++ found in some Faraday FA526 based SoCs. ++ + # AVR32 Architecture + + config AT32AP700X_WDT +--- a/drivers/watchdog/Makefile ++++ b/drivers/watchdog/Makefile +@@ -52,6 +52,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_FA_WATCHDOG) += fa_wdt.o + + # AVR32 Architecture + obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o +--- /dev/null ++++ b/drivers/watchdog/fa_wdt.c +@@ -0,0 +1,413 @@ ++/* ++ * Watchdog driver for SoCs based on the Faraday FA526 core ++ * ++ * Copyright (C) 2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> ++ * Copyright (C) 2010-2012 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/io.h> ++#include <linux/fs.h> ++#include <linux/notifier.h> ++#include <linux/reboot.h> ++#include <linux/uaccess.h> ++#include <linux/miscdevice.h> ++#include <linux/platform_device.h> ++#include <linux/watchdog.h> ++#include <linux/slab.h> ++#include <linux/fa_wdt.h> ++ ++#define FA_WDCOUNTER 0x0 ++#define FA_WDLOAD 0x4 ++#define FA_WDRESTART 0x8 ++ ++#define WDRESTART_MAGIC 0x5AB9 ++ ++#define FA_WDCR 0xC ++ ++#define WDCR_CLOCK_5MHZ (1 << 4) ++#define WDCR_SYS_RST (1 << 1) ++#define WDCR_ENABLE (1 << 0) ++ ++#define WDT_DEFAULT_TIMEOUT 13 ++ ++/* status bits */ ++#define WDT_ACTIVE 0 ++#define WDT_OK_TO_CLOSE 1 ++ ++static unsigned int timeout = WDT_DEFAULT_TIMEOUT; ++static int nowayout = WATCHDOG_NOWAYOUT; ++ ++static DEFINE_SPINLOCK(fa_wdt_lock); ++ ++static struct platform_device *fa_wdt_dev; ++ ++struct fa_wdt_struct { ++ struct resource *res; ++ struct device *dev; ++ void __iomem *base; ++ unsigned long status; ++ unsigned int clock; ++ unsigned int max_timeout; ++}; ++ ++static const struct watchdog_info fa_wdt_info = { ++ .identity = "Faraday watchdog", ++ .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | ++ WDIOF_SETTIMEOUT, ++}; ++ ++/* Disable the watchdog. */ ++static void fa_wdt_stop(struct fa_wdt_struct *fa_wdt) ++{ ++ spin_lock(&fa_wdt_lock); ++ ++ __raw_writel(0, fa_wdt->base + FA_WDCR); ++ ++ clear_bit(WDT_ACTIVE, &fa_wdt->status); ++ ++ spin_unlock(&fa_wdt_lock); ++} ++ ++/* Service the watchdog */ ++static void fa_wdt_service(struct fa_wdt_struct *fa_wdt) ++{ ++ __raw_writel(WDRESTART_MAGIC, fa_wdt->base + FA_WDRESTART); ++} ++ ++/* Enable and reset the watchdog. */ ++static void fa_wdt_start(struct fa_wdt_struct *fa_wdt) ++{ ++ spin_lock(&fa_wdt_lock); ++ ++ __raw_writel(timeout * fa_wdt->clock, ++ fa_wdt->base + FA_WDLOAD); ++ ++ fa_wdt_service(fa_wdt); ++ ++ /* set clock before enabling */ ++ __raw_writel(WDCR_CLOCK_5MHZ | WDCR_SYS_RST, ++ fa_wdt->base + FA_WDCR); ++ ++ __raw_writel(WDCR_CLOCK_5MHZ | WDCR_SYS_RST | WDCR_ENABLE, ++ fa_wdt->base + FA_WDCR); ++ ++ set_bit(WDT_ACTIVE, &fa_wdt->status); ++ ++ spin_unlock(&fa_wdt_lock); ++} ++ ++/* Watchdog device is opened, and watchdog starts running. */ ++static int fa_wdt_open(struct inode *inode, struct file *file) ++{ ++ struct fa_wdt_struct *fa_wdt = platform_get_drvdata(fa_wdt_dev); ++ ++ if (test_bit(WDT_ACTIVE, &fa_wdt->status)) ++ return -EBUSY; ++ ++ file->private_data = fa_wdt; ++ ++ fa_wdt_start(fa_wdt); ++ ++ return nonseekable_open(inode, file); ++} ++ ++/* Close the watchdog device. */ ++static int fa_wdt_close(struct inode *inode, struct file *file) ++{ ++ struct fa_wdt_struct *fa_wdt = file->private_data; ++ ++ /* Disable the watchdog if possible */ ++ if (test_bit(WDT_OK_TO_CLOSE, &fa_wdt->status)) ++ fa_wdt_stop(fa_wdt); ++ else ++ dev_warn(fa_wdt->dev, "Device closed unexpectedly - timer will not stop\n"); ++ ++ return 0; ++} ++ ++/* Handle commands from user-space. */ ++static long fa_wdt_ioctl(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ struct fa_wdt_struct *fa_wdt = file->private_data; ++ ++ int value; ++ ++ switch (cmd) { ++ case WDIOC_KEEPALIVE: ++ fa_wdt_service(fa_wdt); ++ return 0; ++ ++ case WDIOC_GETSUPPORT: ++ return copy_to_user((struct watchdog_info *)arg, &fa_wdt_info, ++ sizeof(fa_wdt_info)) ? -EFAULT : 0; ++ ++ case WDIOC_SETTIMEOUT: ++ if (get_user(value, (int *)arg)) ++ return -EFAULT; ++ ++ if ((value < 1) || (value > fa_wdt->max_timeout)) ++ return -EINVAL; ++ ++ timeout = value; ++ ++ /* restart wdt to use new timeout */ ++ fa_wdt_stop(fa_wdt); ++ fa_wdt_start(fa_wdt); ++ ++ /* Fall through */ ++ case WDIOC_GETTIMEOUT: ++ return put_user(timeout, (int *)arg); ++ ++ case WDIOC_GETTIMELEFT: ++ value = __raw_readl(fa_wdt->base + FA_WDCOUNTER); ++ return put_user(value / fa_wdt->clock, (int *)arg); ++ ++ default: ++ return -ENOTTY; ++ } ++} ++ ++/* Refresh the watchdog whenever device is written to. */ ++static ssize_t fa_wdt_write(struct file *file, const char *data, ++ size_t len, loff_t *ppos) ++{ ++ struct fa_wdt_struct *fa_wdt = file->private_data; ++ ++ if (len) { ++ if (!nowayout) { ++ size_t i; ++ ++ clear_bit(WDT_OK_TO_CLOSE, &fa_wdt->status); ++ for (i = 0; i != len; i++) { ++ char c; ++ ++ if (get_user(c, data + i)) ++ return -EFAULT; ++ if (c == 'V') ++ set_bit(WDT_OK_TO_CLOSE, ++ &fa_wdt->status); ++ } ++ } ++ fa_wdt_service(fa_wdt); ++ } ++ ++ return len; ++} ++ ++static int fa_wdt_notify_sys(struct notifier_block *this, ++ unsigned long code, void *unused) ++{ ++ struct fa_wdt_struct *fa_wdt = platform_get_drvdata(fa_wdt_dev); ++ ++ if (code == SYS_DOWN || code == SYS_HALT) ++ fa_wdt_stop(fa_wdt); ++ ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block fa_wdt_notifier = { ++ .notifier_call = fa_wdt_notify_sys, ++}; ++ ++static const struct file_operations fa_wdt_fops = { ++ .owner = THIS_MODULE, ++ .llseek = no_llseek, ++ .unlocked_ioctl = fa_wdt_ioctl, ++ .open = fa_wdt_open, ++ .release = fa_wdt_close, ++ .write = fa_wdt_write, ++}; ++ ++static struct miscdevice fa_wdt_miscdev = { ++ .minor = WATCHDOG_MINOR, ++ .name = "watchdog", ++ .fops = &fa_wdt_fops, ++}; ++ ++static void fa_wdt_shutdown(struct platform_device *pdev) ++{ ++ struct fa_wdt_struct *fa_wdt = platform_get_drvdata(pdev); ++ ++ fa_wdt_stop(fa_wdt); ++} ++ ++static int fa_wdt_probe(struct platform_device *pdev) ++{ ++ int ret; ++ int res_size; ++ struct resource *res; ++ void __iomem *base; ++ struct fa_wdt_struct *fa_wdt; ++ struct fa_wdt_platform_data *pdata; ++ ++ pdata = pdev->dev.platform_data; ++ if (!pdata) { ++ dev_err(&pdev->dev, "no platform data specified\n"); ++ return -EINVAL; ++ } ++ ++ if (!pdata->clock) { ++ dev_err(&pdev->dev, "invalid clock value\n"); ++ return -EINVAL; ++ } ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ dev_err(&pdev->dev, "can't get device resources\n"); ++ return -ENODEV; ++ } ++ ++ res_size = resource_size(res); ++ if (!request_mem_region(res->start, res_size, res->name)) { ++ dev_err(&pdev->dev, "can't allocate %d bytes at %d address\n", ++ res_size, res->start); ++ return -ENOMEM; ++ } ++ ++ base = ioremap(res->start, res_size); ++ if (!base) { ++ dev_err(&pdev->dev, "ioremap failed\n"); ++ ret = -EIO; ++ goto fail0; ++ } ++ ++ fa_wdt = kzalloc(sizeof(struct fa_wdt_struct), GFP_KERNEL); ++ if (!fa_wdt) { ++ dev_err(&pdev->dev, "can't allocate interface\n"); ++ ret = -ENOMEM; ++ goto fail1; ++ } ++ ++ /* Setup fa_wdt driver structure */ ++ fa_wdt->base = base; ++ fa_wdt->res = res; ++ fa_wdt->dev = &pdev->dev; ++ fa_wdt->clock = pdata->clock; ++ fa_wdt->max_timeout = 0xffffffffU / pdata->clock; ++ ++ /* Set up platform driver data */ ++ platform_set_drvdata(pdev, fa_wdt); ++ fa_wdt_dev = pdev; ++ ++ if (fa_wdt_miscdev.parent) { ++ ret = -EBUSY; ++ goto fail2; ++ } ++ ++ ret = register_reboot_notifier(&fa_wdt_notifier); ++ if (ret) ++ goto fail2; ++ ++ fa_wdt_miscdev.parent = &pdev->dev; ++ ++ ret = misc_register(&fa_wdt_miscdev); ++ if (ret) ++ goto fail3; ++ ++ return 0; ++ ++fail3: ++ unregister_reboot_notifier(&fa_wdt_notifier); ++fail2: ++ platform_set_drvdata(pdev, NULL); ++ kfree(fa_wdt); ++fail1: ++ iounmap(base); ++fail0: ++ release_mem_region(res->start, res_size); ++ ++ return ret; ++} ++ ++static int fa_wdt_remove(struct platform_device *pdev) ++{ ++ struct fa_wdt_struct *fa_wdt = platform_get_drvdata(pdev); ++ ++ platform_set_drvdata(pdev, NULL); ++ misc_deregister(&fa_wdt_miscdev); ++ unregister_reboot_notifier(&fa_wdt_notifier); ++ fa_wdt_dev = NULL; ++ iounmap(fa_wdt->base); ++ release_mem_region(fa_wdt->res->start, resource_size(fa_wdt->res)); ++ ++ kfree(fa_wdt); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int fa_wdt_suspend(struct platform_device *pdev, pm_message_t message) ++{ ++ struct fa_wdt_struct *fa_wdt = platform_get_drvdata(pdev); ++ unsigned int reg; ++ ++ reg = __raw_readw(fa_wdt->base + FA_WDCR); ++ reg &= ~(WDCR_WDENABLE); ++ __raw_writel(reg, fa_wdt->base + FA_WDCR); ++ ++ return 0; ++} ++ ++static int fa_wdt_resume(struct platform_device *pdev) ++{ ++ struct fa_wdt_struct *fa_wdt = platform_get_drvdata(pdev); ++ unsigned int reg; ++ ++ if (fa_wdt->status) { ++ reg = __raw_readw(fa_wdt->base + FA_WDCR); ++ reg |= WDCR_WDENABLE; ++ __raw_writel(reg, fa_wdt->base + FA_WDCR); ++ } ++ ++ return 0; ++} ++#else ++#define fa_wdt_suspend NULL ++#define fa_wdt_resume NULL ++#endif ++ ++static struct platform_driver fa_wdt_driver = { ++ .probe = fa_wdt_probe, ++ .remove = fa_wdt_remove, ++ .shutdown = fa_wdt_shutdown, ++ .suspend = fa_wdt_suspend, ++ .resume = fa_wdt_resume, ++ .driver = { ++ .name = "fa-wdt", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int __init fa_wdt_init(void) ++{ ++ return platform_driver_probe(&fa_wdt_driver, fa_wdt_probe); ++} ++ ++static void __exit fa_wdt_exit(void) ++{ ++ platform_driver_unregister(&fa_wdt_driver); ++} ++ ++module_init(fa_wdt_init); ++module_exit(fa_wdt_exit); ++ ++module_param(timeout, uint, 0); ++MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds"); ++ ++module_param(nowayout, int, 0); ++MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"); ++ ++MODULE_AUTHOR("Paulius Zaleckas"); ++MODULE_AUTHOR("Gabor Juhos"); ++MODULE_DESCRIPTION("Watchdog driver for Faraday FA526 based SoCs"); ++MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); ++MODULE_ALIAS("platform:fa-wdt"); +--- /dev/null ++++ b/include/linux/fa_wdt.h +@@ -0,0 +1,13 @@ ++/* ++ * Platform data definition for the Faraday watchdog driver ++ */ ++ ++#ifndef _FA_WDT_H ++#define _FA_WDT_H ++ ++struct fa_wdt_platform_data { ++ unsigned int clock; ++}; ++ ++#endif /* _FA_WDT_H */ ++ diff --git a/target/linux/cns21xx/patches-3.8/100-cns21xx-core.patch b/target/linux/cns21xx/patches-3.8/100-cns21xx-core.patch new file mode 100644 index 0000000000..04fb1909a5 --- /dev/null +++ b/target/linux/cns21xx/patches-3.8/100-cns21xx-core.patch @@ -0,0 +1,2050 @@ +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -184,6 +184,11 @@ config NEED_RET_TO_USER + config ARCH_MTD_XIP + bool + ++config ARM_L1_CACHE_SHIFT_4 ++ bool ++ help ++ Setting ARM L1 cache line size to 16 bytes. ++ + config VECTORS_BASE + hex + default 0xffff0000 if MMU || CPU_HIGH_VECTOR +@@ -368,6 +373,15 @@ config ARCH_CNS3XXX + help + Support for Cavium Networks CNS3XXX platform. + ++config ARCH_CNS21XX ++ bool "Cavium Networks CNS21xx family" ++ select CPU_FA526 ++ select PLAT_FA ++ select PLAT_FA_TIME ++ select ARM_L1_CACHE_SHIFT_4 ++ help ++ Support for Cavium Networks CNS21xx family. ++ + config ARCH_CLPS711X + bool "Cirrus Logic CLPS711x/EP721x/EP731x-based" + select ARCH_REQUIRE_GPIOLIB +@@ -1030,6 +1044,8 @@ source "arch/arm/mach-davinci/Kconfig" + + source "arch/arm/mach-dove/Kconfig" + ++source "arch/arm/mach-cns21xx/Kconfig" ++ + source "arch/arm/mach-ep93xx/Kconfig" + + source "arch/arm/mach-footbridge/Kconfig" +--- /dev/null ++++ b/arch/arm/mach-cns21xx/Kconfig +@@ -0,0 +1,6 @@ ++if ARCH_CNS21XX ++ ++menu "Cavium Networks CNS21xx based machines" ++endmenu ++ ++endif +--- /dev/null ++++ b/arch/arm/mach-cns21xx/Makefile +@@ -0,0 +1,10 @@ ++# ++# Makefile for the linux kernel. ++# ++ ++# Object file lists. ++ ++obj-y := core.o irq.o mm.o time.o ++ ++# machine specific files ++ +--- /dev/null ++++ b/arch/arm/mach-cns21xx/Makefile.boot +@@ -0,0 +1,3 @@ ++ zreladdr-y += 0x00008000 ++params_phys-y := 0x00000100 ++initrd_phys-y := 0x00C00000 +--- a/arch/arm/Makefile ++++ b/arch/arm/Makefile +@@ -141,6 +141,7 @@ machine-$(CONFIG_ARCH_AT91) += at91 + machine-$(CONFIG_ARCH_BCM) += bcm + machine-$(CONFIG_ARCH_BCM2835) += bcm2835 + machine-$(CONFIG_ARCH_CLPS711X) += clps711x ++machine-$(CONFIG_ARCH_CNS21XX) += cns21xx + machine-$(CONFIG_ARCH_CNS3XXX) += cns3xxx + machine-$(CONFIG_ARCH_DAVINCI) += davinci + machine-$(CONFIG_ARCH_DOVE) += dove +--- /dev/null ++++ b/arch/arm/mach-cns21xx/common.h +@@ -0,0 +1,19 @@ ++/* ++ * Copyright (c) 2008 Cavium Networks ++ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License, Version 2, as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef _MACH_CNS21XX_COMMON_H ++#define _MACH_CNS21XX_COMMON_H ++ ++void cns21xx_restart(char mode, const char *cmd); ++void cns21xx_map_io(void); ++void cns21xx_init_irq(void); ++ ++extern struct sys_timer cns21xx_timer; ++ ++#endif /* _MACH_CNS21XX_COMMON_H */ +--- /dev/null ++++ b/arch/arm/mach-cns21xx/mm.c +@@ -0,0 +1,170 @@ ++/* ++ * Copyright (c) 2008 Cavium Networks ++ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License, Version 2, as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/mm.h> ++#include <linux/init.h> ++ ++#include <asm/mach/map.h> ++ ++#include <mach/hardware.h> ++#include <mach/cns21xx.h> ++ ++#include "common.h" ++ ++/* ++ * Standard IO mapping ++ */ ++static struct map_desc cns21xx_io_desc[] __initdata = { ++ { ++ .virtual = CNS21XX_FLASH_BANK0_BASE_VIRT, ++ .pfn = __phys_to_pfn(CNS21XX_FLASH_BANK0_BASE), ++ .length = SZ_256M, ++ .type = MT_DEVICE ++ }, { ++ .virtual = CNS21XX_IDE_DEVICE_BASE_VIRT, ++ .pfn = __phys_to_pfn(CNS21XX_IDE_DEVICE_BASE), ++ .length = SZ_4K, ++ .type = MT_DEVICE ++ }, { ++ .virtual = CNS21XX_GDMAC_BASE_VIRT, ++ .pfn = __phys_to_pfn(CNS21XX_GDMAC_BASE), ++ .length = SZ_4K, ++ .type = MT_DEVICE ++ }, { ++ .virtual = CNS21XX_NIC_BASE_VIRT, ++ .pfn = __phys_to_pfn(CNS21XX_NIC_BASE), ++ .length = SZ_4K, ++ .type = MT_DEVICE ++ }, { ++ .virtual = CNS21XX_SPI_BASE_VIRT, ++ .pfn = __phys_to_pfn(CNS21XX_SPI_BASE), ++ .length = SZ_4K, ++ .type = MT_DEVICE ++ }, { ++ .virtual = CNS21XX_PCM_BASE_VIRT, ++ .pfn = __phys_to_pfn(CNS21XX_PCM_BASE), ++ .length = SZ_4K, ++ .type = MT_DEVICE ++ }, { ++ .virtual = CNS21XX_I2C_BASE_VIRT, ++ .pfn = __phys_to_pfn(CNS21XX_I2C_BASE), ++ .length = SZ_4K, ++ .type = MT_DEVICE ++ }, { ++ .virtual = CNS21XX_I2S_BASE_VIRT, ++ .pfn = __phys_to_pfn(CNS21XX_I2S_BASE), ++ .length = SZ_4K, ++ .type = MT_DEVICE ++ }, { ++ .virtual = CNS21XX_DDRC_BASE_VIRT, ++ .pfn = __phys_to_pfn(CNS21XX_DDRC_BASE), ++ .length = SZ_4K, ++ .type = MT_DEVICE ++ }, { ++ .virtual = CNS21XX_SMC_BASE_VIRT, ++ .pfn = __phys_to_pfn(CNS21XX_SMC_BASE), ++ .length = SZ_4K, ++ .type = MT_DEVICE ++ }, { ++ .virtual = CNS21XX_IDE_CTRL_BASE_VIRT, ++ .pfn = __phys_to_pfn(CNS21XX_IDE_CTRL_BASE), ++ .length = SZ_4K, ++ .type = MT_DEVICE ++ }, { ++ .virtual = CNS21XX_MISC_BASE_VIRT, ++ .pfn = __phys_to_pfn(CNS21XX_MISC_BASE), ++ .length = SZ_4K, ++ .type = MT_DEVICE ++ }, { ++ .virtual = CNS21XX_CPM_BASE_VIRT, ++ .pfn = __phys_to_pfn(CNS21XX_CPM_BASE), ++ .length = SZ_4K, ++ .type = MT_DEVICE ++ }, { ++ .virtual = CNS21XX_UART0_BASE_VIRT, ++ .pfn = __phys_to_pfn(CNS21XX_UART0_BASE), ++ .length = SZ_4K, ++ .type = MT_DEVICE ++ }, { ++ .virtual = CNS21XX_UART1_BASE_VIRT, ++ .pfn = __phys_to_pfn(CNS21XX_UART1_BASE), ++ .length = SZ_4K, ++ .type = MT_DEVICE ++ }, { ++ .virtual = CNS21XX_TIMER_BASE_VIRT, ++ .pfn = __phys_to_pfn(CNS21XX_TIMER_BASE), ++ .length = SZ_4K, ++ .type = MT_DEVICE ++ }, { ++ .virtual = CNS21XX_WDT_BASE_VIRT, ++ .pfn = __phys_to_pfn(CNS21XX_WDT_BASE), ++ .length = SZ_4K, ++ .type = MT_DEVICE ++ }, { ++ .virtual = CNS21XX_RTC_BASE_VIRT, ++ .pfn = __phys_to_pfn(CNS21XX_RTC_BASE), ++ .length = SZ_4K, ++ .type = MT_DEVICE ++ }, { ++ .virtual = CNS21XX_GPIOA_BASE_VIRT, ++ .pfn = __phys_to_pfn(CNS21XX_GPIOA_BASE), ++ .length = SZ_4K, ++ .type = MT_DEVICE ++ }, { ++ .virtual = CNS21XX_GPIOB_BASE_VIRT, ++ .pfn = __phys_to_pfn(CNS21XX_GPIOB_BASE), ++ .length = SZ_4K, ++ .type = MT_DEVICE ++ }, { ++ .virtual = CNS21XX_PCI_CFGDATA_BASE_VIRT, ++ .pfn = __phys_to_pfn(CNS21XX_PCI_CFGDATA_BASE), ++ .length = SZ_4K, ++ .type = MT_DEVICE ++ }, { ++ .virtual = CNS21XX_PCI_CFGADDR_BASE_VIRT, ++ .pfn = __phys_to_pfn(CNS21XX_PCI_CFGADDR_BASE), ++ .length = SZ_4K, ++ .type = MT_DEVICE ++ }, { ++ .virtual = CNS21XX_OHCI_CONFIG_BASE_VIRT, ++ .pfn = __phys_to_pfn(CNS21XX_OHCI_CONFIG_BASE), ++ .length = SZ_4K, ++ .type = MT_DEVICE ++ }, { ++ .virtual = CNS21XX_OHCI_CTRL_BASE_VIRT, ++ .pfn = __phys_to_pfn(CNS21XX_OHCI_CTRL_BASE), ++ .length = SZ_4K, ++ .type = MT_DEVICE ++ }, { ++ .virtual = CNS21XX_EHCI_CONFIG_BASE_VIRT, ++ .pfn = __phys_to_pfn(CNS21XX_EHCI_CONFIG_BASE), ++ .length = SZ_4K, ++ .type = MT_DEVICE ++ }, { ++ .virtual = CNS21XX_EHCI_CTRL_BASE_VIRT, ++ .pfn = __phys_to_pfn(CNS21XX_EHCI_CTRL_BASE), ++ .length = SZ_4K, ++ .type = MT_DEVICE ++ }, { ++ .virtual = CNS21XX_USB_DEVICE_BASE_VIRT, ++ .pfn = __phys_to_pfn(CNS21XX_USB_DEVICE_BASE), ++ .length = SZ_4K, ++ .type = MT_DEVICE ++ }, { ++ .virtual = CNS21XX_INTC_BASE_VIRT, ++ .pfn = __phys_to_pfn(CNS21XX_INTC_BASE), ++ .length = SZ_4K, ++ .type = MT_DEVICE ++ } ++}; ++ ++void __init cns21xx_map_io(void) ++{ ++ iotable_init(cns21xx_io_desc, ARRAY_SIZE(cns21xx_io_desc)); ++} +--- /dev/null ++++ b/arch/arm/mach-cns21xx/include/mach/hardware.h +@@ -0,0 +1,20 @@ ++/* ++ * Copyright (c) 2008 Cavium Networks ++ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License, Version 2, as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef _CNS21XX_HARDWARE_H ++#define _CNS21XX_HARDWARE_H ++ ++#ifndef __ASSEMBLY__ ++extern unsigned long cns21xx_get_pll_freq(void); ++extern unsigned long cns21xx_get_cpu_freq(void); ++extern unsigned long cns21xx_get_ahb_freq(void); ++extern unsigned long cns21xx_get_apb_freq(void); ++#endif ++ ++#endif /* _CNS21XX_HARDWARE_H */ +--- /dev/null ++++ b/arch/arm/mach-cns21xx/include/mach/debug-macro.S +@@ -0,0 +1,25 @@ ++/* ++ * Copyright (c) 2008 Cavium Networks ++ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License, Version 2, as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <mach/cns21xx.h> ++ ++/* TODO: make it configurable */ ++#define CNS21XX_DEBUG_UART_BASE CNS21XX_UART0_BASE ++#define CNS21XX_DEBUG_UART_BASE_VIRT CNS21XX_UART0_BASE_VIRT ++ ++ .macro addruart, rp, rv ++ mov \rp, #(CNS21XX_DEBUG_UART_BASE) @ physical ++ mov \rv, #(CNS21XX_DEBUG_UART_BASE_VIRT & 0xff000000) @virtual ++ orr \rv, \rv, #(CNS21XX_DEBUG_UART_BASE_VIRT & 0x00ff0000) ++ orr \rv, \rv, #(CNS21XX_DEBUG_UART_BASE_VIRT & 0x0000ff00) ++ orr \rv, \rv, #(CNS21XX_DEBUG_UART_BASE_VIRT & 0x000000ff) ++ .endm ++ ++#define UART_SHIFT 2 ++#include <asm/hardware/debug-8250.S> +--- /dev/null ++++ b/arch/arm/mach-cns21xx/include/mach/entry-macro.S +@@ -0,0 +1,39 @@ ++/* ++ * Copyright (c) 2008 Cavium Networks ++ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License, Version 2, as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <mach/cns21xx.h> ++#include <mach/irqs.h> ++ ++#define INTC_IRQ_STATUS 0x1c ++ ++ .macro disable_fiq ++ .endm ++ ++ .macro get_irqnr_preamble, base, tmp ++ .endm ++ ++ .macro arch_ret_to_user, tmp1, tmp2 ++ .endm ++ ++ .macro get_irqnr_and_base, irqnr, irqstat, base, tmp ++ ldr \base, =(CNS21XX_INTC_BASE_VIRT + INTC_IRQ_STATUS) ++ ldr \irqstat, [\base] ++ mov \irqnr, #0 ++9001: ++ tst \irqstat, #1 ++ bne 9002f ++ add \irqnr, \irqnr, #1 ++ mov \irqstat, \irqstat, lsr #1 ++ cmp \irqnr, #CNS21XX_NR_INTC_IRQS ++ bcc 9001b ++9002: ++ .endm ++ ++ .macro irq_prio_table ++ .endm +--- /dev/null ++++ b/arch/arm/mach-cns21xx/include/mach/io.h +@@ -0,0 +1,18 @@ ++/* ++ * Copyright (c) 2008 Cavium Networks ++ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License, Version 2, as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef _CNS21XX_IO_H ++#define _CNS21XX_IO_H ++ ++#define IO_SPACE_LIMIT 0xffffffff ++ ++#define __io(p) __typesafe_io(p) ++#define __mem_pci(a) (a) ++ ++#endif /* _CNS21XX_IO_H */ +--- /dev/null ++++ b/arch/arm/mach-cns21xx/include/mach/irqs.h +@@ -0,0 +1,53 @@ ++/* ++ * Copyright (c) 2008 Cavium Networks ++ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License, Version 2, as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef _CNS21XX_IRQS_H ++#define _CNS21XX_IRQS_H ++ ++#define CNS21XX_IRQ_TIMER1 0 ++#define CNS21XX_IRQ_TIMER2 1 ++#define CNS21XX_IRQ_CPM 2 ++#define CNS21XX_IRQ_WDT 3 ++#define CNS21XX_IRQ_GPIO 4 ++#define CNS21XX_IRQ_PCI_INTA 5 ++#define CNS21XX_IRQ_PCI_INTB 6 ++#define CNS21XX_IRQ_PCI_BROKEN 7 ++#define CNS21XX_IRQ_AHB2PCI 8 ++#define CNS21XX_IRQ_UART0 9 ++#define CNS21XX_IRQ_UART1 10 ++#define CNS21XX_IRQ_GDMAC_TC 11 ++#define CNS21XX_IRQ_GDMAC_ERR 12 ++#define CNS21XX_IRQ_PCMCIA 13 ++#define CNS21XX_IRQ_RTC 14 ++#define CNS21XX_IRQ_PCM 15 ++#define CNS21XX_IRQ_USB_DEVICE 16 ++#define CNS21XX_IRQ_IDE 17 ++#define CNS21XX_IRQ_NIC_STATUS 18 ++#define CNS21XX_IRQ_NIC_TXTC 19 ++#define CNS21XX_IRQ_NIC_RXRC 20 ++#define CNS21XX_IRQ_NIC_TXQE 21 ++#define CNS21XX_IRQ_NIC_RXQF 22 ++#define CNS21XX_IRQ_OHCI 23 ++#define CNS21XX_IRQ_EHCI 24 ++#define CNS21XX_IRQ_I2S 25 ++#define CNS21XX_IRQ_SPI 26 ++#define CNS21XX_IRQ_I2C 27 ++#define CNS21XX_IRQ_USB_VBUS 28 ++#define CNS21XX_IRQ_EXT_29 29 ++#define CNS21XX_IRQ_EXT_30 30 ++#define CNS21XX_IRQ_HSDMAC 31 ++ ++#define CNS21XX_GPIO_IRQ_BASE 32 ++ ++#define CNS21XX_NR_INTC_IRQS 32 ++#define CNS21XX_NR_GPIO_IRQS 64 ++ ++#define NR_IRQS 96 ++ ++#endif /* _CNS21XX_IRQS_H */ +--- /dev/null ++++ b/arch/arm/mach-cns21xx/include/mach/timex.h +@@ -0,0 +1,15 @@ ++/* ++ * Copyright (c) 2008 Cavium Networks ++ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License, Version 2, as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef _CNS21XX_TIMEX_H ++#define _CNS21XX_TIMEX_H ++ ++#define CLOCK_TICK_RATE 43750000 ++ ++#endif /* _CNS21XX_TIMEX_H */ +--- /dev/null ++++ b/arch/arm/mach-cns21xx/include/mach/uncompress.h +@@ -0,0 +1,40 @@ ++/* ++ * Copyright (c) 2008 Cavium Networks ++ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License, Version 2, as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef _CNS21XX_UNCOMPRESS_H ++#define _CNS21XX_UNCOMPRESS_H ++ ++#define UART_BASE 0x78000000 ++ ++#define UART_REG(offs) (*((volatile unsigned int *)(UART_BASE + offs))) ++ ++#define UART_THR UART_REG(0x00) ++#define UART_LSR UART_REG(0x14) ++#define THR_EMPTY (1 << 5) ++ ++#define UART_THR_EMPTY() (((UART_LSR) & THR_EMPTY) == (THR_EMPTY)) ++ ++static void putc(int c) ++{ ++ if (c != 0) { ++ while (!UART_THR_EMPTY()) ++ barrier(); ++ ++ UART_THR = (int)(c & 0xFF); ++ } ++} ++ ++static inline void flush(void) ++{ ++} ++ ++#define arch_decomp_setup() ++#define arch_decomp_wdog() ++ ++#endif /* _CNS21XX_UNCOMPRESS_H */ +--- /dev/null ++++ b/arch/arm/mach-cns21xx/include/mach/system.h +@@ -0,0 +1,30 @@ ++/* ++ * Copyright (c) 2008 Cavium Networks ++ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License, Version 2, as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef _CNS21XX_SYSTEM_H ++#define _CNS21XX_SYSTEM_H ++ ++#include <mach/cns21xx.h> ++#include <mach/cns21xx_powermgmt.h> ++ ++static inline void arch_idle(void) ++{ ++ /* ++ * Because of broken hardware we have to enable interrupts or the CPU ++ * will never wakeup... Acctualy it is not very good to enable ++ * interrupts here since scheduler can miss a tick, but there is ++ * no other way around this. Platforms that needs it for power saving ++ * should call enable_hlt() in init code, since by default it is ++ * disabled. ++ */ ++ local_irq_enable(); ++ cpu_do_idle(); ++} ++ ++#endif /* _CNS21XX_SYSTEM_H */ +--- /dev/null ++++ b/arch/arm/mach-cns21xx/irq.c +@@ -0,0 +1,176 @@ ++/* ++ * Copyright (c) 2008 Cavium Networks ++ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License, Version 2, as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/init.h> ++#include <linux/interrupt.h> ++#include <linux/irq.h> ++#include <linux/io.h> ++#include <linux/ioport.h> ++ ++#include <asm/system_misc.h> ++ ++#include <mach/cns21xx.h> ++ ++#define INTC_INTERRUPT_RAW_STATUS_REG 0x000 ++#define INTC_EDGE_INTERRUPT_SOURCE_CLEAR_REG 0x004 ++#define INTC_INTERRUPT_MASK_REG 0x008 ++#define INTC_INTERRUPT_MASK_CLEAR_REG 0x00c ++#define INTC_INTERRUPT_TRIGGER_MODE_REG 0x010 ++#define INTC_INTERRUPT_TRIGGER_LEVEL_REG 0x014 ++#define INTC_FIQ_SELECT_REG 0x018 ++#define INTC_IRQ_STATUS_REG 0x01c ++#define INTC_FIQ_STATUS_REG 0x020 ++#define INTC_SOFTWARE_INTERRUPT_REG 0x024 ++#define INTC_SOFTWARE_INTERRUPT_CLEAR_REG 0x028 ++#define INTC_SOFTWARE_PRIORITY_MASK_REG 0x02c ++#define INTC_POWER_MANAGEMENT_INTERRUPT_REG 0x034 ++ ++#define INTC_VECTOR_ADDRESS_REG(_x) ((_x) + 0x040) ++#define INTC_PRIORITY_REG(_x) ((_x) + 0x0c0) ++#define INTC_IRQ_VECTOR_ADDRESS_REG 0x140 ++#define INTC_VECTOR_INTERRUPT_ENABLE_REG 0x144 ++ ++#define INTC_SIZE 0x148 ++ ++static unsigned int cns21xx_irq_types[CNS21XX_NR_INTC_IRQS] = { ++ [CNS21XX_IRQ_TIMER1] = IRQ_TYPE_EDGE_RISING, ++ [CNS21XX_IRQ_TIMER2] = IRQ_TYPE_EDGE_RISING, ++ [CNS21XX_IRQ_CPM] = IRQ_TYPE_EDGE_FALLING, ++ [CNS21XX_IRQ_WDT] = IRQ_TYPE_EDGE_RISING, ++ [CNS21XX_IRQ_GPIO] = IRQ_TYPE_NONE, ++ [CNS21XX_IRQ_PCI_INTA] = IRQ_TYPE_LEVEL_LOW, ++ [CNS21XX_IRQ_PCI_INTB] = IRQ_TYPE_LEVEL_LOW, ++ [CNS21XX_IRQ_PCI_BROKEN] = IRQ_TYPE_LEVEL_HIGH, ++ [CNS21XX_IRQ_AHB2PCI] = IRQ_TYPE_LEVEL_HIGH, ++ [CNS21XX_IRQ_UART0] = IRQ_TYPE_LEVEL_HIGH, ++ [CNS21XX_IRQ_UART1] = IRQ_TYPE_LEVEL_HIGH, ++ [CNS21XX_IRQ_GDMAC_TC] = IRQ_TYPE_LEVEL_HIGH, ++ [CNS21XX_IRQ_GDMAC_ERR] = IRQ_TYPE_LEVEL_HIGH, ++ [CNS21XX_IRQ_PCMCIA] = IRQ_TYPE_NONE, ++ [CNS21XX_IRQ_RTC] = IRQ_TYPE_LEVEL_HIGH, ++ [CNS21XX_IRQ_PCM] = IRQ_TYPE_LEVEL_LOW, ++ [CNS21XX_IRQ_USB_DEVICE] = IRQ_TYPE_LEVEL_LOW, ++ [CNS21XX_IRQ_IDE] = IRQ_TYPE_LEVEL_HIGH, ++ [CNS21XX_IRQ_NIC_STATUS] = IRQ_TYPE_LEVEL_HIGH, ++ [CNS21XX_IRQ_NIC_TXTC] = IRQ_TYPE_EDGE_RISING, ++ [CNS21XX_IRQ_NIC_RXRC] = IRQ_TYPE_EDGE_RISING, ++ [CNS21XX_IRQ_NIC_TXQE] = IRQ_TYPE_EDGE_RISING, ++ [CNS21XX_IRQ_NIC_RXQF] = IRQ_TYPE_EDGE_RISING, ++ [CNS21XX_IRQ_OHCI] = IRQ_TYPE_LEVEL_LOW, ++ [CNS21XX_IRQ_EHCI] = IRQ_TYPE_LEVEL_LOW, ++ [CNS21XX_IRQ_I2S] = IRQ_TYPE_LEVEL_LOW, ++ [CNS21XX_IRQ_SPI] = IRQ_TYPE_LEVEL_LOW, ++ [CNS21XX_IRQ_I2C] = IRQ_TYPE_LEVEL_LOW, ++ [CNS21XX_IRQ_USB_VBUS] = IRQ_TYPE_EDGE_RISING, ++ [CNS21XX_IRQ_EXT_29] = IRQ_TYPE_NONE, ++ [CNS21XX_IRQ_EXT_30] = IRQ_TYPE_NONE, ++ [CNS21XX_IRQ_HSDMAC] = IRQ_TYPE_EDGE_RISING, ++}; ++ ++static void __iomem *cns21xx_intc_base; ++ ++static inline void cns21xx_intc_writel(u32 val, unsigned int reg) ++{ ++ __raw_writel(val, cns21xx_intc_base + reg); ++} ++ ++static inline u32 cns21xx_intc_readl(unsigned int reg) ++{ ++ return __raw_readl(cns21xx_intc_base + reg); ++} ++ ++static void cns21xx_irq_ack(struct irq_data *d) ++{ ++ cns21xx_intc_writel(1 << d->irq, INTC_EDGE_INTERRUPT_SOURCE_CLEAR_REG); ++} ++ ++static void cns21xx_irq_mask(struct irq_data *d) ++{ ++ cns21xx_intc_writel(1 << d->irq, INTC_INTERRUPT_MASK_REG); ++} ++ ++static void cns21xx_irq_unmask(struct irq_data *d) ++{ ++ cns21xx_intc_writel(1 << d->irq, INTC_INTERRUPT_MASK_CLEAR_REG); ++} ++ ++static struct irq_chip cns21xx_irq_chip = { ++ .name = "INTC", ++ .irq_ack = cns21xx_irq_ack, ++ .irq_mask = cns21xx_irq_mask, ++ .irq_unmask = cns21xx_irq_unmask, ++}; ++ ++static struct resource cns21xx_intc_resource = { ++ .name = "INTC", ++ .flags = IORESOURCE_MEM, ++ .start = CNS21XX_INTC_BASE, ++ .end = CNS21XX_INTC_BASE + INTC_SIZE - 1, ++}; ++ ++void __init cns21xx_init_irq(void) ++{ ++ unsigned int mode = 0; ++ unsigned int level = 0; ++ int i; ++ ++ /* ++ * Disable arch_idle() by default since it is buggy ++ * For more info see arch/arm/mach-cns21xx/include/mach/system.h ++ */ ++ disable_hlt(); ++ ++ request_resource(&iomem_resource, &cns21xx_intc_resource); ++ cns21xx_intc_base = ioremap(cns21xx_intc_resource.start, INTC_SIZE); ++ ++ cns21xx_intc_writel(0xffffffff, INTC_INTERRUPT_MASK_REG); ++ cns21xx_intc_writel(0xffffffff, INTC_EDGE_INTERRUPT_SOURCE_CLEAR_REG); ++ cns21xx_intc_writel(0xffffffff, INTC_SOFTWARE_INTERRUPT_CLEAR_REG); ++ cns21xx_intc_writel(0, INTC_SOFTWARE_PRIORITY_MASK_REG); ++ cns21xx_intc_writel(0, INTC_FIQ_SELECT_REG); ++ cns21xx_intc_writel(0, INTC_VECTOR_INTERRUPT_ENABLE_REG); ++ ++ for (i = 0; i < ARRAY_SIZE(cns21xx_irq_types); i++) { ++ irq_flow_handler_t handler; ++ ++ switch (cns21xx_irq_types[i]) { ++ case IRQ_TYPE_EDGE_RISING: ++ handler = handle_edge_irq; ++ mode |= (1 << i); ++ break; ++ ++ case IRQ_TYPE_EDGE_FALLING: ++ handler = handle_edge_irq; ++ mode |= (1 << i); ++ level |= (1 << i); ++ break; ++ ++ case IRQ_TYPE_LEVEL_LOW: ++ handler = handle_level_irq; ++ level |= (1 << i); ++ break; ++ ++ case IRQ_TYPE_LEVEL_HIGH: ++ case IRQ_TYPE_NONE: ++ handler = handle_level_irq; ++ break; ++ ++ default: ++ BUG(); ++ break; ++ } ++ ++ irq_set_chip(i, &cns21xx_irq_chip); ++ irq_set_handler(i, handler); ++ set_irq_flags(i, IRQF_VALID | IRQF_PROBE); ++ } ++ ++ cns21xx_intc_writel(mode, INTC_INTERRUPT_TRIGGER_MODE_REG); ++ cns21xx_intc_writel(level, INTC_INTERRUPT_TRIGGER_LEVEL_REG); ++} +--- /dev/null ++++ b/arch/arm/mach-cns21xx/time.c +@@ -0,0 +1,28 @@ ++/* ++ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License, Version 2, as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/init.h> ++#include <linux/irq.h> ++ ++#include <asm/mach/time.h> ++ ++#include <plat/time.h> ++#include <mach/hardware.h> ++#include <mach/cns21xx.h> ++ ++#include "common.h" ++ ++static void __init cns21xx_timer_init(void) ++{ ++ fa_timer_init(CNS21XX_TIMER_BASE, CNS21XX_IRQ_TIMER1, FA_TIMER1, ++ cns21xx_get_apb_freq()); ++} ++ ++struct sys_timer cns21xx_timer = { ++ .init = cns21xx_timer_init, ++}; +--- /dev/null ++++ b/arch/arm/mach-cns21xx/include/mach/cns21xx_powermgmt.h +@@ -0,0 +1,591 @@ ++/* ++ * Copyright (c) 2008 Cavium Networks ++ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License, Version 2, as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef _CNS21XX_POWERMGMT_H ++#define _CNS21XX_POWERMGMT_H ++ ++#define PWRMGT_MEM_MAP_VALUE(reg_offset) \ ++ (*((u32 volatile *)(CNS21XX_CPM_BASE_VIRT + reg_offset))) ++ ++/* ++ * define access macros ++ */ ++#define PWRMGT_CLOCK_GATE_CONTROL0_REG PWRMGT_MEM_MAP_VALUE(0x00) ++#define PWRMGT_CLOCK_GATE_CONTROL1_REG PWRMGT_MEM_MAP_VALUE(0x04) ++#define PWRMGT_SOFTWARE_RESET_CONTROL_REG PWRMGT_MEM_MAP_VALUE(0x08) ++#define PWRMGT_SYSTEM_CLOCK_CONTROL_REG PWRMGT_MEM_MAP_VALUE(0x0C) ++#define PWRMGT_PLL_POWER_DOWN_CONTROL_REG PWRMGT_MEM_MAP_VALUE(0x10) ++#define PWRMGT_CPU_INITIALIZATION_REG PWRMGT_MEM_MAP_VALUE(0x14) ++#define PWRMGT_PAD_DRIVE_STRENGTH_CONTROL_REG PWRMGT_MEM_MAP_VALUE(0x1C) ++#define PWRMGT_USB_DEVICE_POWERMGT_REG PWRMGT_MEM_MAP_VALUE(0x20) ++#define PWRMGT_REGULATOR_CONTROL_REG PWRMGT_MEM_MAP_VALUE(0x24) ++#define PWRMGT_RTC_XTAL_CONTROL_REG PWRMGT_MEM_MAP_VALUE(0x28) ++#define PWRMGT_PLL250_CONTROL_REG PWRMGT_MEM_MAP_VALUE(0x2C) ++ ++ ++/* ++ * define constants macros ++ */ ++#define PWRMGT_GLOBAL_SOFTWARE_RESET_MASK_BIT_INDEX 0 ++#define PWRMGT_PCMCIA_SOFTWARE_RESET_BIT_INDEX 1 ++#define PWRMGT_IDE_SOFTWARE_RESET_BIT_INDEX 2 ++#define PWRMGT_VIC_SOFTWARE_RESET_BIT_INDEX 3 ++#define PWRMGT_DMA_SOFTWARE_RESET_BIT_INDEX 4 ++#define PWRMGT_NIC_SOFTWARE_RESET_BIT_INDEX 5 ++#define PWRMGT_USB_HOST_SOFTWARE_RESET_BIT_INDEX 6 ++#define PWRMGT_PCI_BRIDGE_SOFTWARE_RESET_BIT_INDEX 7 ++#define PWRMGT_P2S_SOFTWARE_RESET_BIT_INDEX 8 ++#define PWRMGT_UART0_SOFTWARE_RESET_BIT_INDEX 9 ++#define PWRMGT_UART1_SOFTWARE_RESET_BIT_INDEX 10 ++#define PWRMGT_TIMER_SOFTWARE_RESET_BIT_INDEX 11 ++#define PWRMGT_WDTIMER_SOFTWARE_RESET_BIT_INDEX 12 ++#define PWRMGT_GPIO_SOFTWARE_RESET_BIT_INDEX 13 ++#define PWRMGT_USB_DEVICE_SOFTWARE_RESET_BIT_INDEX 14 ++#define PWRMGT_FAST_ETHERNET_PHY_SOFTWARE_RESET_BIT_INDEX 15 ++#define PWRMGT_HSDMA_SOFTWARE_RESET_BIT_INDEX 16 ++ ++#define PWRMGT_PLL_FREQUENCY_175MHZ (0 << 0) ++#define PWRMGT_PLL_FREQUENCY_200MHZ (1 << 0) ++#define PWRMGT_PLL_FREQUENCY_225MHZ (2 << 0) ++#define PWRMGT_PLL_FREQUENCY_250MHZ (3 << 0) ++ ++#define PWRMGT_CPUCLK_DIVIDER_BY_1 (0 << 2) ++#define PWRMGT_CPUCLK_DIVIDER_BY_2 (1 << 2) ++#define PWRMGT_CPUCLK_DIVIDER_BY_3 (2 << 2) ++#define PWRMGT_CPUCLK_DIVIDER_BY_4 (3 << 2) ++ ++#define PWRMGT_HCLK_DIVIDER_BY_1 (0 << 4) ++#define PWRMGT_HCLK_DIVIDER_BY_2 (1 << 4) ++#define PWRMGT_HCLK_DIVIDER_BY_3 (2 << 4) ++#define PWRMGT_HCLK_DIVIDER_BY_4 (3 << 4) ++ ++#define PWRMGT_HCLK_SOURCE_FCLK (0 << 6) ++#define PWRMGT_HCLK_SOURCE_125MHZ (1 << 6) ++ ++#define PWRMGT_PCLK_DIVIDER_BY_1 (0 << 8) ++#define PWRMGT_PCLK_DIVIDER_BY_2 (1 << 8) ++#define PWRMGT_PCLK_DIVIDER_BY_3 (2 << 8) ++#define PWRMGT_PCLK_DIVIDER_BY_4 (3 << 8) ++ ++#define PWRMGT_PCICLK_DIVIDER_BY_1 (0 << 10) ++#define PWRMGT_PCICLK_DIVIDER_BY_2 (1 << 10) ++#define PWRMGT_PCICLK_DIVIDER_BY_3 (2 << 10) ++#define PWRMGT_PCICLK_DIVIDER_BY_4 (3 << 10) ++ ++ ++#define PWRMGT_PLLCLK_TO_CPUCLK_RATIO_BY_1 1 ++#define PWRMGT_PLLCLK_TO_CPUCLK_RATIO_BY_2 2 ++#define PWRMGT_PLLCLK_TO_CPUCLK_RATIO_BY_3 3 ++#define PWRMGT_PLLCLK_TO_CPUCLK_RATIO_BY_4 4 ++ ++#define PWRMGT_CPUCLK_TO_HCLK_RATIO_BY_1 1 ++#define PWRMGT_CPUCLK_TO_HCLK_RATIO_BY_2 2 ++#define PWRMGT_CPUCLK_TO_HCLK_RATIO_BY_3 3 ++#define PWRMGT_CPUCLK_TO_HCLK_RATIO_BY_4 4 ++ ++#define PWRMGT_HCLK_TO_PCLK_RATIO_BY_1 1 ++#define PWRMGT_HCLK_TO_PCLK_RATIO_BY_2 2 ++#define PWRMGT_HCLK_TO_PCLK_RATIO_BY_3 3 ++#define PWRMGT_HCLK_TO_PCLK_RATIO_BY_4 4 ++ ++/* ++ * Macro defines for Clock Gate Control ++ */ ++#define HAL_PWRMGT_DISABLE_DRAMC_CLOCK() \ ++{ \ ++ PWRMGT_CLOCK_GATE_CONTROL0_REG &= ~(0x1); \ ++} ++ ++ ++#define HAL_PWRMGT_ENABLE_NIC_CLOCK() \ ++{ \ ++ PWRMGT_PLL_POWER_DOWN_CONTROL_REG &= ~(0x1 << 0); \ ++ PWRMGT_CLOCK_GATE_CONTROL0_REG |= (0x0F << 20); \ ++ PWRMGT_SOFTWARE_RESET_CONTROL_REG |= (0x1 << 5); \ ++} ++ ++#define HAL_PWRMGT_DISABLE_NIC_CLOCK() \ ++{ \ ++ PWRMGT_CLOCK_GATE_CONTROL0_REG &= ~(0x0F << 20); \ ++} ++ ++ ++#define HAL_PWRMGT_ENABLE_PCI_BRIDGE_33M_CLOCK() \ ++{ \ ++ PWRMGT_PLL_POWER_DOWN_CONTROL_REG &= ~(0x1 << 1); \ ++ PWRMGT_SYSTEM_CLOCK_CONTROL_REG &= ~(0x3 << 10); \ ++ PWRMGT_SYSTEM_CLOCK_CONTROL_REG |= (0x1 << 10); \ ++ PWRMGT_CLOCK_GATE_CONTROL0_REG |= (0x1 << 28) | (0x1 << 30); \ ++ PWRMGT_SOFTWARE_RESET_CONTROL_REG |= (0x1 << 7); \ ++} ++ ++#define HAL_PWRMGT_ENABLE_PCI_BRIDGE_66M_CLOCK() \ ++{ \ ++ PWRMGT_PLL_POWER_DOWN_CONTROL_REG &= ~(0x1 << 1); \ ++ PWRMGT_SYSTEM_CLOCK_CONTROL_REG &= ~(0x3 << 10); \ ++ PWRMGT_SYSTEM_CLOCK_CONTROL_REG |= (0x0 << 10); \ ++ PWRMGT_CLOCK_GATE_CONTROL0_REG |= (0x1 << 28) | (0x1 << 30); \ ++ PWRMGT_SOFTWARE_RESET_CONTROL_REG |= (0x1 << 7); \ ++} ++ ++#define HAL_PWRMGT_DISABLE_PCI_CLOCK() \ ++{ \ ++ PWRMGT_CLOCK_GATE_CONTROL0_REG &= ~((0x1 << 28) | (0x1 << 30)); \ ++} ++ ++ ++#define HAL_PWRMGT_ENABLE_USB_CLOCK() \ ++{ \ ++ PWRMGT_PLL_POWER_DOWN_CONTROL_REG &= ~(0xF << 1); \ ++ PWRMGT_CLOCK_GATE_CONTROL0_REG |= (0x1 << 24); \ ++ PWRMGT_CLOCK_GATE_CONTROL1_REG |= (0x1 << 28); \ ++ PWRMGT_SOFTWARE_RESET_CONTROL_REG |= (0x1 << 6) | (0x1 << 14); \ ++} ++ ++#define HAL_PWRMGT_DISABLE_USB_CLOCK() \ ++{ \ ++ PWRMGT_CLOCK_GATE_CONTROL0_REG &= ~(0x1 << 24); \ ++ PWRMGT_CLOCK_GATE_CONTROL1_REG &= ~(0x1 << 28); \ ++} ++ ++ ++#define HAL_PWRMGT_ENABLE_DMA_CLOCK() \ ++{ \ ++ PWRMGT_CLOCK_GATE_CONTROL0_REG |= (0x1 << 16); \ ++ PWRMGT_SOFTWARE_RESET_CONTROL_REG |= (0x1 << 4); \ ++} ++ ++#define HAL_PWRMGT_DISABLE_DMA_CLOCK() \ ++{ \ ++ PWRMGT_CLOCK_GATE_CONTROL0_REG &= ~(0x1 << 16); \ ++} ++ ++ ++#define HAL_PWRMGT_ENABLE_IDE_CLOCK() \ ++{ \ ++ PWRMGT_CLOCK_GATE_CONTROL0_REG |= (0x1 << 8) | (0x1 << 9); \ ++ PWRMGT_SOFTWARE_RESET_CONTROL_REG |= (0x1 << 2); \ ++} ++ ++#define HAL_PWRMGT_DISABLE_IDE_CLOCK() \ ++{ \ ++ PWRMGT_CLOCK_GATE_CONTROL0_REG &= ~((0x1 << 8) | (0x1 << 9)); \ ++} ++ ++ ++#define HAL_PWRMGT_ENABLE_UART0_CLOCK() \ ++{ \ ++ PWRMGT_PLL_POWER_DOWN_CONTROL_REG &= ~((0x1 << 1) | (0x1 << 2) | (0x1 << 5)); \ ++ PWRMGT_CLOCK_GATE_CONTROL1_REG |= (0x1 << 12); \ ++ PWRMGT_SOFTWARE_RESET_CONTROL_REG |= (0x1 << 9); \ ++} ++ ++#define HAL_PWRMGT_DISABLE_UART0_CLOCK() \ ++{ \ ++ PWRMGT_CLOCK_GATE_CONTROL1_REG &= ~(0x1 << 12); \ ++} ++ ++ ++#define HAL_PWRMGT_ENABLE_UART1_CLOCK() \ ++{ \ ++ PWRMGT_PLL_POWER_DOWN_CONTROL_REG &= ~((0x1 << 1) | (0x1 << 2) | (0x1 << 5)); \ ++ PWRMGT_CLOCK_GATE_CONTROL1_REG |= (0x1 << 13); \ ++ PWRMGT_SOFTWARE_RESET_CONTROL_REG |= (0x1 << 10); \ ++} ++ ++#define HAL_PWRMGT_DISABLE_UART1_CLOCK() \ ++{ \ ++ PWRMGT_CLOCK_GATE_CONTROL1_REG &= ~(0x1 << 13); \ ++} ++ ++ ++#define HAL_PWRMGT_ENABLE_PCMCIA_CLOCK() \ ++{ \ ++ PWRMGT_CLOCK_GATE_CONTROL0_REG |= (0x1 << 4) | (0x1 << 5); \ ++} ++ ++#define HAL_PWRMGT_DISABLE_PCMCIA_CLOCK() \ ++{ \ ++ PWRMGT_CLOCK_GATE_CONTROL0_REG &= ~((0x1 << 4) | (0x1 << 5)); \ ++} ++ ++ ++#define HAL_PWRMGT_ENABLE_GPIO_CLOCK() \ ++{ \ ++ PWRMGT_CLOCK_GATE_CONTROL1_REG |= (0x1 << 25); \ ++} ++ ++#define HAL_PWRMGT_DISABLE_GPIO_CLOCK() \ ++{ \ ++ PWRMGT_CLOCK_GATE_CONTROL1_REG &= ~(0x1 << 25); \ ++} ++ ++ ++#define HAL_PWRMGT_ENABLE_WDTIMER_CLOCK() \ ++{ \ ++ PWRMGT_CLOCK_GATE_CONTROL1_REG |= (0x1 << 21) | (0x1 << 22); \ ++} ++ ++#define HAL_PWRMGT_DISABLE_WDTIMER_CLOCK() \ ++{ \ ++ PWRMGT_CLOCK_GATE_CONTROL1_REG &= ~((0x1 << 21) | (0x1 << 22)); \ ++} ++ ++ ++#define HAL_PWRMGT_ENABLE_RTC_CLOCK() \ ++{ \ ++ PWRMGT_CLOCK_GATE_CONTROL1_REG |= (0x1 << 23); \ ++} ++ ++#define HAL_PWRMGT_DISABLE_RTC_CLOCK() \ ++{ \ ++ PWRMGT_CLOCK_GATE_CONTROL1_REG &= ~(0x1 << 23); \ ++} ++ ++ ++#define HAL_PWRMGT_ENABLE_TIMER_CLOCK() \ ++{ \ ++ PWRMGT_CLOCK_GATE_CONTROL1_REG |= (0x1 << 17) | (0x1 << 18) | (0x1 << 19); \ ++} ++ ++#define HAL_PWRMGT_DISABLE_TIMER_CLOCK() \ ++{ \ ++ PWRMGT_CLOCK_GATE_CONTROL1_REG &= ~((0x1 << 17) | (0x1 << 18) | (0x1 << 19)); \ ++} ++ ++ ++#define HAL_PWRMGT_ENABLE_I2C_CLOCK() \ ++{ \ ++ PWRMGT_CLOCK_GATE_CONTROL1_REG |= (0x1 << 1); \ ++} ++ ++#define HAL_PWRMGT_DISABLE_I2C_CLOCK() \ ++{ \ ++ PWRMGT_CLOCK_GATE_CONTROL1_REG &= ~(0x1 << 1); \ ++} ++ ++ ++#define HAL_PWRMGT_ENABLE_I2S_CLOCK() \ ++{ \ ++ PWRMGT_PLL_POWER_DOWN_CONTROL_REG &= ~((0x1 << 5) | (0x1 << 6)); \ ++ PWRMGT_CLOCK_GATE_CONTROL1_REG |= (0x1 << 1) | (0x1 << 10); \ ++ PWRMGT_SOFTWARE_RESET_CONTROL_REG |= (0x1 << 8); \ ++} ++ ++#define HAL_PWRMGT_DISABLE_I2S_CLOCK() \ ++{ \ ++ PWRMGT_CLOCK_GATE_CONTROL1_REG &= ~((0x1 << 1) | (0x1 << 10)); \ ++} ++ ++ ++#define HAL_PWRMGT_ENABLE_PCM_CLOCK() \ ++{ \ ++ PWRMGT_PLL_POWER_DOWN_CONTROL_REG &= ~(0x1 << 5); \ ++ PWRMGT_CLOCK_GATE_CONTROL1_REG |= (0x1 << 1) | (0x1 << 6); \ ++ PWRMGT_SOFTWARE_RESET_CONTROL_REG |= (0x1 << 8); \ ++} ++ ++#define HAL_PWRMGT_DISABLE_PCM_CLOCK() \ ++{ \ ++ PWRMGT_CLOCK_GATE_CONTROL1_REG &= ~((0x1 << 1) | (0x1 << 6)); \ ++} ++ ++ ++#define HAL_PWRMGT_ENABLE_SPI_CLOCK() \ ++{ \ ++ PWRMGT_CLOCK_GATE_CONTROL1_REG |= (0x1 << 0) | (0x1 << 1); \ ++} ++ ++#define HAL_PWRMGT_DISABLE_SPI_CLOCK() \ ++{ \ ++ PWRMGT_CLOCK_GATE_CONTROL1_REG &= ~((0x1 << 0) | (0x1 << 1)); \ ++} ++ ++ ++#define HAL_PWRMGT_ENABLE_VIC_CLOCK() \ ++{ \ ++ PWRMGT_CLOCK_GATE_CONTROL0_REG |= (0x1 << 12); \ ++} ++ ++#define HAL_PWRMGT_DISABLE_VIC_CLOCK() \ ++{ \ ++ PWRMGT_CLOCK_GATE_CONTROL0_REG &= ~(0x1 << 12); \ ++} ++ ++ ++#define HAL_PWRMGT_ENABLE_SMC_CLOCK() \ ++{ \ ++ PWRMGT_CLOCK_GATE_CONTROL0_REG |= (0x1 << 4) | (0x1 << 5); \ ++} ++ ++#define HAL_PWRMGT_DISABLE_SMC_CLOCK() \ ++{ \ ++ PWRMGT_CLOCK_GATE_CONTROL0_REG &= ~((0x1 << 4) | (0x1 << 5)); \ ++} ++ ++ ++#define HAL_PWRMGT_ENABLE_HSDMA_CLOCK() \ ++{ \ ++ PWRMGT_CLOCK_GATE_CONTROL1_REG |= (0x1 << 29); \ ++ PWRMGT_SOFTWARE_RESET_CONTROL_REG |= (0x1 << 16); \ ++} ++ ++#define HAL_PWRMGT_DISABLE_HSDMA_CLOCK() \ ++{ \ ++ PWRMGT_CLOCK_GATE_CONTROL1_REG &= ~(0x1 << 29); \ ++} ++ ++ ++ ++/* ++ * Macro defines for Reset Control ++ */ ++#define HAL_PWRMGT_GLOBAL_SOFTWARE_RESET() \ ++{ \ ++ PWRMGT_SOFTWARE_RESET_CONTROL_REG |= (0x1); \ ++ PWRMGT_SOFTWARE_RESET_CONTROL_REG &= ~(0x1); \ ++} ++ ++ ++/* ++ * Macro defines for System Clock Control ++ */ ++#define HAL_PWRMGT_SET_PLL_FREQUENCY_175MHZ() \ ++{ \ ++ PWRMGT_SYSTEM_CLOCK_CONTROL_REG &= ~0x3; \ ++} ++ ++ ++#define HAL_PWRMGT_SET_PLL_FREQUENCY_200MHZ() \ ++{ \ ++ PWRMGT_SYSTEM_CLOCK_CONTROL_REG &= ~0x3; \ ++ PWRMGT_SYSTEM_CLOCK_CONTROL_REG |= 0x1; \ ++} ++ ++ ++#define HAL_PWRMGT_SET_PLL_FREQUENCY_225MHZ() \ ++{ \ ++ PWRMGT_SYSTEM_CLOCK_CONTROL_REG &= ~0x3; \ ++ PWRMGT_SYSTEM_CLOCK_CONTROL_REG |= 0x2; \ ++} ++ ++ ++#define HAL_PWRMGT_SET_PLL_FREQUENCY_250MHZ() \ ++{ \ ++ PWRMGT_SYSTEM_CLOCK_CONTROL_REG &= ~0x3; \ ++ PWRMGT_SYSTEM_CLOCK_CONTROL_REG |= 0x3; \ ++} ++ ++ ++#define HAL_PWRMGT_CONFIG_PLLCLK_TO_CPUCLK_RATIO(ratio) \ ++{ \ ++ PWRMGT_SYSTEM_CLOCK_CONTROL_REG &= ~(0x3 << 2); \ ++ PWRMGT_SYSTEM_CLOCK_CONTROL_REG |= (((ratio - 1) & 0x3) << 2); \ ++} ++ ++ ++#define HAL_PWRMGT_CONFIG_CPUCLK_TO_HCLK_RATIO(ratio) \ ++{ \ ++ PWRMGT_SYSTEM_CLOCK_CONTROL_REG &= ~(0x3 << 4); \ ++ PWRMGT_SYSTEM_CLOCK_CONTROL_REG |= (((ratio - 1) & 0x3) << 4); \ ++} ++ ++ ++#define HAL_PWRMGT_HCLK_SOURCE_FCLK() \ ++{ \ ++ PWRMGT_SYSTEM_CLOCK_CONTROL_REG &= ~(0x1 << 6); \ ++} ++ ++ ++#define HAL_PWRMGT_HCLK_SOURCE_125MHZ() \ ++{ \ ++ PWRMGT_SYSTEM_CLOCK_CONTROL_REG |= (0x1 << 6); \ ++} ++ ++ ++#define HAL_PWRMGT_GIGA_NIC_CLOCK_SOURCE_HCLK() \ ++{ \ ++ PWRMGT_SYSTEM_CLOCK_CONTROL_REG &= ~(0x1 << 7); \ ++} ++ ++ ++#define HAL_PWRMGT_GIGA_NIC_CLOCK_SOURCE_62_5MHZ() \ ++{ \ ++ PWRMGT_SYSTEM_CLOCK_CONTROL_REG |= (0x1 << 7); \ ++} ++ ++ ++#define HAL_PWRMGT_CONFIG_HCLK_TO_PCLK_RATIO(ratio) \ ++{ \ ++ PWRMGT_SYSTEM_CLOCK_CONTROL_REG &= ~(0x3 << 8); \ ++ PWRMGT_SYSTEM_CLOCK_CONTROL_REG |= (((ratio - 1) & 0x3) << 8); \ ++} ++ ++ ++#define HAL_PWRMGT_I2S_CLOCK_SOURCE_8192000HZ() \ ++{ \ ++ PWRMGT_SYSTEM_CLOCK_CONTROL_REG &= ~(0x3 << 12); \ ++ PWRMGT_SYSTEM_CLOCK_CONTROL_REG |= (0x0 << 12); \ ++} ++ ++ ++#define HAL_PWRMGT_I2S_CLOCK_SOURCE_11289600HZ() \ ++{ \ ++ PWRMGT_SYSTEM_CLOCK_CONTROL_REG &= ~(0x3 << 12); \ ++ PWRMGT_SYSTEM_CLOCK_CONTROL_REG |= (0x1 << 12); \ ++} ++ ++ ++#define HAL_PWRMGT_I2S_CLOCK_SOURCE_12288000HZ() \ ++{ \ ++ PWRMGT_SYSTEM_CLOCK_CONTROL_REG &= ~(0x3 << 12); \ ++ PWRMGT_SYSTEM_CLOCK_CONTROL_REG |= (0x2 << 12); \ ++} ++ ++ ++#define HAL_PWRMGT_CONFIGURE_MDC_CLOCK_DIVIDER(divided_value) \ ++{ \ ++ PWRMGT_SYSTEM_CLOCK_CONTROL_REG &= ~(0x3 << 14); \ ++ PWRMGT_SYSTEM_CLOCK_CONTROL_REG |= ((divided_value & 0x3) << 14); \ ++} ++ ++ ++#define HAL_PWRMGT_CONFIGURE_CLOCK_OUT_PIN(pin_source_select, divided_value) \ ++{ \ ++ PWRMGT_SYSTEM_CLOCK_CONTROL_REG &= ~(0x3F << 16); \ ++ PWRMGT_SYSTEM_CLOCK_CONTROL_REG |= ((pin_source_select & 0xF) << 16); \ ++ PWRMGT_SYSTEM_CLOCK_CONTROL_REG |= ((divided_value & 0x3) << 20); \ ++} ++ ++ ++/* ++ * Macro defines for PLL Power Down Control ++ */ ++#define HAL_PWRMGT_POWER_DOWN_SYSTEM_XTAL_PAD() \ ++ PWRMGT_PLL_POWER_DOWN_CONTROL_REG |= (0x1 << 7) ++ ++#define HAL_PWRMGT_POWER_ON_SYSTEM_XTAL_PAD() \ ++ PWRMGT_PLL_POWER_DOWN_CONTROL_REG &= ~(0x1 << 7) ++ ++ ++#define HAL_PWRMGT_POWER_DOWN_PLL_X5() \ ++ PWRMGT_PLL_POWER_DOWN_CONTROL_REG |= (0x1 << 0) ++ ++#define HAL_PWRMGT_POWER_ON_PLL_X5() \ ++ PWRMGT_PLL_POWER_DOWN_CONTROL_REG &= ~(0x1 << 0) ++ ++ ++#define HAL_PWRMGT_POWER_DOWN_PLL_X8() \ ++ PWRMGT_PLL_POWER_DOWN_CONTROL_REG |= (0x1 << 1) ++ ++#define HAL_PWRMGT_POWER_ON_PLL_X8() \ ++ PWRMGT_PLL_POWER_DOWN_CONTROL_REG &= ~(0x1 << 1) ++ ++ ++#define HAL_PWRMGT_POWER_DOWN_PLL_X3() \ ++ PWRMGT_PLL_POWER_DOWN_CONTROL_REG |= (0x1 << 2) ++ ++#define HAL_PWRMGT_POWER_ON_PLL_X3() \ ++ PWRMGT_PLL_POWER_DOWN_CONTROL_REG &= ~(0x1 << 2) ++ ++ ++#define HAL_PWRMGT_POWER_DOWN_USBH_PHY_PLL() \ ++ PWRMGT_PLL_POWER_DOWN_CONTROL_REG |= (0x1 << 3) ++ ++#define HAL_PWRMGT_POWER_ON_USBH_PHY_PLL() \ ++ PWRMGT_PLL_POWER_DOWN_CONTROL_REG &= ~(0x1 << 3) ++ ++ ++#define HAL_PWRMGT_POWER_DOWN_USBD_PHY_PLL() \ ++ PWRMGT_PLL_POWER_DOWN_CONTROL_REG |= (0x1 << 4) ++ ++#define HAL_PWRMGT_POWER_ON_USBD_PHY_PLL() \ ++ PWRMGT_PLL_POWER_DOWN_CONTROL_REG &= ~(0x1 << 4) ++ ++ ++#define HAL_PWRMGT_POWER_DOWN_PLL_X2250() \ ++ PWRMGT_PLL_POWER_DOWN_CONTROL_REG |= (0x1 << 5) ++ ++#define HAL_PWRMGT_POWER_ON_PLL_X2250() \ ++ PWRMGT_PLL_POWER_DOWN_CONTROL_REG &= ~(0x1 << 5) ++ ++ ++#define HAL_PWRMGT_POWER_DOWN_PLL_X7() \ ++ PWRMGT_PLL_POWER_DOWN_CONTROL_REG |= (0x1 << 6) ++ ++#define HAL_PWRMGT_POWER_ON_PLL_X7() \ ++ PWRMGT_PLL_POWER_DOWN_CONTROL_REG &= ~(0x1 << 6) ++ ++ ++#define HAL_PWRMGT_POWER_DOWN_ALL_PLL() \ ++ PWRMGT_PLL_POWER_DOWN_CONTROL_REG = 0x7F; ++ ++#define HAL_PWRMGT_POWER_ON_ALL_PLL() \ ++ PWRMGT_PLL_POWER_DOWN_CONTROL_REG = 0; ++ ++ ++/* ++ * Macro defines for Pad Drive Strength Control ++ */ ++#define HAL_PWRMGT_SELECT_PAD_DRIVE_STRENGTH_PCMCIA_CARDBUS_MODE() \ ++{ \ ++ PWRMGT_PAD_DRIVE_STRENGTH_CONTROL_REG &= ~(0x3 << 0); \ ++} ++ ++#define HAL_PWRMGT_SELECT_PAD_DRIVE_STRENGTH_PCI_MODE() \ ++{ \ ++ PWRMGT_PAD_DRIVE_STRENGTH_CONTROL_REG &= ~(0x3 << 0); \ ++ PWRMGT_PAD_DRIVE_STRENGTH_CONTROL_REG |= (0x1 << 0); \ ++} ++ ++#define HAL_PWRMGT_SELECT_PAD_DRIVE_STRENGTH_MII_MODE() \ ++{ \ ++ PWRMGT_PAD_DRIVE_STRENGTH_CONTROL_REG |= (0x1 << 2); \ ++} ++ ++#define HAL_PWRMGT_SELECT_PAD_DRIVE_STRENGTH_RGMII_MODE() \ ++{ \ ++ PWRMGT_PAD_DRIVE_STRENGTH_CONTROL_REG &= ~(0x1 << 2); \ ++} ++ ++#define HAL_PWRMGT_ENABLE_MII_PAD_SIGNAL_NOT_BOUNDED() \ ++{ \ ++ PWRMGT_PAD_DRIVE_STRENGTH_CONTROL_REG |= (0x1 << 3); \ ++} ++ ++#define HAL_PWRMGT_DISABLE_MII_PAD_SIGNAL_NOT_BOUNDED() \ ++{ \ ++ PWRMGT_PAD_DRIVE_STRENGTH_CONTROL_REG &= ~(0x1 << 3); \ ++} ++ ++ ++/* ++ * Macro defines for USB Device Power Management ++ */ ++#define HAL_PWRMGT_REMOTE_WAKEUP_USB_HOST() \ ++{ \ ++ PWRMGT_USB_DEVICE_POWERMGT_REG |= (0x1 << 4); \ ++} ++ ++#define HAL_PWRMGT_USB_DEVICE_PHY_CLOCK_SOURCE_EXTERNAL_12MHZ() \ ++{ \ ++ PWRMGT_USB_DEVICE_POWERMGT_REG &= ~(0x1 << 5); \ ++} ++ ++#define HAL_PWRMGT_USB_DEVICE_PHY_CLOCK_SOURCE_INTERNAL_12MHZ() \ ++{ \ ++ PWRMGT_USB_DEVICE_POWERMGT_REG |= (0x1 << 5); \ ++} ++ ++ ++/* ++ * Macro defines for Regulator Control ++ */ ++ ++#endif /* _CNS21XX_POWERMGMT_H */ +--- /dev/null ++++ b/arch/arm/mach-cns21xx/include/mach/cns21xx.h +@@ -0,0 +1,88 @@ ++/* ++ * Copyright (c) 2008 Cavium Networks ++ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License, Version 2, as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef _CNS21XX_H ++#define _CNS21XX_H ++ ++#define CNS21XX_FLASH_BANK0_BASE 0x10000000 ++#define CNS21XX_FLASH_BANK1_BASE 0x11000000 ++#define CNS21XX_FLASH_BANK2_BASE 0x12000000 ++#define CNS21XX_FLASH_BANK3_BASE 0x13000000 ++#define CNS21XX_PCMCIA_ATTR_BASE 0x14000000 ++#define CNS21XX_PCMCIA_MEM_BASE 0x15000000 ++#define CNS21XX_PCMCIA_IO_BASE 0x16000000 ++#define CNS21XX_IDE_DEVICE_BASE 0x18000000 ++#define CNS21XX_SDRAM_MEMORY_BASE 0x20000000 ++#define CNS21XX_GDMAC_BASE 0x60000000 ++#define CNS21XX_NIC_BASE 0x70000000 ++#define CNS21XX_SPI_BASE 0x71000000 ++#define CNS21XX_PCM_BASE 0x71000000 ++#define CNS21XX_I2C_BASE 0x71000000 ++#define CNS21XX_I2S_BASE 0x71000000 ++#define CNS21XX_DDRC_BASE 0x72000000 ++#define CNS21XX_SMC_BASE 0x73000000 ++#define CNS21XX_PCMCIA_CTRL_BASE 0x73000000 ++#define CNS21XX_IDE_CTRL_BASE 0x74000000 ++#define CNS21XX_MISC_BASE 0x76000000 ++#define CNS21XX_CPM_BASE 0x77000000 ++#define CNS21XX_UART0_BASE 0x78000000 ++#define CNS21XX_UART1_BASE 0x78800000 ++#define CNS21XX_TIMER_BASE 0x79000000 ++#define CNS21XX_WDT_BASE 0x7a000000 ++#define CNS21XX_RTC_BASE 0x7b000000 ++#define CNS21XX_GPIOA_BASE 0x7c000000 ++#define CNS21XX_GPIOB_BASE 0x7c800000 ++#define CNS21XX_PCI_CFGDATA_BASE 0xa0000000 ++#define CNS21XX_PCI_CFGADDR_BASE 0xa4000000 ++#define CNS21XX_PCI_IO_BASE 0xa8000000 ++#define CNS21XX_PCI_MEMORY_BASE 0xb0000000 ++#define CNS21XX_OHCI_CONFIG_BASE 0xc0000000 ++#define CNS21XX_OHCI_CTRL_BASE 0xc4000000 ++#define CNS21XX_EHCI_CONFIG_BASE 0xc8000000 ++#define CNS21XX_EHCI_CTRL_BASE 0xcc000000 ++#define CNS21XX_USB_DEVICE_BASE 0xd0000000 ++#define CNS21XX_INTC_BASE 0xfffff000 ++ ++#define CNS21XX_FLASH_BANK0_BASE_VIRT 0xe0000000 ++#define CNS21XX_FLASH_BANK1_BASE_VIRT 0xe2000000 ++#define CNS21XX_FLASH_BANK2_BASE_VIRT 0xe4000000 ++#define CNS21XX_FLASH_BANK3_BASE_VIRT 0xe8000000 ++#define CNS21XX_IDE_DEVICE_BASE_VIRT 0xfef00000 ++#define CNS21XX_GDMAC_BASE_VIRT 0xfef01000 ++#define CNS21XX_NIC_BASE_VIRT 0xfef02000 ++#define CNS21XX_SPI_BASE_VIRT 0xfef03000 ++#define CNS21XX_PCM_BASE_VIRT 0xfef04000 ++#define CNS21XX_I2C_BASE_VIRT 0xfef05000 ++#define CNS21XX_I2S_BASE_VIRT 0xfef06000 ++#define CNS21XX_DDRC_BASE_VIRT 0xfef07000 ++#define CNS21XX_SMC_BASE_VIRT 0xfef08000 ++#define CNS21XX_PCMCIA_CTRL_BASE_VIRT 0xfef09000 ++#define CNS21XX_IDE_CTRL_BASE_VIRT 0xfef0A000 ++#define CNS21XX_MISC_BASE_VIRT 0xfef0B000 ++#define CNS21XX_CPM_BASE_VIRT 0xfef0C000 ++#define CNS21XX_UART0_BASE_VIRT 0xfef0D000 ++#define CNS21XX_UART1_BASE_VIRT 0xfef0E000 ++#define CNS21XX_TIMER_BASE_VIRT 0xfef0F000 ++#define CNS21XX_WDT_BASE_VIRT 0xfef10000 ++#define CNS21XX_RTC_BASE_VIRT 0xfef11000 ++#define CNS21XX_GPIOA_BASE_VIRT 0xfef12000 ++#define CNS21XX_GPIOB_BASE_VIRT 0xfef13000 ++#define CNS21XX_PCI_CFGDATA_BASE_VIRT 0xfef14000 ++#define CNS21XX_PCI_CFGADDR_BASE_VIRT 0xfef15000 ++#define CNS21XX_OHCI_CONFIG_BASE_VIRT 0xfef16000 ++#define CNS21XX_OHCI_CTRL_BASE_VIRT 0xfef17000 ++#define CNS21XX_EHCI_CONFIG_BASE_VIRT 0xfef18000 ++#define CNS21XX_EHCI_CTRL_BASE_VIRT 0xfef19000 ++#define CNS21XX_USB_DEVICE_BASE_VIRT 0xfef1a000 ++#define CNS21XX_INTC_BASE_VIRT 0xfef1b000 ++ ++#define CNS21XX_PHYS_IO CNS21XX_UART0_BASE ++#define CNS21XX_IO_PAGE_OFFSET ((CNS21XX_UART0_BASE_VIRT) >> 18) & 0xfffc ++ ++#endif /* _CNS21XX_H */ +--- /dev/null ++++ b/arch/arm/mach-cns21xx/core.c +@@ -0,0 +1,85 @@ ++/* ++ * Copyright (c) 2008 Cavium Networks ++ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License, Version 2, as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/kernel.h> ++ ++#include <mach/hardware.h> ++#include <mach/cns21xx.h> ++#include <mach/cns21xx_powermgmt.h> ++ ++static unsigned long cns21xx_pll_freq; ++static unsigned long cns21xx_cpu_freq; ++static unsigned long cns21xx_ahb_freq; ++static unsigned long cns21xx_apb_freq; ++ ++static void cns21xx_init_freq(void) ++{ ++ static int freq_init_done; ++ unsigned int t; ++ ++ if (freq_init_done) ++ return; ++ ++ t = PWRMGT_SYSTEM_CLOCK_CONTROL_REG; ++ switch (t & 0x3) { ++ case 0x00: ++ cns21xx_pll_freq = 175000000; ++ break; ++ ++ case 0x01: ++ cns21xx_pll_freq = 200000000; ++ break; ++ ++ case 0x02: ++ cns21xx_pll_freq = 225000000; ++ break; ++ ++ case 0x03: ++ cns21xx_pll_freq = 250000000; ++ break; ++ } ++ ++ cns21xx_cpu_freq = cns21xx_pll_freq / (((t >> 2) & 0x3) + 1); ++ cns21xx_ahb_freq = cns21xx_cpu_freq / (((t >> 4) & 0x3) + 1); ++ cns21xx_apb_freq = cns21xx_ahb_freq / (((t >> 8) & 0x3) + 1); ++ ++ freq_init_done = 1; ++} ++ ++unsigned long cns21xx_get_pll_freq(void) ++{ ++ cns21xx_init_freq(); ++ return cns21xx_pll_freq; ++} ++ ++unsigned long cns21xx_get_cpu_freq(void) ++{ ++ cns21xx_init_freq(); ++ return cns21xx_cpu_freq; ++} ++ ++unsigned long cns21xx_get_ahb_freq(void) ++{ ++ cns21xx_init_freq(); ++ return cns21xx_ahb_freq; ++} ++ ++unsigned long cns21xx_get_apb_freq(void) ++{ ++ cns21xx_init_freq(); ++ return cns21xx_apb_freq; ++} ++ ++void cns21xx_restart(char mode, const char *cmd) ++{ ++ PWRMGT_SOFTWARE_RESET_CONTROL_REG |= ++ (1UL << PWRMGT_GLOBAL_SOFTWARE_RESET_MASK_BIT_INDEX); ++ PWRMGT_SOFTWARE_RESET_CONTROL_REG &= ++ ~(1UL << PWRMGT_GLOBAL_SOFTWARE_RESET_MASK_BIT_INDEX); ++} +--- a/arch/arm/mm/Kconfig ++++ b/arch/arm/mm/Kconfig +@@ -867,6 +867,7 @@ config ARM_L1_CACHE_SHIFT_6 + config ARM_L1_CACHE_SHIFT + int + default 6 if ARM_L1_CACHE_SHIFT_6 ++ default 4 if ARM_L1_CACHE_SHIFT_4 + default 5 + + config ARM_DMA_MEM_BUFFERABLE +--- a/arch/arm/mm/cache-fa.S ++++ b/arch/arm/mm/cache-fa.S +@@ -28,7 +28,7 @@ + /* + * The total size of the data cache. + */ +-#ifdef CONFIG_ARCH_GEMINI ++#if (defined(CONFIG_ARCH_GEMINI) || defined(CONFIG_ARCH_CNS21XX)) + #define CACHE_DSIZE 8192 + #else + #define CACHE_DSIZE 16384 +--- /dev/null ++++ b/arch/arm/mach-cns21xx/include/mach/cns21xx_misc.h +@@ -0,0 +1,507 @@ ++/******************************************************************************* ++ * ++ * Copyright (c) 2008 Cavium Networks ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License, Version 2, as ++ * published by the Free Software Foundation. ++ * ++ * This file is distributed in the hope that it will be useful, ++ * but AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or ++ * NONINFRINGEMENT. See the GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this file; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA or ++ * visit http://www.gnu.org/licenses/. ++ * ++ * This file may also be available under a different license from Cavium. ++ * Contact Cavium Networks for more information ++ * ++ ******************************************************************************/ ++ ++#ifndef _STAR_MISC_H_ ++#define _STAR_MISC_H_ ++ ++#include <mach/cns21xx.h> ++ ++#define MISC_MEM_MAP_VALUE(reg_offset) \ ++ (*((u32 volatile *)(CNS21XX_MISC_BASE_VIRT + reg_offset))) ++ ++/* ++ * define access macros ++ */ ++#define MISC_MEMORY_REMAP_REG MISC_MEM_MAP_VALUE(0x00) ++#define MISC_CHIP_CONFIG_REG MISC_MEM_MAP_VALUE(0x04) ++#define MISC_DEBUG_PROBE_DATA_REG MISC_MEM_MAP_VALUE(0x08) ++#define MISC_DEBUG_PROBE_SELECTION_REG MISC_MEM_MAP_VALUE(0x0C) ++#define MISC_PCI_CONTROL_BROKEN_MASK_REG MISC_MEM_MAP_VALUE(0x10) ++#define MISC_PCI_BROKEN_STATUS_REG MISC_MEM_MAP_VALUE(0x14) ++#define MISC_PCI_DEVICE_VENDOR_ID_REG MISC_MEM_MAP_VALUE(0x18) ++#define MISC_USB_HOST_PHY_CONTROL_TEST_REG MISC_MEM_MAP_VALUE(0x1C) ++#define MISC_GPIOA_PIN_ENABLE_REG MISC_MEM_MAP_VALUE(0x20) ++#define MISC_GPIOB_PIN_ENABLE_REG MISC_MEM_MAP_VALUE(0x24) ++#define MISC_GPIOA_RESISTOR_CONFIG_REG MISC_MEM_MAP_VALUE(0x28) ++#define MISC_GPIOA_DRIVE_STRENGTH_CONFIG_REG MISC_MEM_MAP_VALUE(0x2C) ++#define MISC_FAST_ETHERNET_PHY_CONFIG_REG MISC_MEM_MAP_VALUE(0x30) ++#define MISC_SOFTWARE_TEST_1_REG MISC_MEM_MAP_VALUE(0x38) ++#define MISC_SOFTWARE_TEST_2_REG MISC_MEM_MAP_VALUE(0x3C) ++ ++#define MISC_E_FUSE_0_REG MISC_MEM_MAP_VALUE(0x60) ++#define MISC_E_FUSE_1_REG MISC_MEM_MAP_VALUE(0x64) ++ ++ ++/* ++ * define constants macros ++ */ ++#define MISC_PARALLEL_FLASH_BOOT 0 ++#define MISC_SPI_SERIAL_FLASH_BOOT 1 ++ ++#define MISC_LITTLE_ENDIAN 0 ++#define MISC_BIG_ENDIAN 1 ++ ++#define MISC_FARADAY_ICE 0 ++#define MISC_ARM_ICE 1 ++ ++#define MISC_EXT_INT29_PINS ((0x1 << 0)) ++#define MISC_EXT_INT30_PINS ((0x1 << 1)) ++#define MISC_EXT_INT31_PINS ((0x1 << 2)) ++#define MISC_I2C_PINS ((0x1 << 13) | (0x1 << 14)) ++#define MISC_I2S_PINS ((0x1 << 15) | (0x1 << 16) | (0x1 << 17)) ++#define MISC_I2SSD_PINS (1 << 15) ++#define MISC_I2SWS_PINS (1 << 16) ++#define MISC_I2SCLK_PINS (1 << 17) ++#define MISC_PCM_PINS ((0x1 << 18) | (0x1 << 19) | (0x1 << 20) | (0x1 << 21)) ++#define MISC_PCMDR_PINS (1 << 18) ++#define MISC_PCMDT_PINS (1 << 19) ++#define MISC_PCMFS_PINS (1 << 20) ++#define MISC_PCMCLK_PINS (1 << 21) ++#define MISC_LED0_PINS ((0x1 << 22)) ++#define MISC_LED1_PINS ((0x1 << 23)) ++#define MISC_LED2_PINS ((0x1 << 24)) ++#define MISC_LED012_PINS ((0x1 << 22) | (0x1 << 23) | (0x1 << 24)) ++#define MISC_WDTIMER_RESET_PINS ((0x1 << 25)) ++#define MISC_SPIDR_PINS (0x1 << 26) ++#define MISC_SPICLK_PINS (0x1 << 27) ++#define MISC_SPICSN0_PINS (0x1 << 28) ++#define MISC_SPICSN1_PINS (0x1 << 29) ++#define MISC_SPICSN2_PINS (0x1 << 30) ++#define MISC_SPICSN3_PINS (0x1 << 31) ++#define MISC_SPI_PINS ((0x1 << 26) | (0x1 << 27) | (0x1 << 28) | (0x1 << 29) | (0x1 << 30) | (0x1 << 31)) ++#define MISC_MDC_MDIO_PINS ((0x1 << 0) | (0x1 << 1)) ++#define MISC_NIC_COL_PINS ((0x1 << 2)) ++#define MISC_IDE_PINS ((0xFF << 3)) ++#define MISC_SRAM_BANK1_PINS ((0x1 << 11) | (0x1 << 14)) ++#define MISC_SRAM_BANK2_PINS ((0x1 << 12) | (0x1 << 15)) ++#define MISC_SRAM_BANK3_PINS ((0x1 << 13) | (0x1 << 16)) ++#define MISC_PCMCIA_PINS ((0x1 << 17) | (0x1 << 18) | (0x1 << 19) | (0x1 << 20)) ++#define MISC_UART1_PINS ((0x1 << 21) | (0x1 << 22)) ++#define MISC_PCI_PINS (((u32)0x1FF << 23)) ++ ++#define MISC_UART0_ACT0_Pin (0x1 << 2) ++#define MISC_UART1_ACT1_Pin (0x1 << 3) ++ ++#define MISC_GPIOA_PIN_0 0 ++#define MISC_GPIOA_PIN_1 1 ++#define MISC_GPIOA_PIN_2 2 ++#define MISC_GPIOA_PIN_3 3 ++#define MISC_GPIOA_PIN_4 4 ++#define MISC_GPIOA_PIN_5 5 ++#define MISC_GPIOA_PIN_6 6 ++#define MISC_GPIOA_PIN_7 7 ++#define MISC_GPIOA_PIN_8 8 ++#define MISC_GPIOA_PIN_9 9 ++#define MISC_GPIOA_PIN_10 10 ++ ++#define MISC_GPIOA_75K_RESISTOR_PULL_DOWN 1 ++#define MISC_GPIOA_75K_RESISTOR_PULL_UP 2 ++#define MISC_GPIOA_75K_RESISTOR_PULL_KEEPER 3 ++ ++#define MISC_GPIOA_DRIVE_STRENGTH_4MA 0 ++#define MISC_GPIOA_DRIVE_STRENGTH_8MA 1 ++ ++ ++/* ++ * macro declarations ++ */ ++#define HAL_MISC_ENABLE_SPI_SERIAL_FLASH_BANK_ACCESS() \ ++{ \ ++ (MISC_CHIP_CONFIG_REG) |= (0x1 << 4); \ ++} ++ ++#define HAL_MISC_DISABLE_SPI_SERIAL_FLASH_BANK_ACCESS() \ ++{ \ ++ (MISC_CHIP_CONFIG_REG) &= ~(0x1 << 4); \ ++} ++ ++ ++/* ++ * Macro defines for GPIOA and GPIOB Pin Enable Register ++ */ ++#define HAL_MISC_ENABLE_EXT_INT29_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) |= (MISC_EXT_INT29_PINS); \ ++} ++ ++#define HAL_MISC_DISABLE_EXT_INT29_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) &= ~(MISC_EXT_INT29_PINS); \ ++} ++ ++#define HAL_MISC_ENABLE_EXT_INT30_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) |= (MISC_EXT_INT30_PINS); \ ++} ++ ++#define HAL_MISC_DISABLE_EXT_INT30_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) &= ~(MISC_EXT_INT30_PINS); \ ++} ++ ++#define HAL_MISC_ENABLE_I2C_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) |= (MISC_I2C_PINS); \ ++} ++ ++#define HAL_MISC_DISABLE_I2C_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) &= ~(MISC_I2C_PINS); \ ++} ++ ++#define HAL_MISC_ENABLE_I2S_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) |= (MISC_I2S_PINS); \ ++} ++ ++#define HAL_MISC_DISABLE_I2S_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) &= ~(MISC_I2S_PINS); \ ++} ++ ++#define HAL_MISC_DISABLE_I2SSD_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) &= ~(MISC_I2SSD_PINS); \ ++} ++ ++#define HAL_MISC_DISABLE_I2SWS_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) &= ~(MISC_I2SWS_PINS); \ ++} ++ ++#define HAL_MISC_DISABLE_I2SCLK_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) &= ~(MISC_I2SCLK_PINS); \ ++} ++ ++#define HAL_MISC_ENABLE_PCM_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) |= (MISC_PCM_PINS); \ ++} ++ ++#define HAL_MISC_DISABLE_PCM_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) &= ~(MISC_PCM_PINS); \ ++} ++ ++#define HAL_MISC_DISABLE_PCMDR_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) &= ~(MISC_PCMDR_PINS); \ ++} ++ ++#define HAL_MISC_DISABLE_PCMDT_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) &= ~(MISC_PCMDT_PINS); \ ++} ++ ++#define HAL_MISC_DISABLE_PCMFS_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) &= ~(MISC_PCMFS_PINS); \ ++} ++ ++#define HAL_MISC_DISABLE_PCMCLK_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) &= ~(MISC_PCMCLK_PINS); \ ++} ++ ++#define HAL_MISC_ENABLE_LED0_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) |= (MISC_LED0_PINS); \ ++} ++ ++#define HAL_MISC_DISABLE_LED0_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) &= ~(MISC_LED0_PINS); \ ++} ++ ++#define HAL_MISC_ENABLE_LED1_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) |= (MISC_LED1_PINS); \ ++} ++ ++#define HAL_MISC_DISABLE_LED1_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) &= ~(MISC_LED1_PINS); \ ++} ++ ++#define HAL_MISC_ENABLE_LED2_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) |= (MISC_LED2_PINS); \ ++} ++ ++#define HAL_MISC_DISABLE_LED2_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) &= ~(MISC_LED2_PINS); \ ++} ++ ++#define HAL_MISC_ENABLE_LED012_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) |= (MISC_LED012_PINS); \ ++} ++ ++#define HAL_MISC_DISABLE_LED012_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) &= ~(MISC_LED012_PINS); \ ++} ++ ++#define HAL_MISC_ENABLE_WDTIMER_RESET_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) |= (MISC_WDTIMER_RESET_PINS); \ ++} ++ ++#define HAL_MISC_DISABLE_WDTIMER_RESET_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) &= ~(MISC_WDTIMER_RESET_PINS); \ ++} ++ ++#define HAL_MISC_ENABLE_SPI_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) |= (MISC_SPI_PINS); \ ++} ++ ++#define HAL_MISC_ENABLE_SPIDR_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) |= (MISC_SPIDR_PINS); \ ++} ++ ++#define HAL_MISC_ENABLE_SPICLK_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) |= (MISC_SPICLK_PINS); \ ++} ++ ++#define HAL_MISC_ENABLE_SPICSN0_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) |= (MISC_SPICSN0_PINS); \ ++} ++ ++#define HAL_MISC_ENABLE_SPICSN0_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) |= (MISC_SPICSN0_PINS); \ ++} ++ ++#define HAL_MISC_ENABLE_SPICSN1_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) |= (MISC_SPICSN1_PINS); \ ++} ++ ++#define HAL_MISC_ENABLE_SPICSN2_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) |= (MISC_SPICSN2_PINS); \ ++} ++ ++#define HAL_MISC_ENABLE_SPICSN3_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) |= (MISC_SPICSN3_PINS); \ ++} ++ ++#define HAL_MISC_DISABLE_SPI_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) &= ~(MISC_SPI_PINS); \ ++} ++ ++#define HAL_MISC_DISABLE_SPIDR_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) &= ~(MISC_SPIDR_PINS); \ ++} ++ ++#define HAL_MISC_DISABLE_SPICLK_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) &= ~(MISC_SPICLK_PINS); \ ++} ++ ++#define HAL_MISC_DISABLE_SPICSN0_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) &= ~(MISC_SPICSN0_PINS); \ ++} ++ ++#define HAL_MISC_DISABLE_SPICSN1_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) &= ~(MISC_SPICSN1_PINS); \ ++} ++ ++#define HAL_MISC_DISABLE_SPICSN2_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) &= ~(MISC_SPICSN2_PINS); \ ++} ++ ++#define HAL_MISC_DISABLE_SPICSN3_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) &= ~(MISC_SPICSN3_PINS); \ ++} ++ ++#define HAL_MISC_ENABLE_UART0_ACT0_PIN() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) |= (MISC_UART0_ACT0_Pin); \ ++} ++ ++#define HAL_MISC_DISABLE_UART0_ACT0_PIN() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) &= ~(MISC_UART0_ACT0_Pin); \ ++} ++ ++#define HAL_MISC_ENABLE_UART1_ACT1_PIN() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) |= (MISC_UART1_ACT1_Pin); \ ++} ++ ++#define HAL_MISC_DISABLE_UART1_ACT1_PIN() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) &= ~(MISC_UART1_ACT1_Pin); \ ++} ++ ++#define HAL_MISC_ENABLE_MDC_MDIO_PINS() \ ++{ \ ++ (MISC_GPIOB_PIN_ENABLE_REG) |= (MISC_MDC_MDIO_PINS); \ ++} ++ ++#define HAL_MISC_DISABLE_MDC_MDIO_PINS() \ ++{ \ ++ (MISC_GPIOB_PIN_ENABLE_REG) &= ~(MISC_MDC_MDIO_PINS); \ ++} ++ ++#define HAL_MISC_ENABLE_NIC_COL_PINS() \ ++{ \ ++ (MISC_GPIOB_PIN_ENABLE_REG) |= (MISC_NIC_COL_PINS); \ ++} ++ ++#define HAL_MISC_DISABLE_NIC_COL_PINS() \ ++{ \ ++ (MISC_GPIOB_PIN_ENABLE_REG) &= ~(MISC_NIC_COL_PINS); \ ++} ++ ++#define HAL_MISC_ENABLE_IDE_PINS() \ ++{ \ ++ (MISC_GPIOB_PIN_ENABLE_REG) |= (MISC_IDE_PINS); \ ++} ++ ++#define HAL_MISC_DISABLE_IDE_PINS() \ ++{ \ ++ (MISC_GPIOB_PIN_ENABLE_REG) &= ~(MISC_IDE_PINS); \ ++} ++ ++#define HAL_MISC_ENABLE_SRAM_BANK1_PINS() \ ++{ \ ++ (MISC_GPIOB_PIN_ENABLE_REG) |= (MISC_SRAM_BANK1_PINS); \ ++} ++ ++#define HAL_MISC_DISABLE_SRAM_BANK1_PINS() \ ++{ \ ++ (MISC_GPIOB_PIN_ENABLE_REG) &= ~(MISC_SRAM_BANK1_PINS); \ ++} ++ ++#define HAL_MISC_ENABLE_SRAM_BANK2_PINS() \ ++{ \ ++ (MISC_GPIOB_PIN_ENABLE_REG) |= (MISC_SRAM_BANK2_PINS); \ ++} ++ ++#define HAL_MISC_DISABLE_SRAM_BANK2_PINS() \ ++{ \ ++ (MISC_GPIOB_PIN_ENABLE_REG) &= ~(MISC_SRAM_BANK2_PINS); \ ++} ++ ++#define HAL_MISC_ENABLE_SRAM_BANK3_PINS() \ ++{ \ ++ (MISC_GPIOB_PIN_ENABLE_REG) |= (MISC_SRAM_BANK3_PINS); \ ++} ++ ++#define HAL_MISC_DISABLE_SRAM_BANK3_PINS() \ ++{ \ ++ (MISC_GPIOB_PIN_ENABLE_REG) &= ~(MISC_SRAM_BANK3_PINS); \ ++} ++ ++#define HAL_MISC_ENABLE_PCMCIA_PINS() \ ++{ \ ++ (MISC_GPIOB_PIN_ENABLE_REG) |= (MISC_PCMCIA_PINS); \ ++} ++ ++#define HAL_MISC_DISABLE_PCMCIA_PINS() \ ++{ \ ++ (MISC_GPIOB_PIN_ENABLE_REG) &= ~(MISC_PCMCIA_PINS); \ ++} ++ ++#define HAL_MISC_ENABLE_UART1_PINS() \ ++{ \ ++ (MISC_GPIOB_PIN_ENABLE_REG) |= (MISC_UART1_PINS); \ ++} ++ ++#define HAL_MISC_DISABLE_UART1_PINS() \ ++{ \ ++ (MISC_GPIOB_PIN_ENABLE_REG) &= ~(MISC_UART1_PINS); \ ++} ++ ++#define HAL_MISC_ENABLE_PCI_PINS() \ ++{ \ ++ (MISC_GPIOB_PIN_ENABLE_REG) |= (MISC_PCI_PINS); \ ++} ++ ++#define HAL_MISC_DISABLE_PCI_PINS() \ ++{ \ ++ (MISC_GPIOB_PIN_ENABLE_REG) &= ~(MISC_PCI_PINS); \ ++} ++ ++#define HAL_MISC_ENABLE_ALL_SHARED_GPIO_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) = (0x0); \ ++ (MISC_GPIOB_PIN_ENABLE_REG) = (0x0); \ ++} ++ ++#define HAL_MISC_DISABLE_ALL_SHARED_GPIO_PINS() \ ++{ \ ++ (MISC_GPIOA_PIN_ENABLE_REG) = (0xFFFFFFFF); \ ++ (MISC_GPIOB_PIN_ENABLE_REG) = (0xFFFFFFFF); \ ++} ++ ++#define HAL_MISC_CONFIGURE_GPIOA_RESISTOR(pin_index, value) \ ++{ \ ++ (MISC_GPIOA_RESISTOR_CONFIG_REG) &= ~(0x3 << (2 * pin_index)); \ ++ (MISC_GPIOA_RESISTOR_CONFIG_REG) |= ((value & 0x3) << (2 * pin_index)); \ ++} ++ ++#define HAL_MISC_CONFIGURE_GPIOA_DRIVE_STRENGTH(pin_index, value) \ ++{ \ ++ (MISC_GPIOA_DRIVE_STRENGTH_CONFIG_REG) &= ~(0x1 << pin_index); \ ++ (MISC_GPIOA_DRIVE_STRENGTH_CONFIG_REG) |= (value << pin_index); \ ++} ++ ++#define HAL_MISC_SELECT_FAST_ETHERNET_PHY_LED_MODE0() \ ++{ \ ++ (MISC_FAST_ETHERNET_PHY_CONFIG_REG) = (0x0); \ ++} ++ ++#define HAL_MISC_SELECT_FAST_ETHERNET_PHY_LED_MODE1() \ ++{ \ ++ (MISC_FAST_ETHERNET_PHY_CONFIG_REG) = (0x1); \ ++} ++ ++#define HAL_MISC_SELECT_FAST_ETHERNET_PHY_LED_MODE2() \ ++{ \ ++ (MISC_FAST_ETHERNET_PHY_CONFIG_REG) = (0x2); \ ++} ++ ++#define HAL_MISC_SELECT_FAST_ETHERNET_PHY_LED_MODE3() \ ++{ \ ++ (MISC_FAST_ETHERNET_PHY_CONFIG_REG) = (0x3); \ ++} ++ ++ ++#endif // end of #ifndef _STAR_MISC_H_ diff --git a/target/linux/cns21xx/patches-3.8/101-cns21xx-serial-support.patch b/target/linux/cns21xx/patches-3.8/101-cns21xx-serial-support.patch new file mode 100644 index 0000000000..05ad3e4682 --- /dev/null +++ b/target/linux/cns21xx/patches-3.8/101-cns21xx-serial-support.patch @@ -0,0 +1,103 @@ +--- a/arch/arm/mach-cns21xx/common.h ++++ b/arch/arm/mach-cns21xx/common.h +@@ -16,4 +16,7 @@ void cns21xx_init_irq(void); + + extern struct sys_timer cns21xx_timer; + ++int cns21xx_register_uart0(void); ++int cns21xx_register_uart1(void); ++ + #endif /* _MACH_CNS21XX_COMMON_H */ +--- /dev/null ++++ b/arch/arm/mach-cns21xx/devices.c +@@ -0,0 +1,79 @@ ++/* ++ * Copyright (c) 2008 Cavium Networks ++ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License, Version 2, as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/platform_device.h> ++#include <linux/serial_8250.h> ++ ++#include <mach/irqs.h> ++#include <mach/hardware.h> ++#include <mach/cns21xx.h> ++#include <mach/cns21xx_misc.h> ++ ++#define CNS21XX_UART_CLOCK 24000000 ++ ++#define CNS21XX_UART_FLAGS (UPF_SKIP_TEST | UPF_FIXED_TYPE | UPF_NO_TXEN_TEST) ++ ++static struct plat_serial8250_port cns21xx_uart0_data[] = { ++ { ++ .mapbase = CNS21XX_UART0_BASE, ++ .membase = (void *) CNS21XX_UART0_BASE_VIRT, ++ .irq = CNS21XX_IRQ_UART0, ++ .uartclk = CNS21XX_UART_CLOCK, ++ .regshift = 2, ++ .iotype = UPIO_MEM, ++ .type = PORT_16550A, ++ .flags = CNS21XX_UART_FLAGS, ++ }, { ++ /* terminating entry */ ++ }, ++}; ++ ++static struct platform_device cns21xx_uart0_device = { ++ .name = "serial8250", ++ .id = PLAT8250_DEV_PLATFORM, ++ .dev = { ++ .platform_data = cns21xx_uart0_data, ++ }, ++}; ++ ++int __init cns21xx_register_uart0(void) ++{ ++ return platform_device_register(&cns21xx_uart0_device); ++} ++ ++static struct plat_serial8250_port cns21xx_uart1_data[] = { ++ { ++ .mapbase = CNS21XX_UART1_BASE, ++ .membase = (void *) CNS21XX_UART1_BASE_VIRT, ++ .irq = CNS21XX_IRQ_UART1, ++ .uartclk = CNS21XX_UART_CLOCK, ++ .regshift = 2, ++ .iotype = UPIO_MEM, ++ .type = PORT_16550A, ++ .flags = CNS21XX_UART_FLAGS, ++ }, { ++ /* terminating entry */ ++ }, ++}; ++ ++static struct platform_device cns21xx_uart1_device = { ++ .name = "serial8250", ++ .id = PLAT8250_DEV_PLATFORM1, ++ .dev = { ++ .platform_data = cns21xx_uart1_data, ++ }, ++}; ++ ++int __init cns21xx_register_uart1(void) ++{ ++ HAL_MISC_ENABLE_UART1_PINS(); ++ return platform_device_register(&cns21xx_uart1_device); ++} +--- a/arch/arm/mach-cns21xx/Makefile ++++ b/arch/arm/mach-cns21xx/Makefile +@@ -4,7 +4,7 @@ + + # Object file lists. + +-obj-y := core.o irq.o mm.o time.o ++obj-y := core.o devices.o irq.o mm.o time.o + + # machine specific files + diff --git a/target/linux/cns21xx/patches-3.8/102-cns21xx-gpiolib-support.patch b/target/linux/cns21xx/patches-3.8/102-cns21xx-gpiolib-support.patch new file mode 100644 index 0000000000..7330b1fb7f --- /dev/null +++ b/target/linux/cns21xx/patches-3.8/102-cns21xx-gpiolib-support.patch @@ -0,0 +1,85 @@ +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -378,6 +378,8 @@ config ARCH_CNS21XX + select CPU_FA526 + select PLAT_FA + select PLAT_FA_TIME ++ select PLAT_FA_GPIO ++ select ARCH_REQUIRE_GPIOLIB + select ARM_L1_CACHE_SHIFT_4 + help + Support for Cavium Networks CNS21xx family. +--- a/arch/arm/mach-cns21xx/common.h ++++ b/arch/arm/mach-cns21xx/common.h +@@ -13,6 +13,7 @@ + void cns21xx_restart(char mode, const char *cmd); + void cns21xx_map_io(void); + void cns21xx_init_irq(void); ++void cns21xx_gpio_init(void); + + extern struct sys_timer cns21xx_timer; + +--- /dev/null ++++ b/arch/arm/mach-cns21xx/gpio.c +@@ -0,0 +1,45 @@ ++/* ++ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License, Version 2, as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <plat/gpio.h> ++ ++#include <mach/cns21xx.h> ++#include <mach/irqs.h> ++ ++static struct fa_gpio_chip cns21xx_gpio_chips[] = { ++ { ++ .gpio_chip = { ++ .label = "GPIOA", ++ .base = 0, ++ .ngpio = 32, ++ }, ++ ++ .map_base = CNS21XX_GPIOA_BASE, ++ .irq_base = CNS21XX_GPIO_IRQ_BASE, ++ }, { ++ .gpio_chip = { ++ .label = "GPIOB", ++ .base = 32, ++ .ngpio = 32, ++ }, ++ ++ .map_base = CNS21XX_GPIOB_BASE, ++ .irq_base = CNS21XX_GPIO_IRQ_BASE + 32, ++ } ++}; ++ ++static struct fa_gpio_data cns21xx_gpio_data = { ++ .chips = cns21xx_gpio_chips, ++ .nchips = ARRAY_SIZE(cns21xx_gpio_chips), ++ .irq = CNS21XX_IRQ_GPIO, ++}; ++ ++void __init cns21xx_gpio_init(void) ++{ ++ fa_gpio_init(&cns21xx_gpio_data); ++} +--- /dev/null ++++ b/arch/arm/mach-cns21xx/include/mach/gpio.h +@@ -0,0 +1,2 @@ ++/* empty */ ++ +--- a/arch/arm/mach-cns21xx/Makefile ++++ b/arch/arm/mach-cns21xx/Makefile +@@ -4,7 +4,7 @@ + + # Object file lists. + +-obj-y := core.o devices.o irq.o mm.o time.o ++obj-y := core.o devices.o gpio.o irq.o mm.o time.o + + # machine specific files + diff --git a/target/linux/cns21xx/patches-3.8/103-cns21xx-usb-ohci-support.patch b/target/linux/cns21xx/patches-3.8/103-cns21xx-usb-ohci-support.patch new file mode 100644 index 0000000000..ea2a2aab9c --- /dev/null +++ b/target/linux/cns21xx/patches-3.8/103-cns21xx-usb-ohci-support.patch @@ -0,0 +1,225 @@ +--- a/drivers/usb/host/ohci-hcd.c ++++ b/drivers/usb/host/ohci-hcd.c +@@ -691,6 +691,9 @@ retry: + + periodic_reinit (ohci); + ++ if (ohci->flags & OHCI_QUIRK_INIT_FMINTERVAL) ++ ohci_writel (ohci, ohci->fminterval, &ohci->regs->fminterval); ++ + /* some OHCI implementations are finicky about how they init. + * bogus values here mean not even enumeration could work. + */ +@@ -1186,6 +1189,11 @@ MODULE_LICENSE ("GPL"); + #define PLATFORM_DRIVER ohci_hcd_tilegx_driver + #endif + ++#ifdef CONFIG_ARCH_CNS21XX ++#include "ohci-cns21xx.c" ++#define PLATFORM_DRIVER ohci_cns21xx_driver ++#endif ++ + #ifdef CONFIG_USB_OHCI_HCD_PLATFORM + #include "ohci-platform.c" + #define OHCI_PLATFORM_DRIVER ohci_platform_driver +--- /dev/null ++++ b/drivers/usb/host/ohci-cns21xx.c +@@ -0,0 +1,178 @@ ++/* ++ * Copyright (c) 2008 Cavium Networks ++ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License, Version 2, as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/platform_device.h> ++ ++#include <mach/cns21xx.h> ++ ++#define DRIVER_NAME "cns21xx-ohci" ++ ++static int cns21xx_ohci_start(struct usb_hcd *hcd) ++{ ++ struct ohci_hcd *ohci = hcd_to_ohci(hcd); ++ int ret; ++ ++ ret = ohci_init(ohci); ++ if (ret) ++ return ret; ++ ++ ret = ohci_run(ohci); ++ if (ret) { ++ ohci_err(ohci, "can't start %s", ++ ohci_to_hcd(ohci)->self.bus_name); ++ goto err; ++ } ++ ++ return 0; ++ ++err: ++ ohci_stop(hcd); ++ return ret; ++} ++ ++static const struct hc_driver ohci_cns21xx_hc_driver = { ++ .description = hcd_name, ++ .product_desc = "cns21xx-ohci", ++ .hcd_priv_size = sizeof(struct ohci_hcd), ++ ++ /* ++ * generic hardware linkage ++ */ ++ .irq = ohci_irq, ++ .flags = HCD_USB11 | HCD_MEMORY, ++ ++ /* ++ * basic lifecycle operations ++ */ ++ .start = cns21xx_ohci_start, ++ .stop = ohci_stop, ++ .shutdown = ohci_shutdown, ++ ++ /* ++ * managing i/o requests and associated device resources ++ */ ++ .urb_enqueue = ohci_urb_enqueue, ++ .urb_dequeue = ohci_urb_dequeue, ++ .endpoint_disable = ohci_endpoint_disable, ++ ++ /* ++ * scheduling support ++ */ ++ .get_frame_number = ohci_get_frame, ++ ++ /* ++ * root hub support ++ */ ++ .hub_status_data = ohci_hub_status_data, ++ .hub_control = ohci_hub_control, ++ .start_port_reset = ohci_start_port_reset, ++}; ++ ++static void cns21xx_ohci_init_hc(void) ++{ ++ void __iomem *base = (void __iomem *) CNS21XX_OHCI_CONFIG_BASE_VIRT; ++ ++ __raw_writel(0x146, base + 0x04); ++ __raw_writel(0x200, base + 0x44); ++ msleep(100); ++} ++ ++static int ohci_cns21xx_probe(struct platform_device *pdev) ++{ ++ struct usb_hcd *hcd; ++ struct resource *res; ++ struct ohci_hcd *ohci; ++ int irq; ++ int ret; ++ ++ if (usb_disabled()) ++ return -ENODEV; ++ ++ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); ++ if (!res) { ++ dev_dbg(&pdev->dev, "no IRQ specified for %s\n", ++ dev_name(&pdev->dev)); ++ return -ENODEV; ++ } ++ irq = res->start; ++ ++ hcd = usb_create_hcd(&ohci_cns21xx_hc_driver, &pdev->dev, ++ dev_name(&pdev->dev)); ++ if (!hcd) ++ return -ENOMEM; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ dev_dbg(&pdev->dev, "no base address specified for %s\n", ++ dev_name(&pdev->dev)); ++ ret = -ENODEV; ++ goto err_put_hcd; ++ } ++ hcd->rsrc_start = res->start; ++ hcd->rsrc_len = res->end - res->start + 1; ++ ++ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { ++ dev_dbg(&pdev->dev, "controller already in use\n"); ++ ret = -EBUSY; ++ goto err_put_hcd; ++ } ++ ++ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); ++ if (!hcd->regs) { ++ dev_dbg(&pdev->dev, "error mapping memory\n"); ++ ret = -EFAULT; ++ goto err_release_region; ++ } ++ ++ cns21xx_ohci_init_hc(); ++ ++ ohci = hcd_to_ohci(hcd); ++ ohci->flags |= OHCI_QUIRK_INIT_FMINTERVAL; ++ ohci_hcd_init(ohci); ++ ++ ret = usb_add_hcd(hcd, irq, IRQF_DISABLED); ++ if (ret) ++ goto err_unmap; ++ ++ platform_set_drvdata(pdev, hcd); ++ return 0; ++ ++err_unmap: ++ iounmap(hcd->regs); ++err_release_region: ++ release_mem_region(hcd->rsrc_start, hcd->rsrc_len); ++err_put_hcd: ++ usb_put_hcd(hcd); ++ return ret; ++} ++ ++static int ohci_cns21xx_remove(struct platform_device *pdev) ++{ ++ struct usb_hcd *hcd = platform_get_drvdata(pdev); ++ ++ usb_remove_hcd(hcd); ++ iounmap(hcd->regs); ++ release_mem_region(hcd->rsrc_start, hcd->rsrc_len); ++ usb_put_hcd(hcd); ++ platform_set_drvdata(pdev, NULL); ++ ++ return 0; ++} ++ ++static struct platform_driver ohci_cns21xx_driver = { ++ .probe = ohci_cns21xx_probe, ++ .remove = ohci_cns21xx_remove, ++ .shutdown = usb_hcd_platform_shutdown, ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = DRIVER_NAME, ++ }, ++}; ++ ++MODULE_ALIAS("platform:" DRIVER_NAME); +--- a/drivers/usb/host/ohci.h ++++ b/drivers/usb/host/ohci.h +@@ -405,6 +405,7 @@ struct ohci_hcd { + #define OHCI_QUIRK_HUB_POWER 0x100 /* distrust firmware power/oc setup */ + #define OHCI_QUIRK_AMD_PLL 0x200 /* AMD PLL quirk*/ + #define OHCI_QUIRK_AMD_PREFETCH 0x400 /* pre-fetch for ISO transfer */ ++#define OHCI_QUIRK_INIT_FMINTERVAL 0x1000 /* fminterval must be initialized */ + // there are also chip quirks/bugs in init logic + + struct work_struct nec_work; /* Worker for NEC quirk */ +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -381,6 +381,7 @@ config ARCH_CNS21XX + select PLAT_FA_GPIO + select ARCH_REQUIRE_GPIOLIB + select ARM_L1_CACHE_SHIFT_4 ++ select USB_ARCH_HAS_OHCI + help + Support for Cavium Networks CNS21xx family. + diff --git a/target/linux/cns21xx/patches-3.8/104-cns21xx-usb-ehci-support.patch b/target/linux/cns21xx/patches-3.8/104-cns21xx-usb-ehci-support.patch new file mode 100644 index 0000000000..d9b9170743 --- /dev/null +++ b/target/linux/cns21xx/patches-3.8/104-cns21xx-usb-ehci-support.patch @@ -0,0 +1,214 @@ +--- a/drivers/usb/host/ehci-hcd.c ++++ b/drivers/usb/host/ehci-hcd.c +@@ -1342,6 +1342,11 @@ MODULE_LICENSE ("GPL"); + #define PLATFORM_DRIVER ehci_hcd_sead3_driver + #endif + ++#ifdef CONFIG_ARCH_CNS21XX ++#include "ehci-cns21xx.c" ++#define PLATFORM_DRIVER ehci_cns21xx_driver ++#endif ++ + #if !IS_ENABLED(CONFIG_USB_EHCI_PCI) && \ + !IS_ENABLED(CONFIG_USB_EHCI_HCD_PLATFORM) && \ + !IS_ENABLED(CONFIG_USB_CHIPIDEA_HOST) && \ +--- /dev/null ++++ b/drivers/usb/host/ehci-cns21xx.c +@@ -0,0 +1,187 @@ ++/* ++ * Copyright (c) 2008 Cavium Networks ++ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License, Version 2, as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/platform_device.h> ++#include <linux/irq.h> ++ ++#include <mach/cns21xx.h> ++ ++#define DRIVER_NAME "cns21xx-ehci" ++ ++static int cns21xx_ehci_reset(struct usb_hcd *hcd) ++{ ++ struct ehci_hcd *ehci = hcd_to_ehci(hcd); ++ int ret; ++ ++ ret = ehci_halt(ehci); ++ if (ret) ++ return ret; ++ ++ ret = ehci_init(hcd); ++ if (ret) ++ return ret; ++ ++ ehci_reset(ehci); ++ ++ return 0; ++} ++ ++static const struct hc_driver ehci_cns21xx_hc_driver = { ++ .description = hcd_name, ++ .product_desc = DRIVER_NAME, ++ .hcd_priv_size = sizeof(struct ehci_hcd), ++ ++ /* ++ * generic hardware linkage ++ */ ++ .irq = ehci_irq, ++ .flags = HCD_MEMORY | HCD_USB2, ++ ++ /* ++ * basic lifecycle operations ++ */ ++ .reset = cns21xx_ehci_reset, ++ .start = ehci_run, ++ .stop = ehci_stop, ++ .shutdown = ehci_shutdown, ++ ++ /* ++ * managing i/o requests and associated device resources ++ */ ++ .urb_enqueue = ehci_urb_enqueue, ++ .urb_dequeue = ehci_urb_dequeue, ++ .endpoint_disable = ehci_endpoint_disable, ++ .endpoint_reset = ehci_endpoint_reset, ++ ++ /* ++ * scheduling support ++ */ ++ .get_frame_number = ehci_get_frame, ++ ++ /* ++ * root hub support ++ */ ++ .hub_status_data = ehci_hub_status_data, ++ .hub_control = ehci_hub_control, ++ .relinquish_port = ehci_relinquish_port, ++ .port_handed_over = ehci_port_handed_over, ++ ++ .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, ++}; ++ ++static void cns21xx_ehci_init_hc(void) ++{ ++ void __iomem *base = (void __iomem *) CNS21XX_EHCI_CONFIG_BASE_VIRT; ++ ++ __raw_writel(0x106, base + 0x04); ++ __raw_writel((3 << 5) | 0x2000, base + 0x40); ++ msleep(100); ++} ++ ++static int ehci_cns21xx_probe(struct platform_device *pdev) ++{ ++ struct usb_hcd *hcd; ++ struct ehci_hcd *ehci; ++ struct resource *res; ++ int irq; ++ int ret; ++ ++ if (usb_disabled()) ++ return -ENODEV; ++ ++ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); ++ if (!res) { ++ dev_dbg(&pdev->dev, "no IRQ specified for %s\n", ++ dev_name(&pdev->dev)); ++ return -ENODEV; ++ } ++ irq = res->start; ++ ++ hcd = usb_create_hcd(&ehci_cns21xx_hc_driver, &pdev->dev, ++ dev_name(&pdev->dev)); ++ if (!hcd) ++ return -ENOMEM; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ dev_dbg(&pdev->dev, "no base address specified for %s\n", ++ dev_name(&pdev->dev)); ++ ret = -ENODEV; ++ goto err_put_hcd; ++ } ++ hcd->rsrc_start = res->start; ++ hcd->rsrc_len = res->end - res->start + 1; ++ ++ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { ++ dev_dbg(&pdev->dev, "controller already in use\n"); ++ ret = -EBUSY; ++ goto err_put_hcd; ++ } ++ ++ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); ++ if (!hcd->regs) { ++ dev_dbg(&pdev->dev, "error mapping memory\n"); ++ ret = -EFAULT; ++ goto err_release_region; ++ } ++ ++ cns21xx_ehci_init_hc(); ++ ++ ehci = hcd_to_ehci(hcd); ++ ++ ehci->caps = hcd->regs; ++ ehci->regs = hcd->regs + ++ HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase)); ++ dbg_hcs_params(ehci, "reset"); ++ dbg_hcc_params(ehci, "reset"); ++ ++ /* cache this readonly data; minimize chip reads */ ++ ehci->hcs_params = readl(&ehci->caps->hcs_params); ++ ehci->sbrn = 0x20; ++ ++ ret = usb_add_hcd(hcd, CNS21XX_IRQ_EHCI, IRQF_DISABLED); ++ if (ret) ++ goto err_unmap; ++ ++ platform_set_drvdata(pdev, hcd); ++ return 0; ++ ++err_unmap: ++ iounmap(hcd->regs); ++err_release_region: ++ release_mem_region(hcd->rsrc_start, hcd->rsrc_len); ++err_put_hcd: ++ usb_put_hcd(hcd); ++ return ret; ++} ++ ++static int ehci_cns21xx_remove(struct platform_device *pdev) ++{ ++ struct usb_hcd *hcd = platform_get_drvdata(pdev); ++ ++ usb_remove_hcd(hcd); ++ iounmap(hcd->regs); ++ release_mem_region(hcd->rsrc_start, hcd->rsrc_len); ++ usb_put_hcd(hcd); ++ platform_set_drvdata(pdev, NULL); ++ ++ return 0; ++} ++ ++static struct platform_driver ehci_cns21xx_driver = { ++ .probe = ehci_cns21xx_probe, ++ .remove = ehci_cns21xx_remove, ++ .shutdown = usb_hcd_platform_shutdown, ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = DRIVER_NAME, ++ }, ++}; ++ ++MODULE_ALIAS("platform:" DRIVER_NAME); +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -382,6 +382,7 @@ config ARCH_CNS21XX + select ARCH_REQUIRE_GPIOLIB + select ARM_L1_CACHE_SHIFT_4 + select USB_ARCH_HAS_OHCI ++ select USB_ARCH_HAS_EHCI + help + Support for Cavium Networks CNS21xx family. + diff --git a/target/linux/cns21xx/patches-3.8/105-cns21xx-spi-driver.patch b/target/linux/cns21xx/patches-3.8/105-cns21xx-spi-driver.patch new file mode 100644 index 0000000000..83c0361507 --- /dev/null +++ b/target/linux/cns21xx/patches-3.8/105-cns21xx-spi-driver.patch @@ -0,0 +1,578 @@ +--- a/include/linux/spi/spi.h ++++ b/include/linux/spi/spi.h +@@ -510,6 +510,8 @@ struct spi_transfer { + u16 delay_usecs; + u32 speed_hz; + ++ unsigned last_in_message_list; ++ + struct list_head transfer_list; + }; + +--- a/drivers/spi/Kconfig ++++ b/drivers/spi/Kconfig +@@ -186,6 +186,14 @@ config SPI_GPIO_OLD + + If unsure, say N. + ++config SPI_CNS21XX ++ tristate "Cavium Netowrks CNS21xx SPI master" ++ depends on ARCH_CNS21XX && EXPERIMENTAL ++ select SPI_BITBANG ++ help ++ This driver supports the buil-in SPI controller of the Cavium Networks ++ CNS21xx SoCs. ++ + config SPI_IMX + tristate "Freescale i.MX SPI controllers" + depends on ARCH_MXC +--- a/drivers/spi/Makefile ++++ b/drivers/spi/Makefile +@@ -20,6 +20,7 @@ obj-$(CONFIG_SPI_BFIN_SPORT) += spi-bfi + obj-$(CONFIG_SPI_BITBANG) += spi-bitbang.o + obj-$(CONFIG_SPI_BUTTERFLY) += spi-butterfly.o + obj-$(CONFIG_SPI_CLPS711X) += spi-clps711x.o ++obj-$(CONFIG_SPI_CNS21XX) += spi-cns21xx.o + obj-$(CONFIG_SPI_COLDFIRE_QSPI) += spi-coldfire-qspi.o + obj-$(CONFIG_SPI_DAVINCI) += spi-davinci.o + obj-$(CONFIG_SPI_DESIGNWARE) += spi-dw.o +--- a/drivers/spi/spi-bitbang.c ++++ b/drivers/spi/spi-bitbang.c +@@ -328,6 +328,13 @@ static void bitbang_work(struct work_str + */ + if (!m->is_dma_mapped) + t->rx_dma = t->tx_dma = 0; ++ ++ if (t->transfer_list.next == &m->transfers) { ++ t->last_in_message_list = 1; ++ } else { ++ t->last_in_message_list = 0; ++ } ++ + status = bitbang->txrx_bufs(spi, t); + } + if (status > 0) +--- /dev/null ++++ b/drivers/spi/spi-cns21xx.c +@@ -0,0 +1,521 @@ ++/* ++ * Copyright (c) 2008 Cavium Networks ++ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License, Version 2, as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/spinlock.h> ++#include <linux/workqueue.h> ++#include <linux/interrupt.h> ++#include <linux/delay.h> ++#include <linux/errno.h> ++#include <linux/platform_device.h> ++#include <linux/io.h> ++#include <linux/spi/spi.h> ++#include <linux/spi/spi_bitbang.h> ++ ++#include <mach/hardware.h> ++#include <mach/cns21xx.h> ++ ++#define DRIVER_NAME "cns21xx-spi" ++ ++#ifdef CONFIG_CNS21XX_SPI_DEBUG ++#define DBG(fmt, args...) pr_info("[CNS21XX_SPI_DEBUG]" fmt, ## args) ++#else ++#define DBG(fmt, args...) do {} while (0) ++#endif /* CNS21XX_SPI_DEBUG */ ++ ++#define SPI_REG_CFG 0x40 ++#define SPI_REG_STAT 0x44 ++#define SPI_REG_BIT_RATE 0x48 ++#define SPI_REG_TX_CTRL 0x4c ++#define SPI_REG_TX_DATA 0x50 ++#define SPI_REG_RX_CTRL 0x54 ++#define SPI_REG_RX_DATA 0x58 ++#define SPI_REG_FIFO_TX_CFG 0x5c ++#define SPI_REG_FIFO_TX_CTRL 0x60 ++#define SPI_REG_FIFO_RX_CFG 0x64 ++#define SPI_REG_INTR_STAT 0x68 ++#define SPI_REG_INTR_ENA 0x6c ++ ++#define CFG_SPI_EN BIT(31) ++#define CFG_SPI_CLKPOL BIT(14) ++#define CFG_SPI_CLKPHA BIT(13) ++#define CFG_SPI_MASTER_EN BIT(11) ++#define CFG_SPI_CHAR_LEN_M 0x3 ++#define CFG_SPI_CHAR_LEN_8BITS 0 ++#define CFG_SPI_CHAR_LEN_16BITS 1 ++#define CFG_SPI_CHAR_LEN_24BITS 2 ++#define CFG_SPI_CHAR_LEN_32BITS 3 ++ ++#define STAT_SPI_BUSY_STA BIT(1) ++ ++#define BIT_RATE_DIV_1 0 ++#define BIT_RATE_DIV_2 1 ++#define BIT_RATE_DIV_4 2 ++#define BIT_RATE_DIV_8 3 ++#define BIT_RATE_DIV_16 4 ++#define BIT_RATE_DIV_32 5 ++#define BIT_RATE_DIV_64 6 ++#define BIT_RATE_DIV_128 7 ++ ++#define TX_CTRL_SPI_TXDAT_EOF BIT(2) ++#define TX_CTRL_SPI_TXCH_NUM_M 0x3 ++#define TX_CTRL_CLEAR_MASK (TX_CTRL_SPI_TXDAT_EOF | \ ++ TX_CTRL_SPI_TXCH_NUM_M) ++ ++#define RX_CTRL_SPI_RXDAT_EOF BIT(2) ++#define RX_CTRL_SPI_RXCH_NUM_M 0x3 ++ ++#define INTR_STAT_SPI_TXBF_UNRN_FG BIT(7) ++#define INTR_STAT_SPI_RXBF_OVRN_FG BIT(6) ++#define INTR_STAT_SPI_TXFF_UNRN_FG BIT(5) ++#define INTR_STAT_SPI_RXFF_OVRN_FG BIT(4) ++#define INTR_STAT_SPI_TXBUF_FG BIT(3) ++#define INTR_STAT_SPI_RXBUF_FG BIT(2) ++#define INTR_STAT_SPI_TXFF_FG BIT(1) ++#define INTR_STAT_SPI_RXFF_FG BIT(0) ++ ++#define INTR_STAT_CLEAR_MASK (INTR_STAT_SPI_TXBF_UNRN_FG | \ ++ INTR_STAT_SPI_RXBF_OVRN_FG | \ ++ INTR_STAT_SPI_TXFF_UNRN_FG | \ ++ INTR_STAT_SPI_RXFF_OVRN_FG) ++ ++#define FIFO_TX_CFG_SPI_TXFF_THRED_M 0x3 ++#define FIFO_TX_CFG_SPI_TXFF_THRED_S 4 ++#define FIFO_TX_CFG_SPI_TXFF_THRED_2 0 ++#define FIFO_TX_CFG_SPI_TXFF_THRED_4 1 ++#define FIFO_TX_CFG_SPI_TXFF_THRED_6 0 ++#define FIFO_TX_CFG_SPI_TXFF_STATUS_M 0xf ++ ++#define FIFO_RX_CFG_SPI_RXFF_THRED_M 0x3 ++#define FIFO_RX_CFG_SPI_RXFF_THRED_S 4 ++#define FIFO_RX_CFG_SPI_RXFF_THRED_2 0 ++#define FIFO_RX_CFG_SPI_RXFF_THRED_4 1 ++#define FIFO_RX_CFG_SPI_RXFF_THRED_6 0 ++#define FIFO_RX_CFG_SPI_RXFF_STATUS_M 0xf ++ ++#define CNS21XX_SPI_NUM_BIT_RATES 8 ++ ++struct cns21xx_spi { ++ struct spi_bitbang bitbang; ++ ++ struct spi_master *master; ++ struct device *dev; ++ void __iomem *base; ++ struct resource *region; ++ ++ unsigned freq_max; ++ unsigned freq_min; ++ ++}; ++ ++static inline struct cns21xx_spi *to_hw(struct spi_device *spi) ++{ ++ return spi_master_get_devdata(spi->master); ++} ++ ++static inline u32 cns21xx_spi_rr(struct cns21xx_spi *hw, unsigned int reg) ++{ ++ return __raw_readl(hw->base + reg); ++} ++ ++static inline void cns21xx_spi_wr(struct cns21xx_spi *hw, u32 val, ++ unsigned int reg) ++{ ++ __raw_writel(val, hw->base + reg); ++} ++ ++#define CNS21XX_SPI_RETRY_COUNT 100 ++static inline int cns21xx_spi_wait(struct cns21xx_spi *hw, unsigned int reg, ++ u32 mask, u32 val) ++{ ++ int retry_cnt = 0; ++ ++ do { ++ if ((cns21xx_spi_rr(hw, reg) & mask) == val) ++ break; ++ ++ if (++retry_cnt > CNS21XX_SPI_RETRY_COUNT) { ++ dev_err(hw->dev, "timeout waiting on register %02x\n", ++ reg); ++ return -EIO; ++ } ++ } while (1); ++ ++ return 0; ++} ++ ++static int cns21xx_spi_txrx_word(struct cns21xx_spi *hw, u8 tx_channel, ++ u8 tx_eof_flag, u32 tx_data, u32 *rx_data) ++{ ++ unsigned int tx_ctrl; ++ u8 rx_channel; ++ u8 rx_eof_flag; ++ int err = 0; ++ ++ err = cns21xx_spi_wait(hw, SPI_REG_STAT, STAT_SPI_BUSY_STA, 0); ++ if (err) ++ return err; ++ ++ err = cns21xx_spi_wait(hw, SPI_REG_INTR_STAT, INTR_STAT_SPI_TXBUF_FG, ++ INTR_STAT_SPI_TXBUF_FG); ++ if (err) ++ return err; ++ ++ tx_ctrl = cns21xx_spi_rr(hw, SPI_REG_TX_CTRL); ++ tx_ctrl &= ~(TX_CTRL_CLEAR_MASK); ++ tx_ctrl |= (tx_channel & TX_CTRL_SPI_TXCH_NUM_M); ++ tx_ctrl |= (tx_eof_flag) ? TX_CTRL_SPI_TXDAT_EOF : 0; ++ cns21xx_spi_wr(hw, tx_ctrl, SPI_REG_TX_CTRL); ++ ++ cns21xx_spi_wr(hw, tx_data, SPI_REG_TX_DATA); ++ ++ err = cns21xx_spi_wait(hw, SPI_REG_INTR_STAT, INTR_STAT_SPI_RXBUF_FG, ++ INTR_STAT_SPI_RXBUF_FG); ++ if (err) ++ return err; ++ ++ rx_channel = cns21xx_spi_rr(hw, SPI_REG_RX_CTRL) & ++ RX_CTRL_SPI_RXCH_NUM_M; ++ ++ rx_eof_flag = (cns21xx_spi_rr(hw, SPI_REG_RX_CTRL) & ++ RX_CTRL_SPI_RXDAT_EOF) ? 1 : 0; ++ ++ *rx_data = cns21xx_spi_rr(hw, SPI_REG_RX_DATA); ++ ++ if ((tx_channel != rx_channel) || (tx_eof_flag != rx_eof_flag)) ++ return -EPROTO; ++ ++ return 0; ++} ++ ++static void cns21xx_spi_chipselect(struct spi_device *spi, int value) ++{ ++ struct cns21xx_spi *hw = to_hw(spi); ++ unsigned int spi_config; ++ unsigned int tx_ctrl; ++ ++ switch (value) { ++ case BITBANG_CS_INACTIVE: ++ break; ++ ++ case BITBANG_CS_ACTIVE: ++ spi_config = cns21xx_spi_rr(hw, SPI_REG_CFG); ++ ++ if (spi->mode & SPI_CPHA) ++ spi_config |= CFG_SPI_CLKPHA; ++ else ++ spi_config &= ~CFG_SPI_CLKPHA; ++ ++ if (spi->mode & SPI_CPOL) ++ spi_config |= CFG_SPI_CLKPOL; ++ else ++ spi_config &= ~CFG_SPI_CLKPOL; ++ ++ cns21xx_spi_wr(hw, spi_config, SPI_REG_CFG); ++ ++ tx_ctrl = cns21xx_spi_rr(hw, SPI_REG_TX_CTRL); ++ tx_ctrl &= ~(TX_CTRL_CLEAR_MASK); ++ tx_ctrl |= (spi->chip_select & TX_CTRL_SPI_TXCH_NUM_M); ++ cns21xx_spi_wr(hw, tx_ctrl, SPI_REG_TX_CTRL); ++ ++ break; ++ } ++} ++ ++static int cns21xx_spi_setup(struct spi_device *spi) ++{ ++ struct cns21xx_spi *hw = to_hw(spi); ++ ++ if (spi->bits_per_word != 8) { ++ dev_err(&spi->dev, "%s: invalid bits_per_word=%u\n", ++ __func__, spi->bits_per_word); ++ return -EINVAL; ++ } ++ ++ if (spi->max_speed_hz == 0) ++ spi->max_speed_hz = hw->freq_max; ++ ++ if (spi->max_speed_hz > hw->freq_max || ++ spi->max_speed_hz < hw->freq_min) { ++ dev_err(&spi->dev, "%s: max_speed_hz=%u out of range\n", ++ __func__, spi->max_speed_hz); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int cns21xx_spi_setup_transfer(struct spi_device *spi, ++ struct spi_transfer *t) ++{ ++ struct cns21xx_spi *hw = to_hw(spi); ++ u8 bits_per_word; ++ u32 hz; ++ int i; ++ ++ bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word; ++ hz = t ? t->speed_hz : spi->max_speed_hz; ++ ++ if (!bits_per_word) ++ bits_per_word = spi->bits_per_word; ++ ++ if (!hz) ++ hz = spi->max_speed_hz; ++ ++ if (bits_per_word != 8) { ++ dev_err(&spi->dev, "%s: invalid bits_per_word=%u\n", ++ __func__, bits_per_word); ++ return -EINVAL; ++ } ++ ++ if (hz > spi->max_speed_hz || hz > hw->freq_max || hz < hw->freq_min) { ++ dev_err(&spi->dev, "%s: max_speed_hz=%u out of range\n", ++ __func__, hz); ++ return -EINVAL; ++ } ++ ++ for (i = 0; i < CNS21XX_SPI_NUM_BIT_RATES; i++) ++ if (spi->max_speed_hz > (cns21xx_get_apb_freq() >> i)) ++ break; ++ ++ DBG("max_speed:%uHz, curr_speed:%luHz, rate_index=%d\n", ++ spi->max_speed_hz, cns21xx_get_apb_freq() / (1 << i), i); ++ ++ cns21xx_spi_wr(hw, i, SPI_REG_BIT_RATE); ++ ++ return 0; ++} ++ ++static int cns21xx_spi_txrx(struct spi_device *spi, struct spi_transfer *t) ++{ ++ struct cns21xx_spi *hw = to_hw(spi); ++ const unsigned char *tx_buf; ++ unsigned char *rx_buf; ++ u32 rx_data; ++ int tx_eof; ++ int err = 0; ++ int i; ++ ++ tx_buf = t->tx_buf; ++ rx_buf = t->rx_buf; ++ tx_eof = t->last_in_message_list; ++ ++ DBG("txrx: tx %p, rx %p, len %d\n", tx_buf, rx_buf, t->len); ++ ++ if (tx_buf) { ++ for (i = 0; i < t->len; i++) ++ DBG("tx_buf[%02d]: 0x%02x\n", i, tx_buf[i]); ++ ++ for (i = 0; i < (t->len - 1); i++) { ++ err = cns21xx_spi_txrx_word(hw, spi->chip_select, 0, ++ tx_buf[i], &rx_data); ++ if (err) ++ goto done; ++ ++ if (rx_buf) { ++ rx_buf[i] = rx_data; ++ DBG("rx_buf[%02d]:0x%02x\n", i, rx_buf[i]); ++ } ++ } ++ ++ err = cns21xx_spi_txrx_word(hw, spi->chip_select, tx_eof, ++ tx_buf[i], &rx_data); ++ if (err) ++ goto done; ++ ++ if ((tx_eof) && rx_buf) { ++ rx_buf[i] = rx_data; ++ DBG("rx_buf[%02d]:0x%02x\n", i, rx_buf[i]); ++ } ++ } else if (rx_buf) { ++ for (i = 0; i < (t->len - 1); i++) { ++ err = cns21xx_spi_txrx_word(hw, spi->chip_select, 0, ++ 0xff, &rx_data); ++ if (err) ++ goto done; ++ ++ rx_buf[i] = rx_data; ++ DBG("rx_buf[%02d]:0x%02x\n", i, rx_buf[i]); ++ } ++ ++ err = cns21xx_spi_txrx_word(hw, spi->chip_select, tx_eof, ++ 0xff, &rx_data); ++ if (err) ++ goto done; ++ ++ rx_buf[i] = rx_data; ++ DBG("rx_buf[%02d]:0x%02x\n", i, rx_buf[i]); ++ } ++ ++ done: ++ return (err) ? err : t->len; ++} ++ ++static void __init cns21xx_spi_hw_init(struct cns21xx_spi *hw) ++{ ++ u32 t; ++ u32 pclk; ++ ++ /* Setup configuration register */ ++ cns21xx_spi_wr(hw, CFG_SPI_MASTER_EN, SPI_REG_CFG); ++ ++ /* Set default clock to PCLK/2 */ ++ cns21xx_spi_wr(hw, BIT_RATE_DIV_2, SPI_REG_BIT_RATE); ++ ++ /* Configure SPI's Tx channel */ ++ cns21xx_spi_wr(hw, 0, SPI_REG_TX_CTRL); ++ ++ /* Configure Tx FIFO Threshold */ ++ t = cns21xx_spi_rr(hw, SPI_REG_FIFO_TX_CFG); ++ t &= ~(FIFO_TX_CFG_SPI_TXFF_THRED_M << FIFO_TX_CFG_SPI_TXFF_THRED_S); ++ t |= (FIFO_TX_CFG_SPI_TXFF_THRED_2 << FIFO_TX_CFG_SPI_TXFF_THRED_S); ++ cns21xx_spi_wr(hw, t, SPI_REG_FIFO_TX_CFG); ++ ++ /* Configure Rx FIFO Threshold */ ++ t = cns21xx_spi_rr(hw, SPI_REG_FIFO_RX_CFG); ++ t &= ~(FIFO_RX_CFG_SPI_RXFF_THRED_M << FIFO_RX_CFG_SPI_RXFF_THRED_S); ++ t |= (FIFO_RX_CFG_SPI_RXFF_THRED_2 << FIFO_RX_CFG_SPI_RXFF_THRED_S); ++ cns21xx_spi_wr(hw, t, SPI_REG_FIFO_RX_CFG); ++ ++ /* Disable interrupts, and clear interrupt status */ ++ cns21xx_spi_wr(hw, 0, SPI_REG_INTR_ENA); ++ cns21xx_spi_wr(hw, INTR_STAT_CLEAR_MASK, SPI_REG_INTR_STAT); ++ ++ (void) cns21xx_spi_rr(hw, SPI_REG_RX_DATA); ++ ++ /* Enable SPI */ ++ t = cns21xx_spi_rr(hw, SPI_REG_CFG); ++ t |= CFG_SPI_EN; ++ cns21xx_spi_wr(hw, t, SPI_REG_CFG); ++ ++ pclk = cns21xx_get_apb_freq(); ++ hw->freq_max = pclk; ++ hw->freq_min = pclk / (1 << BIT_RATE_DIV_128); ++} ++ ++static int __init cns21xx_spi_probe(struct platform_device *pdev) ++{ ++ struct cns21xx_spi *hw; ++ struct spi_master *master; ++ struct resource *res; ++ int err = 0; ++ ++ master = spi_alloc_master(&pdev->dev, sizeof(struct cns21xx_spi)); ++ if (!master) { ++ dev_err(&pdev->dev, "No memory for spi_master\n"); ++ return -ENOMEM; ++ } ++ ++ hw = spi_master_get_devdata(master); ++ ++ platform_set_drvdata(pdev, hw); ++ hw->master = spi_master_get(master); ++ hw->dev = &pdev->dev; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ dev_dbg(&pdev->dev, "no MEM resource found\n"); ++ err = -ENOENT; ++ goto err_put_master; ++ } ++ ++ hw->region = request_mem_region(res->start, resource_size(res), ++ dev_name(&pdev->dev)); ++ if (!hw->region) { ++ dev_err(&pdev->dev, "unable to reserve iomem region\n"); ++ err = -ENXIO; ++ goto err_put_master; ++ } ++ ++ hw->base = ioremap(res->start, resource_size(res)); ++ if (!hw->base) { ++ dev_err(&pdev->dev, "ioremap failed\n"); ++ err = -ENOENT; ++ goto err_release_region; ++ } ++ ++ cns21xx_spi_hw_init(hw); ++ ++ master->bus_num = pdev->id; ++ if (master->bus_num == -1) ++ master->bus_num = 0; ++ ++ master->num_chipselect = 4; ++ master->setup = cns21xx_spi_setup; ++ ++ hw->bitbang.master = hw->master; ++ hw->bitbang.chipselect = cns21xx_spi_chipselect; ++ hw->bitbang.txrx_bufs = cns21xx_spi_txrx; ++ hw->bitbang.setup_transfer = cns21xx_spi_setup_transfer; ++ ++ err = spi_bitbang_start(&hw->bitbang); ++ if (err) { ++ dev_err(hw->dev, "unable to register SPI master\n"); ++ goto err_unmap; ++ } ++ ++ dev_info(hw->dev, "iomem at %08x\n", res->start); ++ ++ return 0; ++ ++ err_unmap: ++ iounmap(hw->base); ++ ++ err_release_region: ++ release_resource(hw->region); ++ kfree(hw->region); ++ ++ err_put_master: ++ spi_master_put(hw->bitbang.master); ++ platform_set_drvdata(pdev, NULL); ++ ++ return err; ++} ++ ++static int cns21xx_spi_remove(struct platform_device *pdev) ++{ ++ struct cns21xx_spi *hw = platform_get_drvdata(pdev); ++ ++ spi_bitbang_stop(&hw->bitbang); ++ iounmap(hw->base); ++ release_resource(hw->region); ++ kfree(hw->region); ++ spi_master_put(hw->bitbang.master); ++ platform_set_drvdata(pdev, NULL); ++ ++ return 0; ++} ++ ++static struct platform_driver cns21xx_spi_driver = { ++ .remove = cns21xx_spi_remove, ++ .driver = { ++ .name = DRIVER_NAME, ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int __init cns21xx_spi_init(void) ++{ ++ return platform_driver_probe(&cns21xx_spi_driver, cns21xx_spi_probe); ++} ++ ++static void __exit cns21xx_spi_exit(void) ++{ ++ platform_driver_unregister(&cns21xx_spi_driver); ++} ++ ++module_init(cns21xx_spi_init); ++module_exit(cns21xx_spi_exit); ++ ++MODULE_DESCRIPTION("Cavium Networks CNS21xx SPI Controller driver"); ++MODULE_AUTHOR("STAR Semi Corp."); ++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>"); ++MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/target/linux/cns21xx/patches-3.8/106-cns21xx-gec-driver.patch b/target/linux/cns21xx/patches-3.8/106-cns21xx-gec-driver.patch new file mode 100644 index 0000000000..a48ba591be --- /dev/null +++ b/target/linux/cns21xx/patches-3.8/106-cns21xx-gec-driver.patch @@ -0,0 +1,2507 @@ +--- /dev/null ++++ b/drivers/net/ethernet/cns21xx/cns21xx_gec_main.c +@@ -0,0 +1,2464 @@ ++/* ++ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * This driver has been derived from the ethernet driver of the ++ * Star STR81xx SoC. ++ * Copyright (c) 2008 Cavium Networks ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License, Version 2, as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/bootmem.h> ++#include <linux/sched.h> ++#include <linux/types.h> ++#include <linux/fcntl.h> ++#include <linux/interrupt.h> ++#include <linux/ptrace.h> ++#include <linux/ioport.h> ++#include <linux/in.h> ++#include <linux/slab.h> ++#include <linux/init.h> ++#include <linux/bitops.h> ++#include <linux/irq.h> ++#include <linux/io.h> ++#include <linux/pci.h> ++#include <linux/errno.h> ++#include <linux/delay.h> ++#include <linux/netdevice.h> ++#include <linux/etherdevice.h> ++#include <linux/platform_device.h> ++#include <linux/skbuff.h> ++#include <linux/ip.h> ++#include <linux/if_ether.h> ++#include <linux/icmp.h> ++#include <linux/udp.h> ++#include <linux/tcp.h> ++#include <linux/if_arp.h> ++#include <net/arp.h> ++ ++#include <mach/hardware.h> ++#include <mach/cns21xx.h> ++#include <mach/cns21xx_misc.h> ++#include <mach/cns21xx_powermgmt.h> ++#include <mach/cns21xx_gec_platform.h> ++ ++#define DRIVER_NAME "cns21xx-gec" ++ ++/* VSC8601 and WavePlus Phy are the same */ ++#define CNS21XX_GEC_PHY_ADDR 0 ++ ++#define CNS21XX_GEC_TX_HW_CHECKSUM ++#define CNS21XX_GEC_RX_HW_CHECKSUM ++ ++#define CNS21XX_PEND_INT_COUNT 16 ++#define CNS21XX_PEND_INT_TIME 5 /* 5 x 20 usecs */ ++ ++#define MAX_PACKET_LEN 1536 ++ ++#define CNS21XX_GEC_NUM_TXDS 48 /* FIXME: original 64 will cause UDP fail */ ++#define CNS21XX_GEC_NUM_RXDS 64 ++ ++struct cns21xx_gec_mib_info { ++ u32 mib_rx_ok_pkt; ++ u64 mib_rx_ok_byte; ++ u32 mib_rx_runt; ++ u32 mib_rx_over_size; ++ u32 mib_rx_no_buffer_drop; ++ u32 mib_rx_crc_err; ++ u32 mib_rx_arl_drop; ++ u32 mib_rx_myvid_drop; ++ u32 mib_rx_csum_err; ++ u32 mib_rx_pause_frame; ++ u32 mib_tx_ok_pkt; ++ u64 mib_tx_ok_byte; ++ u32 mib_tx_pause_frame; ++}; ++ ++/* ++ * Network Driver, Receive/Send and Initial Buffer Function ++ */ ++struct cns21xx_gec_txd { ++ /* 1st 32Bits */ ++ u32 sdp; ++ ++ /* 2nd 32Bits */ ++ u32 length:16; ++ u32 reserved0:7; ++ u32 tco:1; ++ u32 uco:1; ++ u32 ico:1; ++ u32 insv:1; ++ u32 intr:1; ++ u32 ls:1; ++ u32 fs:1; ++ u32 eor:1; ++ u32 cown:1; ++ ++ /* 3rd 32Bits */ ++ u32 vid:12; ++ u32 cfi:1; ++ u32 pri:3; ++ u32 epid:16; ++ ++ /* 4th 32Bits */ ++ u32 reserved1; ++} __packed; ++ ++struct cns21xx_gec_rxd { ++ /* 1st 32Bits */ ++ u32 sdp; ++ ++ /* 2nd 32Bits */ ++ u32 length:16; ++ u32 l4f:1; ++ u32 ipf:1; ++ u32 prot:2; ++ u32 vted:1; ++ u32 mymac:1; ++ u32 hhit:1; ++ u32 rmc:1; ++ u32 crce:1; ++ u32 osize:1; ++ u32 reserved0:2; ++ u32 ls:1; ++ u32 fs:1; ++ u32 eor:1; ++ u32 cown:1; ++ ++ /* 3rd 32Bits */ ++ u32 vid:12; ++ u32 cfi:1; ++ u32 pri:3; ++ u32 epid:16; ++ ++ /* 4th 32Bits */ ++ u32 reserved1; ++} __packed; ++ ++struct cns21xx_gec_ring { ++ u32 desc_dma; ++ void *desc_cpu; ++ u32 curr; ++ u32 dirty; ++ u32 count; ++ struct sk_buff **skbs; ++}; ++ ++#define CNS21XX_GEC_NUM_VLANS 4 ++struct cns21xx_gec_vlan { ++ u32 vid; /* 0~4095 */ ++ u32 control; /* ENABLE or DISABLE */ ++}; ++ ++/* store this information for the driver.. */ ++struct cns21xx_gec { ++ struct napi_struct napi; ++ struct net_device *netdev; ++ struct device *parent; ++ struct cns21xx_gec_ring txring; ++ struct cns21xx_gec_ring rxring; ++ ++ void __iomem *base; ++ struct resource *mem_res; ++ struct cns21xx_gec_plat_data *pdata; ++ spinlock_t lock; ++ spinlock_t tx_lock; ++ ++ int status_irq; ++ int rxrc_irq; ++ int rxqf_irq; ++ int txtc_irq; ++ int txqe_irq; ++ unsigned long rx_queue_full; ++ ++ struct cns21xx_gec_vlan vlans[CNS21XX_GEC_NUM_VLANS]; ++ ++ struct timer_list internal_phy_timer; ++ struct timer_list nic_timer; ++ u8 phy_addr; ++ u16 phy_id; ++ struct cns21xx_gec_mib_info mib_info; ++}; ++ ++#define GEC_REG_PHY_CTRL0 0x000 ++#define GEC_REG_PHY_CTRL1 0x004 ++#define GEC_REG_MAC_CFG 0x008 ++#define GEC_REG_FC_CFG 0x00c ++#define GEC_REG_ARL_CFG 0x010 ++#define GEC_REG_MY_MAC_H 0x014 ++#define GEC_REG_MY_MAC_L 0x018 ++#define GEC_REG_HASH_CTRL 0x01c ++#define GEC_REG_VLAN_CTRL 0x020 ++#define GEC_REG_VLAN_ID_0_1 0x024 ++#define GEC_REG_VLAN_ID_2_3 0x028 ++#define GEC_REG_DMA_CFG 0x030 ++#define GEC_REG_TX_DMA_CTRL 0x034 ++#define GEC_REG_RX_DMA_CTRL 0x038 ++#define GEC_REG_TX_DPTR 0x03c ++#define GEC_REG_RX_DPTR 0x040 ++#define GEC_REG_TX_BASE_ADDR 0x044 ++#define GEC_REG_RX_BASE_ADDR 0x048 ++#define GEC_REG_DLY_INT_CFG 0x04c ++#define GEC_REG_INT 0x050 ++#define GEC_REG_INT_MASK 0x054 ++#define GEC_REG_TEST0 0x058 ++#define GEC_REG_TEST1 0x05c ++#define GEC_REG_EXTEND_CFG 0x060 ++ ++#define GEC_REG_RX_OK_PKT_CNTR 0x100 ++#define GEC_REG_RX_OK_BYTE_CNTR 0x104 ++#define GEC_REG_RX_RUNT_BYTE_CNTR 0x108 ++#define GEC_REG_RX_OSIZE_DROP_PKT_CNTR 0x10c ++#define GEC_REG_RX_NO_BUF_DROP_PKT_CNTR 0x110 ++#define GEC_REG_RX_CRC_ERR_PKT_CNTR 0x114 ++#define GEC_REG_RX_ARL_DROP_PKT_CNTR 0x118 ++#define GEC_REG_MYVLANID_MISMATCH_DROP_PKT_CNTR 0x11c ++#define GEC_REG_RX_CHKSUM_ERR_PKT_CNTR 0x120 ++#define GEC_REG_RX_PAUSE_FRAME_PKT_CNTR 0x124 ++#define GEC_REG_TX_OK_PKT_CNTR 0x128 ++#define GEC_REG_TX_OK_BYTE_CNTR 0x12c ++#define GEC_REG_TX_COLLISION_CNTR 0x130 ++#define GEC_REG_TX_PAUSE_FRAME_CNTR 0x130 ++#define GEC_REG_TX_FIFO_UNDERRUN_RETX_CNTR 0x134 ++ ++#define GEC_INT_MIB_COUNTER_TH BIT(3) ++#define GEC_INT_PORT_STATUS_CHG BIT(2) ++ ++#define FE_PHY_LED_MODE (0x1 << 12) ++ ++static void internal_phy_init_timer(struct cns21xx_gec *gec); ++static void internal_phy_start_timer(struct cns21xx_gec *gec); ++static void internal_phy_stop_timer(struct cns21xx_gec *gec); ++ ++static void cns21xx_gec_phy_powerdown(struct cns21xx_gec *gec); ++static void cns21xx_gec_phy_powerup(struct cns21xx_gec *gec); ++ ++static inline u32 cns21xx_gec_rr(struct cns21xx_gec *gec, unsigned int reg) ++{ ++ return __raw_readl(gec->base + reg); ++} ++ ++static inline void cns21xx_gec_wr(struct cns21xx_gec *gec, unsigned int reg, ++ u32 val) ++{ ++ __raw_writel(val, gec->base + reg); ++} ++ ++static void cns21xx_gec_timer_func(unsigned long data) ++{ ++ struct cns21xx_gec *gec = (struct cns21xx_gec *) data; ++ struct cns21xx_gec_ring *txring = &gec->txring; ++ int i; ++ int txsd_index; ++ int txsd_current; ++ int skb_free_count = 0; ++ struct cns21xx_gec_txd *txd; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ txsd_current = cns21xx_gec_rr(gec, GEC_REG_TX_DPTR); ++ txsd_index = (txsd_current - (u32)txring->desc_dma) >> 4; ++ if (txsd_index > txring->dirty) { ++ skb_free_count = txsd_index - txring->dirty; ++ } else if (txsd_index <= txring->dirty) { ++ skb_free_count = txring->count + txsd_index - ++ txring->dirty; ++ } ++ for (i = 0; i < skb_free_count; i++) { ++ txd = ((struct cns21xx_gec_txd *) txring->desc_cpu) + ++ txring->dirty; ++ ++ if (txd->cown == 0) ++ break; ++ ++ if (txring->skbs[txring->dirty]) { ++ dev_kfree_skb_any(txring->skbs[txring->dirty]); ++ txring->skbs[txring->dirty] = NULL; ++ ++ dma_unmap_single(gec->parent, ++ txd->sdp, ++ txd->length, ++ DMA_TO_DEVICE); ++ } ++ ++ txring->dirty++; ++ if (txring->dirty == txring->count) ++ txring->dirty = 0; ++ } ++ local_irq_restore(flags); ++} ++ ++static void __init cns21xx_gec_timer_init(struct cns21xx_gec *gec) ++{ ++ init_timer(&gec->nic_timer); ++ gec->nic_timer.function = &cns21xx_gec_timer_func; ++ gec->nic_timer.data = (unsigned long) gec; ++} ++ ++static void cns21xx_gec_timer_modify(struct cns21xx_gec *gec, unsigned int t) ++{ ++ mod_timer(&gec->nic_timer, jiffies + t); ++} ++ ++static int cns21xx_gec_write_phy(struct cns21xx_gec *gec, ++ u8 addr, u8 reg, u16 val) ++{ ++ int i; ++ ++ if (addr > 31 || reg > 31) ++ return -EINVAL; ++ ++ /* clear previous rw_ok status */ ++ cns21xx_gec_wr(gec, GEC_REG_PHY_CTRL0, 0x1 << 15); ++ ++ cns21xx_gec_wr(gec, GEC_REG_PHY_CTRL0, ++ addr | (reg << 8) | (val << 16) | (0x1 << 13)); ++ ++ for (i = 0; i < 10000; i++) { ++ u32 status; ++ ++ status = cns21xx_gec_rr(gec, GEC_REG_PHY_CTRL0); ++ if (status & (0x1 << 15)) { ++ /* ++ * clear the rw_ok status, ++ * and clear other bits value ++ */ ++ cns21xx_gec_wr(gec, GEC_REG_PHY_CTRL0, (0x1 << 15)); ++ return 0; ++ } ++ udelay(1000); ++ } ++ ++ dev_err(&gec->netdev->dev, ++ "%s timed out, phy_addr:0x%x, phy_reg:0x%x, write_data:0x%x\n", ++ __func__, addr, reg, val); ++ ++ return -EIO; ++} ++ ++static int cns21xx_gec_read_phy(struct cns21xx_gec *gec, ++ u8 addr, u8 reg, u16 *val) ++{ ++ int i; ++ ++ if (addr > 31 || reg > 31) ++ return -EINVAL; ++ ++ /* clear previous rw_ok status */ ++ cns21xx_gec_wr(gec, GEC_REG_PHY_CTRL0, 0x1 << 15); ++ ++ cns21xx_gec_wr(gec, GEC_REG_PHY_CTRL0, ++ addr | (reg << 8) | (0x1 << 14)); ++ ++ for (i = 0; i < 10000; i++) { ++ u32 status; ++ ++ status = cns21xx_gec_rr(gec, GEC_REG_PHY_CTRL0); ++ if (status & (0x1 << 15)) { ++ /* ++ * clear the rw_ok status, ++ * and clear other bits value ++ */ ++ cns21xx_gec_wr(gec, GEC_REG_PHY_CTRL0, (0x1 << 15)); ++ *val = (status >> 16) & 0xffff; ++ return 0; ++ } ++ udelay(1000); ++ } ++ ++ dev_err(&gec->netdev->dev, ++ "%s timed out, phy_addr:0x%x, phy_reg:0x%x\n", ++ __func__, addr, reg); ++ ++ *val = 0xffff; ++ return -EIO; ++} ++ ++static void cns21xx_gec_dma_config(struct cns21xx_gec *gec) ++{ ++ u32 dma_config = 0; ++ ++ dma_config = cns21xx_gec_rr(gec, GEC_REG_DMA_CFG); ++ ++ /* Config TX DMA */ ++ /* TX auto polling: 1 us */ ++ dma_config &= ~(0x3 << 6); ++ /* TX auto polling :100us */ ++ dma_config |= (0x2 << 6); ++ /* TX auto polling C-bit enable */ ++ dma_config |= (0x1 << 5); ++ /* TX can transmit packets, No suspend */ ++ dma_config &= ~(0x1 << 4); ++ ++ /* Config RX DMA */ ++ /* RX auto polling: 1 us */ ++ dma_config &= ~(0x3 << 2); ++ /* RX auto polling :100us */ ++ dma_config |= (0x2 << 2); ++ /* RX auto polling C-bit enable */ ++ dma_config |= (0x1 << 1); ++ /* RX can receive packets, No suspend */ ++ dma_config &= ~0x1; ++ ++ /* 4N+2(for Linux) */ ++ dma_config &= ~(0x1 << 16); ++ ++ cns21xx_gec_wr(gec, GEC_REG_DMA_CFG, dma_config); ++} ++ ++static void cns21xx_gec_mac_config(struct cns21xx_gec *gec) ++{ ++ u32 mac_config; ++ ++ mac_config = cns21xx_gec_rr(gec, GEC_REG_MAC_CFG); ++ ++#ifdef CNS21XX_GEC_TX_HW_CHECKSUM ++ /* Tx ChkSum offload On: TCP/UDP/IP */ ++ mac_config |= (0x1 << 26); ++#else ++ /* Tx ChkSum offload Off: TCP/UDP/IP */ ++ mac_config &= ~(0x1 << 26); ++#endif ++ ++#ifdef CNS21XX_GEC_RX_HW_CHECKSUM ++ /* Rx ChkSum offload On: TCP/UDP/IP */ ++ mac_config |= (0x1 << 25); ++#else ++ /* Rx ChkSum offload Off: TCP/UDP/IP */ ++ mac_config &= ~(0x1 << 25); ++#endif ++ ++ /* Accept CSUM error pkt */ ++ mac_config |= (0x1 << 24); ++ /* IST disable */ ++ mac_config &= ~(0x1 << 23); ++ /* Strip vlan tag */ ++ mac_config |= (0x1 << 22); ++ /* Accept CRC error pkt */ ++ mac_config |= (0x1 << 21); ++ /* CRC strip */ ++ mac_config |= (0x1 << 20); ++ ++ /* Discard oversize pkt */ ++ mac_config &= ~(0x1 << 18); ++ ++ /* clear, set 1518 */ ++ mac_config &= ~(0x3 << 16); ++ ++ /* 1536 */ ++ mac_config |= (0x2 << 16); ++ ++ /* IPG */ ++ mac_config |= (0x1f << 10); ++ ++ /* Do not skip 16 consecutive collisions pkt */ ++ /* allow to re-tx */ ++ mac_config |= (0x1 << 9); ++ /* Fast retry */ ++ mac_config |= (0x1 << 8); ++ ++ cns21xx_gec_wr(gec, GEC_REG_MAC_CFG, mac_config); ++} ++ ++static void cns21xx_gec_fc_config(struct cns21xx_gec *gec) ++{ ++ u32 fc_config; ++ ++ fc_config = cns21xx_gec_rr(gec, GEC_REG_FC_CFG); ++ ++ /* Send pause on frame threshold */ ++ /* Clear */ ++ fc_config &= ~(0xfff << 16); ++ fc_config |= (0x360 << 16); ++ /* Disable UC_PAUSE */ ++ fc_config &= ~(0x1 << 8); ++ /* Enable Half Duplex backpressure */ ++ fc_config |= (0x1 << 7); ++ /* Collision-based BP */ ++ fc_config &= ~(0x1 << 6); ++ /* Disable max BP collision */ ++ fc_config &= ~(0x1 << 5); ++ /* Clear */ ++ fc_config &= ~(0x1f); ++ /* Set */ ++ fc_config |= (0xc); ++ ++ cns21xx_gec_wr(gec, GEC_REG_FC_CFG, fc_config); ++} ++ ++static void cns21xx_gec_internal_phy_config(struct cns21xx_gec *gec) ++{ ++ u32 phy_ctrl1; ++ u32 phy_addr; ++ ++ dev_info(&gec->netdev->dev, "Internal PHY\n"); ++ ++ phy_addr = CNS21XX_GEC_PHY_ADDR; ++ gec->phy_addr = phy_addr; ++ ++ phy_ctrl1 = cns21xx_gec_rr(gec, GEC_REG_PHY_CTRL1); ++ ++ /* set phy addr for auto-polling */ ++ phy_ctrl1 |= (phy_addr & 0x1f) << 24; ++ ++ /* set internal phy mode */ ++ /* internel 10/100 phy */ ++ phy_ctrl1 |= 0x1 << 18; ++ ++ /* MII */ ++ phy_ctrl1 &= ~(0x1 << 17); ++ ++ /* MAC mode */ ++ phy_ctrl1 &= ~(0x1 << 16); ++ ++ /* config PHY LED bit[13:12] */ ++ cns21xx_gec_read_phy(gec, phy_addr, 31, (u16 *)(&phy_ctrl1)); ++ /* clear LED control */ ++ phy_ctrl1 &= ~(0x3 << 12); ++ phy_ctrl1 |= FE_PHY_LED_MODE; ++ cns21xx_gec_write_phy(gec, phy_addr, 31, phy_ctrl1); ++ ++ cns21xx_gec_wr(gec, GEC_REG_PHY_CTRL1, phy_ctrl1); ++} ++ ++static void cns21xx_gec_vsc8601_phy_config(struct cns21xx_gec *gec) ++{ ++ u32 phy_ctrl1; ++ u32 phy_addr; ++ u16 phy_data; ++ ++ phy_addr = CNS21XX_GEC_PHY_ADDR; ++ gec->phy_addr = phy_addr; ++ ++ phy_ctrl1 = cns21xx_gec_rr(gec, GEC_REG_PHY_CTRL1); ++ ++ /* phy addr for auto-polling */ ++ phy_ctrl1 |= phy_addr << 24; ++ ++ /* set external phy mode */ ++ phy_ctrl1 &= ~(0x1 << 18); ++ ++ /* set RGMII */ ++ phy_ctrl1 |= (0x1 << 17); ++ ++ /* set MII interface */ ++ phy_ctrl1 &= ~(0x1 << 16); ++ ++ cns21xx_gec_wr(gec, GEC_REG_PHY_CTRL1, phy_ctrl1); ++ ++ /* set phy addr for auto-polling */ ++ phy_ctrl1 |= phy_addr << 24; ++ ++ /* set external phy mode */ ++ /* MII/RGMII interface */ ++ phy_ctrl1 &= ~(0x1 << 18); ++ ++ /* RGMII */ ++ phy_ctrl1 |= (0x1 << 17); ++ ++ /* MAC mode */ ++ phy_ctrl1 &= ~(0x1 << 16); ++ ++ cns21xx_gec_read_phy(gec, phy_addr, 3, &phy_data); ++ if ((phy_data & 0x000f) == 0x0000) { ++ /* type A chip */ ++ u16 tmp16; ++ ++ dev_info(&gec->netdev->dev, "VSC8601 Type A Chip\n"); ++ cns21xx_gec_write_phy(gec, phy_addr, 31, 0x52B5); ++ cns21xx_gec_write_phy(gec, phy_addr, 16, 0xAF8A); ++ ++ phy_data = 0x0; ++ cns21xx_gec_read_phy(gec, phy_addr, 18, &tmp16); ++ phy_data |= (tmp16 & ~0x0); ++ cns21xx_gec_write_phy(gec, phy_addr, 18, phy_data); ++ ++ phy_data = 0x0008; ++ cns21xx_gec_read_phy(gec, phy_addr, 17, &tmp16); ++ phy_data |= (tmp16 & ~0x000C); ++ cns21xx_gec_write_phy(gec, phy_addr, 17, phy_data); ++ ++ cns21xx_gec_write_phy(gec, phy_addr, 16, 0x8F8A); ++ cns21xx_gec_write_phy(gec, phy_addr, 16, 0xAF86); ++ ++ phy_data = 0x0008; ++ cns21xx_gec_read_phy(gec, phy_addr, 18, &tmp16); ++ phy_data |= (tmp16 & ~0x000C); ++ cns21xx_gec_write_phy(gec, phy_addr, 18, phy_data); ++ ++ phy_data = 0x0; ++ cns21xx_gec_read_phy(gec, phy_addr, 17, &tmp16); ++ phy_data |= (tmp16 & ~0x0); ++ cns21xx_gec_write_phy(gec, phy_addr, 17, phy_data); ++ ++ cns21xx_gec_write_phy(gec, phy_addr, 16, 0x8F8A); ++ ++ cns21xx_gec_write_phy(gec, phy_addr, 16, 0xAF82); ++ ++ phy_data = 0x0; ++ cns21xx_gec_read_phy(gec, phy_addr, 18, &tmp16); ++ phy_data |= (tmp16 & ~0x0); ++ cns21xx_gec_write_phy(gec, phy_addr, 18, phy_data); ++ ++ phy_data = 0x0100; ++ cns21xx_gec_read_phy(gec, phy_addr, 17, &tmp16); ++ phy_data |= (tmp16 & ~0x0180); ++ cns21xx_gec_write_phy(gec, phy_addr, 17, phy_data); ++ ++ cns21xx_gec_write_phy(gec, phy_addr, 16, 0x8F82); ++ ++ cns21xx_gec_write_phy(gec, phy_addr, 31, 0x0); ++ ++ /* Set port type: single port */ ++ cns21xx_gec_read_phy(gec, phy_addr, 9, &phy_data); ++ phy_data &= ~(0x1 << 10); ++ cns21xx_gec_write_phy(gec, phy_addr, 9, phy_data); ++ } else if ((phy_data & 0x000f) == 0x0001) { ++ /* type B chip */ ++ dev_info(&gec->netdev->dev, "VSC8601 Type B Chip\n"); ++ ++ cns21xx_gec_read_phy(gec, phy_addr, 23, &phy_data); ++ phy_data |= (0x1 << 8); /* set RGMII timing skew */ ++ cns21xx_gec_write_phy(gec, phy_addr, 23, phy_data); ++ } ++ ++ /* change to extened registers */ ++ cns21xx_gec_write_phy(gec, phy_addr, 31, 0x0001); ++ ++ cns21xx_gec_read_phy(gec, phy_addr, 28, &phy_data); ++ phy_data &= ~(0x3 << 14); /* set RGMII TX timing skew */ ++ phy_data |= (0x3 << 14); /* 2.0ns */ ++ phy_data &= ~(0x3 << 12); /* set RGMII RX timing skew */ ++ phy_data |= (0x3 << 12); /* 2.0ns */ ++ cns21xx_gec_write_phy(gec, phy_addr, 28, phy_data); ++ ++ /* change to normal registers */ ++ cns21xx_gec_write_phy(gec, phy_addr, 31, 0x0000); ++ ++#if 0 ++ /* set TX and RX clock skew */ ++ cns21xx_gec_wr(gec, GEC_REG_TEST0, (0x2 << 2) | (0x2 << 0)); ++#endif ++ ++ cns21xx_gec_wr(gec, GEC_REG_PHY_CTRL1, phy_ctrl1); ++} ++ ++static void cns21xx_gec_ip101a_phy_config(struct cns21xx_gec *gec) ++{ ++ u32 phy_ctrl1; ++ u32 phy_addr; ++ ++ dev_info(&gec->netdev->dev, "ICPlus IP101A\n"); ++ ++ phy_addr = 1; ++ gec->phy_addr = phy_addr; ++ ++ phy_ctrl1 = cns21xx_gec_rr(gec, GEC_REG_PHY_CTRL1); ++ ++ /* set phy addr for auto-polling */ ++ phy_ctrl1 |= phy_addr << 24; ++ ++ /* set external phy mode */ ++ /* MII/RGMII interface */ ++ phy_ctrl1 &= ~(0x1 << 18); ++ ++ /* MII */ ++ phy_ctrl1 &= ~(0x1 << 17); ++ ++ /* MAC mode */ ++ phy_ctrl1 &= ~(0x1 << 16); ++ ++ cns21xx_gec_wr(gec, GEC_REG_PHY_CTRL1, phy_ctrl1); ++} ++ ++static void cns21xx_gec_ip1001_phy_config(struct cns21xx_gec *gec) ++{ ++ u32 phy_ctrl1; ++ u32 phy_addr; ++ u16 phy_data; ++ ++ dev_info(&gec->netdev->dev, "ICPlus IP1001\n"); ++ ++ phy_addr = 1; ++ gec->phy_addr = phy_addr; ++ ++ phy_ctrl1 = cns21xx_gec_rr(gec, GEC_REG_PHY_CTRL1); ++ ++ /* set phy addr for auto-polling */ ++ phy_ctrl1 |= phy_addr << 24; ++ ++ /* set external phy mode */ ++ /* MII/RGMII interface */ ++ phy_ctrl1 &= ~(0x1 << 18); ++ ++ /* RGMII */ ++ phy_ctrl1 |= (0x1 << 17); ++ ++ /* MAC mode */ ++ phy_ctrl1 &= ~(0x1 << 16); ++ ++ cns21xx_gec_wr(gec, GEC_REG_PHY_CTRL1, phy_ctrl1); ++ cns21xx_gec_read_phy(gec, phy_addr, 2, &phy_data); ++ ++ /* set AN capability */ ++ cns21xx_gec_read_phy(gec, phy_addr, 4, &phy_data); ++ /* clear existing values */ ++ phy_data &= ~(0xf << 5); ++ /* 10Half */ ++ phy_data |= (0x1 << 5); ++ /* 10Full */ ++ phy_data |= (0x1 << 6); ++ /* 100Half */ ++ phy_data |= (0x1 << 7); ++ /* 100Full */ ++ phy_data |= (0x1 << 8); ++ /* FC on */ ++ phy_data |= (0x1 << 10); ++ cns21xx_gec_write_phy(gec, phy_addr, 4, phy_data); ++ ++ cns21xx_gec_read_phy(gec, phy_addr, 9, &phy_data); ++ /* 1000Full on */ ++ phy_data |= (0x1 << 9); ++ phy_data &= ~(0x1 << 10); ++ phy_data |= (0x1 << 12); ++ cns21xx_gec_write_phy(gec, phy_addr, 9, phy_data); ++ ++ cns21xx_gec_read_phy(gec, phy_addr, 16, &phy_data); ++ /* Smart function off */ ++ phy_data &= ~(0x1 << 11); ++ /* TX delay */ ++ phy_data |= (0x1 << 0); ++ /* RX delay */ ++ phy_data |= (0x1 << 1); ++ cns21xx_gec_write_phy(gec, phy_addr, 16, phy_data); ++ ++ cns21xx_gec_read_phy(gec, phy_addr, 16, &phy_data); ++ ++#if 0 ++ cns21xx_gec_read_phy(gec, phy_addr, 20, &phy_data); ++ phy_data &= ~(0x1<<2); ++ ++ phy_data |= (0x1<<9); ++ cns21xx_gec_write_phy(gec, phy_addr, 20, phy_data); ++#endif ++ ++ cns21xx_gec_read_phy(gec, phy_addr, 0, &phy_data); ++ phy_data |= (0x1 << 9); /* re-AN */ ++ cns21xx_gec_write_phy(gec, phy_addr, 0, phy_data); ++ ++ cns21xx_gec_read_phy(gec, phy_addr, 9, &phy_data); ++ ++ cns21xx_gec_wr(gec, GEC_REG_PHY_CTRL1, phy_ctrl1); ++} ++ ++static int cns21xx_gec_phy_config(struct cns21xx_gec *gec) ++{ ++ u32 phy_ctrl1; ++ ++ switch (gec->pdata->phy_type) { ++ case CNS21XX_GEC_PHY_TYPE_INTERNAL: ++ cns21xx_gec_internal_phy_config(gec); ++ break; ++ ++ case CNS21XX_GEC_PHY_TYPE_VSC8601: ++ cns21xx_gec_vsc8601_phy_config(gec); ++ break; ++ ++ case CNS21XX_GEC_PHY_TYPE_IP101A: ++ cns21xx_gec_ip101a_phy_config(gec); ++ break; ++ ++ case CNS21XX_GEC_PHY_TYPE_IP1001: ++ cns21xx_gec_ip1001_phy_config(gec); ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ ++ phy_ctrl1 = cns21xx_gec_rr(gec, GEC_REG_PHY_CTRL1); ++ ++ /* AN On */ ++ phy_ctrl1 |= (0x1 << 8); ++ if (!((phy_ctrl1 >> 8) & 0x1)) { /* AN disable */ ++ /* Force to FullDuplex mode */ ++ phy_ctrl1 &= ~(0x1 << 11); /* Half */ ++ ++ /* Force to 100Mbps mode */ ++ phy_ctrl1 &= ~(0x3 << 9); /* clear to 10M */ ++ phy_ctrl1 |= (0x1 << 9); /* set to 100M */ ++ } ++ ++ /* Force TX FlowCtrl On,in 1000M */ ++ phy_ctrl1 |= (0x1 << 13); ++ ++ /* Force TX FlowCtrl On, in 10/100M */ ++ phy_ctrl1 |= (0x1 << 12); ++ ++ /* Enable MII auto polling */ ++ phy_ctrl1 &= ~(0x1 << 7); ++ ++ cns21xx_gec_wr(gec, GEC_REG_PHY_CTRL1, phy_ctrl1); ++ cns21xx_gec_phy_powerdown(gec); ++ ++ return 0; ++} ++ ++static void cns21xx_gec_vlan_config(struct cns21xx_gec *gec) ++{ ++ /* setup VLAN entries */ ++ gec->vlans[0].vid = 2; ++ gec->vlans[0].control = 0; ++ gec->vlans[1].vid = 2; ++ gec->vlans[1].control = 1; ++ gec->vlans[2].vid = 1; ++ gec->vlans[2].control = 1; ++ gec->vlans[3].vid = 1; ++ gec->vlans[3].control = 0; ++ ++ cns21xx_gec_wr(gec, GEC_REG_VLAN_ID_0_1, ++ (gec->vlans[0].vid & 0x0fff) | ++ ((gec->vlans[1].vid & 0x0fff) << 16)); ++ ++ cns21xx_gec_wr(gec, GEC_REG_VLAN_ID_2_3, ++ (gec->vlans[2].vid & 0x0fff) | ++ ((gec->vlans[3].vid & 0x0fff) << 16)); ++ ++ cns21xx_gec_wr(gec, GEC_REG_VLAN_CTRL, ++ (gec->vlans[0].control << 0) | ++ (gec->vlans[1].control << 1) | ++ (gec->vlans[2].control << 2) | ++ (gec->vlans[3].control << 3)); ++} ++ ++static int cns21xx_gec_arl_config(struct cns21xx_gec *gec) ++{ ++ u32 arl_config; ++ ++ arl_config = cns21xx_gec_rr(gec, GEC_REG_ARL_CFG); ++ ++ /* Misc Mode ON */ ++ arl_config |= (0x1 << 4); ++ ++ /* My MAC only enable */ ++ arl_config |= (0x1 << 3); ++ ++ /* Learn SA On */ ++ arl_config &= ~(0x1 << 2); ++ ++ /* Forward MC to CPU */ ++ arl_config &= ~(0x1 << 1); ++ ++ /* Hash direct mode */ ++ arl_config &= ~(0x1); ++ ++ cns21xx_gec_wr(gec, GEC_REG_ARL_CFG, arl_config); ++ ++ return 0; ++} ++ ++static void cns21xx_gec_phy_powerdown(struct cns21xx_gec *gec) ++{ ++ u16 phy_data = 0; ++ ++ cns21xx_gec_read_phy(gec, gec->phy_addr, 0, &phy_data); ++ phy_data |= (0x1 << 11); ++ cns21xx_gec_write_phy(gec, gec->phy_addr, 0, phy_data); ++ ++ PWRMGT_SOFTWARE_RESET_CONTROL_REG |= (0x1 << 15); ++ PWRMGT_SOFTWARE_RESET_CONTROL_REG &= ~(0x1 << 15); ++} ++ ++static void cns21xx_gec_phy_powerup(struct cns21xx_gec *gec) ++{ ++ u16 phy_data = 0; ++ ++ cns21xx_gec_read_phy(gec, gec->phy_addr, 0, &phy_data); ++ phy_data &= ~(0x1 << 11); ++ cns21xx_gec_write_phy(gec, gec->phy_addr, 0, phy_data); ++ ++ PWRMGT_SOFTWARE_RESET_CONTROL_REG |= (0x1 << 15); ++} ++ ++static void cns21xx_gec_enable(struct cns21xx_gec *gec) ++{ ++ /* start Rx DMA */ ++ cns21xx_gec_wr(gec, GEC_REG_RX_DMA_CTRL, 1); ++ ++ cns21xx_gec_phy_powerup(gec); ++ internal_phy_start_timer(gec); ++} ++ ++static void cns21xx_gec_shutdown(struct cns21xx_gec *gec) ++{ ++ /* stop Rx and Tx DMA */ ++ cns21xx_gec_wr(gec, GEC_REG_RX_DMA_CTRL, 0); ++ cns21xx_gec_wr(gec, GEC_REG_TX_DMA_CTRL, 0); ++ ++ internal_phy_stop_timer(gec); ++} ++ ++static irqreturn_t cns21xx_gec_receive_isr(int irq, void *dev_id) ++{ ++ struct cns21xx_gec *gec = dev_id; ++ ++ if (!test_bit(NAPI_STATE_SCHED, &gec->napi.state)) { ++ if (likely(napi_schedule_prep(&gec->napi))) ++ __napi_schedule(&gec->napi); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static int cns21xx_gec_install_receive_isr(struct cns21xx_gec *gec) ++{ ++ int err; ++ ++ err = request_irq(gec->rxrc_irq, cns21xx_gec_receive_isr, ++ IRQF_SHARED, dev_name(&gec->netdev->dev), gec); ++ if (err) ++ dev_err(&gec->netdev->dev, ++ "unable to get IRQ %d (err=%d)\n", ++ gec->rxrc_irq, err); ++ ++ return err; ++} ++ ++static void cns21xx_gec_uninstall_receive_isr(struct cns21xx_gec *gec) ++{ ++ free_irq(gec->rxrc_irq, gec); ++} ++ ++static irqreturn_t cns21xx_gec_rxqf_isr(int irq, void *dev_id) ++{ ++ struct cns21xx_gec *gec = dev_id; ++ ++ /* ++ * because in normal state, fsql only invoke once ++ * and set_bit is atomic function, so don't mask it ++ */ ++ set_bit(0, &gec->rx_queue_full); ++ if (!test_bit(NAPI_STATE_SCHED, &gec->napi.state)) { ++ if (likely(napi_schedule_prep(&gec->napi))) ++ __napi_schedule(&gec->napi); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static int cns21xx_gec_install_rxqf_isr(struct cns21xx_gec *gec) ++{ ++ int err; ++ ++ /* QUEUE full interrupt handler */ ++ err = request_irq(gec->rxqf_irq, cns21xx_gec_rxqf_isr, ++ IRQF_SHARED, dev_name(&gec->netdev->dev), gec); ++ if (err) ++ dev_err(&gec->netdev->dev, ++ "unable to get IRQ %d (err=%d)\n", ++ gec->rxqf_irq, err); ++ ++ return err; ++} ++ ++static void cns21xx_gec_uninstall_rxqf_isr(struct cns21xx_gec *gec) ++{ ++ free_irq(gec->rxqf_irq, gec); ++} ++ ++static void cns21xx_gec_mib_reset(struct cns21xx_gec *gec) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ (void) cns21xx_gec_rr(gec, GEC_REG_RX_OK_PKT_CNTR); ++ (void) cns21xx_gec_rr(gec, GEC_REG_RX_OK_BYTE_CNTR); ++ (void) cns21xx_gec_rr(gec, GEC_REG_RX_RUNT_BYTE_CNTR); ++ (void) cns21xx_gec_rr(gec, GEC_REG_RX_OSIZE_DROP_PKT_CNTR); ++ (void) cns21xx_gec_rr(gec, GEC_REG_RX_NO_BUF_DROP_PKT_CNTR); ++ (void) cns21xx_gec_rr(gec, GEC_REG_RX_CRC_ERR_PKT_CNTR); ++ (void) cns21xx_gec_rr(gec, GEC_REG_RX_ARL_DROP_PKT_CNTR); ++ (void) cns21xx_gec_rr(gec, GEC_REG_MYVLANID_MISMATCH_DROP_PKT_CNTR); ++ (void) cns21xx_gec_rr(gec, GEC_REG_RX_CHKSUM_ERR_PKT_CNTR); ++ (void) cns21xx_gec_rr(gec, GEC_REG_RX_PAUSE_FRAME_PKT_CNTR); ++ (void) cns21xx_gec_rr(gec, GEC_REG_TX_OK_PKT_CNTR); ++ (void) cns21xx_gec_rr(gec, GEC_REG_TX_OK_BYTE_CNTR); ++ (void) cns21xx_gec_rr(gec, GEC_REG_TX_PAUSE_FRAME_CNTR); ++ local_irq_restore(flags); ++} ++ ++static void cns21xx_gec_mib_read(struct cns21xx_gec *gec) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ gec->mib_info.mib_rx_ok_pkt += ++ cns21xx_gec_rr(gec, GEC_REG_RX_OK_PKT_CNTR); ++ gec->mib_info.mib_rx_ok_byte += ++ cns21xx_gec_rr(gec, GEC_REG_RX_OK_BYTE_CNTR); ++ gec->mib_info.mib_rx_runt += ++ cns21xx_gec_rr(gec, GEC_REG_RX_RUNT_BYTE_CNTR); ++ gec->mib_info.mib_rx_over_size += ++ cns21xx_gec_rr(gec, GEC_REG_RX_OSIZE_DROP_PKT_CNTR); ++ gec->mib_info.mib_rx_no_buffer_drop += ++ cns21xx_gec_rr(gec, GEC_REG_RX_NO_BUF_DROP_PKT_CNTR); ++ gec->mib_info.mib_rx_crc_err += ++ cns21xx_gec_rr(gec, GEC_REG_RX_CRC_ERR_PKT_CNTR); ++ gec->mib_info.mib_rx_arl_drop += ++ cns21xx_gec_rr(gec, GEC_REG_RX_ARL_DROP_PKT_CNTR); ++ gec->mib_info.mib_rx_myvid_drop += ++ cns21xx_gec_rr(gec, GEC_REG_MYVLANID_MISMATCH_DROP_PKT_CNTR); ++ gec->mib_info.mib_rx_csum_err += ++ cns21xx_gec_rr(gec, GEC_REG_RX_CHKSUM_ERR_PKT_CNTR); ++ gec->mib_info.mib_rx_pause_frame += ++ cns21xx_gec_rr(gec, GEC_REG_RX_PAUSE_FRAME_PKT_CNTR); ++ gec->mib_info.mib_tx_ok_pkt += ++ cns21xx_gec_rr(gec, GEC_REG_TX_OK_PKT_CNTR); ++ gec->mib_info.mib_tx_ok_byte += ++ cns21xx_gec_rr(gec, GEC_REG_TX_OK_BYTE_CNTR); ++ gec->mib_info.mib_tx_pause_frame += ++ cns21xx_gec_rr(gec, GEC_REG_TX_PAUSE_FRAME_CNTR); ++ local_irq_restore(flags); ++} ++ ++static const char *cns21xx_gec_speed_str(u32 phy_ctrl1) ++{ ++ switch ((phy_ctrl1 >> 2) & 3) { ++ case 0: ++ return "10"; ++ case 1: ++ return "100"; ++ case 2: ++ return "1000"; ++ } ++ ++ return "???"; ++} ++ ++static irqreturn_t cns21xx_gec_status_isr(int irq, void *dev_id) ++{ ++ struct cns21xx_gec *gec = dev_id; ++ u32 int_status; ++ ++ int_status = cns21xx_gec_rr(gec, GEC_REG_INT); ++ cns21xx_gec_wr(gec, GEC_REG_INT, int_status); ++ ++ /* flush write */ ++ (void) cns21xx_gec_rr(gec, GEC_REG_INT); ++ ++ if (int_status & GEC_INT_MIB_COUNTER_TH) ++ cns21xx_gec_mib_read(gec); ++ ++ if (int_status & GEC_INT_PORT_STATUS_CHG) { ++ u32 phy_ctrl1; ++ ++ phy_ctrl1 = cns21xx_gec_rr(gec, GEC_REG_PHY_CTRL1); ++ if (phy_ctrl1 & BIT(0)) { ++ netif_carrier_on(gec->netdev); ++ dev_info(&gec->netdev->dev, ++ "link up (%sMbps/%s duplex)\n", ++ cns21xx_gec_speed_str(phy_ctrl1), ++ (phy_ctrl1 & BIT(4)) ? "Full" : "Half"); ++ } else { ++ netif_carrier_off(gec->netdev); ++ dev_info(&gec->netdev->dev, "link down\n"); ++ } ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static inline void cns21xx_gec_enable_interrupt(struct cns21xx_gec *gec, ++ u32 mask) ++{ ++ cns21xx_gec_wr(gec, GEC_REG_INT_MASK, ++ cns21xx_gec_rr(gec, GEC_REG_INT_MASK) & ~mask); ++} ++ ++static int cns21xx_gec_install_status_isr(struct cns21xx_gec *gec) ++{ ++ int err; ++ ++ err = request_irq(gec->status_irq, cns21xx_gec_status_isr, ++ IRQF_DISABLED, dev_name(&gec->netdev->dev), gec); ++ ++ if (err) { ++ dev_err(&gec->netdev->dev, ++ "unable to get IRQ %d (err=%d)\n", ++ gec->status_irq, err); ++ return err; ++ } ++ ++ cns21xx_gec_enable_interrupt(gec, GEC_INT_MIB_COUNTER_TH | ++ GEC_INT_PORT_STATUS_CHG); ++ ++ return 0; ++} ++ ++static inline void cns21xx_gec_uninstall_status_isr(struct cns21xx_gec *gec) ++{ ++ free_irq(gec->status_irq, gec); ++} ++ ++static void cns21xx_gec_uninstall_isr(struct cns21xx_gec *gec) ++{ ++ cns21xx_gec_uninstall_rxqf_isr(gec); ++ cns21xx_gec_uninstall_status_isr(gec); ++ cns21xx_gec_uninstall_receive_isr(gec); ++} ++ ++static int cns21xx_gec_install_isr(struct cns21xx_gec *gec) ++{ ++ int err; ++ ++ /* setup delayed interrupts */ ++ cns21xx_gec_wr(gec, GEC_REG_DLY_INT_CFG, ++ (1 << 16) | ++ ((CNS21XX_PEND_INT_COUNT & 0xFF) << 8) | ++ (CNS21XX_PEND_INT_TIME & 0xFF)); ++ ++ err = cns21xx_gec_install_receive_isr(gec); ++ if (err) ++ goto err_out; ++ ++ err = cns21xx_gec_install_rxqf_isr(gec); ++ if (err) ++ goto err_uninstall_receive; ++ ++ err = cns21xx_gec_install_status_isr(gec); ++ if (err) ++ goto err_uninstall_rxqf; ++ ++ return 0; ++ ++ err_uninstall_rxqf: ++ cns21xx_gec_uninstall_rxqf_isr(gec); ++ err_uninstall_receive: ++ cns21xx_gec_uninstall_receive_isr(gec); ++ err_out: ++ return err; ++} ++ ++static int cns21xx_gec_lan_open(struct net_device *dev) ++{ ++ struct cns21xx_gec *gec = netdev_priv(dev); ++ int err; ++ ++ dev_dbg(&gec->netdev->dev, "open\n"); ++ ++#ifdef MODULE ++ MOD_INC_USE_COUNT; ++#endif ++ ++ napi_enable(&gec->napi); ++ netif_start_queue(dev); ++ err = cns21xx_gec_install_isr(gec); ++ if (err) ++ goto err; ++ ++ cns21xx_gec_enable(gec); ++ ++ return 0; ++ ++ err: ++ netif_stop_queue(dev); ++ napi_disable(&gec->napi); ++ return err; ++} ++ ++static void cns21xx_gec_timeout(struct net_device *dev) ++{ ++ dev_dbg(&dev->dev, "timeout\n"); ++ netif_wake_queue(dev); ++ dev->trans_start = jiffies; ++} ++ ++static int cns21xx_gec_close(struct net_device *dev) ++{ ++ struct cns21xx_gec *gec = netdev_priv(dev); ++ ++ cns21xx_gec_phy_powerdown(gec); ++ cns21xx_gec_uninstall_isr(gec); ++ napi_disable(&gec->napi); ++ netif_stop_queue(dev); ++ cns21xx_gec_shutdown(gec); ++ ++#ifdef MODULE ++ MOD_DEC_USE_COUNT; ++#endif ++ ++ return 0; ++} ++ ++static inline struct sk_buff *cns21xx_gec_alloc_skb(void) ++{ ++ struct sk_buff *skb; ++ ++ skb = dev_alloc_skb(MAX_PACKET_LEN + 2); ++ ++ if (unlikely(!skb)) ++ return NULL; ++ ++ /* Make buffer alignment 2 beyond a 16 byte boundary ++ * this will result in a 16 byte aligned IP header after ++ * the 14 byte MAC header is removed ++ */ ++ skb_reserve(skb, 2); /* 16 bit alignment */ ++ ++ return skb; ++} ++ ++static inline int cns21xx_gec_tx_dma_size(struct cns21xx_gec *gec) ++{ ++ return gec->txring.count * sizeof(struct cns21xx_gec_txd); ++} ++ ++static inline int cns21xx_gec_rx_dma_size(struct cns21xx_gec *gec) ++{ ++ return gec->rxring.count * sizeof(struct cns21xx_gec_rxd); ++} ++ ++static void __init cns21xx_gec_buffer_free(struct cns21xx_gec *gec) ++{ ++ struct cns21xx_gec_ring *txring = &gec->txring; ++ struct cns21xx_gec_ring *rxring = &gec->rxring; ++ int i; ++ ++ if (rxring->desc_cpu) { ++ for (i = 0; i < rxring->count; i++) { ++ if (rxring->skbs[i]) ++ dev_kfree_skb(rxring->skbs[i]); ++ } ++ ++ dma_free_coherent(gec->parent, cns21xx_gec_rx_dma_size(gec), ++ rxring->desc_cpu, rxring->desc_dma); ++ memset((void *)&rxring, 0, cns21xx_gec_rx_dma_size(gec)); ++ } ++ ++ if (txring->desc_cpu) { ++ dma_free_coherent(gec->parent, cns21xx_gec_tx_dma_size(gec), ++ txring->desc_cpu, txring->desc_dma); ++ memset((void *)&txring, 0, cns21xx_gec_tx_dma_size(gec)); ++ } ++ ++ kfree(txring->skbs); ++ kfree(rxring->skbs); ++} ++ ++static int __init cns21xx_gec_buffer_alloc(struct cns21xx_gec *gec) ++{ ++ struct cns21xx_gec_ring *txring = &gec->txring; ++ struct cns21xx_gec_ring *rxring = &gec->rxring; ++ struct cns21xx_gec_rxd *rxd; ++ struct cns21xx_gec_txd *txd; ++ struct sk_buff *skb; ++ int err = -ENOMEM; ++ int i; ++ ++ rxring->skbs = kzalloc(rxring->count * sizeof(struct skb *), ++ GFP_KERNEL); ++ ++ if (rxring->skbs == NULL) { ++ dev_err(&gec->netdev->dev, ++ "%s allocation failed\n", "RX buffer"); ++ goto err_out; ++ } ++ ++ txring->skbs = kzalloc(txring->count * sizeof(struct skb *), ++ GFP_KERNEL); ++ ++ if (txring->skbs == NULL) { ++ dev_err(&gec->netdev->dev, ++ "%s allocation failed\n", "TX buffer"); ++ goto err_out; ++ } ++ ++ rxring->desc_cpu = dma_alloc_coherent(gec->parent, ++ cns21xx_gec_rx_dma_size(gec), ++ &rxring->desc_dma, ++ GFP_KERNEL); ++ if (!rxring->desc_cpu) { ++ dev_err(&gec->netdev->dev, ++ "%s allocation failed\n", "RX ring"); ++ goto err_out; ++ } ++ ++ txring->desc_cpu = dma_alloc_coherent(gec->parent, ++ cns21xx_gec_tx_dma_size(gec), ++ &txring->desc_dma, ++ GFP_KERNEL); ++ if (!txring->desc_cpu) { ++ dev_err(&gec->netdev->dev, ++ "%s allocation failed\n", "TX ring"); ++ goto err_out; ++ } ++ ++ /* Clean RX Memory */ ++ memset((void *)rxring->desc_cpu, 0, cns21xx_gec_rx_dma_size(gec)); ++ dev_dbg(&gec->netdev->dev, ++ "rxring->desc_cpu=0x%08X rxring->desc_dma=0x%08X\n", ++ (u32) rxring->desc_cpu, ++ (u32) rxring->desc_dma); ++ ++ /* Set cur_index Point to Zero */ ++ rxring->curr = 0; ++ rxd = rxring->desc_cpu; ++ for (i = 0; i < rxring->count; i++, rxd++) { ++ if (i == (rxring->count - 1)) { ++ /* End bit == 0; */ ++ rxd->eor = 1; ++ } ++ skb = cns21xx_gec_alloc_skb(); ++ if (!skb) { ++ dev_err(&gec->netdev->dev, ++ "%s allocation failed\n", "skb"); ++ goto err_out; ++ } ++ ++ /* Trans Packet from Virtual Memory to Physical Memory */ ++ rxring->skbs[i] = skb; ++ rxd->sdp = dma_map_single(gec->parent, ++ skb->data, ++ MAX_PACKET_LEN, ++ DMA_TO_DEVICE); ++ rxd->length = MAX_PACKET_LEN; ++ } ++ ++ /* Clear TX Memory */ ++ memset((void *)txring->desc_cpu, 0, cns21xx_gec_tx_dma_size(gec)); ++ dev_dbg(&gec->netdev->dev, ++ "txring->desc_cpu=0x%08X txring->desc_dma=0x%08X\n", ++ (u32) txring->desc_cpu, ++ (u32) txring->desc_dma); ++ ++ /* Set cur_index Point to Zero */ ++ txring->curr = 0; ++ txd = txring->desc_cpu; ++ for (i = 0; i < txring->count; i++, txd++) { ++ if (i == (txring->count - 1)) { ++ /* End of Ring ==1 */ ++ txd->eor = 1; ++ } ++ /* TX Ring , Cown == 1 */ ++ txd->cown = 1; ++ ++#ifdef CNS21XX_GEC_TX_HW_CHECKSUM ++ /* Enable Checksum */ ++ txd->ico = 1; ++ txd->uco = 1; ++ txd->tco = 1; ++#else ++ txd->ico = 0; ++ txd->uco = 0; ++ txd->tco = 0; ++#endif ++ /* clear txring->skbs */ ++ txring->skbs[i] = NULL; ++ } ++ ++ return 0; ++ ++err_out: ++ cns21xx_gec_buffer_free(gec); ++ return err; ++} ++ ++static int cns21xx_gec_get_rfd_buff(struct cns21xx_gec *gec, int index) ++{ ++ struct cns21xx_gec_ring *rxring = &gec->rxring; ++ struct cns21xx_gec_rxd *rxd; ++ struct sk_buff *skb; ++ unsigned char *data; ++ int len; ++ ++ /* TODO: get rxdesc ptr */ ++ rxd = ((struct cns21xx_gec_rxd *) rxring->desc_cpu) + index; ++ skb = rxring->skbs[index]; ++ ++ len = rxd->length; ++ ++ dma_unmap_single(gec->parent, rxd->sdp, len, ++ DMA_FROM_DEVICE); ++ ++ data = skb_put(skb, len); ++ ++ skb->dev = gec->netdev; ++ ++#ifdef CNS21XX_GEC_RX_HW_CHECKSUM ++ if (rxd->ipf == 1 || rxd->l4f == 1) { ++ if (rxd->prot != 0x11) { ++ skb->ip_summed = CHECKSUM_NONE; ++ } else { ++ /* CheckSum Fail */ ++ skb->dev->stats.rx_errors++; ++ goto freepacket; ++ } ++ } else { ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++ } ++#else ++ skb->ip_summed = CHECKSUM_NONE; ++#endif ++ ++ /* this line must, if no, packet will not send to network layer */ ++ skb->protocol = eth_type_trans(skb, skb->dev); ++ ++ skb->dev->stats.rx_packets++; ++ skb->dev->stats.rx_bytes += len; ++ skb->dev->last_rx = jiffies; ++ ++ /* if netif_rx any package, will let this driver core dump. */ ++ netif_receive_skb(skb); ++ ++ return 0; ++ ++freepacket: ++ dev_kfree_skb_any(skb); ++ return 0; ++} ++ ++static void cns21xx_gec_receive_packet(struct cns21xx_gec *gec, ++ int mode, int *work_done, int work_to_do) ++{ ++ struct cns21xx_gec_ring *rxring = &gec->rxring; ++ int rxsd_index; ++ u32 rxsd_current; ++ struct cns21xx_gec_rxd *rxd; ++ struct sk_buff *skb; ++ int i, rxcount = 0; ++ ++ rxd = ((struct cns21xx_gec_rxd *) rxring->desc_cpu) + rxring->curr; ++ rxsd_current = cns21xx_gec_rr(gec, GEC_REG_RX_DPTR); ++ rxsd_index = (rxsd_current - (u32)rxring->desc_dma) >> 4; ++ ++ if (rxsd_index > rxring->curr) { ++ rxcount = rxsd_index - rxring->curr; ++ } else if (rxsd_index < rxring->curr) { ++ rxcount = (rxring->count - rxring->curr) + ++ rxsd_index; ++ } else { ++ if (rxd->cown == 0) { ++ goto receive_packet_exit; ++ } else { ++ /* Queue Full */ ++ rxcount = rxring->count; ++ } ++ } ++ ++ for (i = 0; i < rxcount; i++) { ++ if (*work_done >= work_to_do) ++ break; ++ ++ ++(*work_done); ++ ++ if (rxd->cown != 0) { ++ /* Alloc New skb_buff */ ++ skb = cns21xx_gec_alloc_skb(); ++ ++ /* Check skb_buff */ ++ if (skb != NULL) { ++ cns21xx_gec_get_rfd_buff(gec, rxring->curr); ++ rxring->skbs[rxring->curr] = skb; ++ rxd->sdp = ++ dma_map_single(gec->parent, ++ skb->data, ++ MAX_PACKET_LEN, ++ DMA_TO_DEVICE); ++ rxd->length = MAX_PACKET_LEN; ++ ++ /* set cbit to 0 for CPU Transfer */ ++ rxd->cown = 0; ++ } else { ++ /* ++ * TODO: I will add dev->lp.stats->rx_dropped, ++ * it will effect the performance ++ */ ++ dev_warn(&gec->netdev->dev, ++ "skb allocation failed, reuse the buffer\n"); ++ ++ /* set cbit to 0 for CPU Transfer */ ++ rxd->cown = 0; ++ return; ++ } ++ } else { ++#if 0 ++ dev_err(&gec->netdev->dev, "encounter COWN == 0 BUG\n"); ++#endif ++ } ++ ++ if (rxring->curr == (rxring->count - 1)) { ++ rxring->curr = 0; ++ rxd = rxring->desc_cpu; ++ } else { ++ rxring->curr++; ++ rxd++; ++ } ++ } ++ ++ receive_packet_exit: ++ return; ++} ++ ++static int cns21xx_gec_poll(struct napi_struct *napi, int budget) ++{ ++ struct cns21xx_gec *gec; ++ int work_done = 0; ++ int work_to_do = budget; ++ ++ gec = container_of(napi, struct cns21xx_gec, napi); ++ cns21xx_gec_receive_packet(gec, 0, &work_done, work_to_do); ++ ++ budget -= work_done; ++ ++ /* if no Tx and not enough Rx work done, exit the polling mode */ ++ if (work_done) { ++ if (test_bit(0, &gec->rx_queue_full) == 1) { ++ /* queue full */ ++ clear_bit(0, &gec->rx_queue_full); ++ /* start Rx DMA */ ++ cns21xx_gec_wr(gec, GEC_REG_RX_DMA_CTRL, 1); ++ return 1; ++ } ++ } else { ++ napi_complete(&gec->napi); ++#ifdef CONFIG_STAR_NIC_NAPI_MASK_IRQ ++ enable_irq(gec->rxrc_irq); ++#endif ++ return 0; ++ } ++ ++ return work_done; ++} ++ ++static int cns21xx_gec_send_packet(struct sk_buff *skb, struct net_device *dev) ++{ ++ struct cns21xx_gec *gec = netdev_priv(dev); ++ struct cns21xx_gec_txd *txd; ++ struct cns21xx_gec_ring *txring = &gec->txring; ++ struct sk_buff *skb_free = NULL; ++ unsigned long flags; ++ unsigned int len; ++ ++ if (skb_padto(skb, ETH_ZLEN)) ++ return NETDEV_TX_OK; ++ ++ len = max_t(unsigned int, skb->len, ETH_ZLEN); ++ ++ spin_lock_irqsave(&gec->tx_lock, flags); ++ ++ txd = ((struct cns21xx_gec_txd *) txring->desc_cpu) + txring->curr; ++ if (txd->cown == 0) { ++ /* This TFD is busy */ ++ spin_unlock_irqrestore(&gec->tx_lock, flags); ++ /* re-queue the skb */ ++ return NETDEV_TX_BUSY; ++ } ++ ++ if (txd->sdp != 0) { ++ /* MUST TODO: Free skbuff */ ++ skb_free = txring->skbs[txring->curr]; ++ ++ dma_unmap_single(gec->parent, ++ txd->sdp, ++ txd->length, ++ DMA_TO_DEVICE); ++ txring->dirty = txring->curr + 1; ++ if (txring->dirty == txring->count) ++ txring->dirty = 0; ++ } ++ ++#ifdef CNS21XX_GEC_TX_HW_CHECKSUM ++ if (skb->protocol == __constant_htons(ETH_P_IP)) { ++ if (ip_hdr(skb)->protocol == IPPROTO_UDP) { ++ txd->uco = 1; ++ txd->tco = 0; ++ } else if (ip_hdr(skb)->protocol == IPPROTO_TCP) { ++ txd->uco = 0; ++ txd->tco = 1; ++ } else { ++ txd->uco = 0; ++ txd->tco = 0; ++ } ++ } else { ++ txd->ico = 0; ++ txd->uco = 0; ++ txd->tco = 0; ++ } ++#endif /* CNS21XX_GEC_TX_HW_CHECKSUM */ ++ ++ txring->skbs[txring->curr] = skb; ++ ++ txd->length = len; ++ txd->sdp = dma_map_single(gec->parent, skb->data, len, ++ DMA_TO_DEVICE); ++ ++ txd->fs = 1; ++ txd->ls = 1; ++ ++ /* Wake interrupt */ ++ txd->intr = 0; ++ txd->cown = 0; ++ ++ mb(); ++ ++ /* Start Tx DMA */ ++ cns21xx_gec_wr(gec, GEC_REG_TX_DMA_CTRL, 1); ++ ++ dev->stats.tx_packets++; ++ dev->stats.tx_bytes += skb->len; ++ dev->trans_start = jiffies; ++ ++ txring->curr++; ++ if (txring->curr == txring->count) ++ txring->curr = 0; ++ ++ spin_unlock_irqrestore(&gec->tx_lock, flags); ++ ++ if (skb_free) ++ dev_kfree_skb(skb_free); ++ ++ cns21xx_gec_timer_modify(gec, 10); ++ ++ return NETDEV_TX_OK; ++} ++ ++static void cns21xx_gec_set_mac_addr(struct cns21xx_gec *gec, ++ const char *mac_addr) ++{ ++ cns21xx_gec_wr(gec, GEC_REG_MY_MAC_H, ++ (mac_addr[0] << 8) | mac_addr[1]); ++ ++ cns21xx_gec_wr(gec, GEC_REG_MY_MAC_L, ++ (mac_addr[2] << 24) | (mac_addr[3] << 16) | ++ (mac_addr[4] << 8) | mac_addr[5]); ++ ++ dev_dbg(&gec->netdev->dev, "MAC address: %pM", mac_addr); ++} ++ ++static int cns21xx_gec_set_lan_mac_addr(struct net_device *dev, void *addr) ++{ ++ struct sockaddr *sock_addr = addr; ++ struct cns21xx_gec *gec = netdev_priv(dev); ++ ++ spin_lock_irq(&gec->lock); ++ memcpy(dev->dev_addr, sock_addr->sa_data, 6); ++ cns21xx_gec_set_mac_addr(gec, sock_addr->sa_data); ++ spin_unlock_irq(&gec->lock); ++ ++ return 0; ++} ++ ++static int __init cns21xx_gec_setup(struct cns21xx_gec *gec) ++{ ++ int err; ++ ++ /* set high */ ++ PWRMGT_SOFTWARE_RESET_CONTROL_REG |= (0x1 << 15); ++ /* set low */ ++ PWRMGT_SOFTWARE_RESET_CONTROL_REG &= ~(0x1 << 15); ++ /* set high */ ++ PWRMGT_SOFTWARE_RESET_CONTROL_REG |= (0x1 << 15); ++ /* set NIC clock to 67.5MHz */ ++ PWRMGT_SYSTEM_CLOCK_CONTROL_REG |= (0x1 << 7); ++ ++ /* enable NIC clock */ ++ HAL_PWRMGT_ENABLE_NIC_CLOCK(); ++#if 0 ++ cns21xx_gec_wr(gec, GEC_REG_MAC_CFG, 0x00527C00); ++#endif ++ udelay(100); ++ ++ /* Configure GPIO for NIC MDC/MDIO pins */ ++ HAL_MISC_ENABLE_MDC_MDIO_PINS(); ++ HAL_MISC_ENABLE_NIC_COL_PINS(); ++ ++#if 0 ++ MISC_GPIOA_PIN_ENABLE_REG |= (0x7 << 22); ++ MISC_FAST_ETHERNET_PHY_CONFIG_REG |= (FE_PHY_LED_MODE >> 12) & 0x3; ++ ++ /* set high */ ++ PWRMGT_SOFTWARE_RESET_CONTROL_REG |= (0x1 << 15); ++ /* set low */ ++ PWRMGT_SOFTWARE_RESET_CONTROL_REG &= ~(0x1 << 15); ++ /* set high */ ++ PWRMGT_SOFTWARE_RESET_CONTROL_REG |= (0x1 << 15); ++#endif ++ ++ /* disable all interrupt status sources */ ++ cns21xx_gec_wr(gec, GEC_REG_INT_MASK, ~(0)); ++ /* clear pending interrupts */ ++ cns21xx_gec_wr(gec, GEC_REG_INT, ~(0)); ++ ++ /* stop Rx and Tx DMA */ ++ cns21xx_gec_wr(gec, GEC_REG_TX_DMA_CTRL, 0); ++ cns21xx_gec_wr(gec, GEC_REG_RX_DMA_CTRL, 0); ++ ++ gec->txring.count = CNS21XX_GEC_NUM_TXDS; ++ gec->rxring.count = CNS21XX_GEC_NUM_RXDS; ++ err = cns21xx_gec_buffer_alloc(gec); ++ if (err) ++ return err; ++ ++ cns21xx_gec_mac_config(gec); ++ cns21xx_gec_fc_config(gec); ++ ++ err = cns21xx_gec_phy_config(gec); ++ if (err) { ++ cns21xx_gec_buffer_free(gec); ++ return err; ++ } ++ ++ cns21xx_gec_vlan_config(gec); ++ cns21xx_gec_arl_config(gec); ++ cns21xx_gec_set_mac_addr(gec, gec->netdev->dev_addr); ++ cns21xx_gec_mib_reset(gec); ++ ++ MISC_DEBUG_PROBE_SELECTION_REG = 0x00000125; /* 0x00000105 pb0_nic */ ++ ++ cns21xx_gec_wr(gec, GEC_REG_TX_DPTR, gec->txring.desc_dma); ++ cns21xx_gec_wr(gec, GEC_REG_TX_BASE_ADDR, gec->txring.desc_dma); ++ cns21xx_gec_wr(gec, GEC_REG_RX_DPTR, gec->rxring.desc_dma); ++ cns21xx_gec_wr(gec, GEC_REG_RX_BASE_ADDR, gec->rxring.desc_dma); ++ ++ cns21xx_gec_dma_config(gec); ++ internal_phy_init_timer(gec); ++ cns21xx_gec_timer_init(gec); ++ ++ return 0; ++} ++ ++static const struct net_device_ops cns21xx_gec_netdev_ops = { ++ .ndo_open = cns21xx_gec_lan_open, ++ .ndo_stop = cns21xx_gec_close, ++ .ndo_start_xmit = cns21xx_gec_send_packet, ++ .ndo_set_mac_address = cns21xx_gec_set_lan_mac_addr, ++ .ndo_tx_timeout = cns21xx_gec_timeout, ++ .ndo_validate_addr = eth_validate_addr, ++ .ndo_change_mtu = eth_change_mtu, ++}; ++ ++static int __init cns21xx_gec_probe(struct platform_device *pdev) ++{ ++ struct net_device *netdev; ++ struct cns21xx_gec *gec; ++ struct cns21xx_gec_plat_data *pdata; ++ int err; ++ ++ pdata = pdev->dev.platform_data; ++ if (!pdata) { ++ dev_dbg(&pdev->dev, "no platform data\n"); ++ err = -EINVAL; ++ goto err_out; ++ } ++ ++ if (!pdata->mac_addr) { ++ dev_dbg(&pdev->dev, "no mac address\n"); ++ err = -EINVAL; ++ goto err_out; ++ } ++ ++ netdev = alloc_etherdev(sizeof(struct cns21xx_gec)); ++ if (!netdev) { ++ err = -ENOMEM; ++ goto err_out; ++ } ++ ++ SET_NETDEV_DEV(netdev, &pdev->dev); ++ ++ gec = netdev_priv(netdev); ++ gec->pdata = pdata; ++ gec->parent = &pdev->dev; ++ ++ gec->mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!gec->mem_res) { ++ dev_dbg(&pdev->dev, "no iomem resource\n"); ++ err = -EINVAL; ++ goto err_free_netdev; ++ } ++ ++ gec->status_irq = platform_get_irq_byname(pdev, ++ CNS21XX_GEC_STATUS_IRQ_NAME); ++ if (gec->status_irq < 0) { ++ dev_dbg(&pdev->dev, "%s irq not specified\n", ++ CNS21XX_GEC_STATUS_IRQ_NAME); ++ err = -EINVAL; ++ goto err_free_netdev; ++ } ++ ++ gec->rxrc_irq = platform_get_irq_byname(pdev, ++ CNS21XX_GEC_RXRC_IRQ_NAME); ++ if (gec->rxrc_irq < 0) { ++ dev_dbg(&pdev->dev, "%s irq not specified\n", ++ CNS21XX_GEC_RXRC_IRQ_NAME); ++ err = -EINVAL; ++ goto err_free_netdev; ++ } ++ ++ gec->rxqf_irq = platform_get_irq_byname(pdev, ++ CNS21XX_GEC_RXQF_IRQ_NAME); ++ if (gec->rxqf_irq < 0) { ++ dev_dbg(&pdev->dev, "%s irq not specified\n", ++ CNS21XX_GEC_RXQF_IRQ_NAME); ++ err = -EINVAL; ++ goto err_free_netdev; ++ } ++ ++ gec->txtc_irq = platform_get_irq_byname(pdev, ++ CNS21XX_GEC_TXTC_IRQ_NAME); ++ if (gec->txtc_irq < 0) { ++ dev_dbg(&pdev->dev, "%s irq not specified\n", ++ CNS21XX_GEC_TXTC_IRQ_NAME); ++ err = -EINVAL; ++ goto err_free_netdev; ++ } ++ ++ gec->txqe_irq = platform_get_irq_byname(pdev, ++ CNS21XX_GEC_TXQE_IRQ_NAME); ++ if (gec->txqe_irq < 0) { ++ dev_dbg(&pdev->dev, "%s irq not specified\n", ++ CNS21XX_GEC_TXQE_IRQ_NAME); ++ err = -EINVAL; ++ goto err_free_netdev; ++ } ++ ++ if (!request_mem_region(gec->mem_res->start, ++ resource_size(gec->mem_res), pdev->name)) { ++ dev_err(&pdev->dev, "unable to request mem region\n"); ++ err = -EBUSY; ++ goto err_free_netdev; ++ } ++ ++ gec->base = ioremap(gec->mem_res->start, resource_size(gec->mem_res)); ++ if (!gec->base) { ++ dev_err(&pdev->dev, "ioremap failed \n"); ++ err = -ENXIO; ++ goto err_release_mem; ++ } ++ ++ platform_set_drvdata(pdev, netdev); ++ ++ spin_lock_init(&gec->lock); ++ spin_lock_init(&gec->tx_lock); ++ ++ netdev->base_addr = gec->mem_res->start; ++ netdev->netdev_ops = &cns21xx_gec_netdev_ops; ++#if defined(CNS21XX_GEC_TX_HW_CHECKSUM) ++ netdev->features = NETIF_F_IP_CSUM; ++#endif ++ memcpy(netdev->dev_addr, pdata->mac_addr, 6); ++ netif_napi_add(netdev, &gec->napi, cns21xx_gec_poll, 64); ++ ++ gec->netdev = netdev; ++ err = register_netdev(netdev); ++ if (err) ++ goto err_unmap; ++ ++ err = cns21xx_gec_setup(gec); ++ if (err) ++ goto err_unregister_netdev; ++ ++ return 0; ++ ++ err_unregister_netdev: ++ unregister_netdev(netdev); ++ err_unmap: ++ platform_set_drvdata(pdev, NULL); ++ iounmap(gec->base); ++ err_release_mem: ++ release_mem_region(gec->mem_res->start, resource_size(gec->mem_res)); ++ err_free_netdev: ++ free_netdev(netdev); ++ err_out: ++ return err; ++} ++ ++static int cns21xx_gec_remove(struct platform_device *pdev) ++{ ++ struct net_device *netdev = platform_get_drvdata(pdev); ++ struct cns21xx_gec *gec = netdev_priv(netdev); ++ ++ unregister_netdev(netdev); ++ platform_set_drvdata(pdev, NULL); ++ iounmap(gec->base); ++ release_mem_region(gec->mem_res->start, resource_size(gec->mem_res)); ++ free_netdev(netdev); ++ ++ return 0; ++} ++ ++static struct platform_driver cns21xx_gec_driver = { ++ .remove = cns21xx_gec_remove, ++ .driver = { ++ .name = "cns21xx-gec", ++ .owner = THIS_MODULE, ++ } ++}; ++ ++static int __init cns21xx_gec_init(void) ++{ ++ return platform_driver_probe(&cns21xx_gec_driver, cns21xx_gec_probe); ++} ++ ++static void __exit cns21xx_gec_exit(void) ++{ ++ platform_driver_unregister(&cns21xx_gec_driver); ++} ++ ++module_init(cns21xx_gec_init); ++module_exit(cns21xx_gec_exit); ++ ++#define INTERNAL_PHY_PATCH_CHECKCNT 16 ++#define INTERNAL_PHY_PATCH_CHECK_PERIOD 1000 /* ms */ ++ ++static void (*phy_statemachine)(struct cns21xx_gec*, int, int, int); ++ ++#define ETH3220_PHY_MON_PERIOD INTERNAL_PHY_PATCH_CHECK_PERIOD ++ ++/* phy monitor state */ ++#define NUM_PHY 1 ++#define PHY_STATE_INIT 0 ++#define LINK_DOWN_POSITIVE 1 ++#define WAIT_LINK_UP_POSITIVE 2 ++#define LINK_UP_POSITIVE 3 ++#define WAIT_BYPASS_LINK_UP_POSITIVE 4 ++#define BYPASS_AND_LINK_UP_POSITIVE 5 ++#define LINK_UP_8101_POSITIVE 6 ++#define WAIT_8101_LINK_UP_POSITIVE 7 ++ ++#define PHY_STATE_LAST (WAIT_8101_LINK_UP_POSITIVE+1) ++ ++/* time setting */ ++#define WAIT_BYPASS_LINK_UP_POSITIVE_TIMEOUT 5000 /* 5000 ms */ ++#define WAIT_BYPASS_LINK_UP_NEGATIVE_TIMEOUT 5000 /* 5000 ms */ ++#define LINK_DOWN_ABILITY_DETECT_TIMEOUT 5000 /* 5000 ms */ ++#define DETECT_8101_PERIOD 7000 /* 7000 ms */ ++#define WAIT_8101_LINK_UP_TIMEOUT 3000 /* 3000 ms */ ++ ++#define MAX_PHY_PORT 1 ++#define DEFAULT_AGC_TRAIN 16 ++#define MAX_AGC_TRAIN 16 /* train 16 times */ ++static int agc_train_num = DEFAULT_AGC_TRAIN; ++u32 port_displaybuf[NUM_PHY][MAX_AGC_TRAIN + 1] = { ++ {0} ++}; ++ ++static int cuv[3][3] = { ++ {1, 1, 4}, ++ {1, 1, 0}, ++ {1, 1, -4} ++}; ++ ++static u32 link_status_old; ++ ++struct eth3220_phy { ++ u16 state; ++ u16 linkdown_cnt; ++ u32 state_time; ++ u32 timer; ++}; ++ ++#define DEBUG_PHY_STATE_TRANSITION 1 ++#if DEBUG_PHY_STATE_TRANSITION ++/* ++ * show state transition of debug phy port. ++ * -1 for all ports ++ * -2 for disable all ports ++ * 0 - 4 for each port ++ */ ++static int debug_phy_port = -2; ++static char *phystate_name[] = { ++ "init", /* PHY_STATE_INIT */ ++ "ldp", /* LINK_DOWN_POSITIVE */ ++ "wait_lup", /* WAIT_LINK_UP_POSITIVE */ ++ "lup", /* LINK_UP_POSITIVE */ ++ "wait_bp_lup", /* WAIT_BYPASS_LINK_UP_POSITIVE */ ++ "bp_lup", /* BYPASS_AND_LINK_UP_POSITIVE */ ++ "8101_lup", /* LINK_UP_8101_POSITIVE */ ++ "wait_8101_lup", /* WAIT_8101_LINK_UP_POSITIVE */ ++ "err", ++}; ++#endif /* DEBUG_PHY_STATE_TRANSITION */ ++ ++static struct eth3220_phy phy[5] = { ++ {PHY_STATE_INIT, 0, 0, 0}, ++ {PHY_STATE_INIT, 0, 0, 0}, ++ {PHY_STATE_INIT, 0, 0, 0}, ++ {PHY_STATE_INIT, 0, 0, 0}, ++ {PHY_STATE_INIT, 0, 0, 0} ++}; ++ ++static u16 long_cable_global_reg[32] = { ++ 0x0000, 0x19a0, 0x1d00, 0x0e80, ++ 0x0f60, 0x07c0, 0x07e0, 0x03e0, ++ 0x0000, 0x0000, 0x0000, 0x2000, ++ 0x8250, 0x1700, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x204b, 0x01c2, 0x0000, ++ 0x0000, 0x0000, 0x0fff, 0x4100, ++ 0x9319, 0x0021, 0x0034, 0x270a | FE_PHY_LED_MODE ++}; ++ ++static u16 long_cable_local_reg[32] = { ++ 0x3100, 0x786d, 0x01c1, 0xca51, ++ 0x05e1, 0x45e1, 0x0003, 0x001c, ++ 0x2000, 0x9828, 0xf3c4, 0x400c, ++ 0xf8ff, 0x6940, 0xb906, 0x503c, ++ 0x8000, 0x297a, 0x1010, 0x5010, ++ 0x6ae1, 0x7c73, 0x783c, 0xfbdf, ++ 0x2080, 0x3244, 0x1301, 0x1a80, ++ 0x8e8f, 0x8000, 0x9c29, 0xa70a | FE_PHY_LED_MODE ++}; ++ ++/*=============================================================* ++ * eth3220ac_rt8101_phy_setting ++ *=============================================================*/ ++static void eth3220ac_rt8101_phy_setting(struct cns21xx_gec *gec, int port) ++{ ++ cns21xx_gec_write_phy(gec, port, 12, 0x18ff); ++ cns21xx_gec_write_phy(gec, port, 18, 0x6400); ++} ++ ++static void eth3220ac_release_bpf(struct cns21xx_gec *gec, int port) ++{ ++ cns21xx_gec_write_phy(gec, port, 18, 0x6210); ++} ++ ++static void eth3220ac_def_bpf(struct cns21xx_gec *gec, int port) ++{ ++ cns21xx_gec_write_phy(gec, port, 18, 0x6bff); ++} ++ ++static void eth3220ac_def_linkdown_setting(struct cns21xx_gec *gec, int port) ++{ ++ cns21xx_gec_write_phy(gec, port, 13, 0xe901); ++ cns21xx_gec_write_phy(gec, port, 14, 0xa3c6); ++} ++ ++static void eth3220ac_def_linkup_setting(struct cns21xx_gec *gec, int port) ++{ ++ cns21xx_gec_write_phy(gec, port, 13, 0x6901); ++ cns21xx_gec_write_phy(gec, port, 14, 0xa286); ++} ++ ++/*=============================================================* ++ * eth3220ac_link_agc: ++ *=============================================================*/ ++static int eth3220ac_link_agc(struct cns21xx_gec *gec, int port, int speed) ++{ ++ u16 reg; ++ u32 agc_data = 0; ++ u32 short_cable; ++ int i, jj; ++ ++ /* if speed = 100MHz, then continue */ ++ if (speed == 0) ++ return 0; ++ ++ short_cable = 0; ++ jj = 0; ++ for (i = 0; i < agc_train_num; i++) { ++ cns21xx_gec_read_phy(gec, port, 15, ®); ++ reg &= 0x7f; ++ if (reg <= 0x12) { ++ short_cable = 1; ++ jj++; ++ agc_data += (u32)reg; ++ } ++ } ++ ++ if (short_cable) ++ agc_data = (agc_data / jj) + 4; ++ else ++ agc_data = (cuv[2][0] * agc_data) / cuv[2][1] / ++ agc_train_num - 4; ++ ++ /* Fix AGC */ ++ agc_data = 0xd0 | (agc_data << 9); ++ cns21xx_gec_write_phy(gec, port, 15, agc_data); ++ udelay(1000); ++ cns21xx_gec_read_phy(gec, port, 15, ®); ++ reg &= ~(0x1 << 7); ++ cns21xx_gec_write_phy(gec, port, 15, reg); ++ ++ return 0; ++} ++ ++/*=============================================================* ++ * eth3220ac_unlink_agc: ++ *=============================================================*/ ++static void eth3220ac_unlink_agc(struct cns21xx_gec *gec, int port) ++{ ++ /* start AGC adaptive */ ++ cns21xx_gec_write_phy(gec, port, 15, 0xa050); ++} ++ ++/*=============================================================* ++ * eth3220ac_rt8100_check ++ *=============================================================*/ ++static int eth3220ac_rt8100_check(struct cns21xx_gec *gec, int port) ++{ ++ u16 reg, reg2; ++ ++ /* Read reg27 (error register) */ ++ cns21xx_gec_read_phy(gec, port, 27, ®); ++ /* if error exists, set Bypass Filter enable */ ++ if ((reg & 0xfffc)) { ++ cns21xx_gec_read_phy(gec, port, 15, ®); ++ cns21xx_gec_read_phy(gec, port, 27, ®2); ++ if ((reg2 & 0xfffc) && (((reg >> 9) & 0xff) < 0x1c)) { ++ dev_err(&gec->netdev->dev, "8100 pos err\n"); ++ ++ /* Bypass agcgain disable */ ++ cns21xx_gec_write_phy(gec, port, 15, (reg & (~(0x1 << 7)))); ++ ++ /* repeat counts when reaching threshold error */ ++ cns21xx_gec_write_phy(gec, port, 13, 0x4940); ++ ++ /* ++ * Speed up AN speed and compensate threshold ++ * phase error ++ */ ++ cns21xx_gec_write_phy(gec, port, 14, 0xa306); ++ ++ /* Bypass Filter enable */ ++ cns21xx_gec_read_phy(gec, port, 18, ®2); ++ ++ cns21xx_gec_write_phy(gec, port, 18, (reg | 0x400)); ++ ++ /* restart AN */ ++ cns21xx_gec_write_phy(gec, port, 0, 0x3300); ++ return 1; ++ } ++ } ++ return 0; ++} ++ ++ ++/*=============================================================* ++ * eth3220ac_rt8100_linkdown ++ *=============================================================*/ ++static void eth3220ac_rt8100_linkdown(struct cns21xx_gec *gec, int port) ++{ ++ u16 reg; ++ ++ /* Bypass Filter disable */ ++ cns21xx_gec_read_phy(gec, port, 18, ®); ++ cns21xx_gec_write_phy(gec, port, 18, (reg & (~(0x1 << 10)))); ++ eth3220ac_def_linkdown_setting(gec, port); ++} ++ ++static void eth3220ac_normal_phy_setting(struct cns21xx_gec *gec, int port) ++{ ++ cns21xx_gec_write_phy(gec, port, 12, 0xd8ff); ++ eth3220ac_def_bpf(gec, port); ++} ++ ++/*=============================================================* ++ * wp3220ac_phystate ++ *=============================================================*/ ++static void wp3220ac_phystate(struct cns21xx_gec *gec, int port, int link, int speed) ++{ ++ int next_state; ++ u16 reg, reg2; ++ ++ phy[port].timer += ETH3220_PHY_MON_PERIOD; ++ ++ if (link) { ++ /* Link up state */ ++ switch (phy[port].state) { ++ case LINK_UP_POSITIVE: ++ next_state = eth3220ac_rt8100_check(gec, port) ? ++ WAIT_BYPASS_LINK_UP_POSITIVE : ++ LINK_UP_POSITIVE; ++ break; ++ ++ case PHY_STATE_INIT: ++ case WAIT_LINK_UP_POSITIVE: ++ case LINK_DOWN_POSITIVE: ++ next_state = LINK_UP_POSITIVE; ++ eth3220ac_def_linkup_setting(gec, port); ++ eth3220ac_link_agc(gec, port, speed); ++ eth3220ac_release_bpf(gec, port); ++ break; ++ ++ case WAIT_BYPASS_LINK_UP_POSITIVE: ++ case BYPASS_AND_LINK_UP_POSITIVE: ++ next_state = BYPASS_AND_LINK_UP_POSITIVE; ++ break; ++ ++ case WAIT_8101_LINK_UP_POSITIVE: ++ next_state = LINK_UP_8101_POSITIVE; ++ eth3220ac_link_agc(gec, port, speed); ++ cns21xx_gec_write_phy(gec, port, 12, 0x98ff); ++ break; ++ ++ case LINK_UP_8101_POSITIVE: ++ next_state = LINK_UP_8101_POSITIVE; ++ break; ++ ++ default: ++ next_state = LINK_UP_POSITIVE; ++ eth3220ac_def_linkup_setting(gec, port); ++ eth3220ac_link_agc(gec, port, speed); ++ } ++ } else { ++ /* Link down state */ ++ switch (phy[port].state) { ++ case LINK_DOWN_POSITIVE: ++ cns21xx_gec_read_phy(gec, port, 5, ®); ++ cns21xx_gec_read_phy(gec, port, 28, ®2); ++ ++ /* AN Link Partner Ability Register or NLP */ ++ if (reg || (reg2 & 0x100)) ++ next_state = WAIT_LINK_UP_POSITIVE; ++ else ++ next_state = LINK_DOWN_POSITIVE; ++ break; ++ ++ case WAIT_LINK_UP_POSITIVE: ++ if (phy[port].state_time > ++ LINK_DOWN_ABILITY_DETECT_TIMEOUT) ++ next_state = LINK_DOWN_POSITIVE; ++ else ++ next_state = WAIT_LINK_UP_POSITIVE; ++ break; ++ ++ case WAIT_BYPASS_LINK_UP_POSITIVE: ++ /* set timeout = 5 sec */ ++ if (phy[port].state_time > ++ WAIT_BYPASS_LINK_UP_POSITIVE_TIMEOUT) { ++ next_state = LINK_DOWN_POSITIVE; ++ ++ /* Bypass Filter disable */ ++ eth3220ac_rt8100_linkdown(gec, port); ++ eth3220ac_def_bpf(gec, port); ++ } else { ++ next_state = WAIT_BYPASS_LINK_UP_POSITIVE; ++ } ++ break; ++ ++ case BYPASS_AND_LINK_UP_POSITIVE: ++ next_state = LINK_DOWN_POSITIVE; ++ eth3220ac_rt8100_linkdown(gec, port); ++ eth3220ac_def_bpf(gec, port); ++ break; ++ ++ case WAIT_8101_LINK_UP_POSITIVE: ++ if (phy[port].state_time > WAIT_8101_LINK_UP_TIMEOUT) { ++ next_state = LINK_DOWN_POSITIVE; ++ eth3220ac_normal_phy_setting(gec, port); ++ eth3220ac_def_linkdown_setting(gec, port); ++ } else { ++ next_state = WAIT_8101_LINK_UP_POSITIVE; ++ } ++ break; ++ ++ case LINK_UP_POSITIVE: ++ eth3220ac_unlink_agc(gec, port); ++ eth3220ac_def_linkdown_setting(gec, port); ++ eth3220ac_def_bpf(gec, port); ++ if (phy[port].timer > DETECT_8101_PERIOD) { ++ next_state = LINK_DOWN_POSITIVE; ++ phy[port].timer = 0; ++ phy[port].linkdown_cnt = 1; ++ } else { ++ if (++phy[port].linkdown_cnt > 2) { ++ next_state = WAIT_8101_LINK_UP_POSITIVE; ++ eth3220ac_rt8101_phy_setting(gec, port); ++ } else { ++ next_state = LINK_DOWN_POSITIVE; ++ } ++ } ++ break; ++ ++ case LINK_UP_8101_POSITIVE: ++ eth3220ac_normal_phy_setting(gec, port); ++ /* fall down to phy normal state */ ++ case PHY_STATE_INIT: ++ eth3220ac_def_linkdown_setting(gec, port); ++ eth3220ac_unlink_agc(gec, port); ++ default: ++ next_state = LINK_DOWN_POSITIVE; ++ } ++ } ++ ++ if (phy[port].state != next_state) { ++ phy[port].state_time = 0; ++#if DEBUG_PHY_STATE_TRANSITION ++ if (debug_phy_port == -1 || port == debug_phy_port) { ++ if ((phy[port].state < PHY_STATE_LAST) && ++ (next_state < PHY_STATE_LAST)) ++ dev_dbg(&gec->netdev->dev, ++ "p%d: %s->%s, %d, %d\n", ++ port, phystate_name[phy[port].state], ++ phystate_name[next_state], ++ phy[port].timer, ++ phy[port].linkdown_cnt); ++ else ++ dev_dbg(&gec->netdev->dev, ++ "p%d: %d->%d\n", ++ port, phy[port].state, next_state); ++ } ++#endif /* DEBUG_PHY_STATE_TRANSITION */ ++ } else { ++ phy[port].state_time += ETH3220_PHY_MON_PERIOD; ++ } ++ phy[port].state = next_state; ++} ++ ++/*=============================================================* ++ * eth3220_phyinit: ++ *=============================================================*/ ++static void eth3220ac_10m_agc(struct cns21xx_gec *gec) ++{ ++ /* Force 10M AGC = 2c globally */ ++ cns21xx_gec_write_phy(gec, 0, 31, 0x2f1a); ++ cns21xx_gec_write_phy(gec, 0, 12, 0x112c); ++ cns21xx_gec_write_phy(gec, 0, 13, 0x2e21); ++ cns21xx_gec_write_phy(gec, 0, 31, 0xaf1a); ++} ++ ++static void eth3220ac_dfe_init(struct cns21xx_gec *gec) ++{ ++ int i; ++ ++ cns21xx_gec_write_phy(gec, 0, 31, 0x2f1a); ++ for (i = 0; i <= 7; i++) ++ cns21xx_gec_write_phy(gec, 0, i, 0); ++ cns21xx_gec_write_phy(gec, 0, 11, 0x0b50); ++ cns21xx_gec_write_phy(gec, 0, 31, 0xaf1a); ++} ++ ++static void eth3220ac_phy_cdr_training_init(struct cns21xx_gec *gec) ++{ ++ int i; ++ ++ /* Force all port in 10M FD mode */ ++ for (i = 0; i < NUM_PHY; i++) ++ cns21xx_gec_write_phy(gec, i, 0, 0x100); ++ ++ /* Global setting */ ++ cns21xx_gec_write_phy(gec, 0, 31, 0x2f1a); ++ cns21xx_gec_write_phy(gec, 0, 29, 0x5021); ++ udelay(2000); /* 2ms, wait > 1 ms */ ++ cns21xx_gec_write_phy(gec, 0, 29, 0x4021); ++ udelay(2000); /* 2ms, wait > 1 ms */ ++ cns21xx_gec_write_phy(gec, 0, 31, 0xaf1a); ++ ++ /* Enable phy AN */ ++ for (i = 0; i < NUM_PHY; i++) ++ cns21xx_gec_write_phy(gec, i, 0, 0x3100); ++} ++ ++static void eth3220_phyinit(struct cns21xx_gec *gec) ++{ ++ eth3220ac_10m_agc(gec); ++ eth3220ac_dfe_init(gec); ++ eth3220ac_phy_cdr_training_init(gec); ++} ++ ++static void eth3220_phycfg(struct cns21xx_gec *gec, int phyaddr) ++{ ++ eth3220ac_def_linkdown_setting(gec, phyaddr); ++ eth3220ac_normal_phy_setting(gec, phyaddr); ++ cns21xx_gec_write_phy(gec, phyaddr, 9, 0x7f); ++} ++ ++static void internal_phy_patch_check(struct cns21xx_gec *gec, int init) ++{ ++ u32 short_cable_agc_detect_count; ++ u32 link_status = 0, link_speed; ++ u32 phy_addr = gec->phy_addr; ++ u16 phy_data; ++ u16 phy_data2; ++ int i; ++ ++ cns21xx_gec_read_phy(gec, phy_addr, 1, &phy_data); ++ udelay(100); ++ cns21xx_gec_read_phy(gec, phy_addr, 1, &phy_data2); ++ if (((phy_data & 0x0004) != 0x0004) && ++ ((phy_data2 & 0x0004) != 0x0004)) { ++ /* link down */ ++ short_cable_agc_detect_count = 0; ++ for (i = 0; i < INTERNAL_PHY_PATCH_CHECKCNT; i++) { ++ cns21xx_gec_read_phy(gec, phy_addr, 15, &phy_data); ++ udelay(1000); ++ if ((phy_data & 0x7F) <= 0x12) { ++ /* short cable */ ++ short_cable_agc_detect_count++; ++ break; ++ } ++ } ++ if (short_cable_agc_detect_count) { ++ u32 mac_cfg; ++ ++ /* short cable */ ++ phy_statemachine = wp3220ac_phystate; ++ eth3220_phyinit(gec); ++ cns21xx_gec_read_phy(gec, phy_addr, 1, &phy_data); ++ if (phy_data & 0x0040) ++ link_status = 1; ++ ++ mac_cfg = cns21xx_gec_rr(gec, GEC_REG_MAC_CFG); ++ if ((mac_cfg & 0xC) == 0x4) /* 100Mbps */ ++ link_speed = 1; ++ else ++ link_speed = 0; ++ ++ link_status_old = link_status; ++ for (i = 0; i < MAX_PHY_PORT; link_status >>= 1, i++) ++ eth3220_phycfg(gec, i); ++ } else { ++ /* long cable */ ++ /* set to global domain */ ++ cns21xx_gec_write_phy(gec, phy_addr, 31, ++ 0x2f1a); ++ for (i = 0; i < 32; i++) ++ cns21xx_gec_write_phy(gec, phy_addr, i, ++ long_cable_global_reg[i]); ++ ++ /* set to local domain */ ++ cns21xx_gec_write_phy(gec, phy_addr, 31, ++ 0xaf1a); ++ for (i = 0; i < 32; i++) ++ cns21xx_gec_write_phy(gec, phy_addr, i, ++ long_cable_local_reg[i]); ++ } ++ } ++} ++ ++static void internal_phy_timer_func(unsigned long data) ++{ ++ struct cns21xx_gec *gec = (struct cns21xx_gec *) data; ++ ++ internal_phy_patch_check(gec, 0); ++ mod_timer(&gec->internal_phy_timer, ++ jiffies + INTERNAL_PHY_PATCH_CHECK_PERIOD / 10); ++} ++ ++static void internal_phy_init_timer(struct cns21xx_gec *gec) ++{ ++ init_timer(&gec->internal_phy_timer); ++ gec->internal_phy_timer.function = internal_phy_timer_func; ++ gec->internal_phy_timer.data = (unsigned long) gec; ++} ++ ++static void internal_phy_start_timer(struct cns21xx_gec *gec) ++{ ++ dev_dbg(&gec->netdev->dev, "starting patch check.\n"); ++ ++ internal_phy_patch_check(gec, 1); ++ mod_timer(&gec->internal_phy_timer, ++ jiffies + INTERNAL_PHY_PATCH_CHECK_PERIOD / 10); ++} ++ ++static void internal_phy_stop_timer(struct cns21xx_gec *gec) ++{ ++ dev_dbg(&gec->netdev->dev, "stopping patch check.\n"); ++ ++ del_timer_sync(&gec->internal_phy_timer); ++} +--- /dev/null ++++ b/drivers/net/ethernet/cns21xx/Kconfig +@@ -0,0 +1,7 @@ ++config CNS21XX_GEC ++ tristate "CNS21XX Gigabit Ethernet Controller support" ++ depends on ARCH_CNS21XX ++ help ++ If you wish to compile a kernel for Cavium Networks CNS21XX ++ with ethernet support, then you should always answer Y to this. ++ +--- /dev/null ++++ b/drivers/net/ethernet/cns21xx/Makefile +@@ -0,0 +1,7 @@ ++# ++# Makefile for the Cavium Networks CNS21XX ethernet driver ++# ++ ++cns21xx_gec-y += cns21xx_gec_main.o ++ ++obj-$(CONFIG_CNS21XX_GEC) += cns21xx_gec.o +--- a/drivers/net/ethernet/Kconfig ++++ b/drivers/net/ethernet/Kconfig +@@ -32,6 +32,7 @@ source "drivers/net/ethernet/calxeda/Kco + source "drivers/net/ethernet/chelsio/Kconfig" + source "drivers/net/ethernet/cirrus/Kconfig" + source "drivers/net/ethernet/cisco/Kconfig" ++source "drivers/net/ethernet/cns21xx/Kconfig" + source "drivers/net/ethernet/davicom/Kconfig" + + config DNET +--- a/drivers/net/ethernet/Makefile ++++ b/drivers/net/ethernet/Makefile +@@ -18,6 +18,7 @@ obj-$(CONFIG_NET_CALXEDA_XGMAC) += calxe + obj-$(CONFIG_NET_VENDOR_CHELSIO) += chelsio/ + obj-$(CONFIG_NET_VENDOR_CIRRUS) += cirrus/ + obj-$(CONFIG_NET_VENDOR_CISCO) += cisco/ ++obj-$(CONFIG_CNS21XX_GEC) += cns21xx/ + obj-$(CONFIG_DM9000) += davicom/ + obj-$(CONFIG_DNET) += dnet.o + obj-$(CONFIG_NET_VENDOR_DEC) += dec/ diff --git a/target/linux/cns21xx/patches-3.8/201-cns21xx-add-usb-devices.patch b/target/linux/cns21xx/patches-3.8/201-cns21xx-add-usb-devices.patch new file mode 100644 index 0000000000..c9299b6af3 --- /dev/null +++ b/target/linux/cns21xx/patches-3.8/201-cns21xx-add-usb-devices.patch @@ -0,0 +1,104 @@ +--- /dev/null ++++ b/arch/arm/mach-cns21xx/dev-usb.c +@@ -0,0 +1,71 @@ ++/* ++ * Copyright (c) 2008 Cavium Networks ++ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License, Version 2, as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/init.h> ++#include <linux/irq.h> ++#include <linux/dma-mapping.h> ++#include <linux/platform_device.h> ++ ++#include <mach/cns21xx.h> ++ ++static u64 cns21xx_usb_dmamask = DMA_BIT_MASK(32); ++ ++static struct resource cns21xx_ohci_resources[] = { ++ [0] = { ++ .start = CNS21XX_OHCI_CTRL_BASE, ++ .end = CNS21XX_OHCI_CTRL_BASE + SZ_1M - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = CNS21XX_IRQ_OHCI, ++ .end = CNS21XX_IRQ_OHCI, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device cns21xx_ohci_device = { ++ .name = "cns21xx-ohci", ++ .id = -1, ++ .dev = { ++ .dma_mask = &cns21xx_usb_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ }, ++ .resource = cns21xx_ohci_resources, ++ .num_resources = ARRAY_SIZE(cns21xx_ohci_resources), ++}; ++ ++static struct resource cns21xx_ehci_resources[] = { ++ [0] = { ++ .start = CNS21XX_EHCI_CTRL_BASE, ++ .end = CNS21XX_EHCI_CTRL_BASE + SZ_1M - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = CNS21XX_IRQ_EHCI, ++ .end = CNS21XX_IRQ_EHCI, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device cns21xx_ehci_device = { ++ .name = "cns21xx-ehci", ++ .id = -1, ++ .dev = { ++ .dma_mask = &cns21xx_usb_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ }, ++ .resource = cns21xx_ehci_resources, ++ .num_resources = ARRAY_SIZE(cns21xx_ehci_resources), ++}; ++ ++void __init cns21xx_register_usb(void) ++{ ++ platform_device_register(&cns21xx_ehci_device); ++ platform_device_register(&cns21xx_ohci_device); ++} +--- a/arch/arm/mach-cns21xx/Kconfig ++++ b/arch/arm/mach-cns21xx/Kconfig +@@ -3,4 +3,7 @@ if ARCH_CNS21XX + menu "Cavium Networks CNS21xx based machines" + endmenu + ++config CNS21XX_DEV_USB ++ def_bool n ++ + endif +--- a/arch/arm/mach-cns21xx/Makefile ++++ b/arch/arm/mach-cns21xx/Makefile +@@ -6,5 +6,8 @@ + + obj-y := core.o devices.o gpio.o irq.o mm.o time.o + ++# devices ++obj-$(CONFIG_CNS21XX_DEV_USB) += dev-usb.o ++ + # machine specific files + +--- a/arch/arm/mach-cns21xx/common.h ++++ b/arch/arm/mach-cns21xx/common.h +@@ -19,5 +19,6 @@ extern struct sys_timer cns21xx_timer; + + int cns21xx_register_uart0(void); + int cns21xx_register_uart1(void); ++int cns21xx_register_usb(void); + + #endif /* _MACH_CNS21XX_COMMON_H */ diff --git a/target/linux/cns21xx/patches-3.8/202-cns21xx-add-watchdog-device.patch b/target/linux/cns21xx/patches-3.8/202-cns21xx-add-watchdog-device.patch new file mode 100644 index 0000000000..7b88c53a2e --- /dev/null +++ b/target/linux/cns21xx/patches-3.8/202-cns21xx-add-watchdog-device.patch @@ -0,0 +1,63 @@ +--- a/arch/arm/mach-cns21xx/common.h ++++ b/arch/arm/mach-cns21xx/common.h +@@ -20,5 +20,6 @@ extern struct sys_timer cns21xx_timer; + int cns21xx_register_uart0(void); + int cns21xx_register_uart1(void); + int cns21xx_register_usb(void); ++int cns21xx_register_wdt(void); + + #endif /* _MACH_CNS21XX_COMMON_H */ +--- a/arch/arm/mach-cns21xx/devices.c ++++ b/arch/arm/mach-cns21xx/devices.c +@@ -11,6 +11,7 @@ + #include <linux/init.h> + #include <linux/platform_device.h> + #include <linux/serial_8250.h> ++#include <linux/fa_wdt.h> + + #include <mach/irqs.h> + #include <mach/hardware.h> +@@ -77,3 +78,32 @@ int __init cns21xx_register_uart1(void) + HAL_MISC_ENABLE_UART1_PINS(); + return platform_device_register(&cns21xx_uart1_device); + } ++ ++static struct resource cns21xx_wdt_resources[] = { ++ { ++ .start = CNS21XX_WDT_BASE, ++ .end = CNS21XX_WDT_BASE + SZ_4K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++}; ++ ++#define CNS21XX_WDT_CLOCK 10 /* 10 Hz */ ++ ++static struct fa_wdt_platform_data cns21xx_wdt_data = { ++ .clock = CNS21XX_WDT_CLOCK, ++}; ++ ++static struct platform_device cns21xx_wdt_device = { ++ .name = "fa-wdt", ++ .id = -1, ++ .resource = cns21xx_wdt_resources, ++ .num_resources = ARRAY_SIZE(cns21xx_wdt_resources), ++ .dev = { ++ .platform_data = &cns21xx_wdt_data, ++ }, ++}; ++ ++int __init cns21xx_register_wdt(void) ++{ ++ return platform_device_register(&cns21xx_wdt_device); ++} +--- a/drivers/watchdog/Kconfig ++++ b/drivers/watchdog/Kconfig +@@ -366,7 +366,7 @@ config IMX2_WDT + + config FA_WATCHDOG + tristate "Faraday watchdog" +- depends on ARCH_GEMINI ++ depends on ARCH_GEMINI || ARCH_CNS21XX + help + Say Y here if you want support for the built-in watchdog timer + found in some Faraday FA526 based SoCs. diff --git a/target/linux/cns21xx/patches-3.8/203-cns21xx-add-spi-master-device.patch b/target/linux/cns21xx/patches-3.8/203-cns21xx-add-spi-master-device.patch new file mode 100644 index 0000000000..31d210b4fc --- /dev/null +++ b/target/linux/cns21xx/patches-3.8/203-cns21xx-add-spi-master-device.patch @@ -0,0 +1,117 @@ +--- /dev/null ++++ b/arch/arm/mach-cns21xx/dev-spi-master.c +@@ -0,0 +1,83 @@ ++/* ++ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License, Version 2, as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/spi/spi.h> ++#include <linux/dma-mapping.h> ++#include <linux/platform_device.h> ++ ++#include <mach/hardware.h> ++#include <mach/cns21xx.h> ++#include <mach/cns21xx_misc.h> ++#include <mach/cns21xx_powermgmt.h> ++#include <mach/irqs.h> ++ ++#include "common.h" ++ ++static u64 spi_dmamask = DMA_BIT_MASK(32); ++static struct resource cns21xx_spi_resources[] = { ++ [0] = { ++ .start = CNS21XX_SPI_BASE, ++ .end = CNS21XX_SPI_BASE + SZ_4K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = CNS21XX_IRQ_SPI, ++ .end = CNS21XX_IRQ_SPI, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device cns21xx_spi_master_device = { ++ .name = "cns21xx-spi", ++ .id = -1, ++ .dev = { ++ .dma_mask = &spi_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ }, ++ .resource = cns21xx_spi_resources, ++ .num_resources = ARRAY_SIZE(cns21xx_spi_resources), ++}; ++ ++void __init cns21xx_register_spi_master(int id, struct spi_board_info *info, ++ unsigned int n) ++{ ++ unsigned int i; ++ ++ /* Enable SPI pins */ ++ HAL_MISC_ENABLE_SPIDR_PINS(); ++ HAL_MISC_ENABLE_SPICLK_PINS(); ++ for (i = 0; i < n; i++) { ++ switch (info[i].chip_select) { ++ case 0: ++ HAL_MISC_ENABLE_SPICSN0_PINS(); ++ break; ++ case 1: ++ HAL_MISC_ENABLE_SPICSN1_PINS(); ++ break; ++ case 2: ++ HAL_MISC_ENABLE_SPICSN2_PINS(); ++ break; ++ case 3: ++ HAL_MISC_ENABLE_SPICSN3_PINS(); ++ break; ++ } ++ } ++ ++ /* Disable SPI serial flash access through 0x30000000 region */ ++ HAL_MISC_DISABLE_SPI_SERIAL_FLASH_BANK_ACCESS(); ++ ++ /* Enable SPI clock */ ++ HAL_PWRMGT_ENABLE_SPI_CLOCK(); ++ ++ cns21xx_spi_master_device.id = id; ++ ++ spi_register_board_info(info, n); ++ platform_device_register(&cns21xx_spi_master_device); ++} +--- a/arch/arm/mach-cns21xx/Kconfig ++++ b/arch/arm/mach-cns21xx/Kconfig +@@ -6,4 +6,7 @@ endmenu + config CNS21XX_DEV_USB + def_bool n + ++config CNS21XX_DEV_SPI_MASTER ++ def_bool n ++ + endif +--- a/arch/arm/mach-cns21xx/Makefile ++++ b/arch/arm/mach-cns21xx/Makefile +@@ -8,6 +8,7 @@ obj-y := core.o devices.o gpio.o irq.o + + # devices + obj-$(CONFIG_CNS21XX_DEV_USB) += dev-usb.o ++obj-$(CONFIG_CNS21XX_DEV_SPI_MASTER) += dev-spi-master.o + + # machine specific files + +--- a/arch/arm/mach-cns21xx/common.h ++++ b/arch/arm/mach-cns21xx/common.h +@@ -22,4 +22,8 @@ int cns21xx_register_uart1(void); + int cns21xx_register_usb(void); + int cns21xx_register_wdt(void); + ++struct spi_board_info; ++void __init cns21xx_register_spi_master(int id, struct spi_board_info *info, ++ unsigned int n); ++ + #endif /* _MACH_CNS21XX_COMMON_H */ diff --git a/target/linux/cns21xx/patches-3.8/204-cns21xx-add-gec-device.patch b/target/linux/cns21xx/patches-3.8/204-cns21xx-add-gec-device.patch new file mode 100644 index 0000000000..910913bcc3 --- /dev/null +++ b/target/linux/cns21xx/patches-3.8/204-cns21xx-add-gec-device.patch @@ -0,0 +1,178 @@ +--- a/arch/arm/mach-cns21xx/Kconfig ++++ b/arch/arm/mach-cns21xx/Kconfig +@@ -3,6 +3,9 @@ if ARCH_CNS21XX + menu "Cavium Networks CNS21xx based machines" + endmenu + ++config CNS21XX_DEV_GEC ++ def_bool n ++ + config CNS21XX_DEV_USB + def_bool n + +--- a/arch/arm/mach-cns21xx/Makefile ++++ b/arch/arm/mach-cns21xx/Makefile +@@ -7,6 +7,7 @@ + obj-y := core.o devices.o gpio.o irq.o mm.o time.o + + # devices ++obj-$(CONFIG_CNS21XX_DEV_GEC) += dev-gec.o + obj-$(CONFIG_CNS21XX_DEV_USB) += dev-usb.o + obj-$(CONFIG_CNS21XX_DEV_SPI_MASTER) += dev-spi-master.o + +--- /dev/null ++++ b/arch/arm/mach-cns21xx/dev-gec.c +@@ -0,0 +1,98 @@ ++/* ++ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License, Version 2, as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/init.h> ++#include <linux/dma-mapping.h> ++#include <linux/platform_device.h> ++#include <linux/etherdevice.h> ++ ++#include <asm/sizes.h> ++#include <mach/cns21xx.h> ++#include <mach/irqs.h> ++ ++#include "dev-gec.h" ++ ++static u8 cns21xx_ethaddr[ETH_ALEN]; ++struct cns21xx_gec_plat_data cns21xx_gec_data; ++ ++static struct resource cns21xx_gec_resources[] = { ++ { ++ .start = CNS21XX_NIC_BASE, ++ .end = CNS21XX_NIC_BASE + SZ_4K - 1, ++ .flags = IORESOURCE_MEM, ++ }, { ++ .name = CNS21XX_GEC_STATUS_IRQ_NAME, ++ .start = CNS21XX_IRQ_NIC_STATUS, ++ .end = CNS21XX_IRQ_NIC_STATUS, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .name = CNS21XX_GEC_RXRC_IRQ_NAME, ++ .start = CNS21XX_IRQ_NIC_RXRC, ++ .end = CNS21XX_IRQ_NIC_RXRC, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .name = CNS21XX_GEC_RXQF_IRQ_NAME, ++ .start = CNS21XX_IRQ_NIC_RXQF, ++ .end = CNS21XX_IRQ_NIC_RXQF, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .name = CNS21XX_GEC_TXTC_IRQ_NAME, ++ .start = CNS21XX_IRQ_NIC_TXTC, ++ .end = CNS21XX_IRQ_NIC_TXTC, ++ .flags = IORESOURCE_IRQ, ++ }, { ++ .name = CNS21XX_GEC_TXQE_IRQ_NAME, ++ .start = CNS21XX_IRQ_NIC_TXQE, ++ .end = CNS21XX_IRQ_NIC_TXQE, ++ .flags = IORESOURCE_IRQ, ++ } ++}; ++ ++static u64 cns21xx_gec_dmamask = DMA_BIT_MASK(32); ++static struct platform_device cns21xx_gec_device = { ++ .name = "cns21xx-gec", ++ .id = -1, ++ .resource = cns21xx_gec_resources, ++ .num_resources = ARRAY_SIZE(cns21xx_gec_resources), ++ .dev = { ++ .dma_mask = &cns21xx_gec_dmamask, ++ .coherent_dma_mask = DMA_BIT_MASK(32), ++ .platform_data = &cns21xx_gec_data, ++ }, ++}; ++ ++static int __init cns21xx_ethaddr_setup(char *str) ++{ ++ int t; ++ ++ t = sscanf(str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", ++ &cns21xx_ethaddr[0], &cns21xx_ethaddr[1], ++ &cns21xx_ethaddr[2], &cns21xx_ethaddr[3], ++ &cns21xx_ethaddr[4], &cns21xx_ethaddr[5]); ++ ++ if (t != ETH_ALEN) ++ pr_err("cns21xx: failed to parse mac address \"%s\"\n", str); ++ ++ return 1; ++} ++ ++__setup("ethaddr=", cns21xx_ethaddr_setup); ++ ++__init int cns21xx_register_gec(void) ++{ ++ if (cns21xx_gec_data.mac_addr == NULL) ++ cns21xx_gec_data.mac_addr = cns21xx_ethaddr; ++ ++ if (!is_valid_ether_addr(cns21xx_gec_data.mac_addr)) { ++ random_ether_addr(cns21xx_gec_data.mac_addr); ++ pr_debug("cns21xx: using random MAC address \"%s\"\n", ++ cns21xx_gec_data.mac_addr); ++ } ++ ++ return platform_device_register(&cns21xx_gec_device); ++} +--- /dev/null ++++ b/arch/arm/mach-cns21xx/dev-gec.h +@@ -0,0 +1,18 @@ ++/* ++ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License, Version 2, as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef _CNS21XX_DEV_GEC_H ++#define _CNS21XX_DEV_GEC_H ++ ++#include <mach/cns21xx_gec_platform.h> ++ ++extern struct cns21xx_gec_plat_data cns21xx_gec_data; ++ ++__init int cns21xx_register_gec(void); ++ ++#endif /* _CNS21XX_DEV_GEC_H */ +--- /dev/null ++++ b/arch/arm/mach-cns21xx/include/mach/cns21xx_gec_platform.h +@@ -0,0 +1,31 @@ ++/* ++ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License, Version 2, as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef _CNS21XX_GEC_PLATFORM_H ++#define _CNS21XX_GEC_PLATFORM_H ++ ++#define CNS21XX_GEC_STATUS_IRQ_NAME "status" ++#define CNS21XX_GEC_RXRC_IRQ_NAME "rxrc" ++#define CNS21XX_GEC_RXQF_IRQ_NAME "rxqf" ++#define CNS21XX_GEC_TXTC_IRQ_NAME "txtc" ++#define CNS21XX_GEC_TXQE_IRQ_NAME "txqe" ++ ++enum cns21xx_gec_phy_type { ++ CNS21XX_GEC_PHY_TYPE_INTERNAL = 0, ++ CNS21XX_GEC_PHY_TYPE_VSC8601, ++ CNS21XX_GEC_PHY_TYPE_IP101A, ++ CNS21XX_GEC_PHY_TYPE_IP1001, ++}; ++ ++struct cns21xx_gec_plat_data { ++ u8 *mac_addr; ++ enum cns21xx_gec_phy_type phy_type; ++ u8 phy_addr; ++}; ++ ++#endif /* _CNS21XX_GEC_PLATFORM_H */ diff --git a/target/linux/cns21xx/patches-3.8/301-cns21xx-mach-ns-k330.patch b/target/linux/cns21xx/patches-3.8/301-cns21xx-mach-ns-k330.patch new file mode 100644 index 0000000000..ca649cace3 --- /dev/null +++ b/target/linux/cns21xx/patches-3.8/301-cns21xx-mach-ns-k330.patch @@ -0,0 +1,234 @@ +--- a/arch/arm/mach-cns21xx/Kconfig ++++ b/arch/arm/mach-cns21xx/Kconfig +@@ -1,6 +1,16 @@ + if ARCH_CNS21XX + + menu "Cavium Networks CNS21xx based machines" ++ ++config MACH_NS_K330 ++ bool "NS-K330 NAS" ++ select CNS21XX_DEV_GEC ++ select CNS21XX_DEV_SPI_MASTER ++ select CNS21XX_DEV_USB ++ help ++ Say Y here if you intend to run this kernel on the ++ NS-K330 NAS board. ++ + endmenu + + config CNS21XX_DEV_GEC +--- /dev/null ++++ b/arch/arm/mach-cns21xx/mach-ns-k330.c +@@ -0,0 +1,204 @@ ++/* ++ * NS-K330 NAS board support ++ * ++ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License, Version 2, as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/mtd/mtd.h> ++#include <linux/mtd/map.h> ++#include <linux/mtd/partitions.h> ++#include <linux/spi/spi.h> ++#include <linux/spi/flash.h> ++#include <linux/platform_device.h> ++#include <linux/gpio.h> ++#include <linux/leds.h> ++#include <linux/gpio_keys.h> ++#include <linux/input.h> ++ ++#include <asm/setup.h> ++#include <asm/mach-types.h> ++#include <asm/mach/arch.h> ++#include <asm/mach/time.h> ++#include <mach/hardware.h> ++#include <mach/cns21xx.h> ++#include <mach/cns21xx_misc.h> ++ ++#include "common.h" ++#include "dev-gec.h" ++ ++#define NS_K330_GPIO_LED_LINK 1 ++#define NS_K330_GPIO_LED_USB1 16 ++#define NS_K330_GPIO_LED_USB2 17 ++#define NS_K330_GPIO_LED_ETH_GREEN 22 ++#define NS_K330_GPIO_LED_ETH_ORANGE 23 ++ ++#define NS_K330_GPIO_BTN_RESET 13 ++#define NS_K330_GPIO_BTN_USB1 14 ++#define NS_K330_GPIO_BTN_USB2 15 ++ ++static struct mtd_partition ns_k330_partitions[] = { ++ { ++ .name = "boot", ++ .offset = 0x0, ++ .size = 0x040000, ++ .mask_flags = MTD_WRITEABLE, ++ }, { ++ .name = "config", ++ .offset = 0x040000, ++ .size = 0x020000, ++ .mask_flags = MTD_WRITEABLE, ++ }, { ++ .name = "kernel", ++ .offset = 0x060000, ++ .size = 0x100000, ++ }, { ++ .name = "rootfs", ++ .offset = 0x160000, ++ .size = 0x290000, ++ }, { ++ .name = "firmware", ++ .offset = 0x060000, ++ .size = 0x390000, ++ }, ++}; ++ ++static struct flash_platform_data ns_k330_flash_data = { ++ .parts = ns_k330_partitions, ++ .nr_parts = ARRAY_SIZE(ns_k330_partitions), ++}; ++ ++static struct spi_board_info ns_k330_spi_board_info[] = { ++ { ++ .bus_num = 0, ++ .chip_select = 0, ++ .max_speed_hz = 25000000, ++ .modalias = "m25p80", ++ .platform_data = &ns_k330_flash_data, ++ } ++}; ++ ++static struct gpio_led ns_k330_gpio_leds[] = { ++ { ++ .name = "ns-k330:red:link", ++ .gpio = NS_K330_GPIO_LED_LINK, ++ .active_low = 1, ++ }, { ++ .name = "ns-k330:green:usb1", ++ .gpio = NS_K330_GPIO_LED_USB1, ++ .active_low = 1, ++ }, { ++ .name = "ns-k330:green:usb2", ++ .gpio = NS_K330_GPIO_LED_USB2, ++ .active_low = 1, ++ }, { ++ .name = "ns-k330:green:eth", ++ .gpio = NS_K330_GPIO_LED_ETH_GREEN, ++ .active_low = 1, ++ }, { ++ .name = "ns-k330:orange:eth", ++ .gpio = NS_K330_GPIO_LED_ETH_ORANGE, ++ .active_low = 1, ++ } ++}; ++ ++static struct gpio_led_platform_data ns_k330_gpio_leds_data = { ++ .num_leds = ARRAY_SIZE(ns_k330_gpio_leds), ++ .leds = ns_k330_gpio_leds, ++}; ++ ++static struct platform_device ns_k330_gpio_leds_device = { ++ .name = "leds-gpio", ++ .id = -1, ++ .dev.platform_data = &ns_k330_gpio_leds_data, ++}; ++ ++static struct gpio_keys_button ns_k330_gpio_keys[] = { ++ { ++ .code = KEY_RESTART, ++ .gpio = NS_K330_GPIO_BTN_RESET, ++ .desc = "Reset Button", ++ .active_low = 1, ++ }, ++ { ++ .code = BTN_0, ++ .gpio = NS_K330_GPIO_BTN_USB1, ++ .desc = "USB1 Button", ++ .active_low = 1, ++ }, ++ { ++ .code = BTN_1, ++ .gpio = NS_K330_GPIO_BTN_USB2, ++ .desc = "USB2 Button", ++ .active_low = 0, ++ }, ++}; ++ ++static struct gpio_keys_platform_data ns_k330_gpio_keys_data = { ++ .buttons = ns_k330_gpio_keys, ++ .nbuttons = ARRAY_SIZE(ns_k330_gpio_keys), ++}; ++ ++static struct platform_device ns_k330_gpio_keys_device = { ++ .name = "gpio-keys", ++ .id = -1, ++ .num_resources = 0, ++ .dev = { ++ .platform_data = &ns_k330_gpio_keys_data, ++ }, ++}; ++ ++static void __init ns_k330_fixup(struct tag *tags, char **cmdline, ++ struct meminfo *mi) ++{ ++ struct tag *t; ++ ++ /* The board has 32MB of RAM mapped at 0. */ ++ mi->nr_banks = 1; ++ mi->bank[0].start = 0; ++ mi->bank[0].size = SZ_32M; ++ ++ for (t = tags; t->hdr.size; t = tag_next(t)) { ++ switch (t->hdr.tag) { ++ case ATAG_CORE: ++ if (t->u.core.rootdev == 255) ++ t->u.core.rootdev = 0; ++ break; ++ } ++ } ++} ++ ++static void __init ns_k330_init(void) ++{ ++ cns21xx_gpio_init(); ++ ++ HAL_MISC_DISABLE_LED012_PINS(); ++ HAL_MISC_DISABLE_I2C_PINS(); ++ HAL_MISC_DISABLE_I2S_PINS(); ++ ++ cns21xx_register_uart0(); ++ cns21xx_register_wdt(); ++ cns21xx_register_usb(); ++ cns21xx_register_spi_master(-1, ns_k330_spi_board_info, ++ ARRAY_SIZE(ns_k330_spi_board_info)); ++ ++ cns21xx_gec_data.phy_type = CNS21XX_GEC_PHY_TYPE_INTERNAL; ++ cns21xx_register_gec(); ++ ++ platform_device_register(&ns_k330_gpio_leds_device); ++ platform_device_register(&ns_k330_gpio_keys_device); ++} ++ ++MACHINE_START(NS_K330, "NS-K330 NAS") ++ .fixup = ns_k330_fixup, ++ .map_io = cns21xx_map_io, ++ .init_irq = cns21xx_init_irq, ++ .timer = &cns21xx_timer, ++ .init_machine = ns_k330_init, ++ .restart = cns21xx_restart, ++MACHINE_END +--- a/arch/arm/mach-cns21xx/Makefile ++++ b/arch/arm/mach-cns21xx/Makefile +@@ -12,4 +12,4 @@ obj-$(CONFIG_CNS21XX_DEV_USB) += dev-us + obj-$(CONFIG_CNS21XX_DEV_SPI_MASTER) += dev-spi-master.o + + # machine specific files +- ++obj-$(CONFIG_MACH_NS_K330) += mach-ns-k330.o diff --git a/target/linux/cns21xx/patches-3.8/302-cns21xx-mach-nsb3ast.patch b/target/linux/cns21xx/patches-3.8/302-cns21xx-mach-nsb3ast.patch new file mode 100644 index 0000000000..503df1107d --- /dev/null +++ b/target/linux/cns21xx/patches-3.8/302-cns21xx-mach-nsb3ast.patch @@ -0,0 +1,201 @@ +--- a/arch/arm/mach-cns21xx/Kconfig ++++ b/arch/arm/mach-cns21xx/Kconfig +@@ -2,6 +2,15 @@ if ARCH_CNS21XX + + menu "Cavium Networks CNS21xx based machines" + ++config MACH_NSB3AST ++ bool "AGESTAR NSB3AST support" ++ select CNS21XX_DEV_GEC ++ select CNS21XX_DEV_SPI_MASTER ++ select CNS21XX_DEV_USB ++ help ++ Say Y here if you intend to run this kernel on the ++ AGESTAR NSB3AST board. ++ + config MACH_NS_K330 + bool "NS-K330 NAS" + select CNS21XX_DEV_GEC +--- /dev/null ++++ b/arch/arm/mach-cns21xx/mach-nsb3ast.c +@@ -0,0 +1,173 @@ ++/* ++ * AGESTAR NSB3AST board support ++ * ++ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License, Version 2, as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/mtd/mtd.h> ++#include <linux/mtd/map.h> ++#include <linux/mtd/partitions.h> ++#include <linux/spi/spi.h> ++#include <linux/spi/flash.h> ++#include <linux/platform_device.h> ++#include <linux/gpio.h> ++#include <linux/leds.h> ++#include <linux/gpio_keys.h> ++#include <linux/input.h> ++ ++#include <asm/setup.h> ++#include <asm/mach-types.h> ++#include <asm/mach/arch.h> ++#include <asm/mach/time.h> ++#include <mach/hardware.h> ++#include <mach/cns21xx.h> ++#include <mach/cns21xx_misc.h> ++ ++#include "common.h" ++#include "dev-gec.h" ++ ++static struct mtd_partition nsb3ast_partitions[] = { ++ { ++ .name = "armboot", ++ .offset = 0x0, ++ .size = 0x040000, ++ .mask_flags = MTD_WRITEABLE, ++ }, { ++ .name = "kernel", ++ .offset = 0x040000, ++ .size = 0x100000, ++ }, { ++ .name = "rootfs", ++ .offset = 0x140000, ++ .size = 0x6c0000, ++ }, { ++ .name = "firmware", ++ .offset = 0x040000, ++ .size = 0x7c0000, ++ }, { ++ .name = "wholeflash", ++ .offset = 0x0, ++ .size = 0x800000, ++ .mask_flags = MTD_WRITEABLE, ++ }, ++}; ++ ++static struct flash_platform_data nsb3ast_flash_data = { ++ .parts = nsb3ast_partitions, ++ .nr_parts = ARRAY_SIZE(nsb3ast_partitions), ++}; ++ ++static struct spi_board_info nsb3ast_spi_board_info[] = { ++ { ++ .bus_num = 0, ++ .chip_select = 0, ++ .max_speed_hz = 25000000, ++ .modalias = "m25p80", ++ .platform_data = &nsb3ast_flash_data, ++ } ++}; ++ ++static struct gpio_led nsb3ast_gpio_leds[] = { ++ { ++ .name = "nsb3ast:red:d1", ++ .gpio = 15, ++ .active_low = 1, ++ }, { ++ .name = "nsb3ast:amber:eth", ++ .gpio = 22, ++ .active_low = 1, ++ } ++}; ++ ++static struct gpio_led_platform_data nsb3ast_gpio_leds_data = { ++ .num_leds = ARRAY_SIZE(nsb3ast_gpio_leds), ++ .leds = nsb3ast_gpio_leds, ++}; ++ ++static struct platform_device nsb3ast_gpio_leds_device = { ++ .name = "leds-gpio", ++ .id = -1, ++ .dev.platform_data = &nsb3ast_gpio_leds_data, ++}; ++ ++static struct gpio_keys_button nsb3ast_gpio_keys[] = { ++ { ++ .code = KEY_RESTART, ++ .gpio = 0, ++ .desc = "Reset Button", ++ .active_low = 1, ++ }, ++ { ++ .code = BTN_0, ++ .gpio = 2, ++ .desc = "USB Button", ++ .active_low = 0, ++ }, ++}; ++ ++static struct gpio_keys_platform_data nsb3ast_gpio_keys_data = { ++ .buttons = nsb3ast_gpio_keys, ++ .nbuttons = ARRAY_SIZE(nsb3ast_gpio_keys), ++}; ++ ++static struct platform_device nsb3ast_gpio_keys_device = { ++ .name = "gpio-keys", ++ .id = -1, ++ .num_resources = 0, ++ .dev = { ++ .platform_data = &nsb3ast_gpio_keys_data, ++ }, ++}; ++ ++static void __init nsb3ast_fixup(struct tag *tags, char **cmdline, ++ struct meminfo *mi) ++{ ++ struct tag *t; ++ ++ /* The board has 32MB of RAM mapped at 0. */ ++ mi->nr_banks = 1; ++ mi->bank[0].start = 0; ++ mi->bank[0].size = SZ_32M; ++ ++ for (t = tags; t->hdr.size; t = tag_next(t)) { ++ switch (t->hdr.tag) { ++ case ATAG_CORE: ++ if (t->u.core.rootdev == 255) ++ t->u.core.rootdev = 0; ++ break; ++ } ++ } ++} ++ ++static void __init nsb3ast_init(void) ++{ ++ cns21xx_gpio_init(); ++ cns21xx_register_uart0(); ++ cns21xx_register_uart1(); ++ cns21xx_register_wdt(); ++ cns21xx_register_usb(); ++ cns21xx_register_spi_master(-1, nsb3ast_spi_board_info, ++ ARRAY_SIZE(nsb3ast_spi_board_info)); ++ ++ cns21xx_gec_data.phy_type = CNS21XX_GEC_PHY_TYPE_INTERNAL; ++ cns21xx_register_gec(); ++ ++ HAL_MISC_DISABLE_LED012_PINS(); ++ platform_device_register(&nsb3ast_gpio_leds_device); ++ platform_device_register(&nsb3ast_gpio_keys_device); ++} ++ ++MACHINE_START(NSB3AST, "AGESTAR NSB3AST") ++ .fixup = nsb3ast_fixup, ++ .map_io = cns21xx_map_io, ++ .init_irq = cns21xx_init_irq, ++ .timer = &cns21xx_timer, ++ .init_machine = nsb3ast_init, ++ .restart = cns21xx_restart, ++MACHINE_END +--- a/arch/arm/mach-cns21xx/Makefile ++++ b/arch/arm/mach-cns21xx/Makefile +@@ -13,3 +13,4 @@ obj-$(CONFIG_CNS21XX_DEV_SPI_MASTER) += + + # machine specific files + obj-$(CONFIG_MACH_NS_K330) += mach-ns-k330.o ++obj-$(CONFIG_MACH_NSB3AST) += mach-nsb3ast.o |