cns21xx: add support for 3.2

SVN-Revision: 30971
This commit is contained in:
Gabor Juhos 2012-03-18 12:07:48 +00:00
parent 45d5b24190
commit 6dbe40f7d4
19 changed files with 7863 additions and 0 deletions

View file

@ -0,0 +1,142 @@
CONFIG_ALIGNMENT_TRAP=y
CONFIG_ARCH_CNS21XX=y
CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
CONFIG_ARCH_REQUIRE_GPIOLIB=y
# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
# CONFIG_ARCH_SUPPORTS_MSI is not set
# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
CONFIG_ARM=y
# CONFIG_ARM_CPU_SUSPEND is not set
CONFIG_ARM_L1_CACHE_SHIFT=4
CONFIG_ARM_L1_CACHE_SHIFT_4=y
# CONFIG_ARPD is not set
CONFIG_ATA=m
CONFIG_BCMA_POSSIBLE=y
CONFIG_CC_OPTIMIZE_FOR_SIZE=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_USER is not set
CONFIG_DECOMPRESS_LZMA=y
CONFIG_DLCI=m
CONFIG_DLCI_MAX=8
CONFIG_DMADEVICES=y
CONFIG_DNOTIFY=y
CONFIG_EEPROM_AT25=y
CONFIG_ELF_CORE=y
CONFIG_FA_WATCHDOG=y
CONFIG_FRAME_POINTER=y
CONFIG_GENERIC_ATOMIC64=y
CONFIG_GENERIC_BUG=y
CONFIG_GENERIC_GPIO=y
CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_SYSFS=y
# CONFIG_HAMRADIO is not set
CONFIG_HARDIRQS_SW_RESEND=y
CONFIG_HAS_DMA=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAVE_AOUT=y
CONFIG_HAVE_ARCH_KGDB=y
CONFIG_HAVE_ARCH_PFN_VALID=y
CONFIG_HAVE_C_RECORDMCOUNT=y
CONFIG_HAVE_DMA_API_DEBUG=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_HAVE_GENERIC_DMA_COHERENT=y
CONFIG_HAVE_GENERIC_HARDIRQS=y
CONFIG_HAVE_IRQ_WORK=y
CONFIG_HAVE_KERNEL_GZIP=y
CONFIG_HAVE_KERNEL_LZMA=y
CONFIG_HAVE_KERNEL_LZO=y
CONFIG_HAVE_KERNEL_XZ=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
CONFIG_HAVE_MEMBLOCK=y
CONFIG_HAVE_OPROFILE=y
CONFIG_HAVE_PERF_EVENTS=y
CONFIG_HAVE_PROC_CPU=y
CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
CONFIG_HAVE_SPARSE_IRQ=y
CONFIG_HDLC=m
CONFIG_HDLC_CISCO=m
CONFIG_HDLC_FR=m
CONFIG_HDLC_PPP=m
CONFIG_HDLC_RAW=m
CONFIG_HWMON=y
# CONFIG_HWMON_DEBUG_CHIP is not set
CONFIG_HW_RANDOM=y
CONFIG_INITRAMFS_SOURCE=""
# CONFIG_IP_ADVANCED_ROUTER is not set
CONFIG_IP_PIMSM_V1=y
CONFIG_IP_PIMSM_V2=y
CONFIG_KTIME_SCALAR=y
# CONFIG_LEDS_GPIO is not set
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
CONFIG_M25PXX_USE_FAST_READ=y
CONFIG_MACH_NSB3AST=y
CONFIG_MACH_NS_K330=y
CONFIG_MDIO_BOARDINFO=y
# CONFIG_MTD_CFI is not set
CONFIG_MTD_M25P80=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEED_PER_CPU_KM=y
CONFIG_NLS=m
CONFIG_PAGEFLAGS_EXTENDED=y
CONFIG_PAGE_OFFSET=0xC0000000
# CONFIG_PCI_SYSCALL is not set
CONFIG_PERF_USE_VMALLOC=y
CONFIG_PHYLIB=y
CONFIG_PHYS_OFFSET=0x00000000
CONFIG_PLAT_FA=y
CONFIG_PLAT_FA_GPIO=y
CONFIG_PLAT_FA_TIME=y
# CONFIG_PREEMPT_RCU is not set
# CONFIG_QUOTACTL is not set
CONFIG_SCSI=m
CONFIG_SCSI_MOD=m
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SENSORS_SCH56XX_COMMON is not set
CONFIG_SERIO=y
CONFIG_SERIO_LIBPS2=y
# CONFIG_SERIO_RAW is not set
CONFIG_SERIO_SERPORT=y
CONFIG_SPI=y
CONFIG_SPI_BITBANG=y
CONFIG_SPI_CNS21XX=y
CONFIG_SPI_DEBUG=y
# CONFIG_SPI_GPIO is not set
CONFIG_SPI_MASTER=y
CONFIG_SPLIT_PTLOCK_CPUS=999999
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
CONFIG_UID16=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_XZ_DEC=y
CONFIG_ZBOOT_ROM_BSS=0x0
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZONE_DMA_FLAG=0

View file

@ -0,0 +1,24 @@
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -44,6 +44,10 @@
#include <asm/uaccess.h>
+#ifdef CONFIG_DEBUG_LL
+extern void printascii(char *);
+#endif /* CONFIG_DEBUG_LL */
+
/*
* Architectures can override it:
*/
@@ -897,6 +901,10 @@ asmlinkage int vprintk(const char *fmt,
}
}
+#ifdef CONFIG_DEBUG_LL
+ printascii(printk_buf);
+#endif
+
/*
* Copy the output into log_buf. If the caller didn't provide
* the appropriate log prefix, we insert them here

View file

@ -0,0 +1,56 @@
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1100,10 +1100,15 @@ source "arch/arm/mach-vt8500/Kconfig"
source "arch/arm/mach-w90x900/Kconfig"
+source "arch/arm/plat-fa/Kconfig"
+
# Definitions to make life easier
config ARCH_ACORN
bool
+config PLAT_FA
+ bool
+
config PLAT_IOP
bool
select GENERIC_CLOCKEVENTS
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -206,6 +206,7 @@ plat-$(CONFIG_ARCH_OMAP) := omap
plat-$(CONFIG_ARCH_S3C64XX) := samsung
plat-$(CONFIG_ARCH_TCC_926) := tcc
plat-$(CONFIG_ARCH_ZYNQ) := versatile
+plat-$(CONFIG_PLAT_FA) := fa
plat-$(CONFIG_PLAT_IOP) := iop
plat-$(CONFIG_PLAT_NOMADIK) := nomadik
plat-$(CONFIG_PLAT_ORION) := orion
@@ -304,7 +305,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

View file

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

View file

@ -0,0 +1,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 :=

View file

@ -0,0 +1,458 @@
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -343,6 +343,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
@@ -53,6 +53,7 @@ obj-$(CONFIG_STMP3XXX_WATCHDOG) += stmp3
obj-$(CONFIG_NUC900_WATCHDOG) += nuc900_wdt.o
obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o
obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o
+obj-$(CONFIG_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 __devinit fa_wdt_probe(struct platform_device *pdev)
+{
+ int ret;
+ int res_size;
+ struct resource *res;
+ void __iomem *base;
+ struct fa_wdt_struct *fa_wdt;
+ struct fa_wdt_platform_data *pdata;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&pdev->dev, "no platform data specified\n");
+ return -EINVAL;
+ }
+
+ if (!pdata->clock) {
+ dev_err(&pdev->dev, "invalid clock value\n");
+ return -EINVAL;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "can't get device resources\n");
+ return -ENODEV;
+ }
+
+ res_size = resource_size(res);
+ if (!request_mem_region(res->start, res_size, res->name)) {
+ dev_err(&pdev->dev, "can't allocate %d bytes at %d address\n",
+ res_size, res->start);
+ return -ENOMEM;
+ }
+
+ base = ioremap(res->start, res_size);
+ if (!base) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ ret = -EIO;
+ goto fail0;
+ }
+
+ fa_wdt = kzalloc(sizeof(struct fa_wdt_struct), GFP_KERNEL);
+ if (!fa_wdt) {
+ dev_err(&pdev->dev, "can't allocate interface\n");
+ ret = -ENOMEM;
+ goto fail1;
+ }
+
+ /* Setup fa_wdt driver structure */
+ fa_wdt->base = base;
+ fa_wdt->res = res;
+ fa_wdt->dev = &pdev->dev;
+ fa_wdt->clock = pdata->clock;
+ fa_wdt->max_timeout = 0xffffffffU / pdata->clock;
+
+ /* Set up platform driver data */
+ platform_set_drvdata(pdev, fa_wdt);
+ fa_wdt_dev = pdev;
+
+ if (fa_wdt_miscdev.parent) {
+ ret = -EBUSY;
+ goto fail2;
+ }
+
+ ret = register_reboot_notifier(&fa_wdt_notifier);
+ if (ret)
+ goto fail2;
+
+ fa_wdt_miscdev.parent = &pdev->dev;
+
+ ret = misc_register(&fa_wdt_miscdev);
+ if (ret)
+ goto fail3;
+
+ return 0;
+
+fail3:
+ unregister_reboot_notifier(&fa_wdt_notifier);
+fail2:
+ platform_set_drvdata(pdev, NULL);
+ kfree(fa_wdt);
+fail1:
+ iounmap(base);
+fail0:
+ release_mem_region(res->start, res_size);
+
+ return ret;
+}
+
+static int __devexit fa_wdt_remove(struct platform_device *pdev)
+{
+ struct fa_wdt_struct *fa_wdt = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+ misc_deregister(&fa_wdt_miscdev);
+ unregister_reboot_notifier(&fa_wdt_notifier);
+ fa_wdt_dev = NULL;
+ iounmap(fa_wdt->base);
+ release_mem_region(fa_wdt->res->start, resource_size(fa_wdt->res));
+
+ kfree(fa_wdt);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int fa_wdt_suspend(struct platform_device *pdev, pm_message_t message)
+{
+ struct fa_wdt_struct *fa_wdt = platform_get_drvdata(pdev);
+ unsigned int reg;
+
+ reg = __raw_readw(fa_wdt->base + FA_WDCR);
+ reg &= ~(WDCR_WDENABLE);
+ __raw_writel(reg, fa_wdt->base + FA_WDCR);
+
+ return 0;
+}
+
+static int fa_wdt_resume(struct platform_device *pdev)
+{
+ struct fa_wdt_struct *fa_wdt = platform_get_drvdata(pdev);
+ unsigned int reg;
+
+ if (fa_wdt->status) {
+ reg = __raw_readw(fa_wdt->base + FA_WDCR);
+ reg |= WDCR_WDENABLE;
+ __raw_writel(reg, fa_wdt->base + FA_WDCR);
+ }
+
+ return 0;
+}
+#else
+#define fa_wdt_suspend NULL
+#define fa_wdt_resume NULL
+#endif
+
+static struct platform_driver fa_wdt_driver = {
+ .probe = fa_wdt_probe,
+ .remove = __devexit_p(fa_wdt_remove),
+ .shutdown = fa_wdt_shutdown,
+ .suspend = fa_wdt_suspend,
+ .resume = fa_wdt_resume,
+ .driver = {
+ .name = "fa-wdt",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init fa_wdt_init(void)
+{
+ return platform_driver_probe(&fa_wdt_driver, fa_wdt_probe);
+}
+
+static void __exit fa_wdt_exit(void)
+{
+ platform_driver_unregister(&fa_wdt_driver);
+}
+
+module_init(fa_wdt_init);
+module_exit(fa_wdt_exit);
+
+module_param(timeout, uint, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds");
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
+
+MODULE_AUTHOR("Paulius Zaleckas");
+MODULE_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 */
+

File diff suppressed because it is too large Load diff

View file

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

View file

@ -0,0 +1,85 @@
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -360,6 +360,8 @@ config ARCH_CNS21XX
select CPU_FA526
select PLAT_FA
select PLAT_FA_TIME
+ select PLAT_FA_GPIO
+ select ARCH_REQUIRE_GPIOLIB
select ARM_L1_CACHE_SHIFT_4
help
Support for Cavium Networks CNS21xx family.
--- a/arch/arm/mach-cns21xx/common.h
+++ b/arch/arm/mach-cns21xx/common.h
@@ -12,6 +12,7 @@
void __init cns21xx_map_io(void);
void __init cns21xx_init_irq(void);
+void __init cns21xx_gpio_init(void);
extern struct sys_timer cns21xx_timer;
--- /dev/null
+++ b/arch/arm/mach-cns21xx/gpio.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <plat/gpio.h>
+
+#include <mach/cns21xx.h>
+#include <mach/irqs.h>
+
+static struct fa_gpio_chip cns21xx_gpio_chips[] = {
+ {
+ .gpio_chip = {
+ .label = "GPIOA",
+ .base = 0,
+ .ngpio = 32,
+ },
+
+ .map_base = CNS21XX_GPIOA_BASE,
+ .irq_base = CNS21XX_GPIO_IRQ_BASE,
+ }, {
+ .gpio_chip = {
+ .label = "GPIOB",
+ .base = 32,
+ .ngpio = 32,
+ },
+
+ .map_base = CNS21XX_GPIOB_BASE,
+ .irq_base = CNS21XX_GPIO_IRQ_BASE + 32,
+ }
+};
+
+static struct fa_gpio_data cns21xx_gpio_data = {
+ .chips = cns21xx_gpio_chips,
+ .nchips = ARRAY_SIZE(cns21xx_gpio_chips),
+ .irq = CNS21XX_IRQ_GPIO,
+};
+
+void __init cns21xx_gpio_init(void)
+{
+ fa_gpio_init(&cns21xx_gpio_data);
+}
--- /dev/null
+++ b/arch/arm/mach-cns21xx/include/mach/gpio.h
@@ -0,0 +1,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

View file

@ -0,0 +1,230 @@
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -579,7 +579,6 @@ static int ohci_run (struct ohci_hcd *oh
/* boot firmware should have set this up (5.1.1.3.1) */
if (first) {
-
val = ohci_readl (ohci, &ohci->regs->fminterval);
ohci->fminterval = val & 0x3fff;
if (ohci->fminterval != FI)
@@ -663,6 +662,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.
*/
@@ -1101,6 +1103,11 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ohci_octeon_driver
#endif
+#ifdef CONFIG_ARCH_CNS21XX
+#include "ohci-cns21xx.c"
+#define PLATFORM_DRIVER ohci_cns21xx_driver
+#endif
+
#ifdef CONFIG_USB_CNS3XXX_OHCI
#include "ohci-cns3xxx.c"
#define PLATFORM_DRIVER ohci_hcd_cns3xxx_driver
--- /dev/null
+++ b/drivers/usb/host/ohci-cns21xx.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2008 Cavium Networks
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/platform_device.h>
+
+#include <mach/cns21xx.h>
+
+#define DRIVER_NAME "cns21xx-ohci"
+
+static int __devinit cns21xx_ohci_start(struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+ int ret;
+
+ ret = ohci_init(ohci);
+ if (ret)
+ return ret;
+
+ ret = ohci_run(ohci);
+ if (ret) {
+ err("can't start %s", ohci_to_hcd(ohci)->self.bus_name);
+ goto err;
+ }
+
+ return 0;
+
+err:
+ ohci_stop(hcd);
+ return ret;
+}
+
+static const struct hc_driver ohci_cns21xx_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "cns21xx-ohci",
+ .hcd_priv_size = sizeof(struct ohci_hcd),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ohci_irq,
+ .flags = HCD_USB11 | HCD_MEMORY,
+
+ /*
+ * basic lifecycle operations
+ */
+ .start = cns21xx_ohci_start,
+ .stop = ohci_stop,
+ .shutdown = ohci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = ohci_urb_enqueue,
+ .urb_dequeue = ohci_urb_dequeue,
+ .endpoint_disable = ohci_endpoint_disable,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = ohci_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
+ .start_port_reset = ohci_start_port_reset,
+};
+
+static void cns21xx_ohci_init_hc(void)
+{
+ __raw_writel(0x146, CNS21XX_OHCI_CONFIG_BASE_VIRT + 0x04);
+ __raw_writel(0x200, CNS21XX_OHCI_CONFIG_BASE_VIRT + 0x44);
+ msleep(100);
+}
+
+static int ohci_cns21xx_probe(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd;
+ struct resource *res;
+ struct ohci_hcd *ohci;
+ int irq;
+ int ret;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_dbg(&pdev->dev, "no IRQ specified for %s\n",
+ dev_name(&pdev->dev));
+ return -ENODEV;
+ }
+ irq = res->start;
+
+ hcd = usb_create_hcd(&ohci_cns21xx_hc_driver, &pdev->dev,
+ dev_name(&pdev->dev));
+ if (!hcd)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_dbg(&pdev->dev, "no base address specified for %s\n",
+ dev_name(&pdev->dev));
+ ret = -ENODEV;
+ goto err_put_hcd;
+ }
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = res->end - res->start + 1;
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ dev_dbg(&pdev->dev, "controller already in use\n");
+ ret = -EBUSY;
+ goto err_put_hcd;
+ }
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs) {
+ dev_dbg(&pdev->dev, "error mapping memory\n");
+ ret = -EFAULT;
+ goto err_release_region;
+ }
+
+ cns21xx_ohci_init_hc();
+
+ ohci = hcd_to_ohci(hcd);
+ ohci->flags |= OHCI_QUIRK_INIT_FMINTERVAL;
+ ohci_hcd_init(ohci);
+
+ ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
+ if (ret)
+ goto err_unmap;
+
+ platform_set_drvdata(pdev, hcd);
+ return 0;
+
+err_unmap:
+ iounmap(hcd->regs);
+err_release_region:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err_put_hcd:
+ usb_put_hcd(hcd);
+ return ret;
+}
+
+static int ohci_cns21xx_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+ usb_remove_hcd(hcd);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver ohci_cns21xx_driver = {
+ .probe = ohci_cns21xx_probe,
+ .remove = ohci_cns21xx_remove,
+ .shutdown = usb_hcd_platform_shutdown,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ },
+};
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -403,6 +403,7 @@ struct ohci_hcd {
#define OHCI_QUIRK_HUB_POWER 0x100 /* distrust firmware power/oc setup */
#define OHCI_QUIRK_AMD_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
@@ -363,6 +363,7 @@ config ARCH_CNS21XX
select PLAT_FA_GPIO
select ARCH_REQUIRE_GPIOLIB
select ARM_L1_CACHE_SHIFT_4
+ select USB_ARCH_HAS_OHCI
help
Support for Cavium Networks CNS21xx family.

View file

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

View file

@ -0,0 +1,578 @@
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -445,6 +445,8 @@ struct spi_transfer {
u16 delay_usecs;
u32 speed_hz;
+ unsigned last_in_message_list;
+
struct list_head transfer_list;
};
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -163,6 +163,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
@@ -18,6 +18,7 @@ obj-$(CONFIG_SPI_BFIN) += spi-bfin5xx.
obj-$(CONFIG_SPI_BFIN_SPORT) += spi-bfin-sport.o
obj-$(CONFIG_SPI_BITBANG) += spi-bitbang.o
obj-$(CONFIG_SPI_BUTTERFLY) += spi-butterfly.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
@@ -330,6 +330,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 __devexit cns21xx_spi_remove(struct platform_device *pdev)
+{
+ struct cns21xx_spi *hw = platform_get_drvdata(pdev);
+
+ spi_bitbang_stop(&hw->bitbang);
+ iounmap(hw->base);
+ release_resource(hw->region);
+ kfree(hw->region);
+ spi_master_put(hw->bitbang.master);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver cns21xx_spi_driver = {
+ .remove = __devexit_p(cns21xx_spi_remove),
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init cns21xx_spi_init(void)
+{
+ return platform_driver_probe(&cns21xx_spi_driver, cns21xx_spi_probe);
+}
+
+static void __exit cns21xx_spi_exit(void)
+{
+ platform_driver_unregister(&cns21xx_spi_driver);
+}
+
+module_init(cns21xx_spi_init);
+module_exit(cns21xx_spi_exit);
+
+MODULE_DESCRIPTION("Cavium Networks CNS21xx SPI Controller driver");
+MODULE_AUTHOR("STAR Semi Corp.");
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,233 @@
--- 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,203 @@
+/*
+ * NS-K330 NAS board support
+ *
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <mach/hardware.h>
+#include <mach/cns21xx.h>
+#include <mach/cns21xx_misc.h>
+
+#include "common.h"
+#include "dev-gec.h"
+
+#define NS_K330_GPIO_LED_LINK 1
+#define NS_K330_GPIO_LED_USB1 16
+#define NS_K330_GPIO_LED_USB2 17
+#define NS_K330_GPIO_LED_ETH_GREEN 22
+#define NS_K330_GPIO_LED_ETH_ORANGE 23
+
+#define NS_K330_GPIO_BTN_RESET 13
+#define NS_K330_GPIO_BTN_USB1 14
+#define NS_K330_GPIO_BTN_USB2 15
+
+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,
+MACHINE_END
--- a/arch/arm/mach-cns21xx/Makefile
+++ b/arch/arm/mach-cns21xx/Makefile
@@ -12,4 +12,4 @@ obj-$(CONFIG_CNS21XX_DEV_USB) += dev-us
obj-$(CONFIG_CNS21XX_DEV_SPI_MASTER) += dev-spi-master.o
# machine specific files
-
+obj-$(CONFIG_MACH_NS_K330) += mach-ns-k330.o

View file

@ -0,0 +1,200 @@
--- 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,172 @@
+/*
+ * AGESTAR NSB3AST board support
+ *
+ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <mach/hardware.h>
+#include <mach/cns21xx.h>
+#include <mach/cns21xx_misc.h>
+
+#include "common.h"
+#include "dev-gec.h"
+
+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,
+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