[lantiq] get ready for 3.0

git-svn-id: svn://svn.openwrt.org/openwrt/trunk@27496 3c298f89-4303-0410-b956-a3cf2f4a3e73
master
John Crispin 2011-07-06 17:27:17 +00:00
parent 622243009f
commit 111e5605f9
38 changed files with 39439 additions and 0 deletions

View File

@ -0,0 +1,37 @@
# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set
# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
# CONFIG_ATH79 is not set
CONFIG_GENERIC_ATOMIC64=y
CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_HAVE_ARCH_JUMP_LABEL=y
CONFIG_HAVE_C_RECORDMCOUNT=y
CONFIG_HAVE_DMA_API_DEBUG=y
CONFIG_HAVE_DMA_ATTRS=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_FUNCTION_TRACE_MCOUNT_TEST=y
CONFIG_HAVE_GENERIC_HARDIRQS=y
CONFIG_HAVE_IRQ_WORK=y
CONFIG_HAVE_PERF_EVENTS=y
CONFIG_INPUT=y
CONFIG_INPUT_EVDEV=y
# CONFIG_INPUT_GPIO_BUTTONS is not set
CONFIG_INPUT_POLLDEV=y
# CONFIG_ISDN is not set
CONFIG_LANTIQ_ETOP=y
CONFIG_LANTIQ_MACH_EASY50601=y
CONFIG_MACH_NO_WESTBRIDGE=y
# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set
# CONFIG_MTD_LATCH_ADDR is not set
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEED_PER_CPU_KM=y
CONFIG_PERF_USE_VMALLOC=y
# CONFIG_PREEMPT_RCU is not set
# CONFIG_QUOTACTL is not set
CONFIG_SOC_AMAZON_SE=y
# CONFIG_SOC_FALCON is not set
CONFIG_SOC_TYPE_XWAY=y
# CONFIG_SOC_XWAY is not set
CONFIG_XZ_DEC=y

View File

@ -0,0 +1,112 @@
# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_ARCH_REQUIRE_GPIOLIB=y
# CONFIG_ARCH_SUPPORTS_MSI is not set
CONFIG_ARCH_SUPPORTS_OPROFILE=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
# CONFIG_ATH79 is not set
CONFIG_BCMA_POSSIBLE=y
# CONFIG_BRCMUTIL is not set
CONFIG_CEVT_R4K=y
CONFIG_CEVT_R4K_LIB=y
CONFIG_CPU_BIG_ENDIAN=y
CONFIG_CPU_HAS_PREFETCH=y
CONFIG_CPU_HAS_SYNC=y
CONFIG_CPU_MIPS32=y
# CONFIG_CPU_MIPS32_R1 is not set
CONFIG_CPU_MIPS32_R2=y
CONFIG_CPU_MIPSR2=y
CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
CONFIG_CPU_SUPPORTS_HIGHMEM=y
CONFIG_CSRC_R4K=y
CONFIG_CSRC_R4K_LIB=y
CONFIG_DECOMPRESS_LZMA=y
CONFIG_DMA_NONCOHERENT=y
CONFIG_EARLY_PRINTK=y
# CONFIG_FSNOTIFY is not set
CONFIG_GENERIC_ATOMIC64=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
CONFIG_GENERIC_CMOS_UPDATE=y
CONFIG_GENERIC_GPIO=y
CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_SYSFS=y
CONFIG_HARDWARE_WATCHPOINTS=y
CONFIG_HAS_DMA=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAVE_ARCH_JUMP_LABEL=y
CONFIG_HAVE_ARCH_KGDB=y
CONFIG_HAVE_CLK=y
CONFIG_HAVE_C_RECORDMCOUNT=y
CONFIG_HAVE_DMA_API_DEBUG=y
CONFIG_HAVE_DMA_ATTRS=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_FUNCTION_TRACE_MCOUNT_TEST=y
CONFIG_HAVE_GENERIC_DMA_COHERENT=y
CONFIG_HAVE_GENERIC_HARDIRQS=y
CONFIG_HAVE_IDE=y
CONFIG_HAVE_IRQ_WORK=y
CONFIG_HAVE_OPROFILE=y
CONFIG_HAVE_PERF_EVENTS=y
CONFIG_HW_RANDOM=y
CONFIG_HZ=250
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
CONFIG_IFX_UDP_REDIRECT=y
CONFIG_IMAGE_CMDLINE_HACK=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_IRQ_CPU=y
CONFIG_LANTIQ=y
CONFIG_LANTIQ_MACH_95C3AM1=y
CONFIG_LANTIQ_MACH_EASY98000=y
CONFIG_LANTIQ_MACH_EASY98020=y
CONFIG_LANTIQ_WDT=y
CONFIG_LEDS_GPIO=y
CONFIG_MACH_NO_WESTBRIDGE=y
# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set
CONFIG_MIPS=y
CONFIG_MIPS_L1_CACHE_SHIFT=5
CONFIG_MIPS_MACHINE=y
CONFIG_MIPS_MT_DISABLED=y
# CONFIG_MIPS_MT_SMP is not set
# CONFIG_MIPS_MT_SMTC is not set
# CONFIG_MIPS_VPE_LOADER is not set
CONFIG_MTD_CFI_ADV_OPTIONS=y
CONFIG_MTD_CFI_GEOMETRY=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_LANTIQ=y
CONFIG_MTD_UIMAGE_SPLIT=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEED_PER_CPU_KM=y
CONFIG_NLS=y
CONFIG_PAGEFLAGS_EXTENDED=y
CONFIG_PERF_USE_VMALLOC=y
CONFIG_PHYLIB=y
# CONFIG_PREEMPT_RCU is not set
# CONFIG_QUOTACTL is not set
# CONFIG_RTC_CLASS is not set
CONFIG_RTL8366RB_PHY=y
CONFIG_RTL8366_SMI=y
# CONFIG_SCSI_DMA is not set
# CONFIG_SERIAL_8250 is not set
CONFIG_SERIAL_LANTIQ=y
CONFIG_SWAP_IO_SPACE=y
CONFIG_SWCONFIG=y
CONFIG_SYS_HAS_CPU_MIPS32_R1=y
CONFIG_SYS_HAS_CPU_MIPS32_R2=y
CONFIG_SYS_HAS_EARLY_PRINTK=y
CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
CONFIG_SYS_SUPPORTS_MULTITHREADING=y
CONFIG_XZ_DEC=y
CONFIG_ZONE_DMA_FLAG=0

View File

@ -0,0 +1,25 @@
CONFIG_CPU_MIPSR2_IRQ_EI=y
CONFIG_CPU_MIPSR2_IRQ_VI=y
CONFIG_IFX_VPE_CACHE_SPLIT=y
CONFIG_IFX_VPE_EXT=y
CONFIG_M25PXX_USE_FAST_READ=y
CONFIG_MIPS_MT=y
# CONFIG_MIPS_VPE_APSP_API is not set
CONFIG_MIPS_VPE_LOADER=y
CONFIG_MIPS_VPE_LOADER_TOM=y
CONFIG_MTD_M25P80=y
CONFIG_MTD_NAND=y
CONFIG_MTD_NAND_ECC=y
CONFIG_MTD_NAND_PLATFORM=y
# CONFIG_MTD_SM_COMMON is not set
CONFIG_MTSCHED=y
# CONFIG_PERFCTRS is not set
# CONFIG_SOC_AMAZON_SE is not set
CONFIG_SOC_FALCON=y
# CONFIG_SOC_TYPE_XWAY is not set
# CONFIG_SOC_XWAY is not set
CONFIG_SPI=y
# CONFIG_SPI_BITBANG is not set
CONFIG_SPI_FALCON=y
# CONFIG_SPI_GPIO is not set
CONFIG_SPI_MASTER=y

View File

@ -0,0 +1,20 @@
--- a/arch/mips/lantiq/xway/gpio_ebu.c
+++ b/arch/mips/lantiq/xway/gpio_ebu.c
@@ -63,7 +63,6 @@ static struct gpio_chip ltq_ebu_chip = {
.set = ltq_ebu_set,
.base = 72,
.ngpio = 16,
- .can_sleep = 1,
.owner = THIS_MODULE,
};
--- a/arch/mips/lantiq/xway/gpio_stp.c
+++ b/arch/mips/lantiq/xway/gpio_stp.c
@@ -72,7 +72,6 @@ static struct gpio_chip ltq_stp_chip = {
.set = ltq_stp_set,
.base = 48,
.ngpio = 24,
- .can_sleep = 1,
.owner = THIS_MODULE,
};

View File

@ -0,0 +1,32 @@
--- a/arch/mips/lantiq/xway/mach-easy50601.c
+++ b/arch/mips/lantiq/xway/mach-easy50601.c
@@ -32,12 +32,7 @@
{
.name = "linux",
.offset = 0x20000,
- .size = 0xE0000,
- },
- {
- .name = "rootfs",
- .offset = 0x100000,
- .size = 0x300000,
+ .size = 0x3d0000,
},
};
--- a/arch/mips/lantiq/xway/mach-easy50712.c
+++ b/arch/mips/lantiq/xway/mach-easy50712.c
@@ -34,12 +34,7 @@
{
.name = "linux",
.offset = 0x20000,
- .size = 0xe0000,
- },
- {
- .name = "rootfs",
- .offset = 0x100000,
- .size = 0x300000,
+ .size = 0x3d0000,
},
};

View File

@ -0,0 +1,71 @@
--- a/drivers/mtd/maps/lantiq-flash.c
+++ b/drivers/mtd/maps/lantiq-flash.c
@@ -20,6 +20,8 @@
#include <linux/platform_device.h>
#include <linux/mtd/physmap.h>
+#include "../mtdcore.h"
+
#include <lantiq_soc.h>
#include <lantiq_platform.h>
--- a/arch/mips/lantiq/clk.c
+++ b/arch/mips/lantiq/clk.c
@@ -100,6 +100,17 @@
}
EXPORT_SYMBOL(clk_put);
+int clk_enable(struct clk *clk)
+{
+ /* clocks are always enabled*/
+ return 0;
+}
+
+void clk_disable(struct clk *clk)
+{
+ /* clocks are always enabled*/
+}
+
static inline u32 ltq_get_counter_resolution(void)
{
u32 res;
--- a/arch/mips/lantiq/irq.c
+++ b/arch/mips/lantiq/irq.c
@@ -9,6 +9,7 @@
#include <linux/interrupt.h>
#include <linux/ioport.h>
+#include <linux/module.h>
#include <asm/bootinfo.h>
#include <asm/irq_cpu.h>
@@ -105,6 +106,7 @@
ltq_icu_w32(ltq_icu_r32(ier) & ~(1 << irq_nr), ier);
ltq_icu_w32((1 << irq_nr), isr);
}
+EXPORT_SYMBOL(ltq_mask_and_ack_irq);
static void ltq_ack_irq(struct irq_data *d)
{
--- a/arch/mips/lantiq/setup.c
+++ b/arch/mips/lantiq/setup.c
@@ -18,6 +18,8 @@
#include "devices.h"
#include "prom.h"
+unsigned long physical_memsize = 0L;
+
void __init plat_mem_setup(void)
{
/* assume 16M as default incase uboot fails to pass proper ramsize */
@@ -40,8 +42,8 @@
}
envp++;
}
- memsize *= 1024 * 1024;
- add_memory_region(0x00000000, memsize, BOOT_MEM_RAM);
+ physical_memsize = memsize * 1024 * 1024;
+ add_memory_region(0x00000000, physical_memsize, BOOT_MEM_RAM);
}
static int __init

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,828 @@
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -82,5 +82,6 @@ obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o
obj-$(CONFIG_I2C_STUB) += i2c-stub.o
obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o
+obj-$(CONFIG_I2C_FALCON) += i2c-falcon.o
ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -282,6 +282,10 @@ config I2C_POWERMAC
comment "I2C system bus drivers (mostly embedded / system-on-chip)"
+config I2C_FALCON
+ tristate "Falcon I2C interface"
+# depends on SOC_FALCON
+
config I2C_AT91
tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
depends on ARCH_AT91 && EXPERIMENTAL && BROKEN
--- /dev/null
+++ b/drivers/i2c/busses/i2c-falcon.c
@@ -0,0 +1,803 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* #define DEBUG */
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+
+/* CURRENT ISSUES:
+ * - no high speed support
+ * - rx issue with "address mode" & "tx end" interrupts
+ * - ten bit mode is not tested
+ */
+
+/* mapping for access macros */
+#define reg_r32(reg) __raw_readl(reg)
+#define reg_w32(val, reg) __raw_writel(val, reg)
+#define reg_w32_mask(clear, set, reg) \
+ reg_w32((reg_r32(reg) & ~(clear)) | (set), reg)
+#define reg_r32_table(reg, idx) reg_r32(&((uint32_t *)&reg)[idx])
+#define reg_w32_table(val, reg, idx) reg_w32(val, &((uint32_t *)&reg)[idx])
+#define i2c (priv->membase)
+#include <falcon/i2c_reg.h>
+
+/* enable hacks to overcome current issue */
+#define FALCON_FIX_ME
+
+#define FALCON_I2C_ADDR 0x00
+#define FALCON_I2C_READY_TIMEOUT 1000
+#define FALCON_I2C_WAIT_TIMEOUT 10
+
+#define DRV_NAME "i2c-falcon"
+
+#if defined(DEBUG)
+#define static /* no static functions for better debugging */
+#endif
+
+#define FALCON_I2C_ARB_LOST (1 << 0)
+#define FALCON_I2C_NACK (1 << 1)
+#define FALCON_I2C_RX_UFL (1 << 2)
+#define FALCON_I2C_RX_OFL (1 << 3)
+#define FALCON_I2C_TX_UFL (1 << 4)
+#define FALCON_I2C_TX_OFL (1 << 5)
+#define FALCON_I2C_BURST_REQ (1 << 6)
+#define FALCON_I2C_RX (1 << 7)
+#define FALCON_I2C_TX_END (1 << 8)
+#define FALCON_I2C_ADDR_MATCH (1 << 9) /* doesn't trigger */
+
+struct falcon_i2c {
+ spinlock_t lock;
+
+ enum {
+ FALCON_I2C_MODE_100 = 1,
+ FALCON_I2C_MODE_400 = 2,
+ FALCON_I2C_MODE_3400 = 3
+ } mode; /* current speed mode */
+
+ int ten_bit; /* current address mode */
+ unsigned long status; /* bus events holder */
+ struct clk *clk; /* clock input for i2c hardware block */
+ struct gpon_reg_i2c __iomem *membase; /* base of mapped registers */
+ int irq_lb, irq_b, irq_err, irq_p; /* last burst, burst, error,
+ protocol IRQs */
+ struct completion done;
+ struct i2c_adapter adap;
+ struct device *dev;
+};
+
+#define FALCON_I2C_ERROR_MASK (FALCON_I2C_NACK \
+ | FALCON_I2C_ARB_LOST \
+ | FALCON_I2C_RX_OFL \
+ | FALCON_I2C_RX_UFL \
+ | FALCON_I2C_TX_OFL \
+ | FALCON_I2C_TX_UFL)
+
+#define FALCON_I2C_ERROR(priv) (priv->status & FALCON_I2C_ERROR_MASK)
+#define FALCON_I2C_ERROR_CLEAR(priv) do { \
+ priv->status &= \
+ ~FALCON_I2C_ERROR_MASK; \
+ } while (0)
+
+static void falcon_addr_configure(struct falcon_i2c *priv, int ten_bit)
+{
+ u32 ten_bit_mask = ten_bit ? I2C_ADDR_CFG_TBAM_10bit : 0;
+
+ /* configure address */
+ i2c_w32(I2C_ADDR_CFG_SOPE_EN /* generate stop when no more data in the
+ fifo */
+ | I2C_ADDR_CFG_SONA_EN /* generate stop when NA received */
+ | I2C_ADDR_CFG_MnS_EN /* we are master device */
+ | ten_bit_mask
+ | FALCON_I2C_ADDR, /* our address */
+ addr_cfg);
+}
+
+static irqreturn_t falcon_i2c_isr(int irq, void *dev_id)
+{
+ u32 i_raw, i_pro, i_err;
+ struct falcon_i2c *priv = dev_id;
+ unsigned long flags;
+ unsigned int old_status;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ old_status = (unsigned int)priv->status;
+
+ i_raw = i2c_r32(mis);
+
+ /* protocol interrupt */
+ if (i_raw & I2C_RIS_I2C_P_INT_INTOCC) {
+ i_pro = i2c_r32(p_irqss);
+
+ /* tx -> rx switch */
+ if (i_pro & I2C_P_IRQSS_RX)
+ priv->status |= FALCON_I2C_RX;
+
+ /* tx end */
+ if (i_pro & I2C_P_IRQSS_TX_END)
+ priv->status |= FALCON_I2C_TX_END;
+
+ /* not acknowledge */
+ if (i_pro & I2C_P_IRQSS_NACK)
+ priv->status |= FALCON_I2C_NACK;
+
+ /* arbitration lost */
+ if (i_pro & I2C_P_IRQSS_AL)
+ priv->status |= FALCON_I2C_ARB_LOST;
+
+ /* address match */
+ if (i_pro & I2C_P_IRQSS_AM)
+ priv->status |= FALCON_I2C_ADDR_MATCH;
+
+ i2c_w32(i_pro, p_irqsc);
+ }
+
+ /* error interrupt */
+ if (i_raw & I2C_RIS_I2C_ERR_INT_INTOCC) {
+ i_err = i2c_r32(err_irqss);
+
+ /* tx fifo overflow */
+ if (i_err & I2C_ERR_IRQSS_TXF_OFL)
+ priv->status |= FALCON_I2C_TX_OFL;
+
+ /* tx fifo underflow */
+ if (i_err & I2C_ERR_IRQSS_TXF_UFL)
+ priv->status |= FALCON_I2C_TX_UFL;
+
+ /* rx fifo overflow */
+ if (i_err & I2C_ERR_IRQSS_RXF_OFL)
+ priv->status |= FALCON_I2C_RX_OFL;
+
+ /* rx fifo underflow */
+ if (i_err & I2C_ERR_IRQSS_RXF_UFL)
+ priv->status |= FALCON_I2C_RX_UFL;
+
+ i2c_w32(i_err, err_irqsc);
+ }
+
+ /* burst request */
+ if (i_raw & I2C_RIS_BREQ_INT_INTOCC) {
+ i2c_w32_mask(I2C_IMSC_BREQ_INT_EN, 0, imsc);
+ i2c_w32_mask(0, I2C_ICR_BREQ_INT_CLR, icr);
+
+ priv->status |= FALCON_I2C_BURST_REQ;
+ }
+
+ /* last burst request */
+ if (i_raw & I2C_RIS_LBREQ_INT_INTOCC) {
+ i2c_w32_mask(I2C_IMSC_LBREQ_INT_EN, 0, imsc);
+ i2c_w32_mask(0, I2C_ICR_LBREQ_INT_CLR, icr);
+
+ priv->status |= FALCON_I2C_BURST_REQ;
+ }
+
+ if (old_status != (unsigned int)priv->status)
+ complete(&priv->done);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+static int falcon_i2c_ready(struct falcon_i2c *priv)
+{
+ int timeout;
+ u32 bus_stat;
+ unsigned long flags;
+ int ret;
+
+ for (timeout = 0; timeout < FALCON_I2C_READY_TIMEOUT; timeout++) {
+ bus_stat = i2c_r32(bus_stat);
+
+ if (bus_stat & I2C_BUS_STAT_BS_SC) {
+ cpu_relax();
+ } else {
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (FALCON_I2C_ERROR(priv)) {
+ ret = priv->status;
+
+ dev_dbg(priv->dev, "bus ready wait error 0x%08lx\n", priv->status);
+
+ FALCON_I2C_ERROR_CLEAR(priv);
+ } else {
+ ret = 0;
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return ret;
+ }
+ }
+
+ dev_dbg(priv->dev, "bus ready wait timeout\n");
+
+ return -ETIME;
+}
+
+static int falcon_i2c_wait(struct falcon_i2c *priv, unsigned long status)
+{
+ int ret = 0;
+ unsigned long flags;
+ unsigned int timeout;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ priv->status &= FALCON_I2C_BURST_REQ;
+
+ /* check if the event already occurred */
+ if ((priv->status & status) == status) {
+ priv->status &= ~status;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* unmask burst interrupts */
+ i2c_w32_mask(0, I2C_IMSC_LBREQ_INT_EN | I2C_IMSC_BREQ_INT_EN, imsc);
+
+ for (timeout = 0; timeout < FALCON_I2C_WAIT_TIMEOUT; timeout++) {
+ /* wait for the data request */
+ wait_for_completion_timeout(&priv->done, HZ / 10);
+
+ /* handle errors */
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (FALCON_I2C_ERROR(priv)) {
+ dev_dbg(priv->dev, "wait error 0x%08lx (waiting for 0x%08lx)\n",
+ priv->status,
+ status);
+
+ if (priv->status & FALCON_I2C_NACK)
+ ret = -ENXIO;
+ else
+ ret = -EREMOTEIO;
+
+ FALCON_I2C_ERROR_CLEAR(priv);
+ } else {
+ if ((priv->status & status) == status) {
+ priv->status &= ~status;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+ }
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (ret)
+ return ret;
+ }
+
+ dev_dbg(priv->dev, "wait timeout error 0x%08lx (waiting for 0x%08lx)\n",
+ priv->status,
+ status);
+
+ return -ETIME;
+}
+
+static int falcon_i2c_tx(struct falcon_i2c *priv, int ten_bit, u16 addr,
+ u8 *buf, int len)
+{
+ int i;
+ int ret;
+
+ dev_dbg(priv->dev, "%s\n", __func__);
+
+ /* tell fifo the number of bytes we are going to send */
+ i2c_w32(len + (ten_bit ? 2 : 1), tps_ctrl);
+
+ /* wait for the data request */
+ ret = falcon_i2c_wait(priv, FALCON_I2C_BURST_REQ);
+ if (ret)
+ return ret;
+
+ /* send slave address */
+ if (ten_bit) {
+ i2c_w32(0x78 | ((addr >> 7) & 0x7), txd);
+ i2c_w32(0x78 | ((addr & 0x7f) << 1) | 0, txd);
+ } else {
+ i2c_w32((addr << 1) | 0, txd);
+ }
+
+ /* fill fifo */
+ for (i = 0; i < len; i++) {
+ ret = falcon_i2c_wait(priv, FALCON_I2C_BURST_REQ);
+ if (ret)
+ return ret;
+
+ i2c_w32(buf[i], txd);
+ }
+
+ return falcon_i2c_wait(priv, FALCON_I2C_TX_END);
+}
+
+static int falcon_i2c_rx(struct falcon_i2c *priv, int ten_bit, u16 addr,
+ u8 *buf, int len)
+{
+ int i;
+ int ret;
+
+ dev_dbg(priv->dev, "%s\n", __func__);
+
+ /* we need to transmit address only */
+ i2c_w32(ten_bit ? 2 : 1, tps_ctrl);
+
+ /* set maximum received packet size */
+ i2c_w32(len, mrps_ctrl);
+
+ /* wait for the data request */
+ ret = falcon_i2c_wait(priv, FALCON_I2C_BURST_REQ);
+ if (ret)
+ return ret;
+
+ /* write down the address */
+ if (ten_bit) {
+ i2c_w32(0x78 | ((addr >> 7) & 0x7), txd);
+ i2c_w32(0x78 | ((addr & 0x7f) << 1) | 1, txd);
+ } else {
+ i2c_w32((addr << 1) | 1, txd);
+ }
+
+ /* wait for the read request */
+ ret = falcon_i2c_wait(priv, FALCON_I2C_TX_END
+#ifndef FALCON_FIX_ME
+ | FALCON_I2C_ADDR_MATCH
+#endif
+ | FALCON_I2C_RX);
+
+ if (ret)
+ return ret;
+
+ /* read bytes */
+ for (i = 0; i < len; i++) {
+#ifdef FALCON_FIX_ME
+ while (i2c_r32(rps_stat) == 0)
+ cpu_relax();
+#else
+ ret = falcon_i2c_wait(priv, FALCON_I2C_BURST_REQ);
+
+ if (ret)
+ return ret;
+#endif
+
+ buf[i] = i2c_r32(rxd);
+ }
+
+#ifndef FALCON_FIX_ME
+ /* wait for transmission end */
+ return falcon_i2c_wait(priv, FALCON_I2C_TX_END);
+#else
+ return 0;
+#endif
+}
+
+static int falcon_i2c_xfer_msg(struct falcon_i2c *priv, struct i2c_msg *msg)
+{
+ int ret;
+ int ten_bit;
+ unsigned long flags;
+
+ dev_dbg(priv->dev, "%s %u byte(s) %s 0x%02x\n",
+ (msg->flags & I2C_M_RD) ? "read" : "write", msg->len,
+ (msg->flags & I2C_M_RD) ? "from" : "to", msg->addr);
+
+ if (msg->flags & I2C_M_TEN)
+ ten_bit = 1;
+ else
+ ten_bit = 0;
+
+ /* reconfigure bus if need to send message in different address mode */
+ spin_lock_irqsave(&priv->lock, flags);
+ if (ten_bit != priv->ten_bit) {
+
+ /* disable bus */
+ i2c_w32_mask(I2C_RUN_CTRL_RUN_EN, 0, run_ctrl);
+
+ /* reconfigure address */
+ falcon_addr_configure(priv, ten_bit);
+
+ /* enable bus */
+ i2c_w32_mask(0, I2C_RUN_CTRL_RUN_EN, run_ctrl);
+
+ priv->ten_bit = ten_bit;
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* read/write actual message */
+ if (msg->flags & I2C_M_RD)
+ ret = falcon_i2c_rx(priv, ten_bit, msg->addr, msg->buf,
+ msg->len);
+ else
+ ret = falcon_i2c_tx(priv, ten_bit, msg->addr, msg->buf,
+ msg->len);
+
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int falcon_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
+ int num)
+{
+ int i;
+ int ret;
+ unsigned long flags;
+ struct falcon_i2c *priv = i2c_get_adapdata(adap);
+
+ dev_dbg(priv->dev, "xfer %u messages\n", num);
+
+ /* transfer each message */
+ for (i = 0; i < num; i++) {
+#ifdef FALCON_FIX_ME
+ /* disable bus */
+ i2c_w32_mask(I2C_RUN_CTRL_RUN_EN, 0, run_ctrl);
+ /* enable bus */
+ i2c_w32_mask(0, I2C_RUN_CTRL_RUN_EN, run_ctrl);
+#endif
+
+ /* clear bus status */
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->status = 0;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* wait for the bus to become ready */
+ ret = falcon_i2c_ready(priv);
+ if (ret)
+ return ret;
+
+ /* transfer message */
+ ret = falcon_i2c_xfer_msg(priv, &msg[i]);
+
+ if (ret)
+ return ret;
+
+ /* check for unhandled errors */
+ spin_lock_irqsave(&priv->lock, flags);
+ if (FALCON_I2C_ERROR(priv))
+ ret = priv->status;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (ret) {
+ dev_warn(priv->dev, "message %u unhandled error 0x%x\n",
+ i, ret);
+
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static u32 falcon_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm falcon_i2c_algorithm = {
+ .master_xfer = falcon_i2c_xfer,
+ .functionality = falcon_i2c_func,
+};
+
+static int falcon_i2c_hw_init(struct i2c_adapter *adap)
+{
+ struct falcon_i2c *priv = i2c_get_adapdata(adap);
+
+ /* disable bus */
+ i2c_w32_mask(I2C_RUN_CTRL_RUN_EN, 0, run_ctrl);
+
+ /* set normal operation clock divider */
+ i2c_w32(1 << I2C_CLC_RMC_OFFSET, clc);
+
+ /* set frequency */
+ if (priv->mode == FALCON_I2C_MODE_100) {
+ dev_dbg(priv->dev, "set standard mode (100 kHz)\n");
+
+ i2c_w32(0, fdiv_high_cfg);
+
+ i2c_w32((1 << I2C_FDIV_CFG_INC_OFFSET)
+ | (499 << I2C_FDIV_CFG_DEC_OFFSET),
+ fdiv_cfg);
+ } else if (priv->mode == FALCON_I2C_MODE_400) {
+ dev_dbg(priv->dev, "set fast mode (400 kHz)\n");
+
+ i2c_w32(0, fdiv_high_cfg);
+
+ i2c_w32((1 << I2C_FDIV_CFG_INC_OFFSET)
+ | (124 << I2C_FDIV_CFG_DEC_OFFSET),
+ fdiv_cfg);
+ } else if (priv->mode == FALCON_I2C_MODE_3400) {
+ dev_dbg(priv->dev, "set high mode (3.4 MHz)\n");
+
+ i2c_w32(0, fdiv_cfg);
+
+ /* TODO recalculate value for 100MHz input */
+ i2c_w32((41 << I2C_FDIV_CFG_INC_OFFSET)
+ | (152 << I2C_FDIV_CFG_DEC_OFFSET),
+ fdiv_high_cfg);
+ } else {
+ dev_warn(priv->dev, "unknown mode\n");
+
+ return -ENODEV;
+ }
+
+ /* configure fifo */
+ i2c_w32(I2C_FIFO_CFG_TXFC /* tx fifo as flow controller */
+ | I2C_FIFO_CFG_RXFC /* rx fifo as flow controller */
+ | I2C_FIFO_CFG_TXFA_TXFA2 /* tx fifo 4-byte aligned */
+ | I2C_FIFO_CFG_RXFA_RXFA2 /* rx fifo 4-byte aligned */
+ | I2C_FIFO_CFG_TXBS_TXBS0 /* tx fifo burst size is 1 word */
+ | I2C_FIFO_CFG_RXBS_RXBS0, /* rx fifo burst size is 1 word */
+ fifo_cfg);
+
+ /* configure address */
+ falcon_addr_configure(priv, priv->ten_bit);
+
+ /* enable bus */
+ i2c_w32_mask(0, I2C_RUN_CTRL_RUN_EN, run_ctrl);
+
+ /* mask burst interrupts */
+ i2c_w32_mask(I2C_IMSC_LBREQ_INT_EN | I2C_IMSC_BREQ_INT_EN, 0, imsc);
+
+ /* enable interrupts */
+ i2c_w32(I2C_IMSC_LBREQ_INT_EN
+ | I2C_IMSC_BREQ_INT_EN
+ | I2C_IMSC_I2C_P_INT_EN
+ | I2C_IMSC_I2C_ERR_INT_EN,
+ imsc);
+
+ return 0;
+}
+
+static int __devinit falcon_i2c_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct falcon_i2c *priv;
+ struct i2c_adapter *adap;
+ struct resource *mmres, *ioarea,
+ *irqres_lb, *irqres_b, *irqres_err, *irqres_p;
+ struct clk *clk;
+
+ dev_dbg(&pdev->dev, "probing\n");
+
+ mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irqres_lb = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
+ "i2c_lb");
+ irqres_b = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "i2c_b");
+ irqres_err = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
+ "i2c_err");
+ irqres_p = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "i2c_p");
+
+ if (!mmres || !irqres_lb || !irqres_b || !irqres_err || !irqres_p) {
+ dev_err(&pdev->dev, "no resources\n");
+ return -ENODEV;
+ }
+
+ clk = clk_get(&pdev->dev, "fpi");
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "failed to get fpi clk\n");
+ return -ENOENT;
+ }
+
+ if (clk_get_rate(clk) != 100000000) {
+ dev_err(&pdev->dev, "input clock is not 100MHz\n");
+ return -ENOENT;
+ }
+
+ /* allocate private data */
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ dev_err(&pdev->dev, "can't allocate private data\n");
+ return -ENOMEM;
+ }
+
+ adap = &priv->adap;
+ i2c_set_adapdata(adap, priv);
+ adap->owner = THIS_MODULE;
+ adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ strlcpy(adap->name, DRV_NAME "-adapter", sizeof(adap->name));
+ adap->algo = &falcon_i2c_algorithm;
+
+ priv->ten_bit = 0;
+ priv->mode = FALCON_I2C_MODE_100;
+ priv->clk = clk;
+ priv->dev = &pdev->dev;
+
+ spin_lock_init(&priv->lock);
+
+ ioarea = request_mem_region(mmres->start, resource_size(mmres),
+ pdev->name);
+
+ if (ioarea == NULL) {
+ dev_err(&pdev->dev, "I2C region already claimed\n");
+ ret = -ENXIO;
+ goto err_free_priv;
+ }
+
+ /* map memory */
+ priv->membase = ioremap_nocache(mmres->start & ~KSEG1,
+ resource_size(mmres));
+ if (priv->membase == NULL) {
+ ret = -ENOMEM;
+ goto err_release_region;
+ }
+
+ priv->irq_lb = irqres_lb->start;
+ ret = request_irq(priv->irq_lb, falcon_i2c_isr, IRQF_DISABLED,
+ irqres_lb->name, priv);
+ if (ret) {
+ dev_err(&pdev->dev, "can't get last burst IRQ %d\n", irqres_lb->start);
+ ret = -ENODEV;
+ goto err_unmap_mem;
+ }
+
+ priv->irq_b = irqres_b->start;
+ ret = request_irq(priv->irq_b, falcon_i2c_isr, IRQF_DISABLED,
+ irqres_b->name, priv);
+ if (ret) {
+ dev_err(&pdev->dev, "can't get burst IRQ %d\n", irqres_b->start);
+ ret = -ENODEV;
+ goto err_free_lb_irq;
+ }
+
+ priv->irq_err = irqres_err->start;
+ ret = request_irq(priv->irq_err, falcon_i2c_isr, IRQF_DISABLED,
+ irqres_err->name, priv);
+ if (ret) {
+ dev_err(&pdev->dev, "can't get error IRQ %d\n", irqres_err->start);
+ ret = -ENODEV;
+ goto err_free_b_irq;
+ }
+
+ priv->irq_p = irqres_p->start;
+ ret = request_irq(priv->irq_p, falcon_i2c_isr, IRQF_DISABLED,
+ irqres_p->name, priv);
+ if (ret) {
+ dev_err(&pdev->dev, "can't get protocol IRQ %d\n", irqres_p->start);
+ ret = -ENODEV;
+ goto err_free_err_irq;
+ }
+
+ dev_dbg(&pdev->dev, "mapped io-space to %p\n", priv->membase);
+ dev_dbg(&pdev->dev, "use IRQs %d, %d, %d, %d\n", irqres_lb->start,
+ irqres_b->start, irqres_err->start, irqres_p->start);
+
+ /* add our adapter to the i2c stack */
+ ret = i2c_add_numbered_adapter(adap);
+ if (ret) {
+ dev_err(&pdev->dev, "can't register I2C adapter\n");
+ goto err_free_p_irq;
+ }
+
+ platform_set_drvdata(pdev, priv);
+ i2c_set_adapdata(adap, priv);
+
+ /* print module version information */
+ dev_dbg(&pdev->dev, "module id=%u revision=%u\n",
+ (i2c_r32(id) & I2C_ID_ID_MASK) >> I2C_ID_ID_OFFSET,
+ (i2c_r32(id) & I2C_ID_REV_MASK) >> I2C_ID_REV_OFFSET);
+
+ init_completion(&priv->done);
+
+ /* initialize HW */
+ ret = falcon_i2c_hw_init(adap);
+ if (ret) {
+ dev_err(&pdev->dev, "can't configure adapter\n");
+ goto err_remove_adapter;
+ }
+
+ return 0;
+
+err_remove_adapter:
+ i2c_del_adapter(adap);
+ platform_set_drvdata(pdev, NULL);
+
+err_free_p_irq:
+ free_irq(priv->irq_p, priv);
+
+err_free_err_irq:
+ free_irq(priv->irq_err, priv);
+
+err_free_b_irq:
+ free_irq(priv->irq_b, priv);
+
+err_free_lb_irq:
+ free_irq(priv->irq_lb, priv);
+
+err_unmap_mem:
+ iounmap(priv->membase);
+
+err_release_region:
+ release_mem_region(mmres->start, resource_size(mmres));
+
+err_free_priv:
+ kfree(priv);
+
+ return ret;
+}
+
+static int __devexit falcon_i2c_remove(struct platform_device *pdev)
+{
+ struct falcon_i2c *priv = platform_get_drvdata(pdev);
+ struct resource *mmres;
+
+ /* disable bus */
+ i2c_w32_mask(I2C_RUN_CTRL_RUN_EN, 0, run_ctrl);
+
+ /* remove driver */
+ platform_set_drvdata(pdev, NULL);
+ i2c_del_adapter(&priv->adap);
+
+ free_irq(priv->irq_lb, priv);
+ free_irq(priv->irq_b, priv);
+ free_irq(priv->irq_err, priv);
+ free_irq(priv->irq_p, priv);
+
+ kfree(priv);
+
+ mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(mmres->start, resource_size(mmres));
+
+ dev_dbg(&pdev->dev, "removed\n");
+
+ return 0;
+}
+
+static struct platform_driver falcon_i2c_driver = {
+ .probe = falcon_i2c_probe,
+ .remove = __devexit_p(falcon_i2c_remove),
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init falcon_i2c_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&falcon_i2c_driver);
+
+ if (ret)
+ printk(KERN_DEBUG DRV_NAME ": can't register platform driver");
+
+ return ret;
+}
+
+static void __exit falcon_i2c_exit(void)
+{
+ platform_driver_unregister(&falcon_i2c_driver);
+}
+
+module_init(falcon_i2c_init);
+module_exit(falcon_i2c_exit);
+
+MODULE_DESCRIPTION("Lantiq FALC(tm) ON - I2C bus adapter");
+MODULE_ALIAS("platform:i2c_falcon");
+MODULE_LICENSE("GPL");

View File

@ -0,0 +1,497 @@
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -55,6 +55,7 @@ obj-$(CONFIG_SPI_SH_SCI) += spi_sh_sci.
obj-$(CONFIG_SPI_SH_MSIOF) += spi_sh_msiof.o
obj-$(CONFIG_SPI_STMP3XXX) += spi_stmp.o
obj-$(CONFIG_SPI_NUC900) += spi_nuc900.o
+obj-$(CONFIG_SPI_FALCON) += spi_falcon.o
# special build for s3c24xx spi driver with fiq support
spi_s3c24xx_hw-y := spi_s3c24xx.o
--- /dev/null
+++ b/drivers/spi/spi_falcon.c
@@ -0,0 +1,471 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+
+#include <lantiq.h> /* ebu_lock */
+#include <falcon/ebu_reg.h>
+#include <falcon/sys1_reg.h>
+
+#define DRV_NAME "falcon_spi"
+
+#define FALCON_SPI_XFER_BEGIN (1 << 0)
+#define FALCON_SPI_XFER_END (1 << 1)
+
+/* mapping for access macros */
+#define reg_r32(reg) __raw_readl(reg)
+#define reg_w32(val, reg) __raw_writel(val, reg)
+#define reg_w32_mask(clear, set, reg) reg_w32((reg_r32(reg) \
+ & ~(clear)) | (set), reg)
+#define reg_r32_table(reg, idx) reg_r32(&((uint32_t *)&reg)[idx])
+#define reg_w32_table(val, reg, idx) reg_w32(val, &((uint32_t *)&reg)[idx])
+
+#define ebu (priv->ebu_membase)
+#define sys1 (priv->sys1_membase)
+
+struct falcon_spi {
+ u32 sfcmd; /* for caching of opcode, direction, ... */
+
+ struct spi_master *master;
+
+ struct gpon_reg_ebu __iomem *ebu_membase;
+ struct gpon_reg_sys1 __iomem *sys1_membase;
+};
+
+int falcon_spi_xfer(struct spi_device *spi,
+ struct spi_transfer *t,
+ unsigned long flags)
+{
+ struct device *dev = &spi->dev;
+ struct falcon_spi *priv = spi_master_get_devdata(spi->master);
+ const u8 *txp = t->tx_buf;
+ u8 *rxp = t->rx_buf;
+ unsigned int bytelen = ((8 * t->len + 7) / 8);
+ unsigned int len, alen, dumlen;
+ u32 val;
+ enum {
+ state_init,
+ state_command_prepare,
+ state_write,
+ state_read,
+ state_disable_cs,
+ state_end
+ } state = state_init;
+
+ do {
+ switch (state) {
+ case state_init: /* detect phase of upper layer sequence */
+ {
+ /* initial write ? */
+ if (flags & FALCON_SPI_XFER_BEGIN) {
+ if (!txp) {
+ dev_err(dev,
+ "BEGIN without tx data!\n");
+ return -1;
+ }
+ /*
+ * Prepare the parts of the sfcmd register,
+ * which should not
+ * change during a sequence!
+ * Only exception are the length fields,
+ * especially alen and dumlen.
+ */
+
+ priv->sfcmd = ((spi->chip_select
+ << SFCMD_CS_OFFSET)
+ & SFCMD_CS_MASK);
+ priv->sfcmd |= SFCMD_KEEP_CS_KEEP_SELECTED;
+ priv->sfcmd |= *txp;
+ txp++;
+ bytelen--;
+ if (bytelen) {
+ /* more data:
+ * maybe address and/or dummy */
+ state = state_command_prepare;
+ break;
+ } else {
+ dev_dbg(dev, "write cmd %02X\n",
+ priv->sfcmd & SFCMD_OPC_MASK);
+ }
+ }
+ /* continued write ? */
+ if (txp && bytelen) {
+ state = state_write;
+ break;
+ }
+ /* read data? */
+ if (rxp && bytelen) {
+ state = state_read;
+ break;
+ }
+ /* end of sequence? */
+ if (flags & FALCON_SPI_XFER_END)
+ state = state_disable_cs;
+ else
+ state = state_end;
+ break;
+ }
+ case state_command_prepare: /* collect tx data for
+ address and dummy phase */
+ {
+ /* txp is valid, already checked */
+ val = 0;
+ alen = 0;
+ dumlen = 0;
+ while (bytelen > 0) {
+ if (alen < 3) {
+ val = (val<<8)|(*txp++);
+ alen++;
+ } else if ((dumlen < 15) && (*txp == 0)) {
+ /*
+ * assume dummy bytes are set to 0
+ * from upper layer
+ */
+ dumlen++;
+ txp++;
+ } else
+ break;
+ bytelen--;
+ }
+ priv->sfcmd &= ~(SFCMD_ALEN_MASK | SFCMD_DUMLEN_MASK);
+ priv->sfcmd |= (alen << SFCMD_ALEN_OFFSET) |
+ (dumlen << SFCMD_DUMLEN_OFFSET);
+ if (alen > 0)
+ ebu_w32(val, sfaddr);
+
+ dev_dbg(dev, "write cmd %02X, alen=%d "
+ "(addr=%06X) dumlen=%d\n",
+ priv->sfcmd & SFCMD_OPC_MASK,
+ alen, val, dumlen);
+
+ if (bytelen > 0) {
+ /* continue with write */
+ state = state_write;
+ } else if (flags & FALCON_SPI_XFER_END) {
+ /* end of sequence? */
+ state = state_disable_cs;
+ } else {
+ /* go to end and expect another
+ * call (read or write) */
+ state = state_end;
+ }
+ break;
+ }
+ case state_write:
+ {
+ /* txp still valid */
+ priv->sfcmd |= SFCMD_DIR_WRITE;
+ len = 0;
+ val = 0;
+ do {
+ if (bytelen--)
+ val |= (*txp++) << (8 * len++);
+ if ((flags & FALCON_SPI_XFER_END)
+ && (bytelen == 0)) {
+ priv->sfcmd &=
+ ~SFCMD_KEEP_CS_KEEP_SELECTED;
+ }
+ if ((len == 4) || (bytelen == 0)) {
+ ebu_w32(val, sfdata);
+ ebu_w32(priv->sfcmd
+ | (len<<SFCMD_DLEN_OFFSET),
+ sfcmd);
+ len = 0;
+ val = 0;
+ priv->sfcmd &= ~(SFCMD_ALEN_MASK
+ | SFCMD_DUMLEN_MASK);
+ }
+ } while (bytelen);
+ state = state_end;
+ break;
+ }
+ case state_read:
+ {
+ /* read data */
+ priv->sfcmd &= ~SFCMD_DIR_WRITE;
+ do {
+ if ((flags & FALCON_SPI_XFER_END)
+ && (bytelen <= 4)) {
+ priv->sfcmd &=
+ ~SFCMD_KEEP_CS_KEEP_SELECTED;
+ }
+ len = (bytelen > 4) ? 4 : bytelen;
+ bytelen -= len;
+ ebu_w32(priv->sfcmd
+ |(len<<SFCMD_DLEN_OFFSET), sfcmd);
+ priv->sfcmd &= ~(SFCMD_ALEN_MASK
+ | SFCMD_DUMLEN_MASK);
+ do {
+ val = ebu_r32(sfstat);
+ if (val & SFSTAT_CMD_ERR) {
+ /* reset error status */
+ dev_err(dev, "SFSTAT: CMD_ERR "
+ "(%x)\n", val);
+ ebu_w32(SFSTAT_CMD_ERR, sfstat);
+ return -1;
+ }
+ } while (val & SFSTAT_CMD_PEND);
+ val = ebu_r32(sfdata);
+ do {
+ *rxp = (val & 0xFF);
+ rxp++;
+ val >>= 8;
+ len--;
+ } while (len);
+ } while (bytelen);
+ state = state_end;
+ break;
+ }
+ case state_disable_cs:
+ {
+ priv->sfcmd &= ~SFCMD_KEEP_CS_KEEP_SELECTED;
+ ebu_w32(priv->sfcmd | (0<<SFCMD_DLEN_OFFSET), sfcmd);
+ val = ebu_r32(sfstat);
+ if (val & SFSTAT_CMD_ERR) {
+ /* reset error status */
+ dev_err(dev, "SFSTAT: CMD_ERR (%x)\n", val);
+ ebu_w32(SFSTAT_CMD_ERR, sfstat);
+ return -1;
+ }
+ state = state_end;
+ break;
+ }
+ case state_end:
+ break;
+ }
+ } while (state != state_end);
+
+ return 0;
+}
+
+static int falcon_spi_setup(struct spi_device *spi)
+{
+ struct device *dev = &spi->dev;
+ struct falcon_spi *priv = spi_master_get_devdata(spi->master);
+ const u32 ebuclk = 100*1000*1000;
+ unsigned int i;
+ unsigned long flags;
+
+ dev_dbg(dev, "setup\n");
+
+ if (spi->master->bus_num > 0 || spi->chip_select > 0)
+ return -ENODEV;
+
+ spin_lock_irqsave(&ebu_lock, flags);
+
+ if (ebuclk < spi->max_speed_hz) {
+ /* set EBU clock to 100 MHz */
+ sys1_w32_mask(0, EBUCC_EBUDIV_SELF100, ebucc);
+ i = 1; /* divider */
+ } else {
+ /* set EBU clock to 50 MHz */
+ sys1_w32_mask(EBUCC_EBUDIV_SELF100, 0, ebucc);
+
+ /* search for suitable divider */
+ for (i = 1; i < 7; i++) {
+ if (ebuclk / i <= spi->max_speed_hz)
+ break;
+ }
+ }
+
+ /* setup period of serial clock */
+ ebu_w32_mask(SFTIME_SCKF_POS_MASK
+ | SFTIME_SCKR_POS_MASK
+ | SFTIME_SCK_PER_MASK,
+ (i << SFTIME_SCKR_POS_OFFSET)
+ | (i << (SFTIME_SCK_PER_OFFSET + 1)),
+ sftime);
+
+ /* set some bits of unused_wd, to not trigger HOLD/WP
+ * signals on non QUAD flashes */
+ ebu_w32((SFIO_UNUSED_WD_MASK & (0x8|0x4)), sfio);
+
+ ebu_w32(BUSRCON0_AGEN_SERIAL_FLASH | BUSRCON0_PORTW_8_BIT_MUX,
+ busrcon0);
+ ebu_w32(BUSWCON0_AGEN_SERIAL_FLASH, buswcon0);
+ /* set address wrap around to maximum for 24-bit addresses */
+ ebu_w32_mask(SFCON_DEV_SIZE_MASK, SFCON_DEV_SIZE_A23_0, sfcon);
+
+ spin_unlock_irqrestore(&ebu_lock, flags);
+
+ return 0;
+}
+
+static int falcon_spi_transfer(struct spi_device *spi, struct spi_message *m)
+{
+ struct falcon_spi *priv = spi_master_get_devdata(spi->master);
+ struct spi_transfer *t;
+ unsigned long spi_flags;
+ unsigned long flags;
+ int ret = 0;
+
+ priv->sfcmd = 0;
+ m->actual_length = 0;
+
+ spi_flags = FALCON_SPI_XFER_BEGIN;
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ if (list_is_last(&t->transfer_list, &m->transfers))
+ spi_flags |= FALCON_SPI_XFER_END;
+
+ spin_lock_irqsave(&ebu_lock, flags);
+ ret = falcon_spi_xfer(spi, t, spi_flags);
+ spin_unlock_irqrestore(&ebu_lock, flags);
+
+ if (ret)
+ break;
+
+ m->actual_length += t->len;
+
+ if (t->delay_usecs || t->cs_change)
+ BUG();
+
+ spi_flags = 0;
+ }
+
+ m->status = ret;
+ m->complete(m->context);
+
+ return 0;
+}
+
+static void falcon_spi_cleanup(struct spi_device *spi)
+{
+ struct device *dev = &spi->dev;
+
+ dev_dbg(dev, "cleanup\n");
+}
+
+static int __devinit falcon_spi_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct falcon_spi *priv;
+ struct spi_master *master;
+ struct resource *memres_ebu, *memres_sys1;
+ int ret;
+
+ dev_dbg(dev, "probing\n");
+
+ memres_ebu = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ebu");
+ memres_sys1 = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "sys1");
+
+ if (!memres_ebu || !memres_sys1) {
+ dev_err(dev, "no resources\n");
+ return -ENODEV;
+ }
+
+ master = spi_alloc_master(&pdev->dev, sizeof(*priv));
+ if (!master) {
+ dev_err(dev, "no memory for spi_master\n");
+ return -ENOMEM;
+ }
+
+ priv = spi_master_get_devdata(master);
+
+ priv->ebu_membase = ioremap_nocache(memres_ebu->start & ~KSEG1,
+ resource_size(memres_ebu));
+
+ if (!priv->ebu_membase) {
+ dev_err(dev, "can't map ebu memory\n");
+
+ ret = -ENOMEM;
+ goto free_master;
+ }
+
+ priv->sys1_membase = ioremap_nocache(memres_sys1->start & ~KSEG1,
+ resource_size(memres_sys1));
+
+ if (!priv->sys1_membase) {
+ dev_err(dev, "can't map sys1 memory\n");
+
+ ret = -ENOMEM;
+ goto unmap_ebu;
+ }
+
+ priv->master = master;
+
+ master->mode_bits = SPI_MODE_3;
+ master->num_chipselect = 1;
+ master->bus_num = 0;
+
+ master->setup = falcon_spi_setup;
+ master->transfer = falcon_spi_transfer;
+ master->cleanup = falcon_spi_cleanup;
+
+ platform_set_drvdata(pdev, priv);
+
+ ret = spi_register_master(master);
+ if (ret)
+ goto unmap_sys1;
+
+ return 0;
+
+unmap_sys1:
+ iounmap(priv->sys1_membase);
+
+unmap_ebu:
+ iounmap(priv->ebu_membase);
+
+free_master:
+ spi_master_put(master);
+
+ return ret;
+}
+
+static int __devexit falcon_spi_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct falcon_spi *priv = platform_get_drvdata(pdev);
+
+ dev_dbg(dev, "removed\n");
+
+ spi_unregister_master(priv->master);
+
+ iounmap(priv->sys1_membase);
+ iounmap(priv->ebu_membase);
+
+ return 0;
+}
+
+static struct platform_driver falcon_spi_driver = {
+ .probe = falcon_spi_probe,
+ .remove = __devexit_p(falcon_spi_remove),
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE
+ }
+};
+
+static int __init falcon_spi_init(void)
+{
+ return platform_driver_register(&falcon_spi_driver);
+}
+
+static void __exit falcon_spi_exit(void)
+{
+ platform_driver_unregister(&falcon_spi_driver);
+}
+
+module_init(falcon_spi_init);
+module_exit(falcon_spi_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Lantiq Falcon SPI controller driver");
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -210,6 +210,10 @@ config SPI_MPC52xx
This drivers supports the MPC52xx SPI controller in master SPI
mode.
+config SPI_FALCON
+ tristate "Falcon SPI controller support"
+ depends on SOC_FALCON
+
config SPI_MPC52xx_PSC
tristate "Freescale MPC52xx PSC SPI controller"
depends on PPC_MPC52xx && EXPERIMENTAL

View File

@ -0,0 +1,193 @@
--- a/arch/mips/lantiq/falcon/Makefile
+++ b/arch/mips/lantiq/falcon/Makefile
@@ -2,3 +2,4 @@ obj-y := clk-falcon.o devices.o gpio.o p
obj-y += softdog_vpe.o
obj-$(CONFIG_LANTIQ_MACH_EASY98000) += addon-easy98000.o
obj-$(CONFIG_LANTIQ_MACH_EASY98000) += mach-easy98000.o
+obj-$(CONFIG_LANTIQ_MACH_EASY98000) += dev-leds-easy98000-cpld.o
--- /dev/null
+++ b/arch/mips/lantiq/falcon/dev-leds-easy98000-cpld.c
@@ -0,0 +1,160 @@
+/*
+ * EASY98000 CPLD LED driver
+ *
+ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
+ *
+ * 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/version.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/leds.h>
+#include <linux/slab.h>
+
+#include "dev-leds-easy98000-cpld.h"
+
+const char *led_name[8] = {
+ "ge0_act",
+ "ge0_link",
+ "ge1_act",
+ "ge1_link",
+ "fe2_act",
+ "fe2_link",
+ "fe3_act",
+ "fe3_link"
+};
+
+#define cpld_base7 ((u16 *)(KSEG1 | 0x17c0000c))
+#define cpld_base8 ((u16 *)(KSEG1 | 0x17c00012))
+
+#define ltq_r16(reg) __raw_readw(reg)
+#define ltq_w16(val, reg) __raw_writew(val, reg)
+
+struct cpld_led_dev {
+ struct led_classdev cdev;
+ u8 mask;
+ u16 *base;
+};
+
+struct cpld_led_drvdata {
+ struct cpld_led_dev *led_devs;
+ int num_leds;
+};
+
+void led_set(u8 mask, u16 *base)
+{
+ ltq_w16(ltq_r16(base) | mask, base);
+}
+
+void led_clear(u8 mask, u16 *base)
+{
+ ltq_w16(ltq_r16(base) & (~mask), base);
+}
+
+void led_blink_clear(u8 mask, u16 *base)
+{
+ led_clear(mask, base);
+}
+
+static void led_brightness(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ struct cpld_led_dev *led_dev =
+ container_of(led_cdev, struct cpld_led_dev, cdev);
+
+ if (value)
+ led_set(led_dev->mask, led_dev->base);
+ else
+ led_clear(led_dev->mask, led_dev->base);
+}
+
+static int led_probe(struct platform_device *pdev)
+{
+ int i;
+ char name[32];
+ struct cpld_led_drvdata *drvdata;
+ int ret = 0;
+
+ drvdata = kzalloc(sizeof(struct cpld_led_drvdata) +
+ sizeof(struct cpld_led_dev) * MAX_LED,
+ GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+
+ drvdata->led_devs = (struct cpld_led_dev *) &drvdata[1];
+
+ for (i = 0; i < MAX_LED; i++) {
+ struct cpld_led_dev *led_dev = &drvdata->led_devs[i];
+ led_dev->cdev.brightness_set = led_brightness;
+ led_dev->cdev.default_trigger = NULL;
+ led_dev->mask = 1 << (i % 8);
+ if(i < 8) {
+ sprintf(name, "easy98000-cpld:%s", led_name[i]);
+ led_dev->base = cpld_base8;
+ } else {
+ sprintf(name, "easy98000-cpld:red:%d", i-8);
+ led_dev->base = cpld_base7;
+ }
+ led_dev->cdev.name = name;
+ ret = led_classdev_register(&pdev->dev, &led_dev->cdev);
+ if (ret)
+ goto err;
+ }
+ platform_set_drvdata(pdev, drvdata);
+ return 0;
+
+err:
+ printk("led_probe: 3\n");
+ for (i = i - 1; i >= 0; i--)
+ led_classdev_unregister(&drvdata->led_devs[i].cdev);
+
+ kfree(drvdata);
+ return ret;
+}
+
+static int led_remove(struct platform_device *pdev)
+{
+ int i;
+ struct cpld_led_drvdata *drvdata = platform_get_drvdata(pdev);
+ for (i = 0; i < MAX_LED; i++)
+ led_classdev_unregister(&drvdata->led_devs[i].cdev);
+ kfree(drvdata);
+ return 0;
+}
+
+static struct platform_driver led_driver = {
+ .probe = led_probe,
+ .remove = __devexit_p(led_remove),
+ .driver = {
+ .name = LED_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+int __init easy98000_cpld_led_init(void)
+{
+ pr_info(LED_DESC ", Version " LED_VERSION
+ " (c) Copyright 2011, Lantiq Deutschland GmbH\n");
+ return platform_driver_register(&led_driver);
+}
+
+void __exit easy98000_cpld_led_exit(void)
+{
+ platform_driver_unregister(&led_driver);
+}
+
+module_init(easy98000_cpld_led_init);
+module_exit(easy98000_cpld_led_exit);
+
+MODULE_DESCRIPTION(LED_NAME);
+MODULE_DESCRIPTION(LED_DESC);
+MODULE_AUTHOR("Ralph Hempel <ralph.hempel@lantiq.com>");
+MODULE_LICENSE("GPL v2");
+
--- /dev/null
+++ b/arch/mips/lantiq/falcon/dev-leds-easy98000-cpld.h
@@ -0,0 +1,20 @@
+/*
+ * EASY98000 CPLD LED driver
+ *
+ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ */
+#ifndef _INCLUDE_EASY98000_CPLD_LED_H_
+#define _INCLUDE_EASY98000_CPLD_LED_H_
+
+#define LED_NAME "easy98000_cpld_led"
+#define LED_DESC "EASY98000 LED driver"
+#define LED_VERSION "1.0.0"
+
+#define MAX_LED 16
+
+#endif /* _INCLUDE_EASY98000_CPLD_LED_H_ */

View File

@ -0,0 +1,136 @@
--- /dev/null
+++ b/arch/mips/lantiq/falcon/mach-easy98020.c
@@ -0,0 +1,113 @@
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/gpio.h>
+#include <linux/gpio_buttons.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include "../machtypes.h"
+
+#include "devices.h"
+#include "dev-leds-gpio.h"
+
+#define EASY98020_GPIO_LED_0 9
+#define EASY98020_GPIO_LED_1 10
+#define EASY98020_GPIO_LED_2 11
+#define EASY98020_GPIO_LED_3 12
+#define EASY98020_GPIO_LED_GE0_ACT 110
+#define EASY98020_GPIO_LED_GE0_LINK 109
+#define EASY98020_GPIO_LED_GE1_ACT 106
+#define EASY98020_GPIO_LED_GE1_LINK 105
+
+extern unsigned char ltq_ethaddr[6];
+
+static struct mtd_partition easy98020_spi_partitions[] =
+{
+ {
+ .name = "uboot",
+ .offset = 0x0,
+ .size = 0x40000,
+ },
+ {
+ .name = "uboot_env",
+ .offset = 0x40000,
+ .size = 0x40000, /* 2 sectors for redundant env. */
+ },
+ {
+ .name = "linux",
+ .offset = 0x80000,
+ .size = 0xF80000, /* map only 16 MiB */
+ },
+};
+
+static struct flash_platform_data easy98020_spi_flash_platform_data = {
+ .name = "sflash",
+ .parts = easy98020_spi_partitions,
+ .nr_parts = ARRAY_SIZE(easy98020_spi_partitions)
+};
+
+static struct spi_board_info easy98020_spi_flash_data __initdata = {
+ .modalias = "m25p80",
+ .bus_num = 0,
+ .chip_select = 0,
+ .max_speed_hz = 10 * 1000 * 1000,
+ .mode = SPI_MODE_3,
+ .platform_data = &easy98020_spi_flash_platform_data
+};
+
+static struct gpio_led easy98020_leds_gpio[] __initdata = {
+ {
+ .name = "easy98020:green:0",
+ .gpio = EASY98020_GPIO_LED_0,
+ .active_low = 0,
+ }, {
+ .name = "easy98020:green:1",
+ .gpio = EASY98020_GPIO_LED_1,
+ .active_low = 0,
+ }, {
+ .name = "easy98020:green:2",
+ .gpio = EASY98020_GPIO_LED_2,
+ .active_low = 0,
+ }, {
+ .name = "easy98020:green:3",
+ .gpio = EASY98020_GPIO_LED_3,
+ .active_low = 0,
+ }, {
+ .name = "easy98020:ge0_act",
+ .gpio = EASY98020_GPIO_LED_GE0_ACT,
+ .active_low = 0,
+ }, {
+ .name = "easy98020:ge0_link",
+ .gpio = EASY98020_GPIO_LED_GE0_LINK,
+ .active_low = 0,
+ }, {
+ .name = "easy98020:ge1_act",
+ .gpio = EASY98020_GPIO_LED_GE1_ACT,
+ .active_low = 0,
+ }, {
+ .name = "easy98020:ge1_link",
+ .gpio = EASY98020_GPIO_LED_GE1_LINK,
+ .active_low = 0,
+ }
+};
+
+static void __init easy98020_init(void)
+{
+ falcon_register_asc(0);
+ falcon_register_gpio();
+ falcon_register_wdt();
+ falcon_register_i2c();
+ falcon_register_spi_flash(&easy98020_spi_flash_data);
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(easy98020_leds_gpio),
+ easy98020_leds_gpio);
+ falcon_register_crypto();
+}
+
+MIPS_MACHINE(LANTIQ_MACH_EASY98020,
+ "EASY98020",
+ "EASY98020 Eval Board",
+ easy98020_init);
--- a/arch/mips/lantiq/falcon/Kconfig
+++ b/arch/mips/lantiq/falcon/Kconfig
@@ -6,6 +6,10 @@
bool "Easy98000"
default y
+config LANTIQ_MACH_EASY98020
+ bool "Easy98020"
+ default y
+
endmenu
endif
--- a/arch/mips/lantiq/falcon/Makefile
+++ b/arch/mips/lantiq/falcon/Makefile
@@ -3,3 +3,4 @@
obj-$(CONFIG_LANTIQ_MACH_EASY98000) += addon-easy98000.o
obj-$(CONFIG_LANTIQ_MACH_EASY98000) += mach-easy98000.o
obj-$(CONFIG_LANTIQ_MACH_EASY98000) += dev-leds-easy98000-cpld.o
+obj-$(CONFIG_LANTIQ_MACH_EASY98020) += mach-easy98020.o

View File

@ -0,0 +1,132 @@
--- /dev/null
+++ b/arch/mips/lantiq/falcon/mach-95C3AM1.c
@@ -0,0 +1,99 @@
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/i2c-gpio.h>
+#include "../machtypes.h"
+
+#include "devices.h"
+#include "dev-leds-gpio.h"
+
+#define BOARD_95C3AM1_GPIO_LED_0 10
+#define BOARD_95C3AM1_GPIO_LED_1 11
+#define BOARD_95C3AM1_GPIO_LED_2 12
+#define BOARD_95C3AM1_GPIO_LED_3 13
+
+extern unsigned char ltq_ethaddr[6];
+
+static struct mtd_partition board_95C3AM1_partitions[] =
+{
+ {
+ .name = "uboot",
+ .offset = 0x0,
+ .size = 0x40000,
+ },
+ {
+ .name = "uboot_env",
+ .offset = 0x40000,
+ .size = 0x40000, /* 2 sectors for redundant env. */
+ },
+ {
+ .name = "linux",
+ .offset = 0x80000,
+ .size = 0xF80000, /* map only 16 MiB */
+ },
+};
+
+static struct flash_platform_data board_95C3AM1_flash_platform_data = {
+ .name = "sflash",
+ .parts = board_95C3AM1_partitions,
+ .nr_parts = ARRAY_SIZE(board_95C3AM1_partitions)
+};
+
+static struct spi_board_info board_95C3AM1_flash_data __initdata = {
+ .modalias = "m25p80",
+ .bus_num = 0,
+ .chip_select = 0,
+ .max_speed_hz = 10 * 1000 * 1000,
+ .mode = SPI_MODE_3,
+ .platform_data = &board_95C3AM1_flash_platform_data
+};
+
+static struct gpio_led board_95C3AM1_leds_gpio[] __initdata = {
+ {
+ .name = "power",
+ .gpio = BOARD_95C3AM1_GPIO_LED_0,
+ .active_low = 0,
+ }, {
+ .name = "optical",
+ .gpio = BOARD_95C3AM1_GPIO_LED_1,
+ .active_low = 0,
+ }, {
+ .name = "lan",
+ .gpio = BOARD_95C3AM1_GPIO_LED_2,
+ .active_low = 0,
+ }, {
+ .name = "update",
+ .gpio = BOARD_95C3AM1_GPIO_LED_3,
+ .active_low = 0,
+ }
+};
+
+static struct i2c_gpio_platform_data board_95C3AM1_i2c_gpio_data = {
+ .sda_pin = 107,
+ .scl_pin = 108,
+};
+
+static struct platform_device board_95C3AM1_i2c_gpio_device = {
+ .name = "i2c-gpio",
+ .id = 0,
+ .dev = {
+ .platform_data = &board_95C3AM1_i2c_gpio_data,
+ }
+};
+
+static void __init board_95C3AM1_init(void)
+{
+ falcon_register_asc(0);
+ falcon_register_gpio();
+ falcon_register_wdt();
+ falcon_register_i2c();
+ falcon_register_spi_flash(&board_95C3AM1_flash_data);
+ platform_device_register(&board_95C3AM1_i2c_gpio_device);
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(board_95C3AM1_leds_gpio),
+ board_95C3AM1_leds_gpio);
+ falcon_register_crypto();
+}
+
+MIPS_MACHINE(LANTIQ_MACH_95C3AM1,
+ "95C3AM1",
+ "95C3AM1 Board",
+ board_95C3AM1_init);
--- a/arch/mips/lantiq/falcon/Kconfig
+++ b/arch/mips/lantiq/falcon/Kconfig
@@ -10,6 +10,10 @@
bool "Easy98020"
default y
+config LANTIQ_MACH_95C3AM1
+ bool "95C3AM1"
+ default y
+
endmenu
endif
--- a/arch/mips/lantiq/falcon/Makefile
+++ b/arch/mips/lantiq/falcon/Makefile
@@ -4,3 +4,4 @@
obj-$(CONFIG_LANTIQ_MACH_EASY98000) += mach-easy98000.o
obj-$(CONFIG_LANTIQ_MACH_EASY98000) += dev-leds-easy98000-cpld.o
obj-$(CONFIG_LANTIQ_MACH_EASY98020) += mach-easy98020.o
+obj-$(CONFIG_LANTIQ_MACH_95C3AM1) += mach-95C3AM1.o
--- a/arch/mips/lantiq/machtypes.h
+++ b/arch/mips/lantiq/machtypes.h
@@ -21,6 +21,7 @@
LANTIQ_MACH_EASY98000SF, /* Falcon Eval Board, Serial Flash */
LANTIQ_MACH_EASY98000NAND, /* Falcon Eval Board, NAND Flash */
LANTIQ_MACH_EASY98020, /* Falcon Reference Board */
+ LANTIQ_MACH_95C3AM1, /* Board 95C3AM1 */
};
#endif

View File

@ -0,0 +1,117 @@
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -19,6 +19,7 @@
* Sascha Hauer <s.hauer@pengutronix.de>
*/
+#define DEBUG
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/netdevice.h>
@@ -125,6 +126,8 @@
struct delayed_work phy_poll;
struct net_device *ndev;
+ struct delayed_work irq_poll; /* for use in irq polling mode */
+
spinlock_t lock;
struct mii_if_info mii;
@@ -824,6 +827,8 @@
netif_stop_queue(dev);
dm9000_reset(db);
dm9000_init_dm9000(dev);
+ dm9000_reset(db);
+ dm9000_init_dm9000(dev);
/* We can accept TX packets again */
dev->trans_start = jiffies; /* prevent tx timeout */
netif_wake_queue(dev);
@@ -895,6 +900,12 @@
/* free this SKB */
dev_kfree_skb(skb);
+ /* directly poll afterwards */
+ if (dev->irq == -1) {
+ cancel_delayed_work(&db->irq_poll);
+ schedule_delayed_work(&db->irq_poll, 1);
+ }
+
return NETDEV_TX_OK;
}
@@ -1136,6 +1147,18 @@
}
#endif
+static void dm9000_poll_irq(struct work_struct *w)
+{
+ struct delayed_work *dw = to_delayed_work(w);
+ board_info_t *db = container_of(dw, board_info_t, irq_poll);
+ struct net_device *ndev = db->ndev;
+
+ dm9000_interrupt(0, ndev);
+
+ if (netif_running(ndev))
+ schedule_delayed_work(&db->irq_poll, HZ /100);
+}
+
/*
* Open the interface.
* The interface is opened whenever "ifconfig" actives it.
@@ -1149,14 +1172,15 @@
if (netif_msg_ifup(db))
dev_dbg(db->dev, "enabling %s\n", dev->name);
- /* If there is no IRQ type specified, default to something that
- * may work, and tell the user that this is a problem */
+ if (dev->irq != -1) {
+ /* If there is no IRQ type specified, default to something that
+ * may work, and tell the user that this is a problem */
- if (irqflags == IRQF_TRIGGER_NONE)
- dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n");
-
- irqflags |= IRQF_SHARED;
+ if (irqflags == IRQF_TRIGGER_NONE)
+ dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n");
+ irqflags |= IRQF_SHARED;
+ }
/* GPIO0 on pre-activate PHY, Reg 1F is not set by reset */
iow(db, DM9000_GPR, 0); /* REG_1F bit0 activate phyxcer */
mdelay(1); /* delay needs by DM9000B */
@@ -1165,8 +1189,14 @@
dm9000_reset(db);
dm9000_init_dm9000(dev);
- if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev))
- return -EAGAIN;
+ /* testing: init a second time */
+ dm9000_reset(db);
+ dm9000_init_dm9000(dev);
+
+ if (dev->irq != -1) {
+ if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev))
+ return -EAGAIN;
+ }
/* Init driver variable */
db->dbug_cnt = 0;
@@ -1174,6 +1204,9 @@
mii_check_media(&db->mii, netif_msg_link(db), 1);
netif_start_queue(dev);
+ if (dev->irq == -1)
+ schedule_delayed_work(&db->irq_poll, HZ / 100);
+
dm9000_schedule_poll(db);
return 0;
@@ -1371,6 +1404,7 @@
mutex_init(&db->addr_lock);
INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work);
+ INIT_DELAYED_WORK(&db->irq_poll, dm9000_poll_irq);
db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);

View File

@ -0,0 +1,163 @@
--- a/arch/mips/lantiq/irq.c
+++ b/arch/mips/lantiq/irq.c
@@ -51,6 +51,7 @@
#define ltq_eiu_w32(x, y) ltq_w32((x), ltq_eiu_membase + (y))
#define ltq_eiu_r32(x) ltq_r32(ltq_eiu_membase + (x))
+#ifdef CONFIG_SOC_XWAY
static unsigned short ltq_eiu_irq[MAX_EIU] = {
LTQ_EIU_IR0,
LTQ_EIU_IR1,
@@ -59,6 +60,7 @@
LTQ_EIU_IR4,
LTQ_EIU_IR5,
};
+#endif
static struct resource ltq_icu_resource = {
.name = "icu",
@@ -67,15 +69,19 @@
.flags = IORESOURCE_MEM,
};
+#ifdef CONFIG_SOC_XWAY
static struct resource ltq_eiu_resource = {
.name = "eiu",
.start = LTQ_EIU_BASE_ADDR,
.end = LTQ_EIU_BASE_ADDR + LTQ_ICU_SIZE - 1,
.flags = IORESOURCE_MEM,
};
+#endif
static void __iomem *ltq_icu_membase;
+#ifdef CONFIG_SOC_XWAY
static void __iomem *ltq_eiu_membase;
+#endif
void ltq_disable_irq(struct irq_data *d)
{
@@ -120,6 +126,7 @@
ltq_icu_w32(ltq_icu_r32(ier) | (1 << irq_nr), ier);
}
+#ifdef CONFIG_SOC_XWAY
static unsigned int ltq_startup_eiu_irq(struct irq_data *d)
{
int i;
@@ -159,6 +166,7 @@
}
}
}
+#endif
static struct irq_chip ltq_irq_type = {
"icu",
@@ -170,6 +178,7 @@
.irq_mask_ack = ltq_mask_and_ack_irq,
};
+#ifdef CONFIG_SOC_XWAY
static struct irq_chip ltq_eiu_type = {
"eiu",
.irq_startup = ltq_startup_eiu_irq,
@@ -181,6 +190,7 @@
.irq_mask = ltq_disable_irq,
.irq_mask_ack = ltq_mask_and_ack_irq,
};
+#endif
static void ltq_hw_irqdispatch(int module)
{
@@ -196,10 +206,12 @@
irq = __fls(irq);
do_IRQ((int)irq + INT_NUM_IM0_IRL0 + (INT_NUM_IM_OFFSET * module));
+#ifdef CONFIG_SOC_XWAY
/* if this is a EBU irq, we need to ack it or get a deadlock */
if ((irq == LTQ_ICU_EBU_IRQ) && (module == 0))
ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_ISTAT) | 0x10,
LTQ_EBU_PCC_ISTAT);
+#endif
}
#define DEFINE_HWx_IRQDISPATCH(x) \
@@ -262,6 +274,7 @@
if (!ltq_icu_membase)
panic("Failed to remap icu memory\n");
+#ifdef CONFIG_SOC_XWAY
if (insert_resource(&iomem_resource, &ltq_eiu_resource) < 0)
panic("Failed to insert eiu memory\n");
@@ -273,6 +286,7 @@
resource_size(&ltq_eiu_resource));
if (!ltq_eiu_membase)
panic("Failed to remap eiu memory\n");
+#endif
/* make sure all irqs are turned off by default */
for (i = 0; i < 5; i++)
@@ -298,6 +312,7 @@
for (i = INT_NUM_IRQ0;
i <= (INT_NUM_IRQ0 + (5 * INT_NUM_IM_OFFSET)); i++)
+#ifdef CONFIG_SOC_XWAY
if ((i == LTQ_EIU_IR0) || (i == LTQ_EIU_IR1) ||
(i == LTQ_EIU_IR2))
irq_set_chip_and_handler(i, &ltq_eiu_type,
@@ -308,6 +323,7 @@
irq_set_chip_and_handler(i, &ltq_eiu_type,
handle_level_irq);
else
+#endif
irq_set_chip_and_handler(i, &ltq_irq_type,
handle_level_irq);
--- a/arch/mips/lantiq/clk.c
+++ b/arch/mips/lantiq/clk.c
@@ -46,6 +46,7 @@
},
};
+#ifdef CONFIG_SOC_XWAY
static struct resource ltq_cgu_resource = {
.name = "cgu",
.start = LTQ_CGU_BASE_ADDR,
@@ -55,6 +56,7 @@
/* remapped clock register range */
void __iomem *ltq_cgu_membase;
+#endif
void clk_init(void)
{
@@ -120,6 +122,7 @@
{
struct clk *clk;
+#ifdef CONFIG_SOC_XWAY
if (insert_resource(&iomem_resource, &ltq_cgu_resource) < 0)
panic("Failed to insert cgu memory\n");
@@ -133,6 +136,7 @@
pr_err("Failed to remap cgu memory\n");
unreachable();
}
+#endif
clk = clk_get(0, "cpu");
mips_hpt_frequency = clk_get_rate(clk) / ltq_get_counter_resolution();
write_c0_compare(read_c0_count());
--- a/arch/mips/lantiq/early_printk.c
+++ b/arch/mips/lantiq/early_printk.c
@@ -13,7 +13,11 @@
#include <lantiq_soc.h>
/* no ioremap possible at this early stage, lets use KSEG1 instead */
+#ifdef CONFIG_SOC_FALCON
+#define LTQ_ASC_BASE KSEG1ADDR(LTQ_ASC0_BASE_ADDR)
+#else
#define LTQ_ASC_BASE KSEG1ADDR(LTQ_ASC1_BASE_ADDR)
+#endif
#define ASC_BUF 1024
#define LTQ_ASC_FSTAT ((u32 *)(LTQ_ASC_BASE + 0x0048))
#define LTQ_ASC_TBUF ((u32 *)(LTQ_ASC_BASE + 0x0020))

View File

@ -0,0 +1,43 @@
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef _LTQ_FALCON_H__
+#define _LTQ_FALCON_H__
+
+#ifdef CONFIG_SOC_FALCON
+
+#include <lantiq.h>
+
+/* Chip IDs */
+#define SOC_ID_FALCON 0x01B8
+
+/* SoC Types */
+#define SOC_TYPE_FALCON 0x01
+
+/* ASC0/1 - serial port */
+#define LTQ_ASC0_BASE_ADDR 0x1E100C00
+#define LTQ_ASC1_BASE_ADDR 0x1E100B00
+#define LTQ_ASC_SIZE 0x100
+
+#define LTQ_ASC_TIR(x) (INT_NUM_IM3_IRL0 + (x * 8))
+#define LTQ_ASC_RIR(x) (INT_NUM_IM3_IRL0 + (x * 8) + 1)
+#define LTQ_ASC_EIR(x) (INT_NUM_IM3_IRL0 + (x * 8) + 2)
+
+/* ICU - interrupt control unit */
+#define LTQ_ICU_BASE_ADDR 0x1F880200
+#define LTQ_ICU_SIZE 0x100
+
+/* WDT */
+#define LTQ_WDT_BASE_ADDR 0x1F8803F0
+#define LTQ_WDT_SIZE 0x10
+
+#endif /* CONFIG_SOC_FALCON */
+#endif /* _LTQ_XWAY_H__ */

View File

@ -0,0 +1,17 @@
--- a/drivers/net/lantiq_etop.c
+++ b/drivers/net/lantiq_etop.c
@@ -155,8 +155,12 @@
skb_put(skb, len);
skb->dev = ch->netdev;
- skb->protocol = eth_type_trans(skb, ch->netdev);
- netif_receive_skb(skb);
+ if (priv->phydev && priv->phydev->netif_receive_skb) {
+ priv->phydev->netif_receive_skb(skb);
+ } else {
+ skb->protocol = eth_type_trans(skb, ch->netdev);
+ netif_receive_skb(skb);
+ }
}
static int

View File

@ -0,0 +1,116 @@
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -57,6 +57,10 @@ config MTD_ROOTFS_SPLIT
depends on MTD_PARTITIONS
default y
+config MTD_UIMAGE_SPLIT
+ bool "Automatically split 'linux' partition into 'kernel' and 'rootfs'"
+ default y
+
config MTD_REDBOOT_PARTS
tristate "RedBoot partition table parsing"
---help---
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -860,6 +860,82 @@ static int refresh_rootfs_split(struct m
}
#endif /* CONFIG_MTD_ROOTFS_SPLIT */
+
+#ifdef CONFIG_MTD_UIMAGE_SPLIT
+static unsigned long find_uimage_size(struct mtd_info *mtd,
+ unsigned long offset)
+{
+#define UBOOT_MAGIC 0x56190527
+ unsigned long magic = 0;
+ unsigned long temp;
+ size_t len;
+ int ret;
+
+ ret = mtd->read(mtd, offset, 4, &len, (void *)&magic);
+ if (ret || len != sizeof(magic))
+ return 0;
+
+ if (le32_to_cpu(magic) != UBOOT_MAGIC)
+ return 0;
+
+ ret = mtd->read(mtd, offset + 12, 4, &len, (void *)&temp);
+ if (ret || len != sizeof(temp))
+ return 0;
+
+ return temp + 0x40;
+}
+
+static int detect_squashfs_partition(struct mtd_info *mtd, unsigned long offset)
+{
+ unsigned long temp;
+ size_t len;
+ int ret;
+
+ ret = mtd->read(mtd, offset, 4, &len, (void *)&temp);
+ if (ret || len != sizeof(temp))
+ return 0;
+
+ return le32_to_cpu(temp) == SQUASHFS_MAGIC;
+}
+
+static int split_uimage(struct mtd_info *mtd,
+ const struct mtd_partition *part)
+{
+ static struct mtd_partition split_partitions[] = {
+ {
+ .name = "kernel",
+ .offset = 0x0,
+ .size = 0x0,
+ }, {
+ .name = "rootfs",
+ .offset = 0x0,
+ .size = 0x0,
+ },
+ };
+
+ split_partitions[0].size = find_uimage_size(mtd, part->offset);
+ if (!split_partitions[0].size) {
+ printk(KERN_NOTICE "no uImage found in linux partition\n");
+ return -1;
+ }
+
+ if (!detect_squashfs_partition(mtd,
+ part->offset
+ + split_partitions[0].size)) {
+ split_partitions[0].size &= ~(mtd->erasesize - 1);
+ split_partitions[0].size += mtd->erasesize;
+ }
+
+ split_partitions[0].offset = part->offset;
+ split_partitions[1].offset = part->offset + split_partitions[0].size;
+ split_partitions[1].size = part->size - split_partitions[0].size;
+
+ add_mtd_partitions(mtd, split_partitions, 2);
+
+ return 0;
+}
+#endif
+
/*
* This function, given a master MTD object and a partition table, creates
* and registers slave MTD objects which are bound to the master according to
@@ -893,6 +969,17 @@ int add_mtd_partitions(struct mtd_info *
add_mtd_device(&slave->mtd);
+#ifdef CONFIG_MTD_UIMAGE_SPLIT
+ if (!strcmp(parts[i].name, "linux")) {
+ ret = split_uimage(master, &parts[i]);
+
+ if (ret) {
+ printk(KERN_WARNING
+ "Can't split linux partition\n");
+ }
+ }
+#endif
+
if (!strcmp(parts[i].name, "rootfs")) {
#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV
if (ROOT_DEV == 0) {

View File

@ -0,0 +1,42 @@
--- a/arch/mips/mm/cache.c
+++ b/arch/mips/mm/cache.c
@@ -52,6 +52,8 @@ void (*_dma_cache_wback)(unsigned long s
void (*_dma_cache_inv)(unsigned long start, unsigned long size);
EXPORT_SYMBOL(_dma_cache_wback_inv);
+EXPORT_SYMBOL(_dma_cache_wback);
+EXPORT_SYMBOL(_dma_cache_inv);
#endif /* CONFIG_DMA_NONCOHERENT */
--- a/net/atm/proc.c
+++ b/net/atm/proc.c
@@ -154,7 +154,7 @@ static void *vcc_seq_next(struct seq_fil
static void pvc_info(struct seq_file *seq, struct atm_vcc *vcc)
{
static const char *const class_name[] = {
- "off", "UBR", "CBR", "VBR", "ABR"};
+ "off","UBR","CBR","NTR-VBR","ABR","ANY","RT-VBR","UBR+","GFR"};
static const char *const aal_name[] = {
"---", "1", "2", "3/4", /* 0- 3 */
"???", "5", "???", "???", /* 4- 7 */
--- a/net/atm/common.c
+++ b/net/atm/common.c
@@ -62,11 +62,17 @@ static void vcc_remove_socket(struct soc
write_unlock_irq(&vcc_sklist_lock);
}
+struct sk_buff* (*ifx_atm_alloc_tx)(struct atm_vcc *, unsigned int) = NULL;
+EXPORT_SYMBOL(ifx_atm_alloc_tx);
+
static struct sk_buff *alloc_tx(struct atm_vcc *vcc, unsigned int size)
{
struct sk_buff *skb;
struct sock *sk = sk_atm(vcc);
+ if (ifx_atm_alloc_tx != NULL)
+ return ifx_atm_alloc_tx(vcc, size);
+
if (sk_wmem_alloc_get(sk) && !atm_may_send(vcc, size)) {
pr_debug("Sorry: wmem_alloc = %d, size = %d, sndbuf = %d\n",
sk_wmem_alloc_get(sk), size, sk->sk_sndbuf);

View File

@ -0,0 +1,45 @@
--- a/arch/mips/lantiq/prom.c
+++ b/arch/mips/lantiq/prom.c
@@ -39,6 +39,34 @@ void prom_free_prom_memory(void)
{
}
+#ifdef CONFIG_IMAGE_CMDLINE_HACK
+extern char __image_cmdline[];
+
+static void __init
+prom_init_image_cmdline(void)
+{
+ char *p = __image_cmdline;
+ int replace = 0;
+
+ if (*p == '-') {
+ replace = 1;
+ p++;
+ }
+
+ if (*p == '\0')
+ return;
+
+ if (replace) {
+ strlcpy(arcs_cmdline, p, sizeof(arcs_cmdline));
+ } else {
+ strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline));
+ strlcat(arcs_cmdline, p, sizeof(arcs_cmdline));
+ }
+}
+#else
+static void __init prom_init_image_cmdline(void) { return; }
+#endif
+
static void __init prom_init_cmdline(void)
{
int argc = fw_arg0;
@@ -53,6 +81,7 @@ static void __init prom_init_cmdline(voi
strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline));
}
}
+ prom_init_image_cmdline();
}
void __init prom_init(void)

View File

@ -0,0 +1,348 @@
--- /dev/null
+++ b/include/linux/udp_redirect.h
@@ -0,0 +1,57 @@
+#ifndef _UDP_REDIRECT_H
+#define _UDP_REDIRECT_H
+
+/******************************************************************************
+
+ Copyright (c) 2006
+ Infineon Technologies AG
+ Am Campeon 1-12; 81726 Munich, Germany
+
+ THE DELIVERY OF THIS SOFTWARE AS WELL AS THE HEREBY GRANTED NON-EXCLUSIVE,
+ WORLDWIDE LICENSE TO USE, COPY, MODIFY, DISTRIBUTE AND SUBLICENSE THIS
+ SOFTWARE IS FREE OF CHARGE.
+
+ THE LICENSED SOFTWARE IS PROVIDED "AS IS" AND INFINEON EXPRESSLY DISCLAIMS
+ ALL REPRESENTATIONS AND WARRANTIES, WHETHER EXPRESS OR IMPLIED, INCLUDING
+ WITHOUT LIMITATION, WARRANTIES OR REPRESENTATIONS OF WORKMANSHIP,
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, DURABILITY, THAT THE
+ OPERATING OF THE LICENSED SOFTWARE WILL BE ERROR FREE OR FREE OF ANY THIRD
+ PARTY CLAIMS, INCLUDING WITHOUT LIMITATION CLAIMS OF THIRD PARTY INTELLECTUAL
+ PROPERTY INFRINGEMENT.
+
+ EXCEPT FOR ANY LIABILITY DUE TO WILFUL ACTS OR GROSS NEGLIGENCE AND EXCEPT
+ FOR ANY PERSONAL INJURY INFINEON SHALL IN NO EVENT BE LIABLE FOR ANY CLAIM
+ OR DAMAGES OF ANY KIND, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+
+******************************************************************************/
+
+/* ============================= */
+/* Includes */
+/* ============================= */
+#ifndef _LINUX_TYPES_H
+#include <linux/types.h>
+#endif
+
+
+/* ============================= */
+/* Definitions */
+/* ============================= */
+#define UDP_REDIRECT_MAGIC (void*)0x55445052L
+
+
+/* ============================= */
+/* Global variable declaration */
+/* ============================= */
+extern int (*udp_do_redirect_fn)(struct sock *sk, struct sk_buff *skb);
+extern int (*udpredirect_getfrag_fn)(void *p, char * to,
+ int offset, int fraglen, int odd,
+ struct sk_buff *skb);
+/* ============================= */
+/* Global function declaration */
+/* ============================= */
+
+extern int udpredirect_getfrag(void *p, char * to, int offset,
+ int fraglen, int odd, struct sk_buff *skb);
+#endif
--- /dev/null
+++ b/net/ipv4/udp_redirect_symb.c
@@ -0,0 +1,186 @@
+/******************************************************************************
+
+ Copyright (c) 2006
+ Infineon Technologies AG
+ Am Campeon 1-12; 81726 Munich, Germany
+
+ THE DELIVERY OF THIS SOFTWARE AS WELL AS THE HEREBY GRANTED NON-EXCLUSIVE,
+ WORLDWIDE LICENSE TO USE, COPY, MODIFY, DISTRIBUTE AND SUBLICENSE THIS
+ SOFTWARE IS FREE OF CHARGE.
+
+ THE LICENSED SOFTWARE IS PROVIDED "AS IS" AND INFINEON EXPRESSLY DISCLAIMS
+ ALL REPRESENTATIONS AND WARRANTIES, WHETHER EXPRESS OR IMPLIED, INCLUDING
+ WITHOUT LIMITATION, WARRANTIES OR REPRESENTATIONS OF WORKMANSHIP,
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, DURABILITY, THAT THE
+ OPERATING OF THE LICENSED SOFTWARE WILL BE ERROR FREE OR FREE OF ANY THIRD
+ PARTY CLAIMS, INCLUDING WITHOUT LIMITATION CLAIMS OF THIRD PARTY INTELLECTUAL
+ PROPERTY INFRINGEMENT.
+
+ EXCEPT FOR ANY LIABILITY DUE TO WILFUL ACTS OR GROSS NEGLIGENCE AND EXCEPT
+ FOR ANY PERSONAL INJURY INFINEON SHALL IN NO EVENT BE LIABLE FOR ANY CLAIM
+ OR DAMAGES OF ANY KIND, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+
+******************************************************************************/
+#if defined(CONFIG_IFX_UDP_REDIRECT) || defined(CONFIG_IFX_UDP_REDIRECT_MODULE)
+/* ============================= */
+/* Includes */
+/* ============================= */
+#include <net/checksum.h>
+#include <net/udp.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/udp_redirect.h>
+
+/* ============================= */
+/* Global variable definition */
+/* ============================= */
+int (*udpredirect_getfrag_fn) (void *p, char * to, int offset,
+ int fraglen, int odd, struct sk_buff *skb) = NULL;
+int (*udp_do_redirect_fn)(struct sock *sk, struct sk_buff *skb) = NULL;
+
+/* ============================= */
+/* Local type definitions */
+/* ============================= */
+struct udpfakehdr
+{
+ struct udphdr uh;
+ u32 saddr;
+ u32 daddr;
+ struct iovec *iov;
+ u32 wcheck;
+};
+
+/* ============================= */
+/* Local function declaration */
+/* ============================= */
+static int udpredirect_csum_partial_copy_fromiovecend(unsigned char *kdata,
+ struct iovec *iov, int offset, unsigned int len, __wsum *csump);
+
+static int udpredirect_memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset,
+ int len);
+
+/* ============================= */
+/* Global function definition */
+/* ============================= */
+
+/*
+ Copy of udp_getfrag() from udp.c
+ This function exists because no copy_from_user() is needed for udpredirect.
+*/
+
+int
+udpredirect_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb)
+{
+ struct iovec *iov = from;
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ if (udpredirect_memcpy_fromiovecend(to, iov, offset, len) < 0)
+ return -EFAULT;
+ } else {
+ __wsum csum = 0;
+ if (udpredirect_csum_partial_copy_fromiovecend(to, iov, offset, len, &csum) < 0)
+ return -EFAULT;
+ skb->csum = csum_block_add(skb->csum, csum, odd);
+ }
+ return 0;
+}
+
+static int udpredirect_memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset,
+ int len)
+{
+ /* Skip over the finished iovecs */
+ while (offset >= iov->iov_len) {
+ offset -= iov->iov_len;
+ iov++;
+ }
+
+ while (len > 0) {
+ u8 __user *base = iov->iov_base + offset;
+ int copy = min_t(unsigned int, len, iov->iov_len - offset);
+
+ offset = 0;
+ memcpy(kdata, base, copy);
+ len -= copy;
+ kdata += copy;
+ iov++;
+ }
+
+ return 0;
+}
+
+/*
+ Copy of csum_partial_copy_fromiovecend() from iovec.c
+ This function exists because no copy_from_user() is needed for udpredirect.
+*/
+
+int udpredirect_csum_partial_copy_fromiovecend(unsigned char *kdata, struct iovec *iov,
+ int offset, unsigned int len, __wsum *csump)
+{
+ __wsum csum = *csump;
+ int partial_cnt = 0, err = 0;
+
+ /* Skip over the finished iovecs */
+ while (offset >= iov->iov_len) {
+ offset -= iov->iov_len;
+ iov++;
+ }
+
+ while (len > 0) {
+ u8 __user *base = iov->iov_base + offset;
+ int copy = min_t(unsigned int, len, iov->iov_len - offset);
+
+ offset = 0;
+
+ /* There is a remnant from previous iov. */
+ if (partial_cnt) {
+ int par_len = 4 - partial_cnt;
+
+ /* iov component is too short ... */
+ if (par_len > copy) {
+ memcpy(kdata, base, copy);
+ kdata += copy;
+ base += copy;
+ partial_cnt += copy;
+ len -= copy;
+ iov++;
+ if (len)
+ continue;
+ *csump = csum_partial(kdata - partial_cnt,
+ partial_cnt, csum);
+ goto out;
+ }
+ memcpy(kdata, base, par_len);
+ csum = csum_partial(kdata - partial_cnt, 4, csum);
+ kdata += par_len;
+ base += par_len;
+ copy -= par_len;
+ len -= par_len;
+ partial_cnt = 0;
+ }
+
+ if (len > copy) {
+ partial_cnt = copy % 4;
+ if (partial_cnt) {
+ copy -= partial_cnt;
+ memcpy(kdata + copy, base + copy, partial_cnt);
+ }
+ }
+
+ if (copy) {
+ csum = csum_partial_copy_nocheck(base, kdata, copy, csum);
+ }
+ len -= copy + partial_cnt;
+ kdata += copy + partial_cnt;
+ iov++;
+ }
+ *csump = csum;
+out:
+ return err;
+}
+
+EXPORT_SYMBOL(udpredirect_getfrag);
+EXPORT_SYMBOL(udp_do_redirect_fn);
+EXPORT_SYMBOL(udpredirect_getfrag_fn);
+#endif /* CONFIG_IFX_UDP_REDIRECT* */
--- a/net/ipv4/Makefile
+++ b/net/ipv4/Makefile
@@ -14,6 +14,9 @@ obj-y := route.o inetpeer.o protocol
inet_fragment.o
obj-$(CONFIG_SYSCTL) += sysctl_net_ipv4.o
+ifneq ($(CONFIG_IFX_UDP_REDIRECT),)
+obj-$(CONFIG_IFX_UDP_REDIRECT) += udp_redirect_symb.o
+endif
obj-$(CONFIG_PROC_FS) += proc.o
obj-$(CONFIG_IP_MULTIPLE_TABLES) += fib_rules.o
obj-$(CONFIG_IP_MROUTE) += ipmr.o
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -107,6 +107,10 @@
#include <net/xfrm.h>
#include "udp_impl.h"
+#if defined(CONFIG_IFX_UDP_REDIRECT) || defined(CONFIG_IFX_UDP_REDIRECT_MODULE)
+#include <linux/udp_redirect.h>
+#endif
+
struct udp_table udp_table __read_mostly;
EXPORT_SYMBOL(udp_table);
@@ -802,7 +806,7 @@ int udp_sendmsg(struct kiocb *iocb, stru
u8 tos;
int err, is_udplite = IS_UDPLITE(sk);
int corkreq = up->corkflag || msg->msg_flags&MSG_MORE;
- int (*getfrag)(void *, char *, int, int, int, struct sk_buff *);
+ int (*getfrag)(void *, char *, int, int, int, struct sk_buff *) = NULL;
struct sk_buff *skb;
if (len > 0xFFFF)
@@ -818,7 +822,13 @@ int udp_sendmsg(struct kiocb *iocb, stru
ipc.opt = NULL;
ipc.tx_flags = 0;
- getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag;
+/* UDPREDIRECT */
+#if defined(CONFIG_IFX_UDP_REDIRECT) || defined(CONFIG_IFX_UDP_REDIRECT_MODULE)
+ if(udpredirect_getfrag_fn && sk->sk_user_data == UDP_REDIRECT_MAGIC)
+ getfrag = udpredirect_getfrag_fn;
+ else
+#endif /* IFX_UDP_REDIRECT */
+ getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag;
if (up->pending) {
/*
@@ -1608,6 +1618,7 @@ int __udp4_lib_rcv(struct sk_buff *skb,
struct rtable *rt = skb_rtable(skb);
__be32 saddr, daddr;
struct net *net = dev_net(skb->dev);
+ int ret = 0;
/*
* Validate the packet.
@@ -1640,7 +1651,16 @@ int __udp4_lib_rcv(struct sk_buff *skb,
sk = __udp4_lib_lookup_skb(skb, uh->source, uh->dest, udptable);
if (sk != NULL) {
- int ret = udp_queue_rcv_skb(sk, skb);
+ /* UDPREDIRECT */
+#if defined(CONFIG_IFX_UDP_REDIRECT) || defined(CONFIG_IFX_UDP_REDIRECT_MODULE)
+ if(udp_do_redirect_fn && sk->sk_user_data == UDP_REDIRECT_MAGIC)
+ {
+ udp_do_redirect_fn(sk,skb);
+ kfree_skb(skb);
+ return(0);
+ }
+#endif
+ ret = udp_queue_rcv_skb(sk, skb);
sock_put(sk);
/* a return value > 0 means to resubmit the input, but
@@ -1937,7 +1957,7 @@ struct proto udp_prot = {
.clear_sk = sk_prot_clear_portaddr_nulls,
};
EXPORT_SYMBOL(udp_prot);
-
+EXPORT_SYMBOL(udp_rcv);
/* ------------------------------------------------------------------------ */
#ifdef CONFIG_PROC_FS
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -72,6 +72,12 @@ config INET
Short answer: say Y.
+config IFX_UDP_REDIRECT
+ bool "IFX Kernel Packet Interface for UDP redirection"
+ help
+ You can say Y here if you want to use hooks from kernel for
+ UDP redirection.
+
if INET
source "net/ipv4/Kconfig"
source "net/ipv6/Kconfig"

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,301 @@
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -1878,6 +1878,28 @@ config IFX_VPE_EXT
help
IFX included extensions in APRP
+config IFX_VPE_CACHE_SPLIT
+ bool "IFX Cache Split Ways"
+ depends on IFX_VPE_EXT
+ help
+ IFX extension for reserving (splitting) cache ways among VPEs. You must
+ give kernel command line arguments vpe_icache_shared=0 or
+ vpe_dcache_shared=0 to enable splitting of icache or dcache
+ respectively. Then you can specify which cache ways should be
+ assigned to which VPE. There are total 8 cache ways, 4 each
+ for dcache and icache: dcache_way0, dcache_way1,dcache_way2,
+ dcache_way3 and icache_way0,icache_way1, icache_way2,icache_way3.
+
+ For example, if you specify vpe_icache_shared=0 and icache_way2=1,
+ then the 3rd icache way will be assigned to VPE0 and denied in VPE1.
+
+ For icache, software is required to make at least one cache way available
+ for a VPE at all times i.e., one can't assign all the icache ways to one
+ VPE.
+
+ By default, vpe_dcache_shared and vpe_icache_shared are set to 1
+ (i.e., both icache and dcache are shared among VPEs)
+
config PERFCTRS
bool "34K Performance counters"
depends on MIPS_MT && PROC_FS
--- a/arch/mips/kernel/vpe.c
+++ b/arch/mips/kernel/vpe.c
@@ -128,6 +128,13 @@ __setup("vpe1_wdog_timeout=", wdog_timeo
EXPORT_SYMBOL(vpe1_wdog_timeout);
#endif
+
+#ifdef CONFIG_IFX_VPE_CACHE_SPLIT /* Code for splitting the cache ways among VPEs. */
+extern int vpe_icache_shared,vpe_dcache_shared;
+extern int icache_way0,icache_way1,icache_way2,icache_way3;
+extern int dcache_way0,dcache_way1,dcache_way2,dcache_way3;
+#endif
+
/* grab the likely amount of memory we will need. */
#ifdef CONFIG_MIPS_VPE_LOADER_TOM
#define P_SIZE (2 * 1024 * 1024)
@@ -866,6 +873,65 @@ static int vpe_run(struct vpe * v)
/* enable this VPE */
write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA);
+#ifdef CONFIG_IFX_VPE_CACHE_SPLIT
+ if ( (!vpe_icache_shared) || (!vpe_dcache_shared) ) {
+
+ /* PCP bit must be 1 to split the cache */
+ if(read_c0_mvpconf0() & MVPCONF0_PCP) {
+
+ if ( !vpe_icache_shared ){
+ write_vpe_c0_vpeconf0((read_vpe_c0_vpeconf0()) & ~VPECONF0_ICS);
+
+ /*
+ * If any cache way is 1, then that way is denied
+ * in VPE1. Otherwise assign that way to VPE1.
+ */
+ if (!icache_way0)
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_IWX0 );
+ else
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_IWX0 );
+ if (!icache_way1)
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_IWX1 );
+ else
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_IWX1 );
+ if (!icache_way2)
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_IWX2 );
+ else
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_IWX2 );
+ if (!icache_way3)
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_IWX3 );
+ else
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_IWX3 );
+ }
+
+ if ( !vpe_dcache_shared ) {
+ write_vpe_c0_vpeconf0((read_vpe_c0_vpeconf0()) & ~VPECONF0_DCS);
+
+ /*
+ * If any cache way is 1, then that way is denied
+ * in VPE1. Otherwise assign that way to VPE1.
+ */
+ if (!dcache_way0)
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_DWX0 );
+ else
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_DWX0 );
+ if (!dcache_way1)
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_DWX1 );
+ else
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_DWX1 );
+ if (!dcache_way2)
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_DWX2 );
+ else
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_DWX2 );
+ if (!dcache_way3)
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_DWX3 );
+ else
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_DWX3 );
+ }
+ }
+ }
+#endif /* endif CONFIG_IFX_VPE_CACHE_SPLIT */
+
/* clear out any left overs from a previous program */
write_vpe_c0_status(0);
write_vpe_c0_cause(0);
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -1345,6 +1345,106 @@ static int __init setcoherentio(char *st
__setup("coherentio", setcoherentio);
#endif
+#ifdef CONFIG_IFX_VPE_CACHE_SPLIT /* Code for splitting the cache ways among VPEs. */
+
+#include <asm/mipsmtregs.h>
+
+/*
+ * By default, vpe_icache_shared and vpe_dcache_shared
+ * values are 1 i.e., both icache and dcache are shared
+ * among the VPEs.
+ */
+
+int vpe_icache_shared = 1;
+static int __init vpe_icache_shared_val(char *str)
+{
+ get_option(&str, &vpe_icache_shared);
+ return 1;
+}
+__setup("vpe_icache_shared=", vpe_icache_shared_val);
+EXPORT_SYMBOL(vpe_icache_shared);
+
+int vpe_dcache_shared = 1;
+static int __init vpe_dcache_shared_val(char *str)
+{
+ get_option(&str, &vpe_dcache_shared);
+ return 1;
+}
+__setup("vpe_dcache_shared=", vpe_dcache_shared_val);
+EXPORT_SYMBOL(vpe_dcache_shared);
+
+/*
+ * Software is required to make atleast one icache
+ * way available for a VPE at all times i.e., one
+ * can't assign all the icache ways to one VPE.
+ */
+
+int icache_way0 = 0;
+static int __init icache_way0_val(char *str)
+{
+ get_option(&str, &icache_way0);
+ return 1;
+}
+__setup("icache_way0=", icache_way0_val);
+
+int icache_way1 = 0;
+static int __init icache_way1_val(char *str)
+{
+ get_option(&str, &icache_way1);
+ return 1;
+}
+__setup("icache_way1=", icache_way1_val);
+
+int icache_way2 = 0;
+static int __init icache_way2_val(char *str)
+{
+ get_option(&str, &icache_way2);
+ return 1;
+}
+__setup("icache_way2=", icache_way2_val);
+
+int icache_way3 = 0;
+static int __init icache_way3_val(char *str)
+{
+ get_option(&str, &icache_way3);
+ return 1;
+}
+__setup("icache_way3=", icache_way3_val);
+
+int dcache_way0 = 0;
+static int __init dcache_way0_val(char *str)
+{
+ get_option(&str, &dcache_way0);
+ return 1;
+}
+__setup("dcache_way0=", dcache_way0_val);
+
+int dcache_way1 = 0;
+static int __init dcache_way1_val(char *str)
+{
+ get_option(&str, &dcache_way1);
+ return 1;
+}
+__setup("dcache_way1=", dcache_way1_val);
+
+int dcache_way2 = 0;
+static int __init dcache_way2_val(char *str)
+{
+ get_option(&str, &dcache_way2);
+ return 1;
+}
+__setup("dcache_way2=", dcache_way2_val);
+
+int dcache_way3 = 0;
+static int __init dcache_way3_val(char *str)
+{
+ get_option(&str, &dcache_way3);
+ return 1;
+}
+__setup("dcache_way3=", dcache_way3_val);
+
+#endif /* endif CONFIG_IFX_VPE_CACHE_SPLIT */
+
void __cpuinit r4k_cache_init(void)
{
extern void build_clear_page(void);
@@ -1364,6 +1464,78 @@ void __cpuinit r4k_cache_init(void)
break;
}
+#ifdef CONFIG_IFX_VPE_CACHE_SPLIT
+ /*
+ * We split the cache ways appropriately among the VPEs
+ * based on cache ways values we received as command line
+ * arguments
+ */
+ if ( (!vpe_icache_shared) || (!vpe_dcache_shared) ){
+
+ /* PCP bit must be 1 to split the cache */
+ if(read_c0_mvpconf0() & MVPCONF0_PCP) {
+
+ /* Set CPA bit which enables us to modify VPEOpt register */
+ write_c0_mvpcontrol((read_c0_mvpcontrol()) | MVPCONTROL_CPA);
+
+ if ( !vpe_icache_shared ){
+ write_c0_vpeconf0((read_c0_vpeconf0()) & ~VPECONF0_ICS);
+ /*
+ * If any cache way is 1, then that way is denied
+ * in VPE0. Otherwise assign that way to VPE0.
+ */
+ printk(KERN_DEBUG "icache is split\n");
+ printk(KERN_DEBUG "icache_way0=%d icache_way1=%d icache_way2=%d icache_way3=%d\n",
+ icache_way0, icache_way1,icache_way2, icache_way3);
+ if (icache_way0)
+ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_IWX0 );
+ else
+ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_IWX0 );
+ if (icache_way1)
+ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_IWX1 );
+ else
+ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_IWX1 );
+ if (icache_way2)
+ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_IWX2 );
+ else
+ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_IWX2 );
+ if (icache_way3)
+ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_IWX3 );
+ else
+ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_IWX3 );
+ }
+
+ if ( !vpe_dcache_shared ) {
+ /*
+ * If any cache way is 1, then that way is denied
+ * in VPE0. Otherwise assign that way to VPE0.
+ */
+ printk(KERN_DEBUG "dcache is split\n");
+ printk(KERN_DEBUG "dcache_way0=%d dcache_way1=%d dcache_way2=%d dcache_way3=%d\n",
+ dcache_way0, dcache_way1, dcache_way2, dcache_way3);
+ write_c0_vpeconf0((read_c0_vpeconf0()) & ~VPECONF0_DCS);
+ if (dcache_way0)
+ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_DWX0 );
+ else
+ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_DWX0 );
+ if (dcache_way1)
+ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_DWX1 );
+ else
+ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_DWX1 );
+ if (dcache_way2)
+ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_DWX2 );
+ else
+ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_DWX2 );
+ if (dcache_way3)
+ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_DWX3 );
+ else
+ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_DWX3 );
+ }
+ }
+ }
+
+#endif /* endif CONFIG_IFX_VPE_CACHE_SPLIT */
+
probe_pcache();
setup_scache();

View File

@ -0,0 +1,8 @@
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -1,3 +1,5 @@
+
+
/*
* MTD SPI driver for ST M25Pxx (and similar) serial flash chips
*

View File

@ -0,0 +1,36 @@
From: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>
Date: Thu, 3 Mar 2011 17:15:58 +0000 (+0100)
Subject: MIPS: lantiq: Add platform data for Lantiq SoC SPI controller driver
X-Git-Url: http://nbd.name/gitweb.cgi?p=lantiq.git;a=commitdiff_plain;h=3d21b04682ae8eb1c1965aba39d1796e8c5ad84b;hp=06b420500fe98e37662837e78d8e51aead8aea81
MIPS: lantiq: Add platform data for Lantiq SoC SPI controller driver
Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>
---
--- a/arch/mips/include/asm/mach-lantiq/lantiq_platform.h
+++ b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h
@@ -50,4 +50,13 @@ struct ltq_eth_data {
int mii_mode;
};
+
+struct ltq_spi_platform_data {
+ u16 num_chipselect;
+};
+
+struct ltq_spi_controller_data {
+ unsigned gpio;
+};
+
#endif
--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
+++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
@@ -75,6 +75,7 @@
#define PMU_DMA 0x0020
#define PMU_USB 0x8041
+#define PMU_SPI 0x0100
#define PMU_LED 0x0800
#define PMU_GPT 0x1000
#define PMU_PPE 0x2000

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,89 @@
From: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>
Date: Thu, 3 Mar 2011 20:42:26 +0000 (+0100)
Subject: MIPS: lantiq: Add device register helper for SPI controller and devices
X-Git-Url: http://nbd.name/gitweb.cgi?p=lantiq.git;a=commitdiff_plain;h=b35b07062b718ece9b9cb7b23b12d83a087eafb0;hp=653c95b8b9066c9c6ac08bd64d0ceee439e9fd90
MIPS: lantiq: Add device register helper for SPI controller and devices
Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>
---
--- a/arch/mips/lantiq/xway/devices.h
+++ b/arch/mips/lantiq/xway/devices.h
@@ -11,10 +11,13 @@
#include "../devices.h"
#include <linux/phy.h>
+#include <linux/spi/spi.h>
extern void ltq_register_gpio(void);
extern void ltq_register_gpio_stp(void);
extern void ltq_register_ase_asc(void);
extern void ltq_register_etop(struct ltq_eth_data *eth);
+extern void ltq_register_spi(struct ltq_spi_platform_data *pdata,
+ struct spi_board_info const *info, unsigned n);
#endif
--- a/arch/mips/lantiq/xway/devices.c
+++ b/arch/mips/lantiq/xway/devices.c
@@ -21,6 +21,7 @@
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/leds.h>
+#include <linux/spi/spi.h>
#include <asm/bootinfo.h>
#include <asm/irq.h>
@@ -119,3 +120,41 @@
platform_device_register(&ltq_etop);
}
}
+
+static struct resource ltq_spi_resources[] = {
+ {
+ .start = LTQ_SSC_BASE_ADDR,
+ .end = LTQ_SSC_BASE_ADDR + LTQ_SSC_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ IRQ_RES(spi_tx, LTQ_SSC_TIR),
+ IRQ_RES(spi_rx, LTQ_SSC_RIR),
+ IRQ_RES(spi_err, LTQ_SSC_EIR),
+};
+
+static struct resource ltq_spi_resources_ar9[] = {
+ {
+ .start = LTQ_SSC_BASE_ADDR,
+ .end = LTQ_SSC_BASE_ADDR + LTQ_SSC_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ IRQ_RES(spi_tx, LTQ_SSC_TIR_AR9),
+ IRQ_RES(spi_rx, LTQ_SSC_RIR_AR9),
+ IRQ_RES(spi_err, LTQ_SSC_EIR),
+};
+
+static struct platform_device ltq_spi = {
+ .name = "ltq-spi",
+ .resource = ltq_spi_resources,
+ .num_resources = ARRAY_SIZE(ltq_spi_resources),
+};
+
+void __init ltq_register_spi(struct ltq_spi_platform_data *pdata,
+ struct spi_board_info const *info, unsigned n)
+{
+ if(ltq_is_ar9())
+ ltq_spi.resource = ltq_spi_resources_ar9;
+ spi_register_board_info(info, n);
+ ltq_spi.dev.platform_data = pdata;
+ platform_device_register(&ltq_spi);
+}
--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h
+++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h
@@ -27,6 +27,8 @@
#define LTQ_SSC_TIR (INT_NUM_IM0_IRL0 + 15)
#define LTQ_SSC_RIR (INT_NUM_IM0_IRL0 + 14)
+#define LTQ_SSC_TIR_AR9 (INT_NUM_IM0_IRL0 + 14)
+#define LTQ_SSC_RIR_AR9 (INT_NUM_IM0_IRL0 + 15)
#define LTQ_SSC_EIR (INT_NUM_IM0_IRL0 + 16)
#define LTQ_MEI_DYING_GASP_INT (INT_NUM_IM1_IRL0 + 21)

View File

@ -0,0 +1,999 @@
--- /dev/null
+++ b/arch/mips/lantiq/xway/timer.c
@@ -0,0 +1,830 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+#include <linux/uaccess.h>
+#include <linux/unistd.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+
+#include <asm/irq.h>
+#include <asm/div64.h>
+
+#include <lantiq_soc.h>
+#include <lantiq_irq.h>
+#include <lantiq_timer.h>
+
+#define MAX_NUM_OF_32BIT_TIMER_BLOCKS 6
+
+#ifdef TIMER1A
+#define FIRST_TIMER TIMER1A
+#else
+#define FIRST_TIMER 2
+#endif
+
+/*
+ * GPTC divider is set or not.
+ */
+#define GPTU_CLC_RMC_IS_SET 0
+
+/*
+ * Timer Interrupt (IRQ)
+ */
+/* Must be adjusted when ICU driver is available */
+#define TIMER_INTERRUPT (INT_NUM_IM3_IRL0 + 22)
+
+/*
+ * Bits Operation
+ */
+#define GET_BITS(x, msb, lsb) \
+ (((x) & ((1 << ((msb) + 1)) - 1)) >> (lsb))
+#define SET_BITS(x, msb, lsb, value) \
+ (((x) & ~(((1 << ((msb) + 1)) - 1) ^ ((1 << (lsb)) - 1))) | \
+ (((value) & ((1 << (1 + (msb) - (lsb))) - 1)) << (lsb)))
+
+/*
+ * GPTU Register Mapping
+ */
+#define LQ_GPTU (KSEG1 + 0x1E100A00)
+#define LQ_GPTU_CLC ((volatile u32 *)(LQ_GPTU + 0x0000))
+#define LQ_GPTU_ID ((volatile u32 *)(LQ_GPTU + 0x0008))
+#define LQ_GPTU_CON(n, X) ((volatile u32 *)(LQ_GPTU + 0x0010 + ((X) * 4) + ((n) - 1) * 0x0020)) /* X must be either A or B */
+#define LQ_GPTU_RUN(n, X) ((volatile u32 *)(LQ_GPTU + 0x0018 + ((X) * 4) + ((n) - 1) * 0x0020)) /* X must be either A or B */
+#define LQ_GPTU_RELOAD(n, X) ((volatile u32 *)(LQ_GPTU + 0x0020 + ((X) * 4) + ((n) - 1) * 0x0020)) /* X must be either A or B */
+#define LQ_GPTU_COUNT(n, X) ((volatile u32 *)(LQ_GPTU + 0x0028 + ((X) * 4) + ((n) - 1) * 0x0020)) /* X must be either A or B */
+#define LQ_GPTU_IRNEN ((volatile u32 *)(LQ_GPTU + 0x00F4))
+#define LQ_GPTU_IRNICR ((volatile u32 *)(LQ_GPTU + 0x00F8))
+#define LQ_GPTU_IRNCR ((volatile u32 *)(LQ_GPTU + 0x00FC))
+
+/*
+ * Clock Control Register
+ */
+#define GPTU_CLC_SMC GET_BITS(*LQ_GPTU_CLC, 23, 16)
+#define GPTU_CLC_RMC GET_BITS(*LQ_GPTU_CLC, 15, 8)
+#define GPTU_CLC_FSOE (*LQ_GPTU_CLC & (1 << 5))
+#define GPTU_CLC_EDIS (*LQ_GPTU_CLC & (1 << 3))
+#define GPTU_CLC_SPEN (*LQ_GPTU_CLC & (1 << 2))
+#define GPTU_CLC_DISS (*LQ_GPTU_CLC & (1 << 1))
+#define GPTU_CLC_DISR (*LQ_GPTU_CLC & (1 << 0))
+
+#define GPTU_CLC_SMC_SET(value) SET_BITS(0, 23, 16, (value))
+#define GPTU_CLC_RMC_SET(value) SET_BITS(0, 15, 8, (value))
+#define GPTU_CLC_FSOE_SET(value) ((value) ? (1 << 5) : 0)
+#define GPTU_CLC_SBWE_SET(value) ((value) ? (1 << 4) : 0)
+#define GPTU_CLC_EDIS_SET(value) ((value) ? (1 << 3) : 0)
+#define GPTU_CLC_SPEN_SET(value) ((value) ? (1 << 2) : 0)
+#define GPTU_CLC_DISR_SET(value) ((value) ? (1 << 0) : 0)
+
+/*
+ * ID Register
+ */
+#define GPTU_ID_ID GET_BITS(*LQ_GPTU_ID, 15, 8)
+#define GPTU_ID_CFG GET_BITS(*LQ_GPTU_ID, 7, 5)
+#define GPTU_ID_REV GET_BITS(*LQ_GPTU_ID, 4, 0)
+
+/*
+ * Control Register of Timer/Counter nX
+ * n is the index of block (1 based index)
+ * X is either A or B
+ */
+#define GPTU_CON_SRC_EG(n, X) (*LQ_GPTU_CON(n, X) & (1 << 10))
+#define GPTU_CON_SRC_EXT(n, X) (*LQ_GPTU_CON(n, X) & (1 << 9))
+#define GPTU_CON_SYNC(n, X) (*LQ_GPTU_CON(n, X) & (1 << 8))
+#define GPTU_CON_EDGE(n, X) GET_BITS(*LQ_GPTU_CON(n, X), 7, 6)
+#define GPTU_CON_INV(n, X) (*LQ_GPTU_CON(n, X) & (1 << 5))
+#define GPTU_CON_EXT(n, X) (*LQ_GPTU_CON(n, A) & (1 << 4)) /* Timer/Counter B does not have this bit */
+#define GPTU_CON_STP(n, X) (*LQ_GPTU_CON(n, X) & (1 << 3))
+#define GPTU_CON_CNT(n, X) (*LQ_GPTU_CON(n, X) & (1 << 2))
+#define GPTU_CON_DIR(n, X) (*LQ_GPTU_CON(n, X) & (1 << 1))
+#define GPTU_CON_EN(n, X) (*LQ_GPTU_CON(n, X) & (1 << 0))
+
+#define GPTU_CON_SRC_EG_SET(value) ((value) ? 0 : (1 << 10))
+#define GPTU_CON_SRC_EXT_SET(value) ((value) ? (1 << 9) : 0)
+#define GPTU_CON_SYNC_SET(value) ((value) ? (1 << 8) : 0)
+#define GPTU_CON_EDGE_SET(value) SET_BITS(0, 7, 6, (value))
+#define GPTU_CON_INV_SET(value) ((value) ? (1 << 5) : 0)
+#define GPTU_CON_EXT_SET(value) ((value) ? (1 << 4) : 0)
+#define GPTU_CON_STP_SET(value) ((value) ? (1 << 3) : 0)
+#define GPTU_CON_CNT_SET(value) ((value) ? (1 << 2) : 0)
+#define GPTU_CON_DIR_SET(value) ((value) ? (1 << 1) : 0)
+
+#define GPTU_RUN_RL_SET(value) ((value) ? (1 << 2) : 0)
+#define GPTU_RUN_CEN_SET(value) ((value) ? (1 << 1) : 0)
+#define GPTU_RUN_SEN_SET(value) ((value) ? (1 << 0) : 0)
+
+#define GPTU_IRNEN_TC_SET(n, X, value) ((value) ? (1 << (((n) - 1) * 2 + (X))) : 0)
+#define GPTU_IRNCR_TC_SET(n, X, value) ((value) ? (1 << (((n) - 1) * 2 + (X))) : 0)
+
+#define TIMER_FLAG_MASK_SIZE(x) (x & 0x0001)
+#define TIMER_FLAG_MASK_TYPE(x) (x & 0x0002)
+#define TIMER_FLAG_MASK_STOP(x) (x & 0x0004)
+#define TIMER_FLAG_MASK_DIR(x) (x & 0x0008)
+#define TIMER_FLAG_NONE_EDGE 0x0000
+#define TIMER_FLAG_MASK_EDGE(x) (x & 0x0030)
+#define TIMER_FLAG_REAL 0x0000
+#define TIMER_FLAG_INVERT 0x0040
+#define TIMER_FLAG_MASK_INVERT(x) (x & 0x0040)
+#define TIMER_FLAG_MASK_TRIGGER(x) (x & 0x0070)
+#define TIMER_FLAG_MASK_SYNC(x) (x & 0x0080)
+#define TIMER_FLAG_CALLBACK_IN_HB 0x0200
+#define TIMER_FLAG_MASK_HANDLE(x) (x & 0x0300)
+#define TIMER_FLAG_MASK_SRC(x) (x & 0x1000)
+
+struct timer_dev_timer {
+ unsigned int f_irq_on;
+ unsigned int irq;
+ unsigned int flag;
+ unsigned long arg1;
+ unsigned long arg2;
+};
+
+struct timer_dev {
+ struct mutex gptu_mutex;
+ unsigned int number_of_timers;
+ unsigned int occupation;
+ unsigned int f_gptu_on;
+ struct timer_dev_timer timer[MAX_NUM_OF_32BIT_TIMER_BLOCKS * 2];
+};
+
+unsigned int ltq_get_fpi_bus_clock(int fpi);
+
+static long gptu_ioctl(struct file *, unsigned int, unsigned long);
+static int gptu_open(struct inode *, struct file *);
+static int gptu_release(struct inode *, struct file *);
+
+static struct file_operations gptu_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = gptu_ioctl,
+ .open = gptu_open,
+ .release = gptu_release
+};
+
+static struct miscdevice gptu_miscdev = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "gptu",
+ .fops = &gptu_fops,
+};
+
+static struct timer_dev timer_dev;
+
+static irqreturn_t timer_irq_handler(int irq, void *p)
+{
+ unsigned int timer;
+ unsigned int flag;
+ struct timer_dev_timer *dev_timer = (struct timer_dev_timer *)p;
+
+ timer = irq - TIMER_INTERRUPT;
+ if (timer < timer_dev.number_of_timers
+ && dev_timer == &timer_dev.timer[timer]) {
+ /* Clear interrupt. */
+ ltq_w32(1 << timer, LQ_GPTU_IRNCR);
+
+ /* Call user hanler or signal. */
+ flag = dev_timer->flag;
+ if (!(timer & 0x01)
+ || TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT) {
+ /* 16-bit timer or timer A of 32-bit timer */
+ switch (TIMER_FLAG_MASK_HANDLE(flag)) {
+ case TIMER_FLAG_CALLBACK_IN_IRQ:
+ case TIMER_FLAG_CALLBACK_IN_HB:
+ if (dev_timer->arg1)
+ (*(timer_callback)dev_timer->arg1)(dev_timer->arg2);
+ break;
+ case TIMER_FLAG_SIGNAL:
+ send_sig((int)dev_timer->arg2, (struct task_struct *)dev_timer->arg1, 0);
+ break;
+ }
+ }
+ }
+ return IRQ_HANDLED;
+}
+
+static inline void lq_enable_gptu(void)
+{
+ ltq_pmu_enable(PMU_GPT);
+
+ /* Set divider as 1, disable write protection for SPEN, enable module. */
+ *LQ_GPTU_CLC =
+ GPTU_CLC_SMC_SET(0x00) |
+ GPTU_CLC_RMC_SET(0x01) |
+ GPTU_CLC_FSOE_SET(0) |
+ GPTU_CLC_SBWE_SET(1) |
+ GPTU_CLC_EDIS_SET(0) |
+ GPTU_CLC_SPEN_SET(0) |
+ GPTU_CLC_DISR_SET(0);
+}
+
+static inline void lq_disable_gptu(void)
+{
+ ltq_w32(0x00, LQ_GPTU_IRNEN);
+ ltq_w32(0xfff, LQ_GPTU_IRNCR);
+
+ /* Set divider as 0, enable write protection for SPEN, disable module. */
+ *LQ_GPTU_CLC =
+ GPTU_CLC_SMC_SET(0x00) |
+ GPTU_CLC_RMC_SET(0x00) |
+ GPTU_CLC_FSOE_SET(0) |
+ GPTU_CLC_SBWE_SET(0) |
+ GPTU_CLC_EDIS_SET(0) |
+ GPTU_CLC_SPEN_SET(0) |
+ GPTU_CLC_DISR_SET(1);
+
+ ltq_pmu_disable(PMU_GPT);
+}
+
+int lq_request_timer(unsigned int timer, unsigned int flag,
+ unsigned long value, unsigned long arg1, unsigned long arg2)
+{
+ int ret = 0;
+ unsigned int con_reg, irnen_reg;
+ int n, X;
+
+ if (timer >= FIRST_TIMER + timer_dev.number_of_timers)
+ return -EINVAL;
+
+ printk(KERN_INFO "request_timer(%d, 0x%08X, %lu)...",
+ timer, flag, value);
+
+ if (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT)
+ value &= 0xFFFF;
+ else
+ timer &= ~0x01;
+
+ mutex_lock(&timer_dev.gptu_mutex);
+
+ /*
+ * Allocate timer.
+ */
+ if (timer < FIRST_TIMER) {
+ unsigned int mask;
+ unsigned int shift;
+ /* This takes care of TIMER1B which is the only choice for Voice TAPI system */
+ unsigned int offset = TIMER2A;
+
+ /*
+ * Pick up a free timer.
+ */
+ if (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT) {
+ mask = 1 << offset;
+ shift = 1;
+ } else {
+ mask = 3 << offset;
+ shift = 2;
+ }
+ for (timer = offset;
+ timer < offset + timer_dev.number_of_timers;
+ timer += shift, mask <<= shift)
+ if (!(timer_dev.occupation & mask)) {
+ timer_dev.occupation |= mask;
+ break;
+ }
+ if (timer >= offset + timer_dev.number_of_timers) {
+ printk("failed![%d]\n", __LINE__);
+ mutex_unlock(&timer_dev.gptu_mutex);
+ return -EINVAL;
+ } else
+ ret = timer;
+ } else {
+ register unsigned int mask;
+
+ /*
+ * Check if the requested timer is free.
+ */
+ mask = (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer;
+ if ((timer_dev.occupation & mask)) {
+ printk("failed![%d] mask %#x, timer_dev.occupation %#x\n",
+ __LINE__, mask, timer_dev.occupation);
+ mutex_unlock(&timer_dev.gptu_mutex);
+ return -EBUSY;
+ } else {
+ timer_dev.occupation |= mask;
+ ret = 0;
+ }
+ }
+
+ /*
+ * Prepare control register value.
+ */
+ switch (TIMER_FLAG_MASK_EDGE(flag)) {
+ default:
+ case TIMER_FLAG_NONE_EDGE:
+ con_reg = GPTU_CON_EDGE_SET(0x00);
+ break;
+ case TIMER_FLAG_RISE_EDGE:
+ con_reg = GPTU_CON_EDGE_SET(0x01);
+ break;
+ case TIMER_FLAG_FALL_EDGE:
+ con_reg = GPTU_CON_EDGE_SET(0x02);
+ break;
+ case TIMER_FLAG_ANY_EDGE:
+ con_reg = GPTU_CON_EDGE_SET(0x03);
+ break;
+ }
+ if (TIMER_FLAG_MASK_TYPE(flag) == TIMER_FLAG_TIMER)
+ con_reg |=
+ TIMER_FLAG_MASK_SRC(flag) ==
+ TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EXT_SET(1) :
+ GPTU_CON_SRC_EXT_SET(0);
+ else
+ con_reg |=
+ TIMER_FLAG_MASK_SRC(flag) ==
+ TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EG_SET(1) :
+ GPTU_CON_SRC_EG_SET(0);
+ con_reg |=
+ TIMER_FLAG_MASK_SYNC(flag) ==
+ TIMER_FLAG_UNSYNC ? GPTU_CON_SYNC_SET(0) :
+ GPTU_CON_SYNC_SET(1);
+ con_reg |=
+ TIMER_FLAG_MASK_INVERT(flag) ==
+ TIMER_FLAG_REAL ? GPTU_CON_INV_SET(0) : GPTU_CON_INV_SET(1);
+ con_reg |=
+ TIMER_FLAG_MASK_SIZE(flag) ==
+ TIMER_FLAG_16BIT ? GPTU_CON_EXT_SET(0) :
+ GPTU_CON_EXT_SET(1);
+ con_reg |=
+ TIMER_FLAG_MASK_STOP(flag) ==
+ TIMER_FLAG_ONCE ? GPTU_CON_STP_SET(1) : GPTU_CON_STP_SET(0);
+ con_reg |=
+ TIMER_FLAG_MASK_TYPE(flag) ==
+ TIMER_FLAG_TIMER ? GPTU_CON_CNT_SET(0) :
+ GPTU_CON_CNT_SET(1);
+ con_reg |=
+ TIMER_FLAG_MASK_DIR(flag) ==
+ TIMER_FLAG_UP ? GPTU_CON_DIR_SET(1) : GPTU_CON_DIR_SET(0);
+
+ /*
+ * Fill up running data.
+ */
+ timer_dev.timer[timer - FIRST_TIMER].flag = flag;
+ timer_dev.timer[timer - FIRST_TIMER].arg1 = arg1;
+ timer_dev.timer[timer - FIRST_TIMER].arg2 = arg2;
+ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT)
+ timer_dev.timer[timer - FIRST_TIMER + 1].flag = flag;
+
+ /*
+ * Enable GPTU module.
+ */
+ if (!timer_dev.f_gptu_on) {
+ lq_enable_gptu();
+ timer_dev.f_gptu_on = 1;
+ }
+
+ /*
+ * Enable IRQ.
+ */
+ if (TIMER_FLAG_MASK_HANDLE(flag) != TIMER_FLAG_NO_HANDLE) {
+ if (TIMER_FLAG_MASK_HANDLE(flag) == TIMER_FLAG_SIGNAL)
+ timer_dev.timer[timer - FIRST_TIMER].arg1 =
+ (unsigned long) find_task_by_vpid((int) arg1);
+
+ irnen_reg = 1 << (timer - FIRST_TIMER);
+
+ if (TIMER_FLAG_MASK_HANDLE(flag) == TIMER_FLAG_SIGNAL
+ || (TIMER_FLAG_MASK_HANDLE(flag) ==
+ TIMER_FLAG_CALLBACK_IN_IRQ
+ && timer_dev.timer[timer - FIRST_TIMER].arg1)) {
+ enable_irq(timer_dev.timer[timer - FIRST_TIMER].irq);
+ timer_dev.timer[timer - FIRST_TIMER].f_irq_on = 1;
+ }
+ } else
+ irnen_reg = 0;
+
+ /*
+ * Write config register, reload value and enable interrupt.
+ */
+ n = timer >> 1;
+ X = timer & 0x01;
+ *LQ_GPTU_CON(n, X) = con_reg;
+ *LQ_GPTU_RELOAD(n, X) = value;
+ /* printk("reload value = %d\n", (u32)value); */
+ *LQ_GPTU_IRNEN |= irnen_reg;
+
+ mutex_unlock(&timer_dev.gptu_mutex);
+ printk("successful!\n");
+ return ret;
+}
+EXPORT_SYMBOL(lq_request_timer);
+
+int lq_free_timer(unsigned int timer)
+{
+ unsigned int flag;
+ unsigned int mask;
+ int n, X;
+
+ if (!timer_dev.f_gptu_on)
+ return -EINVAL;
+
+ if (timer < FIRST_TIMER || timer >= FIRST_TIMER + timer_dev.number_of_timers)
+ return -EINVAL;
+
+ mutex_lock(&timer_dev.gptu_mutex);
+
+ flag = timer_dev.timer[timer - FIRST_TIMER].flag;
+ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT)
+ timer &= ~0x01;
+
+ mask = (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer;
+ if (((timer_dev.occupation & mask) ^ mask)) {
+ mutex_unlock(&timer_dev.gptu_mutex);
+ return -EINVAL;
+ }
+
+ n = timer >> 1;
+ X = timer & 0x01;
+
+ if (GPTU_CON_EN(n, X))
+ *LQ_GPTU_RUN(n, X) = GPTU_RUN_CEN_SET(1);
+
+ *LQ_GPTU_IRNEN &= ~GPTU_IRNEN_TC_SET(n, X, 1);
+ *LQ_GPTU_IRNCR |= GPTU_IRNCR_TC_SET(n, X, 1);
+
+ if (timer_dev.timer[timer - FIRST_TIMER].f_irq_on) {
+ disable_irq(timer_dev.timer[timer - FIRST_TIMER].irq);
+ timer_dev.timer[timer - FIRST_TIMER].f_irq_on = 0;
+ }
+
+ timer_dev.occupation &= ~mask;
+ if (!timer_dev.occupation && timer_dev.f_gptu_on) {
+ lq_disable_gptu();
+ timer_dev.f_gptu_on = 0;
+ }
+
+ mutex_unlock(&timer_dev.gptu_mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL(lq_free_timer);
+
+int lq_start_timer(unsigned int timer, int is_resume)
+{
+ unsigned int flag;
+ unsigned int mask;
+ int n, X;
+
+ if (!timer_dev.f_gptu_on)
+ return -EINVAL;
+
+ if (timer < FIRST_TIMER || timer >= FIRST_TIMER + timer_dev.number_of_timers)
+ return -EINVAL;
+
+ mutex_lock(&timer_dev.gptu_mutex);
+
+ flag = timer_dev.timer[timer - FIRST_TIMER].flag;
+ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT)
+ timer &= ~0x01;
+
+ mask = (TIMER_FLAG_MASK_SIZE(flag) ==
+ TIMER_FLAG_16BIT ? 1 : 3) << timer;
+ if (((timer_dev.occupation & mask) ^ mask)) {
+ mutex_unlock(&timer_dev.gptu_mutex);
+ return -EINVAL;
+ }
+
+ n = timer >> 1;
+ X = timer & 0x01;
+
+ *LQ_GPTU_RUN(n, X) = GPTU_RUN_RL_SET(!is_resume) | GPTU_RUN_SEN_SET(1);
+
+ mutex_unlock(&timer_dev.gptu_mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL(lq_start_timer);
+
+int lq_stop_timer(unsigned int timer)
+{
+ unsigned int flag;
+ unsigned int mask;
+ int n, X;
+
+ if (!timer_dev.f_gptu_on)
+ return -EINVAL;
+
+ if (timer < FIRST_TIMER
+ || timer >= FIRST_TIMER + timer_dev.number_of_timers)
+ return -EINVAL;
+
+ mutex_lock(&timer_dev.gptu_mutex);
+
+ flag = timer_dev.timer[timer - FIRST_TIMER].flag;
+ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT)
+ timer &= ~0x01;
+
+ mask = (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer;
+ if (((timer_dev.occupation & mask) ^ mask)) {
+ mutex_unlock(&timer_dev.gptu_mutex);
+ return -EINVAL;
+ }
+
+ n = timer >> 1;
+ X = timer & 0x01;
+
+ *LQ_GPTU_RUN(n, X) = GPTU_RUN_CEN_SET(1);
+
+ mutex_unlock(&timer_dev.gptu_mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL(lq_stop_timer);
+
+int lq_reset_counter_flags(u32 timer, u32 flags)
+{
+ unsigned int oflag;
+ unsigned int mask, con_reg;
+ int n, X;
+
+ if (!timer_dev.f_gptu_on)
+ return -EINVAL;
+
+ if (timer < FIRST_TIMER || timer >= FIRST_TIMER + timer_dev.number_of_timers)
+ return -EINVAL;
+
+ mutex_lock(&timer_dev.gptu_mutex);
+
+ oflag = timer_dev.timer[timer - FIRST_TIMER].flag;
+ if (TIMER_FLAG_MASK_SIZE(oflag) != TIMER_FLAG_16BIT)
+ timer &= ~0x01;
+
+ mask = (TIMER_FLAG_MASK_SIZE(oflag) == TIMER_FLAG_16BIT ? 1 : 3) << timer;
+ if (((timer_dev.occupation & mask) ^ mask)) {
+ mutex_unlock(&timer_dev.gptu_mutex);
+ return -EINVAL;
+ }
+
+ switch (TIMER_FLAG_MASK_EDGE(flags)) {
+ default:
+ case TIMER_FLAG_NONE_EDGE:
+ con_reg = GPTU_CON_EDGE_SET(0x00);
+ break;
+ case TIMER_FLAG_RISE_EDGE:
+ con_reg = GPTU_CON_EDGE_SET(0x01);
+ break;
+ case TIMER_FLAG_FALL_EDGE:
+ con_reg = GPTU_CON_EDGE_SET(0x02);
+ break;
+ case TIMER_FLAG_ANY_EDGE:
+ con_reg = GPTU_CON_EDGE_SET(0x03);
+ break;
+ }
+ if (TIMER_FLAG_MASK_TYPE(flags) == TIMER_FLAG_TIMER)
+ con_reg |= TIMER_FLAG_MASK_SRC(flags) == TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EXT_SET(1) : GPTU_CON_SRC_EXT_SET(0);
+ else
+ con_reg |= TIMER_FLAG_MASK_SRC(flags) == TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EG_SET(1) : GPTU_CON_SRC_EG_SET(0);
+ con_reg |= TIMER_FLAG_MASK_SYNC(flags) == TIMER_FLAG_UNSYNC ? GPTU_CON_SYNC_SET(0) : GPTU_CON_SYNC_SET(1);
+ con_reg |= TIMER_FLAG_MASK_INVERT(flags) == TIMER_FLAG_REAL ? GPTU_CON_INV_SET(0) : GPTU_CON_INV_SET(1);
+ con_reg |= TIMER_FLAG_MASK_SIZE(flags) == TIMER_FLAG_16BIT ? GPTU_CON_EXT_SET(0) : GPTU_CON_EXT_SET(1);
+ con_reg |= TIMER_FLAG_MASK_STOP(flags) == TIMER_FLAG_ONCE ? GPTU_CON_STP_SET(1) : GPTU_CON_STP_SET(0);
+ con_reg |= TIMER_FLAG_MASK_TYPE(flags) == TIMER_FLAG_TIMER ? GPTU_CON_CNT_SET(0) : GPTU_CON_CNT_SET(1);
+ con_reg |= TIMER_FLAG_MASK_DIR(flags) == TIMER_FLAG_UP ? GPTU_CON_DIR_SET(1) : GPTU_CON_DIR_SET(0);
+
+ timer_dev.timer[timer - FIRST_TIMER].flag = flags;
+ if (TIMER_FLAG_MASK_SIZE(flags) != TIMER_FLAG_16BIT)
+ timer_dev.timer[timer - FIRST_TIMER + 1].flag = flags;
+
+ n = timer >> 1;
+ X = timer & 0x01;
+
+ *LQ_GPTU_CON(n, X) = con_reg;
+ smp_wmb();
+ printk(KERN_INFO "[%s]: counter%d oflags %#x, nflags %#x, GPTU_CON %#x\n", __func__, timer, oflag, flags, *LQ_GPTU_CON(n, X));
+ mutex_unlock(&timer_dev.gptu_mutex);
+ return 0;
+}
+EXPORT_SYMBOL(lq_reset_counter_flags);
+
+int lq_get_count_value(unsigned int timer, unsigned long *value)
+{
+ unsigned int flag;
+ unsigned int mask;
+ int n, X;
+
+ if (!timer_dev.f_gptu_on)
+ return -EINVAL;
+
+ if (timer < FIRST_TIMER
+ || timer >= FIRST_TIMER + timer_dev.number_of_timers)
+ return -EINVAL;
+
+ mutex_lock(&timer_dev.gptu_mutex);
+
+ flag = timer_dev.timer[timer - FIRST_TIMER].flag;
+ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT)
+ timer &= ~0x01;
+
+ mask = (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer;
+ if (((timer_dev.occupation & mask) ^ mask)) {
+ mutex_unlock(&timer_dev.gptu_mutex);
+ return -EINVAL;
+ }
+
+ n = timer >> 1;
+ X = timer & 0x01;
+
+ *value = *LQ_GPTU_COUNT(n, X);
+
+ mutex_unlock(&timer_dev.gptu_mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL(lq_get_count_value);
+
+u32 lq_cal_divider(unsigned long freq)
+{
+ u64 module_freq, fpi = ltq_get_fpi_bus_clock(2);
+ u32 clock_divider = 1;
+ module_freq = fpi * 1000;
+ do_div(module_freq, clock_divider * freq);
+ return module_freq;
+}
+EXPORT_SYMBOL(lq_cal_divider);
+
+int lq_set_timer(unsigned int timer, unsigned int freq, int is_cyclic,
+ int is_ext_src, unsigned int handle_flag, unsigned long arg1,
+ unsigned long arg2)
+{
+ unsigned long divider;
+ unsigned int flag;
+
+ divider = lq_cal_divider(freq);
+ if (divider == 0)
+ return -EINVAL;
+ flag = ((divider & ~0xFFFF) ? TIMER_FLAG_32BIT : TIMER_FLAG_16BIT)
+ | (is_cyclic ? TIMER_FLAG_CYCLIC : TIMER_FLAG_ONCE)
+ | (is_ext_src ? TIMER_FLAG_EXT_SRC : TIMER_FLAG_INT_SRC)
+ | TIMER_FLAG_TIMER | TIMER_FLAG_DOWN
+ | TIMER_FLAG_MASK_HANDLE(handle_flag);
+
+ printk(KERN_INFO "lq_set_timer(%d, %d), divider = %lu\n",
+ timer, freq, divider);
+ return lq_request_timer(timer, flag, divider, arg1, arg2);
+}
+EXPORT_SYMBOL(lq_set_timer);
+
+int lq_set_counter(unsigned int timer, unsigned int flag, u32 reload,
+ unsigned long arg1, unsigned long arg2)
+{
+ printk(KERN_INFO "lq_set_counter(%d, %#x, %d)\n", timer, flag, reload);
+ return lq_request_timer(timer, flag, reload, arg1, arg2);
+}
+EXPORT_SYMBOL(lq_set_counter);
+
+static long gptu_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int ret;
+ struct gptu_ioctl_param param;
+
+ if (!access_ok(VERIFY_READ, arg, sizeof(struct gptu_ioctl_param)))
+ return -EFAULT;
+ copy_from_user(&param, (void *) arg, sizeof(param));
+
+ if ((((cmd == GPTU_REQUEST_TIMER || cmd == GPTU_SET_TIMER
+ || GPTU_SET_COUNTER) && param.timer < 2)
+ || cmd == GPTU_GET_COUNT_VALUE || cmd == GPTU_CALCULATE_DIVIDER)
+ && !access_ok(VERIFY_WRITE, arg,
+ sizeof(struct gptu_ioctl_param)))
+ return -EFAULT;
+
+ switch (cmd) {
+ case GPTU_REQUEST_TIMER:
+ ret = lq_request_timer(param.timer, param.flag, param.value,
+ (unsigned long) param.pid,
+ (unsigned long) param.sig);
+ if (ret > 0) {
+ copy_to_user(&((struct gptu_ioctl_param *) arg)->
+ timer, &ret, sizeof(&ret));
+ ret = 0;
+ }
+ break;
+ case GPTU_FREE_TIMER:
+ ret = lq_free_timer(param.timer);
+ break;
+ case GPTU_START_TIMER:
+ ret = lq_start_timer(param.timer, param.flag);
+ break;
+ case GPTU_STOP_TIMER:
+ ret = lq_stop_timer(param.timer);
+ break;
+ case GPTU_GET_COUNT_VALUE:
+ ret = lq_get_count_value(param.timer, &param.value);
+ if (!ret)
+ copy_to_user(&((struct gptu_ioctl_param *) arg)->
+ value, &param.value,
+ sizeof(param.value));
+ break;
+ case GPTU_CALCULATE_DIVIDER:
+ param.value = lq_cal_divider(param.value);
+ if (param.value == 0)
+ ret = -EINVAL;
+ else {
+ copy_to_user(&((struct gptu_ioctl_param *) arg)->
+ value, &param.value,
+ sizeof(param.value));
+ ret = 0;
+ }
+ break;
+ case GPTU_SET_TIMER:
+ ret = lq_set_timer(param.timer, param.value,
+ TIMER_FLAG_MASK_STOP(param.flag) !=
+ TIMER_FLAG_ONCE ? 1 : 0,
+ TIMER_FLAG_MASK_SRC(param.flag) ==
+ TIMER_FLAG_EXT_SRC ? 1 : 0,
+ TIMER_FLAG_MASK_HANDLE(param.flag) ==
+ TIMER_FLAG_SIGNAL ? TIMER_FLAG_SIGNAL :
+ TIMER_FLAG_NO_HANDLE,
+ (unsigned long) param.pid,
+ (unsigned long) param.sig);
+ if (ret > 0) {
+ copy_to_user(&((struct gptu_ioctl_param *) arg)->
+ timer, &ret, sizeof(&ret));
+ ret = 0;
+ }
+ break;
+ case GPTU_SET_COUNTER:
+ lq_set_counter(param.timer, param.flag, param.value, 0, 0);
+ if (ret > 0) {
+ copy_to_user(&((struct gptu_ioctl_param *) arg)->
+ timer, &ret, sizeof(&ret));
+ ret = 0;
+ }
+ break;
+ default:
+ ret = -ENOTTY;
+ }
+
+ return ret;
+}
+
+static int gptu_open(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static int gptu_release(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+int __init lq_gptu_init(void)
+{
+ int ret;
+ unsigned int i;
+
+ ltq_w32(0, LQ_GPTU_IRNEN);
+ ltq_w32(0xfff, LQ_GPTU_IRNCR);
+
+ memset(&timer_dev, 0, sizeof(timer_dev));
+ mutex_init(&timer_dev.gptu_mutex);
+
+ lq_enable_gptu();
+ timer_dev.number_of_timers = GPTU_ID_CFG * 2;
+ lq_disable_gptu();
+ if (timer_dev.number_of_timers > MAX_NUM_OF_32BIT_TIMER_BLOCKS * 2)
+ timer_dev.number_of_timers = MAX_NUM_OF_32BIT_TIMER_BLOCKS * 2;
+ printk(KERN_INFO "gptu: totally %d 16-bit timers/counters\n", timer_dev.number_of_timers);
+
+ ret = misc_register(&gptu_miscdev);
+ if (ret) {
+ printk(KERN_ERR "gptu: can't misc_register, get error %d\n", -ret);
+ return ret;
+ } else {
+ printk(KERN_INFO "gptu: misc_register on minor %d\n", gptu_miscdev.minor);
+ }
+
+ for (i = 0; i < timer_dev.number_of_timers; i++) {
+ ret = request_irq(TIMER_INTERRUPT + i, timer_irq_handler, IRQF_TIMER, gptu_miscdev.name, &timer_dev.timer[i]);
+ if (ret) {
+ for (; i >= 0; i--)
+ free_irq(TIMER_INTERRUPT + i, &timer_dev.timer[i]);
+ misc_deregister(&gptu_miscdev);
+ printk(KERN_ERR "gptu: failed in requesting irq (%d), get error %d\n", i, -ret);
+ return ret;
+ } else {
+ timer_dev.timer[i].irq = TIMER_INTERRUPT + i;
+ disable_irq(timer_dev.timer[i].irq);
+ printk(KERN_INFO "gptu: succeeded to request irq %d\n", timer_dev.timer[i].irq);
+ }
+ }
+
+ return 0;
+}
+
+void __exit lq_gptu_exit(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < timer_dev.number_of_timers; i++) {
+ if (timer_dev.timer[i].f_irq_on)
+ disable_irq(timer_dev.timer[i].irq);
+ free_irq(timer_dev.timer[i].irq, &timer_dev.timer[i]);
+ }
+ lq_disable_gptu();
+ misc_deregister(&gptu_miscdev);
+}
+
+module_init(lq_gptu_init);
+module_exit(lq_gptu_exit);
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/lantiq_timer.h
@@ -0,0 +1,155 @@
+#ifndef __DANUBE_GPTU_DEV_H__2005_07_26__10_19__
+#define __DANUBE_GPTU_DEV_H__2005_07_26__10_19__
+
+
+/******************************************************************************
+ Copyright (c) 2002, Infineon Technologies. All rights reserved.
+
+ No Warranty
+ Because the program is licensed free of charge, there is no warranty for
+ the program, to the extent permitted by applicable law. Except when
+ otherwise stated in writing the copyright holders and/or other parties
+ provide the program "as is" without warranty of any kind, either
+ expressed or implied, including, but not limited to, the implied
+ warranties of merchantability and fitness for a particular purpose. The
+ entire risk as to the quality and performance of the program is with
+ you. should the program prove defective, you assume the cost of all
+ necessary servicing, repair or correction.
+
+ In no event unless required by applicable law or agreed to in writing
+ will any copyright holder, or any other party who may modify and/or
+ redistribute the program as permitted above, be liable to you for
+ damages, including any general, special, incidental or consequential
+ damages arising out of the use or inability to use the program
+ (including but not limited to loss of data or data being rendered
+ inaccurate or losses sustained by you or third parties or a failure of
+ the program to operate with any other programs), even if such holder or
+ other party has been advised of the possibility of such damages.
+******************************************************************************/
+
+
+/*
+ * ####################################
+ * Definition
+ * ####################################
+ */
+
+/*
+ * Available Timer/Counter Index
+ */
+#define TIMER(n, X) (n * 2 + (X ? 1 : 0))
+#define TIMER_ANY 0x00
+#define TIMER1A TIMER(1, 0)
+#define TIMER1B TIMER(1, 1)
+#define TIMER2A TIMER(2, 0)
+#define TIMER2B TIMER(2, 1)
+#define TIMER3A TIMER(3, 0)
+#define TIMER3B TIMER(3, 1)
+
+/*
+ * Flag of Timer/Counter
+ * These flags specify the way in which timer is configured.
+ */
+/* Bit size of timer/counter. */
+#define TIMER_FLAG_16BIT 0x0000
+#define TIMER_FLAG_32BIT 0x0001
+/* Switch between timer and counter. */
+#define TIMER_FLAG_TIMER 0x0000
+#define TIMER_FLAG_COUNTER 0x0002
+/* Stop or continue when overflowing/underflowing. */
+#define TIMER_FLAG_ONCE 0x0000
+#define TIMER_FLAG_CYCLIC 0x0004
+/* Count up or counter down. */
+#define TIMER_FLAG_UP 0x0000
+#define TIMER_FLAG_DOWN 0x0008
+/* Count on specific level or edge. */
+#define TIMER_FLAG_HIGH_LEVEL_SENSITIVE 0x0000
+#define TIMER_FLAG_LOW_LEVEL_SENSITIVE 0x0040
+#define TIMER_FLAG_RISE_EDGE 0x0010
+#define TIMER_FLAG_FALL_EDGE 0x0020
+#define TIMER_FLAG_ANY_EDGE 0x0030
+/* Signal is syncronous to module clock or not. */
+#define TIMER_FLAG_UNSYNC 0x0000
+#define TIMER_FLAG_SYNC 0x0080
+/* Different interrupt handle type. */
+#define TIMER_FLAG_NO_HANDLE 0x0000
+#if defined(__KERNEL__)
+ #define TIMER_FLAG_CALLBACK_IN_IRQ 0x0100
+#endif // defined(__KERNEL__)
+#define TIMER_FLAG_SIGNAL 0x0300
+/* Internal clock source or external clock source */
+#define TIMER_FLAG_INT_SRC 0x0000
+#define TIMER_FLAG_EXT_SRC 0x1000
+
+
+/*
+ * ioctl Command
+ */
+#define GPTU_REQUEST_TIMER 0x01 /* General method to setup timer/counter. */
+#define GPTU_FREE_TIMER 0x02 /* Free timer/counter. */
+#define GPTU_START_TIMER 0x03 /* Start or resume timer/counter. */
+#define GPTU_STOP_TIMER 0x04 /* Suspend timer/counter. */
+#define GPTU_GET_COUNT_VALUE 0x05 /* Get current count value. */
+#define GPTU_CALCULATE_DIVIDER 0x06 /* Calculate timer divider from given freq.*/
+#define GPTU_SET_TIMER 0x07 /* Simplified method to setup timer. */
+#define GPTU_SET_COUNTER 0x08 /* Simplified method to setup counter. */
+
+/*
+ * Data Type Used to Call ioctl
+ */
+struct gptu_ioctl_param {
+ unsigned int timer; /* In command GPTU_REQUEST_TIMER, GPTU_SET_TIMER, and *
+ * GPTU_SET_COUNTER, this field is ID of expected *
+ * timer/counter. If it's zero, a timer/counter would *
+ * be dynamically allocated and ID would be stored in *
+ * this field. *
+ * In command GPTU_GET_COUNT_VALUE, this field is *
+ * ignored. *
+ * In other command, this field is ID of timer/counter *
+ * allocated. */
+ unsigned int flag; /* In command GPTU_REQUEST_TIMER, GPTU_SET_TIMER, and *
+ * GPTU_SET_COUNTER, this field contains flags to *
+ * specify how to configure timer/counter. *
+ * In command GPTU_START_TIMER, zero indicate start *
+ * and non-zero indicate resume timer/counter. *
+ * In other command, this field is ignored. */
+ unsigned long value; /* In command GPTU_REQUEST_TIMER, this field contains *
+ * init/reload value. *
+ * In command GPTU_SET_TIMER, this field contains *
+ * frequency (0.001Hz) of timer. *
+ * In command GPTU_GET_COUNT_VALUE, current count *
+ * value would be stored in this field. *
+ * In command GPTU_CALCULATE_DIVIDER, this field *
+ * contains frequency wanted, and after calculation, *
+ * divider would be stored in this field to overwrite *
+ * the frequency. *
+ * In other command, this field is ignored. */
+ int pid; /* In command GPTU_REQUEST_TIMER and GPTU_SET_TIMER, *
+ * if signal is required, this field contains process *
+ * ID to which signal would be sent. *
+ * In other command, this field is ignored. */
+ int sig; /* In command GPTU_REQUEST_TIMER and GPTU_SET_TIMER, *
+ * if signal is required, this field contains signal *
+ * number which would be sent. *
+ * In other command, this field is ignored. */
+};
+
+/*
+ * ####################################
+ * Data Type
+ * ####################################
+ */
+typedef void (*timer_callback)(unsigned long arg);
+
+extern int lq_request_timer(unsigned int, unsigned int, unsigned long, unsigned long, unsigned long);
+extern int lq_free_timer(unsigned int);
+extern int lq_start_timer(unsigned int, int);
+extern int lq_stop_timer(unsigned int);
+extern int lq_reset_counter_flags(u32 timer, u32 flags);
+extern int lq_get_count_value(unsigned int, unsigned long *);
+extern u32 lq_cal_divider(unsigned long);
+extern int lq_set_timer(unsigned int, unsigned int, int, int, unsigned int, unsigned long, unsigned long);
+extern int lq_set_counter(unsigned int timer, unsigned int flag,
+ u32 reload, unsigned long arg1, unsigned long arg2);
+
+#endif /* __DANUBE_GPTU_DEV_H__2005_07_26__10_19__ */
--- a/arch/mips/lantiq/xway/Makefile
+++ b/arch/mips/lantiq/xway/Makefile
@@ -1,4 +1,4 @@
-obj-y := pmu.o ebu.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o
+obj-y := pmu.o ebu.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o timer.o
obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o setup-xway.o
obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o setup-ase.o

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,547 @@
--- a/arch/mips/lantiq/xway/Kconfig
+++ b/arch/mips/lantiq/xway/Kconfig
@@ -6,6 +6,10 @@
bool "Easy50712 - Danube"
default y
+config LANTIQ_MACH_ARV45XX
+ bool "ARV45XX"
+ default y
+
endmenu
endif
--- a/arch/mips/lantiq/xway/Makefile
+++ b/arch/mips/lantiq/xway/Makefile
@@ -5,3 +5,4 @@
obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o
obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o
+obj-$(CONFIG_LANTIQ_MACH_ARV45XX) += mach-arv45xx.o
--- /dev/null
+++ b/arch/mips/lantiq/xway/mach-arv45xx.c
@@ -0,0 +1,504 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/gpio.h>
+#include <linux/gpio_buttons.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/input.h>
+#include <linux/etherdevice.h>
+#include <linux/ath5k_platform.h>
+#include <linux/pci.h>
+
+#include <lantiq_soc.h>
+#include <lantiq_platform.h>
+
+#include "../machtypes.h"
+#include "devices.h"
+#include "dev-leds-gpio.h"
+#include "dev-dwc_otg.h"
+
+#ifdef CONFIG_MTD_PARTITIONS
+static struct mtd_partition arv4510_partitions[] =
+{
+ {
+ .name = "uboot",
+ .offset = 0x0,
+ .size = 0x20000,
+ },
+ {
+ .name = "uboot_env",
+ .offset = 0x20000,
+ .size = 0x120000,
+ },
+ {
+ .name = "linux",
+ .offset = 0x40000,
+ .size = 0xfa0000,
+ },
+ {
+ .name = "board_config",
+ .offset = 0xfe0000,
+ .size = 0x20000,
+ },
+};
+
+static struct mtd_partition arv45xx_partitions[] =
+{
+ {
+ .name = "uboot",
+ .offset = 0x0,
+ .size = 0x20000,
+ },
+ {
+ .name = "uboot_env",
+ .offset = 0x20000,
+ .size = 0x10000,
+ },
+ {
+ .name = "linux",
+ .offset = 0x30000,
+ .size = 0x3c0000,
+ },
+ {
+ .name = "board_config",
+ .offset = 0x3f0000,
+ .size = 0x10000,
+ },
+};
+
+static struct mtd_partition arv75xx_partitions[] =
+{
+ {
+ .name = "uboot",
+ .offset = 0x0,
+ .size = 0x10000,
+ },
+ {
+ .name = "uboot_env",
+ .offset = 0x10000,
+ .size = 0x10000,
+ },
+ {
+ .name = "linux",
+ .offset = 0x20000,
+ .size = 0x7d0000,
+ },
+ {
+ .name = "board_config",
+ .offset = 0x7f0000,
+ .size = 0x10000,
+ },
+};
+
+#endif
+
+static struct physmap_flash_data arv4510_flash_data = {
+#ifdef CONFIG_MTD_PARTITIONS
+ .nr_parts = ARRAY_SIZE(arv4510_partitions),
+ .parts = arv4510_partitions,
+#endif
+};
+
+static struct physmap_flash_data arv45xx_flash_data = {
+#ifdef CONFIG_MTD_PARTITIONS
+ .nr_parts = ARRAY_SIZE(arv45xx_partitions),
+ .parts = arv45xx_partitions,
+#endif
+};
+
+static struct physmap_flash_data arv75xx_flash_data = {
+#ifdef CONFIG_MTD_PARTITIONS
+ .nr_parts = ARRAY_SIZE(arv75xx_partitions),
+ .parts = arv75xx_partitions,
+#endif
+};
+
+static struct ltq_pci_data ltq_pci_data = {
+ .clock = PCI_CLOCK_EXT,
+ .gpio = PCI_GNT1 | PCI_REQ1,
+ .irq = {
+ [14] = INT_NUM_IM0_IRL0 + 22,
+ },
+};
+
+static struct ltq_eth_data ltq_eth_data = {
+ .mii_mode = PHY_INTERFACE_MODE_RMII,
+};
+
+static struct gpio_led
+arv4510pw_leds_gpio[] __initdata = {
+ { .name = "soc:green:foo", .gpio = 4, .active_low = 1, },
+};
+
+static struct gpio_led
+arv4518pw_leds_gpio[] __initdata = {
+ { .name = "soc:green:power", .gpio = 3, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:adsl", .gpio = 4, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:internet", .gpio = 5, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:wlan", .gpio = 6, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:yellow:wps", .gpio = 7, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:red:fail", .gpio = 8, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:usb", .gpio = 19, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:voip", .gpio = 72, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:fxs1", .gpio = 73, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:fxs2", .gpio = 74, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:fxo", .gpio = 75, .active_low = 1, .default_trigger = "default-on" },
+};
+
+static struct gpio_button
+arv4518pw_gpio_buttons[] __initdata = {
+ { .desc = "wlan", .type = EV_KEY, .code = BTN_0, .threshold = 3, .gpio = 28, .active_low = 1, },
+ { .desc = "wps", .type = EV_KEY, .code = BTN_1, .threshold = 3, .gpio = 29, .active_low = 1, },
+ { .desc = "reset", .type = EV_KEY, .code = BTN_2, .threshold = 3, .gpio = 30, .active_low = 1, },
+};
+
+static struct gpio_led
+arv4520pw_leds_gpio[] __initdata = {
+ { .name = "soc:blue:power", .gpio = 3, .active_low = 1, },
+ { .name = "soc:blue:adsl", .gpio = 4, .active_low = 1, },
+ { .name = "soc:blue:internet", .gpio = 5, .active_low = 1, },
+ { .name = "soc:red:power", .gpio = 6, .active_low = 1, },
+ { .name = "soc:yellow:wps", .gpio = 7, .active_low = 1, },
+ { .name = "soc:red:wps", .gpio = 9, .active_low = 1, },
+ { .name = "soc:blue:voip", .gpio = 72, .active_low = 1, },
+ { .name = "soc:blue:fxs1", .gpio = 73, .active_low = 1, },
+ { .name = "soc:blue:fxs2", .gpio = 74, .active_low = 1, },
+ { .name = "soc:blue:fxo", .gpio = 75, .active_low = 1, },
+ { .name = "soc:blue:voice", .gpio = 76, .active_low = 1, },
+ { .name = "soc:blue:usb", .gpio = 77, .active_low = 1, },
+ { .name = "soc:blue:wlan", .gpio = 78, .active_low = 1, },
+};
+
+static struct gpio_led
+arv452cpw_leds_gpio[] __initdata = {
+ { .name = "soc:blue:power", .gpio = 3, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:adsl", .gpio = 4, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:isdn", .gpio = 5, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:red:power", .gpio = 6, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:yellow:wps", .gpio = 7, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:red:wps", .gpio = 9, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:fxs1", .gpio = 72, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:fxs2", .gpio = 73, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:wps", .gpio = 74, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:fxo", .gpio = 75, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:voice", .gpio = 76, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:usb", .gpio = 77, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:wlan", .gpio = 78, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:internet", .gpio = 80, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:red:internet", .gpio = 81, .active_low = 1, .default_trigger = "default-on" },
+};
+
+static struct gpio_led
+arv4525pw_leds_gpio[] __initdata = {
+ { .name = "soc:green:festnetz", .gpio = 4, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:internet", .gpio = 5, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:dsl", .gpio = 6, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:wlan", .gpio = 8, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:online", .gpio = 9, .active_low = 1, .default_trigger = "default-on" },
+};
+
+static struct gpio_led
+arv752dpw22_leds_gpio[] __initdata = {
+ { .name = "soc:blue:power", .gpio = 3, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:red:internet", .gpio = 5, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:red:power", .gpio = 6, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:red:wps", .gpio = 8, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:red:fxo", .gpio = 75, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:red:voice", .gpio = 76, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:usb", .gpio = 77, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:wlan", .gpio = 78, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:wlan1", .gpio = 79, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:wlan", .gpio = 80, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:wlan1", .gpio = 81, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:eth1", .gpio = 83, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:eth2", .gpio = 84, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:eth3", .gpio = 85, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:eth4", .gpio = 86, .active_low = 1, .default_trigger = "default-on", },
+};
+
+static struct gpio_button
+arv752dpw22_gpio_buttons[] __initdata = {
+ { .desc = "btn0", .type = EV_KEY, .code = BTN_0, .threshold = 3, .gpio = 12, .active_low = 1, },
+ { .desc = "btn1", .type = EV_KEY, .code = BTN_1, .threshold = 3, .gpio = 13, .active_low = 1, },
+ { .desc = "btn2", .type = EV_KEY, .code = BTN_2, .threshold = 3, .gpio = 28, .active_low = 1, },
+};
+
+static struct gpio_led
+arv7518pw_leds_gpio[] __initdata = {
+ { .name = "soc:green:power", .gpio = 2, .active_low = 1, },
+ { .name = "soc:green:adsl", .gpio = 4, .active_low = 1, },
+ { .name = "soc:green:internet", .gpio = 5, .active_low = 1, },
+ { .name = "soc:green:wlan", .gpio = 6, .active_low = 1, },
+ { .name = "soc:red:internet", .gpio = 8, .active_low = 1, },
+ { .name = "soc:green:usb", .gpio = 19, .active_low = 1, },
+};
+
+static struct gpio_button
+arv7518pw_gpio_buttons[] __initdata = {
+ { .desc = "reset", .type = EV_KEY, .code = BTN_0, .threshold = 3, .gpio = 23, .active_low = 1, },
+ { .desc = "wlan", .type = EV_KEY, .code = BTN_1, .threshold = 3, .gpio = 25, .active_low = 1, },
+};
+
+static void
+arv45xx_register_ethernet(void)
+{
+#define ARV45XX_BRN_MAC 0x3f0016
+ memcpy_fromio(&ltq_eth_data.mac.sa_data,
+ (void *)KSEG1ADDR(LTQ_FLASH_START + ARV45XX_BRN_MAC), 6);
+ ltq_register_etop(&ltq_eth_data);
+}
+
+static void
+arv75xx_register_ethernet(void)
+{
+#define ARV75XX_BRN_MAC 0x7f0016
+ memcpy_fromio(&ltq_eth_data.mac.sa_data,
+ (void *)KSEG1ADDR(LTQ_FLASH_START + ARV75XX_BRN_MAC), 6);
+ ltq_register_etop(&ltq_eth_data);
+}
+
+static void
+bewan_register_ethernet(void)
+{
+#define BEWAN_BRN_MAC 0x3f0014
+ memcpy_fromio(&ltq_eth_data.mac.sa_data,
+ (void *)KSEG1ADDR(LTQ_FLASH_START + BEWAN_BRN_MAC), 6);
+ ltq_register_etop(&ltq_eth_data);
+}
+
+static u16 arv45xx_ath5k_eeprom_data[ATH5K_PLAT_EEP_MAX_WORDS];
+static struct ath5k_platform_data arv45xx_ath5k_platform_data;
+
+/*static int arv45xx_pci_plat_dev_init(struct pci_dev *dev)
+{
+ dev->dev.platform_data = &arv45xx_ath5k_platform_data;
+ return 0;
+}
+*/
+void __init
+arv45xx_register_ath5k(void)
+{
+#define ARV45XX_BRN_ATH 0x3f0478
+ int i;
+ unsigned char eeprom_mac[6];
+ static u16 eeprom_data[ATH5K_PLAT_EEP_MAX_WORDS];
+ u32 *p = (u32*)arv45xx_ath5k_eeprom_data;
+
+ memcpy_fromio(eeprom_mac,
+ (void *)KSEG1ADDR(LTQ_FLASH_START + ARV45XX_BRN_MAC), 6);
+ eeprom_mac[5]++;
+ memcpy_fromio(arv45xx_ath5k_eeprom_data,
+ (void *)KSEG1ADDR(LTQ_FLASH_START + ARV45XX_BRN_ATH), ATH5K_PLAT_EEP_MAX_WORDS);
+ // swap eeprom bytes
+ for (i = 0; i < ATH5K_PLAT_EEP_MAX_WORDS>>1; i++){
+ //arv4518_ath5k_eeprom_data[i] = ((eeprom_data[i]&0xff)<<8)|((eeprom_data[i]&0xff00)>>8);
+ p[i] = ((eeprom_data[(i<<1)+1]&0xff)<<24)|((eeprom_data[(i<<1)+1]&0xff00)<<8)|((eeprom_data[i<<1]&0xff)<<8)|((eeprom_data[i<<1]&0xff00)>>8);
+ if (i == 0xbf>>1){
+ // printk ("regdomain: 0x%x --> 0x%x\n", p[i], (p[i] & 0xffff0000)|0x67);
+ /* regdomain is invalid?? how did original fw convert
+ * value to 0x82d4 ??
+ * for now, force to 0x67 */
+ p[i] &= 0xffff0000;
+ p[i] |= 0x67;
+ }
+ }
+ arv45xx_ath5k_platform_data.eeprom_data = arv45xx_ath5k_eeprom_data;
+ arv45xx_ath5k_platform_data.macaddr = eeprom_mac;
+ //lqpci_plat_dev_init = arv45xx_pci_plat_dev_init;
+}
+
+static void __init
+arv3527p_init(void)
+{
+ ltq_register_gpio_stp();
+ //ltq_add_device_leds_gpio(arv3527p_leds_gpio, ARRAY_SIZE(arv3527p_leds_gpio));
+ ltq_register_nor(&arv45xx_flash_data);
+ arv45xx_register_ethernet();
+}
+
+MIPS_MACHINE(LANTIQ_MACH_ARV3527P,
+ "ARV3527P",
+ "ARV3527P - Arcor Easybox 401",
+ arv3527p_init);
+
+static void __init
+arv4510pw_init(void)
+{
+ ltq_register_gpio_stp();
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv4510pw_leds_gpio), arv4510pw_leds_gpio);
+ ltq_register_nor(&arv4510_flash_data);
+ ltq_pci_data.irq[12] = (INT_NUM_IM2_IRL0 + 31);
+ ltq_pci_data.irq[15] = (INT_NUM_IM0_IRL0 + 26);
+ ltq_pci_data.gpio |= PCI_EXIN2 | PCI_REQ2;
+ ltq_register_pci(&ltq_pci_data);
+ bewan_register_ethernet();
+}
+
+MIPS_MACHINE(LANTIQ_MACH_ARV4510PW,
+ "ARV4510PW",
+ "ARV4510PW - Wippies Homebox",
+ arv4510pw_init);
+
+static void __init
+arv4518pw_init(void)
+{
+#define ARV4518PW_EBU 0
+#define ARV4518PW_USB 14
+#define ARV4518PW_SWITCH_RESET 13
+
+ ltq_register_gpio_ebu(ARV4518PW_EBU);
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv4518pw_leds_gpio), arv4518pw_leds_gpio);
+ ltq_register_gpio_buttons(arv4518pw_gpio_buttons, ARRAY_SIZE(arv4518pw_gpio_buttons));
+ ltq_register_nor(&arv45xx_flash_data);
+ ltq_pci_data.gpio = PCI_GNT2 | PCI_REQ2;
+ ltq_register_pci(&ltq_pci_data);
+ ltq_register_madwifi_eep();
+ xway_register_dwc(ARV4518PW_USB);
+ arv45xx_register_ethernet();
+ arv45xx_register_ath5k();
+
+ gpio_request(ARV4518PW_SWITCH_RESET, "switch");
+ gpio_direction_output(ARV4518PW_SWITCH_RESET, 1);
+ gpio_export(ARV4518PW_SWITCH_RESET, 0);
+}
+
+MIPS_MACHINE(LANTIQ_MACH_ARV4518PW,
+ "ARV4518PW",
+ "ARV4518PW - SMC7908A-ISP, Airties WAV-221",
+ arv4518pw_init);
+
+static void __init
+arv4520pw_init(void)
+{
+#define ARV4520PW_EBU 0x400
+#define ARV4520PW_USB 28
+#define ARV4520PW_SWITCH_RESET 82
+
+ ltq_register_gpio_ebu(ARV4520PW_EBU);
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv4520pw_leds_gpio), arv4520pw_leds_gpio);
+ ltq_register_nor(&arv45xx_flash_data);
+ ltq_register_pci(&ltq_pci_data);
+ ltq_register_tapi();
+ arv45xx_register_ethernet();
+ xway_register_dwc(ARV4520PW_USB);
+
+ gpio_request(ARV4520PW_SWITCH_RESET, "switch");
+ gpio_set_value(ARV4520PW_SWITCH_RESET, 1);
+}
+
+MIPS_MACHINE(LANTIQ_MACH_ARV4520PW,
+ "ARV4520PW",
+ "ARV4520PW - Airties WAV-281, Arcor A800",
+ arv4520pw_init);
+
+static void __init
+arv452Cpw_init(void)
+{
+#define ARV452CPW_EBU 0x77f
+#define ARV452CPW_USB 28
+#define ARV452CPW_RELAY1 31
+#define ARV452CPW_RELAY2 79
+#define ARV452CPW_SWITCH_RESET 82
+
+ ltq_register_gpio_ebu(ARV452CPW_EBU);
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv452cpw_leds_gpio), arv452cpw_leds_gpio);
+ ltq_register_nor(&arv45xx_flash_data);
+ ltq_register_pci(&ltq_pci_data);
+ ltq_register_madwifi_eep();
+ xway_register_dwc(ARV452CPW_USB);
+ arv45xx_register_ethernet();
+ arv45xx_register_ath5k();
+
+ gpio_request(ARV452CPW_SWITCH_RESET, "switch");
+ gpio_set_value(ARV452CPW_SWITCH_RESET, 1);
+ gpio_export(ARV452CPW_SWITCH_RESET, 0);
+
+ gpio_request(ARV452CPW_RELAY1, "relay1");
+ gpio_direction_output(ARV452CPW_RELAY1, 1);
+ gpio_export(ARV452CPW_RELAY1, 0);
+
+ gpio_request(ARV452CPW_RELAY2, "relay2");
+ gpio_set_value(ARV452CPW_RELAY2, 1);
+ gpio_export(ARV452CPW_RELAY2, 0);
+}
+
+MIPS_MACHINE(LANTIQ_MACH_ARV452CPW,
+ "ARV452CPW",
+ "ARV452CPW - Arcor A801",
+ arv452Cpw_init);
+
+static void __init
+arv4525pw_init(void)
+{
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv4525pw_leds_gpio), arv4525pw_leds_gpio);
+ ltq_register_nor(&arv45xx_flash_data);
+ ltq_pci_data.clock = PCI_CLOCK_INT;
+ ltq_register_pci(&ltq_pci_data);
+ ltq_register_madwifi_eep();
+ ltq_eth_data.mii_mode = PHY_INTERFACE_MODE_MII;
+ arv45xx_register_ethernet();
+}
+
+MIPS_MACHINE(LANTIQ_MACH_ARV4525PW,
+ "ARV4525PW",
+ "ARV4525PW - Speedport W502V",
+ arv4525pw_init);
+
+static void __init
+arv7518pw_init(void)
+{
+#define ARV7518PW_EBU 0x2
+#define ARV7518PW_USB 14
+
+ ltq_register_gpio_ebu(ARV7518PW_EBU);
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv7518pw_leds_gpio), arv7518pw_leds_gpio);
+ ltq_register_gpio_buttons(arv7518pw_gpio_buttons, ARRAY_SIZE(arv7518pw_gpio_buttons));
+ ltq_register_nor(&arv75xx_flash_data);
+ ltq_register_pci(&ltq_pci_data);
+ ltq_register_tapi();
+ xway_register_dwc(ARV7518PW_USB);
+ arv75xx_register_ethernet();
+ //arv7518_register_ath9k(mac);
+}
+
+MIPS_MACHINE(LANTIQ_MACH_ARV7518PW,
+ "ARV7518PW",
+ "ARV7518PW - ASTORIA",
+ arv7518pw_init);
+
+static void __init
+arv752dpw22_init(void)
+{
+#define ARV752DPW22_EBU 0x2
+#define ARV752DPW22_USB 72
+#define ARV752DPW22_RELAY 73
+
+ ltq_register_gpio_ebu(ARV752DPW22_EBU);
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv752dpw22_leds_gpio), arv752dpw22_leds_gpio);
+ ltq_register_gpio_buttons(arv752dpw22_gpio_buttons, ARRAY_SIZE(arv752dpw22_gpio_buttons));
+ ltq_register_nor(&arv75xx_flash_data);
+ ltq_pci_data.irq[15] = (INT_NUM_IM2_IRL0 + 31);
+ ltq_pci_data.gpio |= PCI_EXIN1 | PCI_REQ2;
+ ltq_register_pci(&ltq_pci_data);
+ xway_register_dwc(ARV752DPW22_USB);
+ arv75xx_register_ethernet();
+
+ gpio_request(ARV752DPW22_RELAY, "relay");
+ gpio_set_value(ARV752DPW22_RELAY, 1);
+ gpio_export(ARV752DPW22_RELAY, 0);
+}
+
+MIPS_MACHINE(LANTIQ_MACH_ARV752DPW22,
+ "ARV752DPW22",
+ "ARV752DPW22 - Arcor A803",
+ arv752dpw22_init);
--- a/arch/mips/lantiq/machtypes.h
+++ b/arch/mips/lantiq/machtypes.h
@@ -22,6 +22,17 @@
LANTIQ_MACH_EASY98000NAND, /* Falcon Eval Board, NAND Flash */
LANTIQ_MACH_EASY98020, /* Falcon Reference Board */
LANTIQ_MACH_95C3AM1, /* Board 95C3AM1 */
+
+ /* Arcadyan */
+ LANTIQ_MACH_ARV3527P, /* Arcor easybox a401 */
+ LANTIQ_MACH_ARV4510PW, /* Wippies Homebox */
+ LANTIQ_MACH_ARV4518PW, /* Airties WAV-221, SMC-7908A-ISP */
+ LANTIQ_MACH_ARV4520PW, /* Airties WAV-281, Arcor EasyboxA800 */
+ LANTIQ_MACH_ARV452CPW, /* Arcor EasyboxA801 */
+ LANTIQ_MACH_ARV4525PW, /* Speedport W502V */
+ LANTIQ_MACH_ARV752DPW, /* Arcor easybox a802 */
+ LANTIQ_MACH_ARV752DPW22, /* Arcor easybox a803 */
+ LANTIQ_MACH_ARV7518PW, /* ASTORIA */
};
#endif

View File

@ -0,0 +1,92 @@
--- a/arch/mips/lantiq/machtypes.h
+++ b/arch/mips/lantiq/machtypes.h
@@ -33,6 +33,9 @@
LANTIQ_MACH_ARV752DPW, /* Arcor easybox a802 */
LANTIQ_MACH_ARV752DPW22, /* Arcor easybox a803 */
LANTIQ_MACH_ARV7518PW, /* ASTORIA */
+
+ /* Netgear */
+ LANTIQ_MACH_DGN3500B, /* Netgear DGN3500 */
};
#endif
--- a/arch/mips/lantiq/xway/Kconfig
+++ b/arch/mips/lantiq/xway/Kconfig
@@ -10,6 +10,10 @@
bool "ARV45XX"
default y
+config LANTIQ_MACH_NETGEAR
+ bool "Netgear"
+ default y
+
endmenu
endif
--- a/arch/mips/lantiq/xway/Makefile
+++ b/arch/mips/lantiq/xway/Makefile
@@ -6,3 +6,4 @@
obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o
obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o
obj-$(CONFIG_LANTIQ_MACH_ARV45XX) += mach-arv45xx.o
+obj-$(CONFIG_LANTIQ_MACH_NETGEAR) += mach-netgear.o
--- /dev/null
+++ b/arch/mips/lantiq/xway/mach-netgear.c
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/input.h>
+#include <linux/phy.h>
+#include <linux/spi/spi.h>
+
+#include <lantiq_soc.h>
+#include <irq.h>
+
+#include "../machtypes.h"
+#include "devices.h"
+
+static struct ltq_pci_data ltq_pci_data = {
+ .clock = PCI_CLOCK_INT,
+ .gpio = PCI_GNT1 | PCI_REQ1,
+ .irq = {
+ [14] = INT_NUM_IM0_IRL0 + 22,
+ },
+};
+
+static struct ltq_eth_data ltq_eth_data = {
+ .mii_mode = PHY_INTERFACE_MODE_MII,
+};
+
+struct spi_board_info spi_info = {
+ .bus_num = 0,
+ .chip_select = 3,
+ .max_speed_hz = 25000000,
+ .modalias = "mx25l12805d",
+};
+
+struct ltq_spi_platform_data ltq_spi_data = {
+ .num_chipselect = 4,
+};
+
+static void __init dgn3500_init(void)
+{
+ ltq_register_pci(&ltq_pci_data);
+ ltq_register_etop(&ltq_eth_data);
+ ltq_register_spi(&ltq_spi_data, &spi_info, 1);
+}
+
+MIPS_MACHINE(LANTIQ_MACH_DGN3500B,
+ "DGN3500B",
+ "Netgear DGN3500B",
+ dgn3500_init);

View File

@ -0,0 +1,148 @@
--- a/arch/mips/lantiq/xway/Kconfig
+++ b/arch/mips/lantiq/xway/Kconfig
@@ -14,6 +14,10 @@
bool "Netgear"
default y
+config LANTIQ_MACH_GIGASX76X
+ bool "GIGASX76X"
+ default y
+
endmenu
endif
--- a/arch/mips/lantiq/xway/Makefile
+++ b/arch/mips/lantiq/xway/Makefile
@@ -7,3 +7,4 @@
obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o
obj-$(CONFIG_LANTIQ_MACH_ARV45XX) += mach-arv45xx.o
obj-$(CONFIG_LANTIQ_MACH_NETGEAR) += mach-netgear.o
+obj-$(CONFIG_LANTIQ_MACH_GIGASX76X) += mach-gigasx76x.o
--- /dev/null
+++ b/arch/mips/lantiq/xway/mach-gigasx76x.c
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2011 Andrej Vlašić
+ * Copyright (C) 2011 Luka Perkov
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/gpio.h>
+#include <linux/gpio_buttons.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/input.h>
+#include <linux/ath5k_platform.h>
+#include <linux/pci.h>
+#include <linux/phy.h>
+
+#include <irq.h>
+
+#include <lantiq_soc.h>
+#include <lantiq_platform.h>
+
+#include "../machtypes.h"
+#include "devices.h"
+#include "dev-dwc_otg.h"
+#include "dev-leds-gpio.h"
+
+#ifdef CONFIG_MTD_PARTITIONS
+static struct mtd_partition gigasx76x_partitions[] =
+{
+ {
+ .name = "secondary_env",
+ .offset = 0xe000,
+ .size = 0x2000,
+ },
+ {
+ .name = "secondary_boot",
+ .offset = 0x10000,
+ .size = 0x10000,
+ },
+ {
+ .name = "uboot",
+ .offset = 0x20000,
+ .size = 0x30000,
+ },
+ {
+ .name = "linux",
+ .offset = 0x50000,
+ .size = 0x7a0000,
+ },
+ {
+ .name = "board_config",
+ .offset = 0x7f0000,
+ .size = 0x10000,
+ },
+};
+#endif
+
+static struct gpio_led
+gigasx76x_leds_gpio[] __initdata = {
+ { .name = "soc:green:usb", .gpio = 50, },
+ { .name = "soc:green:wlan", .gpio = 51, },
+ { .name = "soc:green:phone2", .gpio = 52, },
+ { .name = "soc:green:phone1", .gpio = 53, },
+ { .name = "soc:green:line", .gpio = 54, },
+ { .name = "soc:green:online", .gpio = 55, },
+};
+
+
+static struct physmap_flash_data gigasx76x_flash_data = {
+#ifdef CONFIG_MTD_PARTITIONS
+ .nr_parts = ARRAY_SIZE(gigasx76x_partitions),
+ .parts = gigasx76x_partitions,
+#endif
+};
+
+static struct ltq_pci_data ltq_pci_data = {
+ .clock = PCI_CLOCK_INT,
+ .gpio = PCI_GNT1 | PCI_REQ1,
+ .irq = {
+ [14] = INT_NUM_IM0_IRL0 + 22,
+ },
+};
+
+static struct ltq_eth_data ltq_eth_data = {
+ .mii_mode = PHY_INTERFACE_MODE_MII,
+};
+
+static void __init
+gigasx76x_init(void)
+{
+#define GIGASX76X_USB 29
+
+ ltq_register_gpio_stp();
+ ltq_register_nor(&gigasx76x_flash_data);
+ ltq_register_pci(&ltq_pci_data);
+ ltq_register_etop(&ltq_eth_data);
+ xway_register_dwc(GIGASX76X_USB);
+ ltq_register_tapi();
+ ltq_register_madwifi_eep();
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(gigasx76x_leds_gpio), gigasx76x_leds_gpio);
+}
+
+MIPS_MACHINE(LANTIQ_MACH_GIGASX76X,
+ "GIGASX76X",
+ "GIGASX76X - Gigaset SX761,SX762,SX763",
+ gigasx76x_init);
--- a/arch/mips/lantiq/machtypes.h
+++ b/arch/mips/lantiq/machtypes.h
@@ -36,6 +36,9 @@
/* Netgear */
LANTIQ_MACH_DGN3500B, /* Netgear DGN3500 */
+
+ /* Gigaset */
+ LANTIQ_MACH_GIGASX76X, /* Gigaset SX76x */
};
#endif

View File

@ -0,0 +1,28 @@
--- a/arch/mips/lantiq/xway/devices.c
+++ b/arch/mips/lantiq/xway/devices.c
@@ -121,6 +121,16 @@
}
}
+/* madwifi */
+int lantiq_emulate_madwifi_eep = 0;
+EXPORT_SYMBOL(lantiq_emulate_madwifi_eep);
+
+void __init
+ltq_register_madwifi_eep(void)
+{
+ lantiq_emulate_madwifi_eep = 1;
+}
+
static struct resource ltq_spi_resources[] = {
{
.start = LTQ_SSC_BASE_ADDR,
--- a/arch/mips/lantiq/xway/devices.h
+++ b/arch/mips/lantiq/xway/devices.h
@@ -19,5 +19,6 @@
extern void ltq_register_etop(struct ltq_eth_data *eth);
extern void ltq_register_spi(struct ltq_spi_platform_data *pdata,
struct spi_board_info const *info, unsigned n);
+extern void ltq_register_madwifi_eep(void);
#endif

View File

@ -0,0 +1,46 @@
--- a/arch/mips/lantiq/xway/devices.c
+++ b/arch/mips/lantiq/xway/devices.c
@@ -131,6 +131,26 @@
lantiq_emulate_madwifi_eep = 1;
}
+/* gpio buttons */
+static struct gpio_buttons_platform_data ltq_gpio_buttons_platform_data;
+
+static struct platform_device ltq_gpio_buttons_platform_device =
+{
+ .name = "gpio-buttons",
+ .id = 0,
+ .dev = {
+ .platform_data = (void *) &ltq_gpio_buttons_platform_data,
+ },
+};
+
+void __init
+ltq_register_gpio_buttons(struct gpio_button *buttons, int cnt)
+{
+ ltq_gpio_buttons_platform_data.buttons = buttons;
+ ltq_gpio_buttons_platform_data.nbuttons = cnt;
+ platform_device_register(&ltq_gpio_buttons_platform_device);
+}
+
static struct resource ltq_spi_resources[] = {
{
.start = LTQ_SSC_BASE_ADDR,
--- a/arch/mips/lantiq/xway/devices.h
+++ b/arch/mips/lantiq/xway/devices.h
@@ -12,6 +12,7 @@
#include "../devices.h"
#include <linux/phy.h>
#include <linux/spi/spi.h>
+#include <linux/gpio_buttons.h>
extern void ltq_register_gpio(void);
extern void ltq_register_gpio_stp(void);
@@ -20,5 +21,6 @@
extern void ltq_register_spi(struct ltq_spi_platform_data *pdata,
struct spi_board_info const *info, unsigned n);
extern void ltq_register_madwifi_eep(void);
+extern void ltq_register_gpio_buttons(struct gpio_button *buttons, int cnt);
#endif

View File

@ -0,0 +1,42 @@
--- a/arch/mips/lantiq/devices.c
+++ b/arch/mips/lantiq/devices.c
@@ -120,3 +120,20 @@
pr_err("kernel is compiled without PCI support\n");
}
#endif
+
+static unsigned int *cp1_base = 0;
+unsigned int*
+ltq_get_cp1_base(void)
+{
+ return cp1_base;
+}
+EXPORT_SYMBOL(ltq_get_cp1_base);
+
+void __init
+ltq_register_tapi(void)
+{
+#define CP1_SIZE (1 << 20)
+ dma_addr_t dma;
+ cp1_base =
+ (void*)CPHYSADDR(dma_alloc_coherent(NULL, CP1_SIZE, &dma, GFP_ATOMIC));
+}
--- a/arch/mips/lantiq/devices.h
+++ b/arch/mips/lantiq/devices.h
@@ -19,5 +19,6 @@
extern void ltq_register_wdt(void);
extern void ltq_register_asc(int port);
extern void ltq_register_pci(struct ltq_pci_data *data);
+extern void ltq_register_tapi(void);
#endif
--- a/arch/mips/lantiq/xway/mach-easy50712.c
+++ b/arch/mips/lantiq/xway/mach-easy50712.c
@@ -61,6 +61,7 @@
ltq_register_nor(&easy50712_flash_data);
ltq_register_pci(&ltq_pci_data);
ltq_register_etop(&ltq_eth_data);
+ ltq_register_tapi();
}
MIPS_MACHINE(LTQ_MACH_EASY50712,

View File

@ -0,0 +1,95 @@
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/dev-leds-gpio.h
@@ -0,0 +1,21 @@
+/*
+ * Lantiq GPIO LED device support
+ *
+ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#ifndef _LANTIQ_DEV_LEDS_GPIO_H
+#define _LANTIQ_DEV_LEDS_GPIO_H
+
+#include <linux/leds.h>
+
+void ltq_add_device_leds_gpio(int id,
+ unsigned num_leds,
+ struct gpio_led *leds) __init;
+
+#endif /* _LANTIQ_DEV_LEDS_GPIO_H */
--- /dev/null
+++ b/arch/mips/lantiq/dev-leds-gpio.c
@@ -0,0 +1,57 @@
+/*
+ * Lantiq GPIO LED device support
+ *
+ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * Parts of this file are based on Atheros' 2.6.15 BSP
+ *
+ * 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/init.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+
+#include "dev-leds-gpio.h"
+
+void __init ltq_add_device_leds_gpio(int id, unsigned num_leds,
+ struct gpio_led *leds)
+{
+ struct platform_device *pdev;
+ struct gpio_led_platform_data pdata;
+ struct gpio_led *p;
+ int err;
+
+ p = kmalloc(num_leds * sizeof(*p), GFP_KERNEL);
+ if (!p)
+ return;
+
+ memcpy(p, leds, num_leds * sizeof(*p));
+
+ pdev = platform_device_alloc("leds-gpio", id);
+ if (!pdev)
+ goto err_free_leds;
+
+ memset(&pdata, 0, sizeof(pdata));
+ pdata.num_leds = num_leds;
+ pdata.leds = p;
+
+ err = platform_device_add_data(pdev, &pdata, sizeof(pdata));
+ if (err)
+ goto err_put_pdev;
+
+ err = platform_device_add(pdev);
+ if (err)
+ goto err_put_pdev;
+
+ return;
+
+err_put_pdev:
+ platform_device_put(pdev);
+
+err_free_leds:
+ kfree(p);
+}
--- a/arch/mips/lantiq/Makefile
+++ b/arch/mips/lantiq/Makefile
@@ -4,7 +4,7 @@
# under the terms of the GNU General Public License version 2 as published
# by the Free Software Foundation.
-obj-y := irq.o setup.o clk.o prom.o devices.o
+obj-y := irq.o setup.o clk.o prom.o devices.o dev-leds-gpio.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o

View File

@ -0,0 +1,42 @@
--- a/arch/mips/lantiq/xway/devices.c
+++ b/arch/mips/lantiq/xway/devices.c
@@ -151,6 +151,29 @@
platform_device_register(&ltq_gpio_buttons_platform_device);
}
+/* ebu */
+static struct resource ltq_ebu_resource =
+{
+ .name = "gpio_ebu",
+ .start = LTQ_EBU_GPIO_START,
+ .end = LTQ_EBU_GPIO_START + LTQ_EBU_GPIO_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device ltq_ebu =
+{
+ .name = "ltq_ebu",
+ .resource = &ltq_ebu_resource,
+ .num_resources = 1,
+};
+
+void __init
+ltq_register_gpio_ebu(unsigned int value)
+{
+ ltq_ebu.dev.platform_data = (void*) value;
+ platform_device_register(&ltq_ebu);
+}
+
static struct resource ltq_spi_resources[] = {
{
.start = LTQ_SSC_BASE_ADDR,
--- a/arch/mips/lantiq/xway/devices.h
+++ b/arch/mips/lantiq/xway/devices.h
@@ -16,6 +16,7 @@
extern void ltq_register_gpio(void);
extern void ltq_register_gpio_stp(void);
+extern void ltq_register_gpio_ebu(unsigned int value);
extern void ltq_register_ase_asc(void);
extern void ltq_register_etop(struct ltq_eth_data *eth);
extern void ltq_register_spi(struct ltq_spi_platform_data *pdata,

View File

@ -0,0 +1,51 @@
CONFIG_ADM6996_PHY=y
CONFIG_AR8216_PHY=y
# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set
# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
# CONFIG_ATH79 is not set
CONFIG_GENERIC_ATOMIC64=y
CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_HAVE_ARCH_JUMP_LABEL=y
CONFIG_HAVE_C_RECORDMCOUNT=y
CONFIG_HAVE_DMA_API_DEBUG=y
CONFIG_HAVE_DMA_ATTRS=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_FUNCTION_TRACE_MCOUNT_TEST=y
CONFIG_HAVE_GENERIC_HARDIRQS=y
CONFIG_HAVE_IRQ_WORK=y
CONFIG_HAVE_PERF_EVENTS=y
CONFIG_HW_HAS_PCI=y
CONFIG_INPUT=y
CONFIG_INPUT_EVDEV=y
# CONFIG_INPUT_GPIO_BUTTONS is not set
CONFIG_INPUT_POLLDEV=y
# CONFIG_ISDN is not set
CONFIG_LANTIQ_ETOP=y
CONFIG_LANTIQ_MACH_ARV45XX=y
CONFIG_LANTIQ_MACH_EASY50712=y
CONFIG_LANTIQ_MACH_NETGEAR=y
CONFIG_LANTIQ_MACH_GIGASX76X=y
CONFIG_MACH_NO_WESTBRIDGE=y
# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEED_PER_CPU_KM=y
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
CONFIG_PERF_USE_VMALLOC=y
# CONFIG_PREEMPT_RCU is not set
# CONFIG_QUOTACTL is not set
CONFIG_RTL8306_PHY=y
# CONFIG_SOC_AMAZON_SE is not set
# CONFIG_SOC_FALCON is not set
CONFIG_SOC_TYPE_XWAY=y
CONFIG_SOC_XWAY=y
CONFIG_SPI=y
CONFIG_SPI_BITBANG=y
# CONFIG_SPI_GPIO is not set
CONFIG_SPI_LANTIQ=y
CONFIG_SPI_MASTER=y
CONFIG_USB_SUPPORT=y
CONFIG_XZ_DEC=y