parent
200227e0b4
commit
7d638fbb2f
@ -1,30 +0,0 @@ |
|||||||
CONFIG_ADM6996_PHY=y |
|
||||||
CONFIG_AR8216_PHY=y |
|
||||||
CONFIG_DEVPORT=y |
|
||||||
# CONFIG_DM9000 is not set |
|
||||||
CONFIG_HW_HAS_PCI=y |
|
||||||
# CONFIG_I2C_DESIGNWARE is not set |
|
||||||
CONFIG_INPUT=y |
|
||||||
CONFIG_INPUT_EVDEV=y |
|
||||||
# CONFIG_INPUT_GPIO_BUTTONS is not set |
|
||||||
CONFIG_INPUT_POLLDEV=y |
|
||||||
# CONFIG_INPUT_YEALINK is not set |
|
||||||
# CONFIG_ISDN is not set |
|
||||||
CONFIG_LANTIQ_ETOP=y |
|
||||||
# CONFIG_LANTIQ_MACH_ARV45XX is not set |
|
||||||
# CONFIG_LANTIQ_MACH_EASY50712 is not set |
|
||||||
CONFIG_LANTIQ_MACH_NETGEAR=y |
|
||||||
CONFIG_PCI=y |
|
||||||
CONFIG_PCI_DOMAINS=y |
|
||||||
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_MASTER=y |
|
||||||
# CONFIG_SPI_SPIDEV is not set |
|
||||||
# CONFIG_TC35815 is not set |
|
||||||
CONFIG_USB_SUPPORT=y |
|
@ -1,13 +0,0 @@ |
|||||||
# CONFIG_DM9000 is not set |
|
||||||
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_SOC_AMAZON_SE=y |
|
||||||
# CONFIG_SOC_FALCON is not set |
|
||||||
CONFIG_SOC_TYPE_XWAY=y |
|
||||||
# CONFIG_SOC_XWAY is not set |
|
||||||
# CONFIG_I2C_DESIGNWARE is not set |
|
@ -1,149 +0,0 @@ |
|||||||
CONFIG_32BIT=y |
|
||||||
# CONFIG_64BIT is not set |
|
||||||
# CONFIG_ALCHEMY_GPIO_INDIRECT is not set |
|
||||||
# CONFIG_AR7 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_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_BCM47XX is not set |
|
||||||
# CONFIG_BCM63XX is not set |
|
||||||
CONFIG_BITREVERSE=y |
|
||||||
CONFIG_BOOT_RAW=y |
|
||||||
# CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD is not set |
|
||||||
# CONFIG_CAVIUM_OCTEON_SIMULATOR is not set |
|
||||||
CONFIG_CEVT_R4K=y |
|
||||||
CONFIG_CEVT_R4K_LIB=y |
|
||||||
CONFIG_CFG80211_DEFAULT_PS_VALUE=0 |
|
||||||
CONFIG_CPU_BIG_ENDIAN=y |
|
||||||
# CONFIG_CPU_CAVIUM_OCTEON is not set |
|
||||||
CONFIG_CPU_HAS_PREFETCH=y |
|
||||||
CONFIG_CPU_HAS_SYNC=y |
|
||||||
# CONFIG_CPU_LITTLE_ENDIAN is not set |
|
||||||
# CONFIG_CPU_LOONGSON2E is not set |
|
||||||
CONFIG_CPU_MIPS32=y |
|
||||||
# CONFIG_CPU_MIPS32_R1 is not set |
|
||||||
CONFIG_CPU_MIPS32_R2=y |
|
||||||
# CONFIG_CPU_MIPS64_R1 is not set |
|
||||||
# CONFIG_CPU_MIPS64_R2 is not set |
|
||||||
CONFIG_CPU_MIPSR2=y |
|
||||||
# CONFIG_CPU_NEVADA is not set |
|
||||||
# CONFIG_CPU_R10000 is not set |
|
||||||
# CONFIG_CPU_R3000 is not set |
|
||||||
# CONFIG_CPU_R4300 is not set |
|
||||||
# CONFIG_CPU_R4X00 is not set |
|
||||||
# CONFIG_CPU_R5000 is not set |
|
||||||
# CONFIG_CPU_R5432 is not set |
|
||||||
# CONFIG_CPU_R5500 is not set |
|
||||||
# CONFIG_CPU_R6000 is not set |
|
||||||
# CONFIG_CPU_R8000 is not set |
|
||||||
# CONFIG_CPU_RM7000 is not set |
|
||||||
# CONFIG_CPU_RM9000 is not set |
|
||||||
# CONFIG_CPU_SB1 is not set |
|
||||||
CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y |
|
||||||
CONFIG_CPU_SUPPORTS_HIGHMEM=y |
|
||||||
# CONFIG_CPU_TX39XX is not set |
|
||||||
# CONFIG_CPU_TX49XX is not set |
|
||||||
# CONFIG_CPU_VR41XX is not set |
|
||||||
CONFIG_CSRC_R4K=y |
|
||||||
CONFIG_CSRC_R4K_LIB=y |
|
||||||
CONFIG_DECOMPRESS_LZMA=y |
|
||||||
CONFIG_DMA_NEED_PCI_MAP_STATE=y |
|
||||||
CONFIG_DMA_NONCOHERENT=y |
|
||||||
CONFIG_EARLY_PRINTK=y |
|
||||||
# CONFIG_FSNOTIFY is not set |
|
||||||
CONFIG_GENERIC_CLOCKEVENTS=y |
|
||||||
CONFIG_GENERIC_CLOCKEVENTS_BUILD=y |
|
||||||
CONFIG_GENERIC_CMOS_UPDATE=y |
|
||||||
CONFIG_GENERIC_FIND_LAST_BIT=y |
|
||||||
CONFIG_GENERIC_FIND_NEXT_BIT=y |
|
||||||
CONFIG_GENERIC_GPIO=y |
|
||||||
CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=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_KGDB=y |
|
||||||
CONFIG_HAVE_CLK=y |
|
||||||
CONFIG_HAVE_GENERIC_DMA_COHERENT=y |
|
||||||
CONFIG_HAVE_IDE=y |
|
||||||
CONFIG_HAVE_OPROFILE=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_WDT=y |
|
||||||
CONFIG_LEDS_GPIO=y |
|
||||||
# CONFIG_MACH_ALCHEMY is not set |
|
||||||
# CONFIG_MACH_DECSTATION is not set |
|
||||||
# CONFIG_MACH_JAZZ is not set |
|
||||||
# CONFIG_MACH_LOONGSON is not set |
|
||||||
# CONFIG_MACH_TX39XX is not set |
|
||||||
# CONFIG_MACH_TX49XX is not set |
|
||||||
# CONFIG_MACH_VR41XX is not set |
|
||||||
# CONFIG_MIKROTIK_RB532 is not set |
|
||||||
CONFIG_MIPS=y |
|
||||||
# CONFIG_MIPS_COBALT is not set |
|
||||||
CONFIG_MIPS_L1_CACHE_SHIFT=5 |
|
||||||
CONFIG_MIPS_MACHINE=y |
|
||||||
# CONFIG_MIPS_MALTA is not set |
|
||||||
CONFIG_MIPS_MT_DISABLED=y |
|
||||||
# CONFIG_MIPS_MT_SMP is not set |
|
||||||
# CONFIG_MIPS_MT_SMTC is not set |
|
||||||
# CONFIG_MIPS_SIM 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_NLS=y |
|
||||||
# CONFIG_NO_IOPORT is not set |
|
||||||
# CONFIG_NXP_STB220 is not set |
|
||||||
# CONFIG_NXP_STB225 is not set |
|
||||||
CONFIG_PAGEFLAGS_EXTENDED=y |
|
||||||
CONFIG_PHYLIB=y |
|
||||||
# CONFIG_PMC_MSP is not set |
|
||||||
# CONFIG_PMC_YOSEMITE is not set |
|
||||||
# CONFIG_PNX8550_JBS is not set |
|
||||||
# CONFIG_PNX8550_STB810 is not set |
|
||||||
CONFIG_SCHED_OMIT_FRAME_POINTER=y |
|
||||||
# CONFIG_SCSI_DMA is not set |
|
||||||
# CONFIG_SERIAL_8250 is not set |
|
||||||
CONFIG_SERIAL_LANTIQ=y |
|
||||||
# CONFIG_SGI_IP22 is not set |
|
||||||
# CONFIG_SGI_IP27 is not set |
|
||||||
# CONFIG_SGI_IP28 is not set |
|
||||||
# CONFIG_SGI_IP32 is not set |
|
||||||
# CONFIG_SIBYTE_BIGSUR is not set |
|
||||||
# CONFIG_SIBYTE_CARMEL is not set |
|
||||||
# CONFIG_SIBYTE_CRHINE is not set |
|
||||||
# CONFIG_SIBYTE_CRHONE is not set |
|
||||||
# CONFIG_SIBYTE_LITTLESUR is not set |
|
||||||
# CONFIG_SIBYTE_RHONE is not set |
|
||||||
# CONFIG_SIBYTE_SENTOSA is not set |
|
||||||
# CONFIG_SIBYTE_SWARM is not set |
|
||||||
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_TRAD_SIGNALS=y |
|
||||||
# CONFIG_TREE_PREEMPT_RCU is not set |
|
||||||
CONFIG_TREE_RCU=y |
|
||||||
CONFIG_ZONE_DMA_FLAG=0 |
|
@ -1,29 +0,0 @@ |
|||||||
CONFIG_ADM6996_PHY=y |
|
||||||
CONFIG_AR8216_PHY=y |
|
||||||
CONFIG_DEVPORT=y |
|
||||||
# CONFIG_DM9000 is not set |
|
||||||
CONFIG_HW_HAS_PCI=y |
|
||||||
# CONFIG_I2C_DESIGNWARE is not set |
|
||||||
CONFIG_INPUT=y |
|
||||||
CONFIG_INPUT_EVDEV=y |
|
||||||
# CONFIG_INPUT_GPIO_BUTTONS is not set |
|
||||||
CONFIG_INPUT_POLLDEV=y |
|
||||||
# CONFIG_INPUT_YEALINK is not set |
|
||||||
# CONFIG_ISDN is not set |
|
||||||
CONFIG_LANTIQ_ETOP=y |
|
||||||
CONFIG_LANTIQ_MACH_ARV45XX=y |
|
||||||
CONFIG_LANTIQ_MACH_EASY50712=y |
|
||||||
CONFIG_PCI=y |
|
||||||
CONFIG_PCI_DOMAINS=y |
|
||||||
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_MASTER=y |
|
||||||
# CONFIG_SPI_SPIDEV is not set |
|
||||||
# CONFIG_TC35815 is not set |
|
||||||
CONFIG_USB_SUPPORT=y |
|
@ -1,26 +0,0 @@ |
|||||||
CONFIG_CPU_MIPSR2_IRQ_EI=y |
|
||||||
CONFIG_CPU_MIPSR2_IRQ_VI=y |
|
||||||
CONFIG_IFX_VPE_CACHE_SPLIT=y |
|
||||||
CONFIG_IFX_VPE_EXT=y |
|
||||||
CONFIG_LANTIQ_MACH_95C3AM1=y |
|
||||||
CONFIG_LANTIQ_MACH_EASY98000=y |
|
||||||
CONFIG_LANTIQ_MACH_EASY98020=y |
|
||||||
CONFIG_M25PXX_USE_FAST_READ=y |
|
||||||
CONFIG_MIPS_MT=y |
|
||||||
# CONFIG_I2C_DESIGNWARE is not set |
|
||||||
# CONFIG_MIPS_VPE_APSP_API is not set |
|
||||||
CONFIG_MIPS_VPE_LOADER=y |
|
||||||
CONFIG_MIPS_VPE_LOADER_TOM=y |
|
||||||
CONFIG_MTD_M25P80=y |
|
||||||
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 |
|
||||||
# CONFIG_SPI_SPIDEV is not set |
|
@ -1 +0,0 @@ |
|||||||
../falcon/profiles |
|
@ -1,11 +0,0 @@ |
|||||||
|
|
||||||
include $(PLATFORM_SUBDIR)/../falcon/target.mk |
|
||||||
|
|
||||||
LINUX_VERSION:=2.6.32.33
|
|
||||||
|
|
||||||
SUBTARGET:=falcon-stable
|
|
||||||
BOARDNAME:=Falcon-Stable
|
|
||||||
|
|
||||||
define Target/Description |
|
||||||
Lantiq Falcon (Stable Kernel)
|
|
||||||
endef |
|
@ -1,898 +0,0 @@ |
|||||||
From 9e0235e97ea2617beaacaa16ab5f0b9e75f4680e Mon Sep 17 00:00:00 2001
|
|
||||||
From: John Crispin <blogic@openwrt.org>
|
|
||||||
Date: Wed, 30 Mar 2011 09:27:47 +0200
|
|
||||||
Subject: [PATCH 01/13] MIPS: Lantiq: Add initial support for Lantiq SoCs
|
|
||||||
|
|
||||||
Add initial support for Mips based SoCs made by Lantiq. This series will add
|
|
||||||
support for the XWAY family.
|
|
||||||
|
|
||||||
The series allows booting a minimal system using a initramfs or NOR. Missing
|
|
||||||
drivers and support for Amazon and GPON family will be provided in a later
|
|
||||||
series.
|
|
||||||
|
|
||||||
[Ralf: Remove some cargo cult programming and fixed formatting.]
|
|
||||||
|
|
||||||
Signed-off-by: John Crispin <blogic@openwrt.org>
|
|
||||||
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
|
|
||||||
Signed-off-by: David Daney <ddaney@caviumnetworks.com>
|
|
||||||
Cc: linux-mips@linux-mips.org
|
|
||||||
Patchwork: https://patchwork.linux-mips.org/patch/2252/
|
|
||||||
Patchwork: https://patchwork.linux-mips.org/patch/2371/
|
|
||||||
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
|
|
||||||
---
|
|
||||||
arch/mips/Kbuild.platforms | 1 +
|
|
||||||
arch/mips/Kconfig | 17 ++
|
|
||||||
arch/mips/include/asm/mach-lantiq/lantiq.h | 63 ++++++
|
|
||||||
arch/mips/include/asm/mach-lantiq/war.h | 24 ++
|
|
||||||
arch/mips/lantiq/Makefile | 9 +
|
|
||||||
arch/mips/lantiq/Platform | 7 +
|
|
||||||
arch/mips/lantiq/clk.c | 140 ++++++++++++
|
|
||||||
arch/mips/lantiq/clk.h | 18 ++
|
|
||||||
arch/mips/lantiq/early_printk.c | 33 +++
|
|
||||||
arch/mips/lantiq/irq.c | 326 ++++++++++++++++++++++++++++
|
|
||||||
arch/mips/lantiq/prom.c | 71 ++++++
|
|
||||||
arch/mips/lantiq/prom.h | 24 ++
|
|
||||||
arch/mips/lantiq/setup.c | 41 ++++
|
|
||||||
13 files changed, 774 insertions(+), 0 deletions(-)
|
|
||||||
create mode 100644 arch/mips/include/asm/mach-lantiq/lantiq.h
|
|
||||||
create mode 100644 arch/mips/include/asm/mach-lantiq/war.h
|
|
||||||
create mode 100644 arch/mips/lantiq/Makefile
|
|
||||||
create mode 100644 arch/mips/lantiq/Platform
|
|
||||||
create mode 100644 arch/mips/lantiq/clk.c
|
|
||||||
create mode 100644 arch/mips/lantiq/clk.h
|
|
||||||
create mode 100644 arch/mips/lantiq/early_printk.c
|
|
||||||
create mode 100644 arch/mips/lantiq/irq.c
|
|
||||||
create mode 100644 arch/mips/lantiq/prom.c
|
|
||||||
create mode 100644 arch/mips/lantiq/prom.h
|
|
||||||
create mode 100644 arch/mips/lantiq/setup.c
|
|
||||||
|
|
||||||
--- a/arch/mips/Kconfig
|
|
||||||
+++ b/arch/mips/Kconfig
|
|
||||||
@@ -174,6 +174,23 @@
|
|
||||||
Members include the Acer PICA, MIPS Magnum 4000, MIPS Millennium and
|
|
||||||
Olivetti M700-10 workstations.
|
|
||||||
|
|
||||||
+config LANTIQ
|
|
||||||
+ bool "Lantiq based platforms"
|
|
||||||
+ select DMA_NONCOHERENT
|
|
||||||
+ select IRQ_CPU
|
|
||||||
+ select CEVT_R4K
|
|
||||||
+ select CSRC_R4K
|
|
||||||
+ select SYS_HAS_CPU_MIPS32_R1
|
|
||||||
+ select SYS_HAS_CPU_MIPS32_R2
|
|
||||||
+ select SYS_SUPPORTS_BIG_ENDIAN
|
|
||||||
+ select SYS_SUPPORTS_32BIT_KERNEL
|
|
||||||
+ select SYS_SUPPORTS_MULTITHREADING
|
|
||||||
+ select SYS_HAS_EARLY_PRINTK
|
|
||||||
+ select ARCH_REQUIRE_GPIOLIB
|
|
||||||
+ select SWAP_IO_SPACE
|
|
||||||
+ select BOOT_RAW
|
|
||||||
+ select HAVE_CLK
|
|
||||||
+
|
|
||||||
config LASAT
|
|
||||||
bool "LASAT Networks platforms"
|
|
||||||
select CEVT_R4K
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/arch/mips/include/asm/mach-lantiq/lantiq.h
|
|
||||||
@@ -0,0 +1,63 @@
|
|
||||||
+/*
|
|
||||||
+ * 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 _LANTIQ_H__
|
|
||||||
+#define _LANTIQ_H__
|
|
||||||
+
|
|
||||||
+#include <linux/irq.h>
|
|
||||||
+
|
|
||||||
+/* generic reg access functions */
|
|
||||||
+#define ltq_r32(reg) __raw_readl(reg)
|
|
||||||
+#define ltq_w32(val, reg) __raw_writel(val, reg)
|
|
||||||
+#define ltq_w32_mask(clear, set, reg) \
|
|
||||||
+ ltq_w32((ltq_r32(reg) & ~(clear)) | (set), reg)
|
|
||||||
+#define ltq_r8(reg) __raw_readb(reg)
|
|
||||||
+#define ltq_w8(val, reg) __raw_writeb(val, reg)
|
|
||||||
+
|
|
||||||
+/* register access macros for EBU and CGU */
|
|
||||||
+#define ltq_ebu_w32(x, y) ltq_w32((x), ltq_ebu_membase + (y))
|
|
||||||
+#define ltq_ebu_r32(x) ltq_r32(ltq_ebu_membase + (x))
|
|
||||||
+#define ltq_cgu_w32(x, y) ltq_w32((x), ltq_cgu_membase + (y))
|
|
||||||
+#define ltq_cgu_r32(x) ltq_r32(ltq_cgu_membase + (x))
|
|
||||||
+
|
|
||||||
+extern __iomem void *ltq_ebu_membase;
|
|
||||||
+extern __iomem void *ltq_cgu_membase;
|
|
||||||
+
|
|
||||||
+extern unsigned int ltq_get_cpu_ver(void);
|
|
||||||
+extern unsigned int ltq_get_soc_type(void);
|
|
||||||
+
|
|
||||||
+/* clock speeds */
|
|
||||||
+#define CLOCK_60M 60000000
|
|
||||||
+#define CLOCK_83M 83333333
|
|
||||||
+#define CLOCK_111M 111111111
|
|
||||||
+#define CLOCK_133M 133333333
|
|
||||||
+#define CLOCK_167M 166666667
|
|
||||||
+#define CLOCK_200M 200000000
|
|
||||||
+#define CLOCK_266M 266666666
|
|
||||||
+#define CLOCK_333M 333333333
|
|
||||||
+#define CLOCK_400M 400000000
|
|
||||||
+
|
|
||||||
+/* spinlock all ebu i/o */
|
|
||||||
+extern spinlock_t ebu_lock;
|
|
||||||
+
|
|
||||||
+/* some irq helpers */
|
|
||||||
+extern void ltq_disable_irq(unsigned int irq);
|
|
||||||
+extern void ltq_mask_and_ack_irq(unsigned int irq);
|
|
||||||
+extern void ltq_enable_irq(unsigned int irq);
|
|
||||||
+
|
|
||||||
+/* find out what caused the last cpu reset */
|
|
||||||
+extern int ltq_reset_cause(void);
|
|
||||||
+#define LTQ_RST_CAUSE_WDTRST 0x20
|
|
||||||
+
|
|
||||||
+#define IOPORT_RESOURCE_START 0x10000000
|
|
||||||
+#define IOPORT_RESOURCE_END 0xffffffff
|
|
||||||
+#define IOMEM_RESOURCE_START 0x10000000
|
|
||||||
+#define IOMEM_RESOURCE_END 0xffffffff
|
|
||||||
+#define LTQ_FLASH_START 0x10000000
|
|
||||||
+#define LTQ_FLASH_MAX 0x04000000
|
|
||||||
+
|
|
||||||
+#endif
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/arch/mips/include/asm/mach-lantiq/war.h
|
|
||||||
@@ -0,0 +1,24 @@
|
|
||||||
+/*
|
|
||||||
+ * This file is subject to the terms and conditions of the GNU General Public
|
|
||||||
+ * License. See the file "COPYING" in the main directory of this archive
|
|
||||||
+ * for more details.
|
|
||||||
+ *
|
|
||||||
+ */
|
|
||||||
+#ifndef __ASM_MIPS_MACH_LANTIQ_WAR_H
|
|
||||||
+#define __ASM_MIPS_MACH_LANTIQ_WAR_H
|
|
||||||
+
|
|
||||||
+#define R4600_V1_INDEX_ICACHEOP_WAR 0
|
|
||||||
+#define R4600_V1_HIT_CACHEOP_WAR 0
|
|
||||||
+#define R4600_V2_HIT_CACHEOP_WAR 0
|
|
||||||
+#define R5432_CP0_INTERRUPT_WAR 0
|
|
||||||
+#define BCM1250_M3_WAR 0
|
|
||||||
+#define SIBYTE_1956_WAR 0
|
|
||||||
+#define MIPS4K_ICACHE_REFILL_WAR 0
|
|
||||||
+#define MIPS_CACHE_SYNC_WAR 0
|
|
||||||
+#define TX49XX_ICACHE_INDEX_INV_WAR 0
|
|
||||||
+#define RM9000_CDEX_SMP_WAR 0
|
|
||||||
+#define ICACHE_REFILLS_WORKAROUND_WAR 0
|
|
||||||
+#define R10000_LLSC_WAR 0
|
|
||||||
+#define MIPS34K_MISSED_ITLB_WAR 0
|
|
||||||
+
|
|
||||||
+#endif
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/arch/mips/lantiq/Makefile
|
|
||||||
@@ -0,0 +1,9 @@
|
|
||||||
+# Copyright (C) 2010 John Crispin <blogic@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.
|
|
||||||
+
|
|
||||||
+obj-y := irq.o setup.o clk.o prom.o
|
|
||||||
+
|
|
||||||
+obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/arch/mips/lantiq/Platform
|
|
||||||
@@ -0,0 +1,7 @@
|
|
||||||
+#
|
|
||||||
+# Lantiq
|
|
||||||
+#
|
|
||||||
+
|
|
||||||
+platform-$(CONFIG_LANTIQ) += lantiq/
|
|
||||||
+cflags-$(CONFIG_LANTIQ) += -I$(srctree)/arch/mips/include/asm/mach-lantiq
|
|
||||||
+load-$(CONFIG_LANTIQ) = 0xffffffff80002000
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/arch/mips/lantiq/clk.c
|
|
||||||
@@ -0,0 +1,144 @@
|
|
||||||
+/*
|
|
||||||
+ * 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 Thomas Langer <thomas.langer@lantiq.com>
|
|
||||||
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
|
|
||||||
+ */
|
|
||||||
+#include <linux/io.h>
|
|
||||||
+#include <linux/module.h>
|
|
||||||
+#include <linux/init.h>
|
|
||||||
+#include <linux/kernel.h>
|
|
||||||
+#include <linux/types.h>
|
|
||||||
+#include <linux/clk.h>
|
|
||||||
+#include <linux/err.h>
|
|
||||||
+#include <linux/list.h>
|
|
||||||
+
|
|
||||||
+#include <asm/time.h>
|
|
||||||
+#include <asm/irq.h>
|
|
||||||
+#include <asm/div64.h>
|
|
||||||
+
|
|
||||||
+#include <lantiq_soc.h>
|
|
||||||
+
|
|
||||||
+#include "clk.h"
|
|
||||||
+
|
|
||||||
+struct clk {
|
|
||||||
+ const char *name;
|
|
||||||
+ unsigned long rate;
|
|
||||||
+ unsigned long (*get_rate) (void);
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static struct clk *cpu_clk;
|
|
||||||
+static int cpu_clk_cnt;
|
|
||||||
+
|
|
||||||
+/* lantiq socs have 3 static clocks */
|
|
||||||
+static struct clk cpu_clk_generic[] = {
|
|
||||||
+ {
|
|
||||||
+ .name = "cpu",
|
|
||||||
+ .get_rate = ltq_get_cpu_hz,
|
|
||||||
+ }, {
|
|
||||||
+ .name = "fpi",
|
|
||||||
+ .get_rate = ltq_get_fpi_hz,
|
|
||||||
+ }, {
|
|
||||||
+ .name = "io",
|
|
||||||
+ .get_rate = ltq_get_io_region_clock,
|
|
||||||
+ },
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+#ifdef CONFIG_SOC_TYPE_XWAY
|
|
||||||
+static struct resource ltq_cgu_resource = {
|
|
||||||
+ .name = "cgu",
|
|
||||||
+ .start = LTQ_CGU_BASE_ADDR,
|
|
||||||
+ .end = LTQ_CGU_BASE_ADDR + LTQ_CGU_SIZE - 1,
|
|
||||||
+ .flags = IORESOURCE_MEM,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+/* remapped clock register range */
|
|
||||||
+void __iomem *ltq_cgu_membase;
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
+void clk_init(void)
|
|
||||||
+{
|
|
||||||
+ cpu_clk = cpu_clk_generic;
|
|
||||||
+ cpu_clk_cnt = ARRAY_SIZE(cpu_clk_generic);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static inline int clk_good(struct clk *clk)
|
|
||||||
+{
|
|
||||||
+ return clk && !IS_ERR(clk);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+unsigned long clk_get_rate(struct clk *clk)
|
|
||||||
+{
|
|
||||||
+ if (unlikely(!clk_good(clk)))
|
|
||||||
+ return 0;
|
|
||||||
+
|
|
||||||
+ if (clk->rate != 0)
|
|
||||||
+ return clk->rate;
|
|
||||||
+
|
|
||||||
+ if (clk->get_rate != NULL)
|
|
||||||
+ return clk->get_rate();
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+EXPORT_SYMBOL(clk_get_rate);
|
|
||||||
+
|
|
||||||
+struct clk *clk_get(struct device *dev, const char *id)
|
|
||||||
+{
|
|
||||||
+ int i;
|
|
||||||
+
|
|
||||||
+ for (i = 0; i < cpu_clk_cnt; i++)
|
|
||||||
+ if (!strcmp(id, cpu_clk[i].name))
|
|
||||||
+ return &cpu_clk[i];
|
|
||||||
+ BUG();
|
|
||||||
+ return ERR_PTR(-ENOENT);
|
|
||||||
+}
|
|
||||||
+EXPORT_SYMBOL(clk_get);
|
|
||||||
+
|
|
||||||
+void clk_put(struct clk *clk)
|
|
||||||
+{
|
|
||||||
+ /* not used */
|
|
||||||
+}
|
|
||||||
+EXPORT_SYMBOL(clk_put);
|
|
||||||
+
|
|
||||||
+static inline u32 ltq_get_counter_resolution(void)
|
|
||||||
+{
|
|
||||||
+ u32 res;
|
|
||||||
+
|
|
||||||
+ __asm__ __volatile__(
|
|
||||||
+ ".set push\n"
|
|
||||||
+ ".set mips32r2\n"
|
|
||||||
+ "rdhwr %0, $3\n"
|
|
||||||
+ ".set pop\n"
|
|
||||||
+ : "=&r" (res)
|
|
||||||
+ : /* no input */
|
|
||||||
+ : "memory");
|
|
||||||
+
|
|
||||||
+ return res;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void __init plat_time_init(void)
|
|
||||||
+{
|
|
||||||
+ struct clk *clk;
|
|
||||||
+
|
|
||||||
+#ifdef CONFIG_SOC_TYPE_XWAY
|
|
||||||
+ if (insert_resource(&iomem_resource, <q_cgu_resource) < 0)
|
|
||||||
+ panic("Failed to insert cgu memory\n");
|
|
||||||
+
|
|
||||||
+ if (request_mem_region(ltq_cgu_resource.start,
|
|
||||||
+ resource_size(<q_cgu_resource), "cgu") < 0)
|
|
||||||
+ panic("Failed to request cgu memory\n");
|
|
||||||
+
|
|
||||||
+ ltq_cgu_membase = ioremap_nocache(ltq_cgu_resource.start,
|
|
||||||
+ resource_size(<q_cgu_resource));
|
|
||||||
+ if (!ltq_cgu_membase) {
|
|
||||||
+ 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());
|
|
||||||
+ clk_put(clk);
|
|
||||||
+}
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/arch/mips/lantiq/clk.h
|
|
||||||
@@ -0,0 +1,18 @@
|
|
||||||
+/*
|
|
||||||
+ * 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_CLK_H__
|
|
||||||
+#define _LTQ_CLK_H__
|
|
||||||
+
|
|
||||||
+extern void clk_init(void);
|
|
||||||
+
|
|
||||||
+extern unsigned long ltq_get_cpu_hz(void);
|
|
||||||
+extern unsigned long ltq_get_fpi_hz(void);
|
|
||||||
+extern unsigned long ltq_get_io_region_clock(void);
|
|
||||||
+
|
|
||||||
+#endif
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/arch/mips/lantiq/early_printk.c
|
|
||||||
@@ -0,0 +1,37 @@
|
|
||||||
+/*
|
|
||||||
+ * 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/cpu.h>
|
|
||||||
+
|
|
||||||
+#include <lantiq.h>
|
|
||||||
+#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))
|
|
||||||
+#define TXMASK 0x3F00
|
|
||||||
+#define TXOFFSET 8
|
|
||||||
+
|
|
||||||
+void prom_putchar(char c)
|
|
||||||
+{
|
|
||||||
+ unsigned long flags;
|
|
||||||
+
|
|
||||||
+ local_irq_save(flags);
|
|
||||||
+ do { } while ((ltq_r32(LTQ_ASC_FSTAT) & TXMASK) >> TXOFFSET);
|
|
||||||
+ if (c == '\n')
|
|
||||||
+ ltq_w32('\r', LTQ_ASC_TBUF);
|
|
||||||
+ ltq_w32(c, LTQ_ASC_TBUF);
|
|
||||||
+ local_irq_restore(flags);
|
|
||||||
+}
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/arch/mips/lantiq/irq.c
|
|
||||||
@@ -0,0 +1,353 @@
|
|
||||||
+/*
|
|
||||||
+ * 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>
|
|
||||||
+ * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com>
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#include <linux/interrupt.h>
|
|
||||||
+#include <linux/ioport.h>
|
|
||||||
+#include <linux/module.h>
|
|
||||||
+
|
|
||||||
+#include <asm/bootinfo.h>
|
|
||||||
+#include <asm/irq_cpu.h>
|
|
||||||
+
|
|
||||||
+#include <lantiq_soc.h>
|
|
||||||
+#include <irq.h>
|
|
||||||
+
|
|
||||||
+/* register definitions */
|
|
||||||
+#define LTQ_ICU_IM0_ISR 0x0000
|
|
||||||
+#define LTQ_ICU_IM0_IER 0x0008
|
|
||||||
+#define LTQ_ICU_IM0_IOSR 0x0010
|
|
||||||
+#define LTQ_ICU_IM0_IRSR 0x0018
|
|
||||||
+#define LTQ_ICU_IM0_IMR 0x0020
|
|
||||||
+#define LTQ_ICU_IM1_ISR 0x0028
|
|
||||||
+#define LTQ_ICU_OFFSET (LTQ_ICU_IM1_ISR - LTQ_ICU_IM0_ISR)
|
|
||||||
+
|
|
||||||
+#ifdef CONFIG_SOC_TYPE_XWAY
|
|
||||||
+
|
|
||||||
+#define LTQ_EIU_EXIN_C 0x0000
|
|
||||||
+#define LTQ_EIU_EXIN_INIC 0x0004
|
|
||||||
+#define LTQ_EIU_EXIN_INEN 0x000C
|
|
||||||
+
|
|
||||||
+/* irq numbers used by the external interrupt unit (EIU) */
|
|
||||||
+#define LTQ_EIU_IR0 (INT_NUM_IM4_IRL0 + 30)
|
|
||||||
+#define LTQ_EIU_IR1 (INT_NUM_IM3_IRL0 + 31)
|
|
||||||
+#define LTQ_EIU_IR2 (INT_NUM_IM1_IRL0 + 26)
|
|
||||||
+#define LTQ_EIU_IR3 INT_NUM_IM1_IRL0
|
|
||||||
+#define LTQ_EIU_IR4 (INT_NUM_IM1_IRL0 + 1)
|
|
||||||
+#define LTQ_EIU_IR5 (INT_NUM_IM1_IRL0 + 2)
|
|
||||||
+#define LTQ_EIU_IR6 (INT_NUM_IM2_IRL0 + 30)
|
|
||||||
+
|
|
||||||
+#define MAX_EIU 6
|
|
||||||
+
|
|
||||||
+/* irqs generated by device attached to the EBU need to be acked in
|
|
||||||
+ * a special manner
|
|
||||||
+ */
|
|
||||||
+#define LTQ_ICU_EBU_IRQ 22
|
|
||||||
+
|
|
||||||
+#define ltq_eiu_w32(x, y) ltq_w32((x), ltq_eiu_membase + (y))
|
|
||||||
+#define ltq_eiu_r32(x) ltq_r32(ltq_eiu_membase + (x))
|
|
||||||
+
|
|
||||||
+static unsigned short ltq_eiu_irq[MAX_EIU] = {
|
|
||||||
+ LTQ_EIU_IR0,
|
|
||||||
+ LTQ_EIU_IR1,
|
|
||||||
+ LTQ_EIU_IR2,
|
|
||||||
+ LTQ_EIU_IR3,
|
|
||||||
+ LTQ_EIU_IR4,
|
|
||||||
+ LTQ_EIU_IR5,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static void __iomem *ltq_eiu_membase;
|
|
||||||
+
|
|
||||||
+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 struct resource ltq_icu_resource = {
|
|
||||||
+ .name = "icu",
|
|
||||||
+ .start = LTQ_ICU_BASE_ADDR,
|
|
||||||
+ .end = LTQ_ICU_BASE_ADDR + LTQ_ICU_SIZE - 1,
|
|
||||||
+ .flags = IORESOURCE_MEM,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+#define ltq_icu_w32(x, y) ltq_w32((x), ltq_icu_membase + (y))
|
|
||||||
+#define ltq_icu_r32(x) ltq_r32(ltq_icu_membase + (x))
|
|
||||||
+
|
|
||||||
+static void __iomem *ltq_icu_membase;
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+ltq_disable_irq(unsigned int irq_nr)
|
|
||||||
+{
|
|
||||||
+ u32 ier = LTQ_ICU_IM0_IER;
|
|
||||||
+
|
|
||||||
+ irq_nr -= INT_NUM_IRQ0;
|
|
||||||
+ ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
|
|
||||||
+ irq_nr %= INT_NUM_IM_OFFSET;
|
|
||||||
+ ltq_icu_w32(ltq_icu_r32(ier) & ~(1 << irq_nr), ier);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+ltq_mask_and_ack_irq(unsigned int irq_nr)
|
|
||||||
+{
|
|
||||||
+ u32 ier = LTQ_ICU_IM0_IER;
|
|
||||||
+ u32 isr = LTQ_ICU_IM0_ISR;
|
|
||||||
+
|
|
||||||
+ irq_nr -= INT_NUM_IRQ0;
|
|
||||||
+ ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
|
|
||||||
+ isr += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
|
|
||||||
+ irq_nr %= INT_NUM_IM_OFFSET;
|
|
||||||
+ 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(unsigned int irq_nr)
|
|
||||||
+{
|
|
||||||
+ u32 isr = LTQ_ICU_IM0_ISR;
|
|
||||||
+
|
|
||||||
+ irq_nr -= INT_NUM_IRQ0;
|
|
||||||
+ isr += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
|
|
||||||
+ irq_nr %= INT_NUM_IM_OFFSET;
|
|
||||||
+ ltq_icu_w32((1 << irq_nr), isr);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+ltq_enable_irq(unsigned int irq_nr)
|
|
||||||
+{
|
|
||||||
+ u32 ier = LTQ_ICU_IM0_IER;
|
|
||||||
+
|
|
||||||
+ irq_nr -= INT_NUM_IRQ0;
|
|
||||||
+ ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
|
|
||||||
+ irq_nr %= INT_NUM_IM_OFFSET;
|
|
||||||
+ ltq_icu_w32(ltq_icu_r32(ier) | (1 << irq_nr), ier);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+#ifdef CONFIG_SOC_TYPE_XWAY
|
|
||||||
+static unsigned int
|
|
||||||
+ltq_startup_eiu_irq(unsigned int irq)
|
|
||||||
+{
|
|
||||||
+ int i;
|
|
||||||
+
|
|
||||||
+ ltq_enable_irq(irq);
|
|
||||||
+ for (i = 0; i < MAX_EIU; i++) {
|
|
||||||
+ if (irq == ltq_eiu_irq[i]) {
|
|
||||||
+ /* low level - we should really handle set_type */
|
|
||||||
+ ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_C) | (0x6 << (i * 4)),
|
|
||||||
+ LTQ_EIU_EXIN_C);
|
|
||||||
+ /* clear all pending */
|
|
||||||
+ ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INIC) & ~(1 << i),
|
|
||||||
+ LTQ_EIU_EXIN_INIC);
|
|
||||||
+ /* enable */
|
|
||||||
+ ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) | (1 << i),
|
|
||||||
+ LTQ_EIU_EXIN_INEN);
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+ltq_shutdown_eiu_irq(unsigned int irq)
|
|
||||||
+{
|
|
||||||
+ int i;
|
|
||||||
+
|
|
||||||
+ ltq_disable_irq(irq);
|
|
||||||
+ for (i = 0; i < MAX_EIU; i++) {
|
|
||||||
+ if (irq == ltq_eiu_irq[i]) {
|
|
||||||
+ /* disable */
|
|
||||||
+ ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) & ~(1 << i),
|
|
||||||
+ LTQ_EIU_EXIN_INEN);
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+ltq_end_irq(unsigned int irq)
|
|
||||||
+{
|
|
||||||
+ if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
|
|
||||||
+ ltq_enable_irq(irq);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static struct irq_chip
|
|
||||||
+ltq_irq_type = {
|
|
||||||
+ "ltq_irq",
|
|
||||||
+ .enable = ltq_enable_irq,
|
|
||||||
+ .disable = ltq_disable_irq,
|
|
||||||
+ .unmask = ltq_enable_irq,
|
|
||||||
+ .ack = ltq_ack_irq,
|
|
||||||
+ .mask = ltq_disable_irq,
|
|
||||||
+ .mask_ack = ltq_mask_and_ack_irq,
|
|
||||||
+ .end = ltq_end_irq,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+#ifdef CONFIG_SOC_TYPE_XWAY
|
|
||||||
+static struct irq_chip
|
|
||||||
+ltq_eiu_type = {
|
|
||||||
+ "ltq_eiu_irq",
|
|
||||||
+ .startup = ltq_startup_eiu_irq,
|
|
||||||
+ .shutdown = ltq_shutdown_eiu_irq,
|
|
||||||
+ .enable = ltq_enable_irq,
|
|
||||||
+ .disable = ltq_disable_irq,
|
|
||||||
+ .unmask = ltq_enable_irq,
|
|
||||||
+ .ack = ltq_ack_irq,
|
|
||||||
+ .mask = ltq_disable_irq,
|
|
||||||
+ .mask_ack = ltq_mask_and_ack_irq,
|
|
||||||
+ .end = ltq_end_irq,
|
|
||||||
+};
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
+static void ltq_hw_irqdispatch(int module)
|
|
||||||
+{
|
|
||||||
+ u32 irq;
|
|
||||||
+
|
|
||||||
+ irq = ltq_icu_r32(LTQ_ICU_IM0_IOSR + (module * LTQ_ICU_OFFSET));
|
|
||||||
+ if (irq == 0)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ /* silicon bug causes only the msb set to 1 to be valid. all
|
|
||||||
+ * other bits might be bogus
|
|
||||||
+ */
|
|
||||||
+ irq = __fls(irq);
|
|
||||||
+ do_IRQ((int)irq + INT_NUM_IM0_IRL0 + (INT_NUM_IM_OFFSET * module));
|
|
||||||
+
|
|
||||||
+#ifdef CONFIG_SOC_TYPE_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) \
|
|
||||||
+ static void ltq_hw ## x ## _irqdispatch(void) \
|
|
||||||
+ { \
|
|
||||||
+ ltq_hw_irqdispatch(x); \
|
|
||||||
+ }
|
|
||||||
+DEFINE_HWx_IRQDISPATCH(0)
|
|
||||||
+DEFINE_HWx_IRQDISPATCH(1)
|
|
||||||
+DEFINE_HWx_IRQDISPATCH(2)
|
|
||||||
+DEFINE_HWx_IRQDISPATCH(3)
|
|
||||||
+DEFINE_HWx_IRQDISPATCH(4)
|
|
||||||
+
|
|
||||||
+static void ltq_hw5_irqdispatch(void)
|
|
||||||
+{
|
|
||||||
+ do_IRQ(MIPS_CPU_TIMER_IRQ);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+asmlinkage void plat_irq_dispatch(void)
|
|
||||||
+{
|
|
||||||
+ unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
|
|
||||||
+ unsigned int i;
|
|
||||||
+
|
|
||||||
+ if (pending & CAUSEF_IP7) {
|
|
||||||
+ do_IRQ(MIPS_CPU_TIMER_IRQ);
|
|
||||||
+ goto out;
|
|
||||||
+ } else {
|
|
||||||
+ for (i = 0; i < 5; i++) {
|
|
||||||
+ if (pending & (CAUSEF_IP2 << i)) {
|
|
||||||
+ ltq_hw_irqdispatch(i);
|
|
||||||
+ goto out;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ pr_alert("Spurious IRQ: CAUSE=0x%08x\n", read_c0_status());
|
|
||||||
+
|
|
||||||
+out:
|
|
||||||
+ return;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static struct irqaction cascade = {
|
|
||||||
+ .handler = no_action,
|
|
||||||
+ .flags = IRQF_DISABLED,
|
|
||||||
+ .name = "cascade",
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+void __init arch_init_irq(void)
|
|
||||||
+{
|
|
||||||
+ int i;
|
|
||||||
+
|
|
||||||
+ if (insert_resource(&iomem_resource, <q_icu_resource) < 0)
|
|
||||||
+ panic("Failed to insert icu memory\n");
|
|
||||||
+
|
|
||||||
+ if (request_mem_region(ltq_icu_resource.start,
|
|
||||||
+ resource_size(<q_icu_resource), "icu") < 0)
|
|
||||||
+ panic("Failed to request icu memory\n");
|
|
||||||
+
|
|
||||||
+ ltq_icu_membase = ioremap_nocache(ltq_icu_resource.start,
|
|
||||||
+ resource_size(<q_icu_resource));
|
|
||||||
+ if (!ltq_icu_membase)
|
|
||||||
+ panic("Failed to remap icu memory\n");
|
|
||||||
+
|
|
||||||
+#ifdef CONFIG_SOC_TYPE_XWAY
|
|
||||||
+ if (insert_resource(&iomem_resource, <q_eiu_resource) < 0)
|
|
||||||
+ panic("Failed to insert eiu memory\n");
|
|
||||||
+
|
|
||||||
+ if (request_mem_region(ltq_eiu_resource.start,
|
|
||||||
+ resource_size(<q_eiu_resource), "eiu") < 0)
|
|
||||||
+ panic("Failed to request eiu memory\n");
|
|
||||||
+
|
|
||||||
+ ltq_eiu_membase = ioremap_nocache(ltq_eiu_resource.start,
|
|
||||||
+ resource_size(<q_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++)
|
|
||||||
+ ltq_icu_w32(0, LTQ_ICU_IM0_IER + (i * LTQ_ICU_OFFSET));
|
|
||||||
+
|
|
||||||
+ /* clear all possibly pending interrupts */
|
|
||||||
+ ltq_icu_w32(~0, LTQ_ICU_IM0_ISR + (i * LTQ_ICU_OFFSET));
|
|
||||||
+
|
|
||||||
+ mips_cpu_irq_init();
|
|
||||||
+
|
|
||||||
+ for (i = 2; i <= 6; i++)
|
|
||||||
+ setup_irq(i, &cascade);
|
|
||||||
+
|
|
||||||
+ if (cpu_has_vint) {
|
|
||||||
+ pr_info("Setting up vectored interrupts\n");
|
|
||||||
+ set_vi_handler(2, ltq_hw0_irqdispatch);
|
|
||||||
+ set_vi_handler(3, ltq_hw1_irqdispatch);
|
|
||||||
+ set_vi_handler(4, ltq_hw2_irqdispatch);
|
|
||||||
+ set_vi_handler(5, ltq_hw3_irqdispatch);
|
|
||||||
+ set_vi_handler(6, ltq_hw4_irqdispatch);
|
|
||||||
+ set_vi_handler(7, ltq_hw5_irqdispatch);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ for (i = INT_NUM_IRQ0;
|
|
||||||
+ i <= (INT_NUM_IRQ0 + (5 * INT_NUM_IM_OFFSET)); i++)
|
|
||||||
+#ifdef CONFIG_SOC_TYPE_XWAY
|
|
||||||
+ if ((i == LTQ_EIU_IR0) || (i == LTQ_EIU_IR1) || (i == LTQ_EIU_IR2))
|
|
||||||
+ set_irq_chip_and_handler(i, <q_eiu_type, handle_level_irq);
|
|
||||||
+ /* EIU3-5 only exist on ar9 and vr9 */
|
|
||||||
+ else if (((i == LTQ_EIU_IR3) || (i == LTQ_EIU_IR4) ||
|
|
||||||
+ (i == LTQ_EIU_IR5)) && (ltq_is_ar9() || ltq_is_vr9()))
|
|
||||||
+ set_irq_chip_and_handler(i, <q_eiu_type, handle_level_irq);
|
|
||||||
+ else
|
|
||||||
+#endif
|
|
||||||
+ set_irq_chip_and_handler(i, <q_irq_type, handle_level_irq);
|
|
||||||
+
|
|
||||||
+#if !defined(CONFIG_MIPS_MT_SMP) && !defined(CONFIG_MIPS_MT_SMTC)
|
|
||||||
+ set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 |
|
|
||||||
+ IE_IRQ3 | IE_IRQ4 | IE_IRQ5);
|
|
||||||
+#else
|
|
||||||
+ set_c0_status(IE_SW0 | IE_SW1 | IE_IRQ0 | IE_IRQ1 |
|
|
||||||
+ IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5);
|
|
||||||
+#endif
|
|
||||||
+ cp0_compare_irq = CP0_LEGACY_COMPARE_IRQ;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+unsigned int __cpuinit get_c0_compare_int(void)
|
|
||||||
+{
|
|
||||||
+ return CP0_LEGACY_COMPARE_IRQ;
|
|
||||||
+}
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/arch/mips/lantiq/prom.c
|
|
||||||
@@ -0,0 +1,71 @@
|
|
||||||
+/*
|
|
||||||
+ * 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/module.h>
|
|
||||||
+#include <linux/clk.h>
|
|
||||||
+#include <asm/bootinfo.h>
|
|
||||||
+#include <asm/time.h>
|
|
||||||
+
|
|
||||||
+#include <lantiq.h>
|
|
||||||
+
|
|
||||||
+#include "prom.h"
|
|
||||||
+#include "clk.h"
|
|
||||||
+
|
|
||||||
+static struct ltq_soc_info soc_info;
|
|
||||||
+
|
|
||||||
+unsigned int ltq_get_cpu_ver(void)
|
|
||||||
+{
|
|
||||||
+ return soc_info.rev;
|
|
||||||
+}
|
|
||||||
+EXPORT_SYMBOL(ltq_get_cpu_ver);
|
|
||||||
+
|
|
||||||
+unsigned int ltq_get_soc_type(void)
|
|
||||||
+{
|
|
||||||
+ return soc_info.type;
|
|
||||||
+}
|
|
||||||
+EXPORT_SYMBOL(ltq_get_soc_type);
|
|
||||||
+
|
|
||||||
+const char *get_system_type(void)
|
|
||||||
+{
|
|
||||||
+ return soc_info.sys_type;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void prom_free_prom_memory(void)
|
|
||||||
+{
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void __init prom_init_cmdline(void)
|
|
||||||
+{
|
|
||||||
+ int argc = fw_arg0;
|
|
||||||
+ char **argv = (char **) KSEG1ADDR(fw_arg1);
|
|
||||||
+ int i;
|
|
||||||
+
|
|
||||||
+ for (i = 0; i < argc; i++) {
|
|
||||||
+ char *p = (char *) KSEG1ADDR(argv[i]);
|
|
||||||
+
|
|
||||||
+ if (p && *p) {
|
|
||||||
+ strlcat(arcs_cmdline, p, sizeof(arcs_cmdline));
|
|
||||||
+ strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline));
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void __init prom_init(void)
|
|
||||||
+{
|
|
||||||
+ struct clk *clk;
|
|
||||||
+
|
|
||||||
+ ltq_soc_detect(&soc_info);
|
|
||||||
+ clk_init();
|
|
||||||
+ clk = clk_get(0, "cpu");
|
|
||||||
+ snprintf(soc_info.sys_type, LTQ_SYS_TYPE_LEN - 1, "%s rev1.%d",
|
|
||||||
+ soc_info.name, soc_info.rev);
|
|
||||||
+ clk_put(clk);
|
|
||||||
+ soc_info.sys_type[LTQ_SYS_TYPE_LEN - 1] = '\0';
|
|
||||||
+ pr_info("SoC: %s\n", soc_info.sys_type);
|
|
||||||
+ prom_init_cmdline();
|
|
||||||
+}
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/arch/mips/lantiq/prom.h
|
|
||||||
@@ -0,0 +1,24 @@
|
|
||||||
+/*
|
|
||||||
+ * 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_PROM_H__
|
|
||||||
+#define _LTQ_PROM_H__
|
|
||||||
+
|
|
||||||
+#define LTQ_SYS_TYPE_LEN 0x100
|
|
||||||
+
|
|
||||||
+struct ltq_soc_info {
|
|
||||||
+ unsigned char *name;
|
|
||||||
+ unsigned int rev;
|
|
||||||
+ unsigned int partnum;
|
|
||||||
+ unsigned int type;
|
|
||||||
+ unsigned char sys_type[LTQ_SYS_TYPE_LEN];
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+extern void ltq_soc_detect(struct ltq_soc_info *i);
|
|
||||||
+
|
|
||||||
+#endif
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/arch/mips/lantiq/setup.c
|
|
||||||
@@ -0,0 +1,41 @@
|
|
||||||
+/*
|
|
||||||
+ * 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/kernel.h>
|
|
||||||
+#include <linux/module.h>
|
|
||||||
+#include <linux/io.h>
|
|
||||||
+#include <linux/ioport.h>
|
|
||||||
+#include <asm/bootinfo.h>
|
|
||||||
+
|
|
||||||
+#include <lantiq_soc.h>
|
|
||||||
+
|
|
||||||
+void __init plat_mem_setup(void)
|
|
||||||
+{
|
|
||||||
+ /* assume 16M as default incase uboot fails to pass proper ramsize */
|
|
||||||
+ unsigned long memsize = 16;
|
|
||||||
+ char **envp = (char **) KSEG1ADDR(fw_arg2);
|
|
||||||
+
|
|
||||||
+ ioport_resource.start = IOPORT_RESOURCE_START;
|
|
||||||
+ ioport_resource.end = IOPORT_RESOURCE_END;
|
|
||||||
+ iomem_resource.start = IOMEM_RESOURCE_START;
|
|
||||||
+ iomem_resource.end = IOMEM_RESOURCE_END;
|
|
||||||
+
|
|
||||||
+ set_io_port_base((unsigned long) KSEG1);
|
|
||||||
+
|
|
||||||
+ while (*envp) {
|
|
||||||
+ char *e = (char *)KSEG1ADDR(*envp);
|
|
||||||
+ if (!strncmp(e, "memsize=", 8)) {
|
|
||||||
+ e += 8;
|
|
||||||
+ if (strict_strtoul(e, 0, &memsize))
|
|
||||||
+ pr_warn("bad memsize specified\n");
|
|
||||||
+ }
|
|
||||||
+ envp++;
|
|
||||||
+ }
|
|
||||||
+ memsize *= 1024 * 1024;
|
|
||||||
+ add_memory_region(0x00000000, memsize, BOOT_MEM_RAM);
|
|
||||||
+}
|
|
File diff suppressed because it is too large
Load Diff
@ -1,546 +0,0 @@ |
|||||||
From 08127ed36bad367903591bbf0f244179683ccb28 Mon Sep 17 00:00:00 2001
|
|
||||||
From: John Crispin <blogic@openwrt.org>
|
|
||||||
Date: Wed, 30 Mar 2011 09:27:49 +0200
|
|
||||||
Subject: [PATCH 03/13] MIPS: Lantiq: Add PCI controller support.
|
|
||||||
|
|
||||||
The Lantiq family of SoCs have a EBU (External Bus Unit). This patch adds
|
|
||||||
the driver that allows us to use the EBU as a PCI controller. In order for
|
|
||||||
PCI to work the EBU is set to endianess swap all the data. In addition we
|
|
||||||
need to make use of SWAP_IO_SPACE for device->host DMA to work.
|
|
||||||
|
|
||||||
The clock of the PCI works in several modes (internal/external). If this
|
|
||||||
is not configured correctly the SoC will hang.
|
|
||||||
|
|
||||||
Signed-off-by: John Crispin <blogic@openwrt.org>
|
|
||||||
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
|
|
||||||
Cc: linux-mips@linux-mips.org
|
|
||||||
Patchwork: https://patchwork.linux-mips.org/patch/2250/
|
|
||||||
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
|
|
||||||
---
|
|
||||||
.../mips/include/asm/mach-lantiq/lantiq_platform.h | 46 +++
|
|
||||||
arch/mips/pci/Makefile | 1 +
|
|
||||||
arch/mips/pci/ops-lantiq.c | 116 ++++++++
|
|
||||||
arch/mips/pci/pci-lantiq.c | 297 ++++++++++++++++++++
|
|
||||||
arch/mips/pci/pci-lantiq.h | 18 ++
|
|
||||||
5 files changed, 478 insertions(+), 0 deletions(-)
|
|
||||||
create mode 100644 arch/mips/include/asm/mach-lantiq/lantiq_platform.h
|
|
||||||
create mode 100644 arch/mips/pci/ops-lantiq.c
|
|
||||||
create mode 100644 arch/mips/pci/pci-lantiq.c
|
|
||||||
create mode 100644 arch/mips/pci/pci-lantiq.h
|
|
||||||
|
|
||||||
diff --git a/arch/mips/include/asm/mach-lantiq/lantiq_platform.h b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000..1f1dba6
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h
|
|
||||||
@@ -0,0 +1,46 @@
|
|
||||||
+/*
|
|
||||||
+ * 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 _LANTIQ_PLATFORM_H__
|
|
||||||
+#define _LANTIQ_PLATFORM_H__
|
|
||||||
+
|
|
||||||
+#include <linux/mtd/partitions.h>
|
|
||||||
+
|
|
||||||
+/* struct used to pass info to the pci core */
|
|
||||||
+enum {
|
|
||||||
+ PCI_CLOCK_INT = 0,
|
|
||||||
+ PCI_CLOCK_EXT
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+#define PCI_EXIN0 0x0001
|
|
||||||
+#define PCI_EXIN1 0x0002
|
|
||||||
+#define PCI_EXIN2 0x0004
|
|
||||||
+#define PCI_EXIN3 0x0008
|
|
||||||
+#define PCI_EXIN4 0x0010
|
|
||||||
+#define PCI_EXIN5 0x0020
|
|
||||||
+#define PCI_EXIN_MAX 6
|
|
||||||
+
|
|
||||||
+#define PCI_GNT1 0x0040
|
|
||||||
+#define PCI_GNT2 0x0080
|
|
||||||
+#define PCI_GNT3 0x0100
|
|
||||||
+#define PCI_GNT4 0x0200
|
|
||||||
+
|
|
||||||
+#define PCI_REQ1 0x0400
|
|
||||||
+#define PCI_REQ2 0x0800
|
|
||||||
+#define PCI_REQ3 0x1000
|
|
||||||
+#define PCI_REQ4 0x2000
|
|
||||||
+#define PCI_REQ_SHIFT 10
|
|
||||||
+#define PCI_REQ_MASK 0xf
|
|
||||||
+
|
|
||||||
+struct ltq_pci_data {
|
|
||||||
+ int clock;
|
|
||||||
+ int gpio;
|
|
||||||
+ int irq[16];
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+#endif
|
|
||||||
diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile
|
|
||||||
index f0d5329..4df8799 100644
|
|
||||||
--- a/arch/mips/pci/Makefile
|
|
||||||
+++ b/arch/mips/pci/Makefile
|
|
||||||
@@ -41,6 +41,7 @@ obj-$(CONFIG_SIBYTE_SB1250) += fixup-sb1250.o pci-sb1250.o
|
|
||||||
obj-$(CONFIG_SIBYTE_BCM112X) += fixup-sb1250.o pci-sb1250.o
|
|
||||||
obj-$(CONFIG_SIBYTE_BCM1x80) += pci-bcm1480.o pci-bcm1480ht.o
|
|
||||||
obj-$(CONFIG_SNI_RM) += fixup-sni.o ops-sni.o
|
|
||||||
+obj-$(CONFIG_SOC_XWAY) += pci-lantiq.o ops-lantiq.o
|
|
||||||
obj-$(CONFIG_TANBAC_TB0219) += fixup-tb0219.o
|
|
||||||
obj-$(CONFIG_TANBAC_TB0226) += fixup-tb0226.o
|
|
||||||
obj-$(CONFIG_TANBAC_TB0287) += fixup-tb0287.o
|
|
||||||
diff --git a/arch/mips/pci/ops-lantiq.c b/arch/mips/pci/ops-lantiq.c
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000..1f2afb5
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/arch/mips/pci/ops-lantiq.c
|
|
||||||
@@ -0,0 +1,116 @@
|
|
||||||
+/*
|
|
||||||
+ * 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/types.h>
|
|
||||||
+#include <linux/pci.h>
|
|
||||||
+#include <linux/kernel.h>
|
|
||||||
+#include <linux/init.h>
|
|
||||||
+#include <linux/delay.h>
|
|
||||||
+#include <linux/mm.h>
|
|
||||||
+#include <asm/addrspace.h>
|
|
||||||
+#include <linux/vmalloc.h>
|
|
||||||
+
|
|
||||||
+#include <lantiq_soc.h>
|
|
||||||
+
|
|
||||||
+#include "pci-lantiq.h"
|
|
||||||
+
|
|
||||||
+#define LTQ_PCI_CFG_BUSNUM_SHF 16
|
|
||||||
+#define LTQ_PCI_CFG_DEVNUM_SHF 11
|
|
||||||
+#define LTQ_PCI_CFG_FUNNUM_SHF 8
|
|
||||||
+
|
|
||||||
+#define PCI_ACCESS_READ 0
|
|
||||||
+#define PCI_ACCESS_WRITE 1
|
|
||||||
+
|
|
||||||
+static int ltq_pci_config_access(unsigned char access_type, struct pci_bus *bus,
|
|
||||||
+ unsigned int devfn, unsigned int where, u32 *data)
|
|
||||||
+{
|
|
||||||
+ unsigned long cfg_base;
|
|
||||||
+ unsigned long flags;
|
|
||||||
+ u32 temp;
|
|
||||||
+
|
|
||||||
+ /* we support slot from 0 to 15 dev_fn & 0x68 (AD29) is the
|
|
||||||
+ SoC itself */
|
|
||||||
+ if ((bus->number != 0) || ((devfn & 0xf8) > 0x78)
|
|
||||||
+ || ((devfn & 0xf8) == 0) || ((devfn & 0xf8) == 0x68))
|
|
||||||
+ return 1;
|
|
||||||
+
|
|
||||||
+ spin_lock_irqsave(&ebu_lock, flags);
|
|
||||||
+
|
|
||||||
+ cfg_base = (unsigned long) ltq_pci_mapped_cfg;
|
|
||||||
+ cfg_base |= (bus->number << LTQ_PCI_CFG_BUSNUM_SHF) | (devfn <<
|
|
||||||
+ LTQ_PCI_CFG_FUNNUM_SHF) | (where & ~0x3);
|
|
||||||
+
|
|
||||||
+ /* Perform access */
|
|
||||||
+ if (access_type == PCI_ACCESS_WRITE) {
|
|
||||||
+ ltq_w32(swab32(*data), ((u32 *)cfg_base));
|
|
||||||
+ } else {
|
|
||||||
+ *data = ltq_r32(((u32 *)(cfg_base)));
|
|
||||||
+ *data = swab32(*data);
|
|
||||||
+ }
|
|
||||||
+ wmb();
|
|
||||||
+
|
|
||||||
+ /* clean possible Master abort */
|
|
||||||
+ cfg_base = (unsigned long) ltq_pci_mapped_cfg;
|
|
||||||
+ cfg_base |= (0x0 << LTQ_PCI_CFG_FUNNUM_SHF) + 4;
|
|
||||||
+ temp = ltq_r32(((u32 *)(cfg_base)));
|
|
||||||
+ temp = swab32(temp);
|
|
||||||
+ cfg_base = (unsigned long) ltq_pci_mapped_cfg;
|
|
||||||
+ cfg_base |= (0x68 << LTQ_PCI_CFG_FUNNUM_SHF) + 4;
|
|
||||||
+ ltq_w32(temp, ((u32 *)cfg_base));
|
|
||||||
+
|
|
||||||
+ spin_unlock_irqrestore(&ebu_lock, flags);
|
|
||||||
+
|
|
||||||
+ if (((*data) == 0xffffffff) && (access_type == PCI_ACCESS_READ))
|
|
||||||
+ return 1;
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+int ltq_pci_read_config_dword(struct pci_bus *bus, unsigned int devfn,
|
|
||||||
+ int where, int size, u32 *val)
|
|
||||||
+{
|
|
||||||
+ u32 data = 0;
|
|
||||||
+
|
|
||||||
+ if (ltq_pci_config_access(PCI_ACCESS_READ, bus, devfn, where, &data))
|
|
||||||
+ return PCIBIOS_DEVICE_NOT_FOUND;
|
|
||||||
+
|
|
||||||
+ if (size == 1)
|
|
||||||
+ *val = (data >> ((where & 3) << 3)) & 0xff;
|
|
||||||
+ else if (size == 2)
|
|
||||||
+ *val = (data >> ((where & 3) << 3)) & 0xffff;
|
|
||||||
+ else
|
|
||||||
+ *val = data;
|
|
||||||
+
|
|
||||||
+ return PCIBIOS_SUCCESSFUL;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+int ltq_pci_write_config_dword(struct pci_bus *bus, unsigned int devfn,
|
|
||||||
+ int where, int size, u32 val)
|
|
||||||
+{
|
|
||||||
+ u32 data = 0;
|
|
||||||
+
|
|
||||||
+ if (size == 4) {
|
|
||||||
+ data = val;
|
|
||||||
+ } else {
|
|
||||||
+ if (ltq_pci_config_access(PCI_ACCESS_READ, bus,
|
|
||||||
+ devfn, where, &data))
|
|
||||||
+ return PCIBIOS_DEVICE_NOT_FOUND;
|
|
||||||
+
|
|
||||||
+ if (size == 1)
|
|
||||||
+ data = (data & ~(0xff << ((where & 3) << 3))) |
|
|
||||||
+ (val << ((where & 3) << 3));
|
|
||||||
+ else if (size == 2)
|
|
||||||
+ data = (data & ~(0xffff << ((where & 3) << 3))) |
|
|
||||||
+ (val << ((where & 3) << 3));
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (ltq_pci_config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data))
|
|
||||||
+ return PCIBIOS_DEVICE_NOT_FOUND;
|
|
||||||
+
|
|
||||||
+ return PCIBIOS_SUCCESSFUL;
|
|
||||||
+}
|
|
||||||
diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000..603d749
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/arch/mips/pci/pci-lantiq.c
|
|
||||||
@@ -0,0 +1,297 @@
|
|
||||||
+/*
|
|
||||||
+ * 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/types.h>
|
|
||||||
+#include <linux/pci.h>
|
|
||||||
+#include <linux/kernel.h>
|
|
||||||
+#include <linux/init.h>
|
|
||||||
+#include <linux/delay.h>
|
|
||||||
+#include <linux/mm.h>
|
|
||||||
+#include <linux/vmalloc.h>
|
|
||||||
+#include <linux/platform_device.h>
|
|
||||||
+
|
|
||||||
+#include <asm/pci.h>
|
|
||||||
+#include <asm/gpio.h>
|
|
||||||
+#include <asm/addrspace.h>
|
|
||||||
+
|
|
||||||
+#include <lantiq_soc.h>
|
|
||||||
+#include <lantiq_irq.h>
|
|
||||||
+#include <lantiq_platform.h>
|
|
||||||
+
|
|
||||||
+#include "pci-lantiq.h"
|
|
||||||
+
|
|
||||||
+#define LTQ_PCI_CFG_BASE 0x17000000
|
|
||||||
+#define LTQ_PCI_CFG_SIZE 0x00008000
|
|
||||||
+#define LTQ_PCI_MEM_BASE 0x18000000
|
|
||||||
+#define LTQ_PCI_MEM_SIZE 0x02000000
|
|
||||||
+#define LTQ_PCI_IO_BASE 0x1AE00000
|
|
||||||
+#define LTQ_PCI_IO_SIZE 0x00200000
|
|
||||||
+
|
|
||||||
+#define PCI_CR_FCI_ADDR_MAP0 0x00C0
|
|
||||||
+#define PCI_CR_FCI_ADDR_MAP1 0x00C4
|
|
||||||
+#define PCI_CR_FCI_ADDR_MAP2 0x00C8
|
|
||||||
+#define PCI_CR_FCI_ADDR_MAP3 0x00CC
|
|
||||||
+#define PCI_CR_FCI_ADDR_MAP4 0x00D0
|
|
||||||
+#define PCI_CR_FCI_ADDR_MAP5 0x00D4
|
|
||||||
+#define PCI_CR_FCI_ADDR_MAP6 0x00D8
|
|
||||||
+#define PCI_CR_FCI_ADDR_MAP7 0x00DC
|
|
||||||
+#define PCI_CR_CLK_CTRL 0x0000
|
|
||||||
+#define PCI_CR_PCI_MOD 0x0030
|
|
||||||
+#define PCI_CR_PC_ARB 0x0080
|
|
||||||
+#define PCI_CR_FCI_ADDR_MAP11hg 0x00E4
|
|
||||||
+#define PCI_CR_BAR11MASK 0x0044
|
|
||||||
+#define PCI_CR_BAR12MASK 0x0048
|
|
||||||
+#define PCI_CR_BAR13MASK 0x004C
|
|
||||||
+#define PCI_CS_BASE_ADDR1 0x0010
|
|
||||||
+#define PCI_CR_PCI_ADDR_MAP11 0x0064
|
|
||||||
+#define PCI_CR_FCI_BURST_LENGTH 0x00E8
|
|
||||||
+#define PCI_CR_PCI_EOI 0x002C
|
|
||||||
+#define PCI_CS_STS_CMD 0x0004
|
|
||||||
+
|
|
||||||
+#define PCI_MASTER0_REQ_MASK_2BITS 8
|
|
||||||
+#define PCI_MASTER1_REQ_MASK_2BITS 10
|
|
||||||
+#define PCI_MASTER2_REQ_MASK_2BITS 12
|
|
||||||
+#define INTERNAL_ARB_ENABLE_BIT 0
|
|
||||||
+
|
|
||||||
+#define LTQ_CGU_IFCCR 0x0018
|
|
||||||
+#define LTQ_CGU_PCICR 0x0034
|
|
||||||
+
|
|
||||||
+#define ltq_pci_w32(x, y) ltq_w32((x), ltq_pci_membase + (y))
|
|
||||||
+#define ltq_pci_r32(x) ltq_r32(ltq_pci_membase + (x))
|
|
||||||
+
|
|
||||||
+#define ltq_pci_cfg_w32(x, y) ltq_w32((x), ltq_pci_mapped_cfg + (y))
|
|
||||||
+#define ltq_pci_cfg_r32(x) ltq_r32(ltq_pci_mapped_cfg + (x))
|
|
||||||
+
|
|
||||||
+struct ltq_pci_gpio_map {
|
|
||||||
+ int pin;
|
|
||||||
+ int alt0;
|
|
||||||
+ int alt1;
|
|
||||||
+ int dir;
|
|
||||||
+ char *name;
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+/* the pci core can make use of the following gpios */
|
|
||||||
+static struct ltq_pci_gpio_map ltq_pci_gpio_map[] = {
|
|
||||||
+ { 0, 1, 0, 0, "pci-exin0" },
|
|
||||||
+ { 1, 1, 0, 0, "pci-exin1" },
|
|
||||||
+ { 2, 1, 0, 0, "pci-exin2" },
|
|
||||||
+ { 39, 1, 0, 0, "pci-exin3" },
|
|
||||||
+ { 10, 1, 0, 0, "pci-exin4" },
|
|
||||||
+ { 9, 1, 0, 0, "pci-exin5" },
|
|
||||||
+ { 30, 1, 0, 1, "pci-gnt1" },
|
|
||||||
+ { 23, 1, 0, 1, "pci-gnt2" },
|
|
||||||
+ { 19, 1, 0, 1, "pci-gnt3" },
|
|
||||||
+ { 38, 1, 0, 1, "pci-gnt4" },
|
|
||||||
+ { 29, 1, 0, 0, "pci-req1" },
|
|
||||||
+ { 31, 1, 0, 0, "pci-req2" },
|
|
||||||
+ { 3, 1, 0, 0, "pci-req3" },
|
|
||||||
+ { 37, 1, 0, 0, "pci-req4" },
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+__iomem void *ltq_pci_mapped_cfg;
|
|
||||||
+static __iomem void *ltq_pci_membase;
|
|
||||||
+
|
|
||||||
+int (*ltqpci_plat_dev_init)(struct pci_dev *dev) = NULL;
|
|
||||||
+
|
|
||||||
+/* Since the PCI REQ pins can be reused for other functionality, make it
|
|
||||||
+ possible to exclude those from interpretation by the PCI controller */
|
|
||||||
+static int ltq_pci_req_mask = 0xf;
|
|
||||||
+
|
|
||||||
+static int *ltq_pci_irq_map;
|
|
||||||
+
|
|
||||||
+struct pci_ops ltq_pci_ops = {
|
|
||||||
+ .read = ltq_pci_read_config_dword,
|
|
||||||
+ .write = ltq_pci_write_config_dword
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static struct resource pci_io_resource = {
|
|
||||||
+ .name = "pci io space",
|
|
||||||
+ .start = LTQ_PCI_IO_BASE,
|
|
||||||
+ .end = LTQ_PCI_IO_BASE + LTQ_PCI_IO_SIZE - 1,
|
|
||||||
+ .flags = IORESOURCE_IO
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static struct resource pci_mem_resource = {
|
|
||||||
+ .name = "pci memory space",
|
|
||||||
+ .start = LTQ_PCI_MEM_BASE,
|
|
||||||
+ .end = LTQ_PCI_MEM_BASE + LTQ_PCI_MEM_SIZE - 1,
|
|
||||||
+ .flags = IORESOURCE_MEM
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static struct pci_controller ltq_pci_controller = {
|
|
||||||
+ .pci_ops = <q_pci_ops,
|
|
||||||
+ .mem_resource = &pci_mem_resource,
|
|
||||||
+ .mem_offset = 0x00000000UL,
|
|
||||||
+ .io_resource = &pci_io_resource,
|
|
||||||
+ .io_offset = 0x00000000UL,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+int pcibios_plat_dev_init(struct pci_dev *dev)
|
|
||||||
+{
|
|
||||||
+ if (ltqpci_plat_dev_init)
|
|
||||||
+ return ltqpci_plat_dev_init(dev);
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static u32 ltq_calc_bar11mask(void)
|
|
||||||
+{
|
|
||||||
+ u32 mem, bar11mask;
|
|
||||||
+
|
|
||||||
+ /* BAR11MASK value depends on available memory on system. */
|
|
||||||
+ mem = num_physpages * PAGE_SIZE;
|
|
||||||
+ bar11mask = (0x0ffffff0 & ~((1 << (fls(mem) - 1)) - 1)) | 8;
|
|
||||||
+
|
|
||||||
+ return bar11mask;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void ltq_pci_setup_gpio(int gpio)
|
|
||||||
+{
|
|
||||||
+ int i;
|
|
||||||
+ for (i = 0; i < ARRAY_SIZE(ltq_pci_gpio_map); i++) {
|
|
||||||
+ if (gpio & (1 << i)) {
|
|
||||||
+ ltq_gpio_request(ltq_pci_gpio_map[i].pin,
|
|
||||||
+ ltq_pci_gpio_map[i].alt0,
|
|
||||||
+ ltq_pci_gpio_map[i].alt1,
|
|
||||||
+ ltq_pci_gpio_map[i].dir,
|
|
||||||
+ ltq_pci_gpio_map[i].name);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ ltq_gpio_request(21, 0, 0, 1, "pci-reset");
|
|
||||||
+ ltq_pci_req_mask = (gpio >> PCI_REQ_SHIFT) & PCI_REQ_MASK;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int __devinit ltq_pci_startup(struct ltq_pci_data *conf)
|
|
||||||
+{
|
|
||||||
+ u32 temp_buffer;
|
|
||||||
+
|
|
||||||
+ /* set clock to 33Mhz */
|
|
||||||
+ ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~0xf00000, LTQ_CGU_IFCCR);
|
|
||||||
+ ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | 0x800000, LTQ_CGU_IFCCR);
|
|
||||||
+
|
|
||||||
+ /* external or internal clock ? */
|
|
||||||
+ if (conf->clock) {
|
|
||||||
+ ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~(1 << 16),
|
|
||||||
+ LTQ_CGU_IFCCR);
|
|
||||||
+ ltq_cgu_w32((1 << 30), LTQ_CGU_PCICR);
|
|
||||||
+ } else {
|
|
||||||
+ ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | (1 << 16),
|
|
||||||
+ LTQ_CGU_IFCCR);
|
|
||||||
+ ltq_cgu_w32((1 << 31) | (1 << 30), LTQ_CGU_PCICR);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* setup pci clock and gpis used by pci */
|
|
||||||
+ ltq_pci_setup_gpio(conf->gpio);
|
|
||||||
+
|
|
||||||
+ /* enable auto-switching between PCI and EBU */
|
|
||||||
+ ltq_pci_w32(0xa, PCI_CR_CLK_CTRL);
|
|
||||||
+
|
|
||||||
+ /* busy, i.e. configuration is not done, PCI access has to be retried */
|
|
||||||
+ ltq_pci_w32(ltq_pci_r32(PCI_CR_PCI_MOD) & ~(1 << 24), PCI_CR_PCI_MOD);
|
|
||||||
+ wmb();
|
|
||||||
+ /* BUS Master/IO/MEM access */
|
|
||||||
+ ltq_pci_cfg_w32(ltq_pci_cfg_r32(PCI_CS_STS_CMD) | 7, PCI_CS_STS_CMD);
|
|
||||||
+
|
|
||||||
+ /* enable external 2 PCI masters */
|
|
||||||
+ temp_buffer = ltq_pci_r32(PCI_CR_PC_ARB);
|
|
||||||
+ temp_buffer &= (~(ltq_pci_req_mask << 16));
|
|
||||||
+ /* enable internal arbiter */
|
|
||||||
+ temp_buffer |= (1 << INTERNAL_ARB_ENABLE_BIT);
|
|
||||||
+ /* enable internal PCI master reqest */
|
|
||||||
+ temp_buffer &= (~(3 << PCI_MASTER0_REQ_MASK_2BITS));
|
|
||||||
+
|
|
||||||
+ /* enable EBU request */
|
|
||||||
+ temp_buffer &= (~(3 << PCI_MASTER1_REQ_MASK_2BITS));
|
|
||||||
+
|
|
||||||
+ /* enable all external masters request */
|
|
||||||
+ temp_buffer &= (~(3 << PCI_MASTER2_REQ_MASK_2BITS));
|
|
||||||
+ ltq_pci_w32(temp_buffer, PCI_CR_PC_ARB);
|
|
||||||
+ wmb();
|
|
||||||
+
|
|
||||||
+ /* setup BAR memory regions */
|
|
||||||
+ ltq_pci_w32(0x18000000, PCI_CR_FCI_ADDR_MAP0);
|
|
||||||
+ ltq_pci_w32(0x18400000, PCI_CR_FCI_ADDR_MAP1);
|
|
||||||
+ ltq_pci_w32(0x18800000, PCI_CR_FCI_ADDR_MAP2);
|
|
||||||
+ ltq_pci_w32(0x18c00000, PCI_CR_FCI_ADDR_MAP3);
|
|
||||||
+ ltq_pci_w32(0x19000000, PCI_CR_FCI_ADDR_MAP4);
|
|
||||||
+ ltq_pci_w32(0x19400000, PCI_CR_FCI_ADDR_MAP5);
|
|
||||||
+ ltq_pci_w32(0x19800000, PCI_CR_FCI_ADDR_MAP6);
|
|
||||||
+ ltq_pci_w32(0x19c00000, PCI_CR_FCI_ADDR_MAP7);
|
|
||||||
+ ltq_pci_w32(0x1ae00000, PCI_CR_FCI_ADDR_MAP11hg);
|
|
||||||
+ ltq_pci_w32(ltq_calc_bar11mask(), PCI_CR_BAR11MASK);
|
|
||||||
+ ltq_pci_w32(0, PCI_CR_PCI_ADDR_MAP11);
|
|
||||||
+ ltq_pci_w32(0, PCI_CS_BASE_ADDR1);
|
|
||||||
+ /* both TX and RX endian swap are enabled */
|
|
||||||
+ ltq_pci_w32(ltq_pci_r32(PCI_CR_PCI_EOI) | 3, PCI_CR_PCI_EOI);
|
|
||||||
+ wmb();
|
|
||||||
+ ltq_pci_w32(ltq_pci_r32(PCI_CR_BAR12MASK) | 0x80000000,
|
|
||||||
+ PCI_CR_BAR12MASK);
|
|
||||||
+ ltq_pci_w32(ltq_pci_r32(PCI_CR_BAR13MASK) | 0x80000000,
|
|
||||||
+ PCI_CR_BAR13MASK);
|
|
||||||
+ /*use 8 dw burst length */
|
|
||||||
+ ltq_pci_w32(0x303, PCI_CR_FCI_BURST_LENGTH);
|
|
||||||
+ ltq_pci_w32(ltq_pci_r32(PCI_CR_PCI_MOD) | (1 << 24), PCI_CR_PCI_MOD);
|
|
||||||
+ wmb();
|
|
||||||
+
|
|
||||||
+ /* setup irq line */
|
|
||||||
+ ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_CON) | 0xc, LTQ_EBU_PCC_CON);
|
|
||||||
+ ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_IEN) | 0x10, LTQ_EBU_PCC_IEN);
|
|
||||||
+
|
|
||||||
+ /* toggle reset pin */
|
|
||||||
+ __gpio_set_value(21, 0);
|
|
||||||
+ wmb();
|
|
||||||
+ mdelay(1);
|
|
||||||
+ __gpio_set_value(21, 1);
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
|
||||||
+{
|
|
||||||
+ if (ltq_pci_irq_map[slot])
|
|
||||||
+ return ltq_pci_irq_map[slot];
|
|
||||||
+ printk(KERN_ERR "ltq_pci: trying to map irq for unknown slot %d\n",
|
|
||||||
+ slot);
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int __devinit ltq_pci_probe(struct platform_device *pdev)
|
|
||||||
+{
|
|
||||||
+ struct ltq_pci_data *ltq_pci_data =
|
|
||||||
+ (struct ltq_pci_data *) pdev->dev.platform_data;
|
|
||||||
+ pci_probe_only = 0;
|
|
||||||
+ ltq_pci_irq_map = ltq_pci_data->irq;
|
|
||||||
+ ltq_pci_membase = ioremap_nocache(PCI_CR_BASE_ADDR, PCI_CR_SIZE);
|
|
||||||
+ ltq_pci_mapped_cfg =
|
|
||||||
+ ioremap_nocache(LTQ_PCI_CFG_BASE, LTQ_PCI_CFG_BASE);
|
|
||||||
+ ltq_pci_controller.io_map_base =
|
|
||||||
+ (unsigned long)ioremap(LTQ_PCI_IO_BASE, LTQ_PCI_IO_SIZE - 1);
|
|
||||||
+ ltq_pci_startup(ltq_pci_data);
|
|
||||||
+ register_pci_controller(<q_pci_controller);
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static struct platform_driver
|
|
||||||
+ltq_pci_driver = {
|
|
||||||
+ .probe = ltq_pci_probe,
|
|
||||||
+ .driver = {
|
|
||||||
+ .name = "ltq_pci",
|
|
||||||
+ .owner = THIS_MODULE,
|
|
||||||
+ },
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+int __init pcibios_init(void)
|
|
||||||
+{
|
|
||||||
+ int ret = platform_driver_register(<q_pci_driver);
|
|
||||||
+ if (ret)
|
|
||||||
+ printk(KERN_INFO "ltq_pci: Error registering platfom driver!");
|
|
||||||
+ return ret;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+arch_initcall(pcibios_init);
|
|
||||||
diff --git a/arch/mips/pci/pci-lantiq.h b/arch/mips/pci/pci-lantiq.h
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000..66bf6cd
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/arch/mips/pci/pci-lantiq.h
|
|
||||||
@@ -0,0 +1,18 @@
|
|
||||||
+/*
|
|
||||||
+ * 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_PCI_H__
|
|
||||||
+#define _LTQ_PCI_H__
|
|
||||||
+
|
|
||||||
+extern __iomem void *ltq_pci_mapped_cfg;
|
|
||||||
+extern int ltq_pci_read_config_dword(struct pci_bus *bus,
|
|
||||||
+ unsigned int devfn, int where, int size, u32 *val);
|
|
||||||
+extern int ltq_pci_write_config_dword(struct pci_bus *bus,
|
|
||||||
+ unsigned int devfn, int where, int size, u32 val);
|
|
||||||
+
|
|
||||||
+#endif
|
|
||||||
--
|
|
||||||
1.7.2.3
|
|
||||||
|
|
@ -1,301 +0,0 @@ |
|||||||
From cd0d53b24ca744295d2cdf69bb2b659571091b75 Mon Sep 17 00:00:00 2001
|
|
||||||
From: John Crispin <blogic@openwrt.org>
|
|
||||||
Date: Tue, 12 Apr 2011 18:10:01 +0200
|
|
||||||
Subject: [PATCH 04/13] MIPS: Lantiq: Add NOR flash support
|
|
||||||
|
|
||||||
This patch adds the driver/map for NOR devices attached to the SoC via the
|
|
||||||
External Bus Unit (EBU).
|
|
||||||
|
|
||||||
Signed-off-by: John Crispin <blogic@openwrt.org>
|
|
||||||
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
|
|
||||||
Cc: David Woodhouse <dwmw2@infradead.org>
|
|
||||||
Cc: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>
|
|
||||||
Cc: linux-mips@linux-mips.org
|
|
||||||
Cc: linux-mtd@lists.infradead.org
|
|
||||||
Acked-by: Artem Bityutskiy <dedekind1@gmail.com>
|
|
||||||
Patchwork: https://patchwork.linux-mips.org/patch/2285/
|
|
||||||
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
|
|
||||||
---
|
|
||||||
drivers/mtd/maps/Kconfig | 7 +
|
|
||||||
drivers/mtd/maps/Makefile | 1 +
|
|
||||||
drivers/mtd/maps/lantiq-flash.c | 251 +++++++++++++++++++++++++++++++++++++++
|
|
||||||
3 files changed, 259 insertions(+), 0 deletions(-)
|
|
||||||
create mode 100644 drivers/mtd/maps/lantiq-flash.c
|
|
||||||
|
|
||||||
--- a/drivers/mtd/maps/Kconfig
|
|
||||||
+++ b/drivers/mtd/maps/Kconfig
|
|
||||||
@@ -259,6 +259,13 @@
|
|
||||||
help
|
|
||||||
Flash memory access on AMD Alchemy Pb/Db/RDK Reference Boards
|
|
||||||
|
|
||||||
+config MTD_LANTIQ
|
|
||||||
+ tristate "Lantiq SoC NOR support"
|
|
||||||
+ depends on LANTIQ
|
|
||||||
+ select MTD_PARTITIONS
|
|
||||||
+ help
|
|
||||||
+ Support for NOR flash attached to the Lantiq SoC's External Bus Unit.
|
|
||||||
+
|
|
||||||
config MTD_DILNETPC
|
|
||||||
tristate "CFI Flash device mapped on DIL/Net PC"
|
|
||||||
depends on X86 && MTD_CONCAT && MTD_PARTITIONS && MTD_CFI_INTELEXT && BROKEN
|
|
||||||
--- a/drivers/mtd/maps/Makefile
|
|
||||||
+++ b/drivers/mtd/maps/Makefile
|
|
||||||
@@ -61,3 +61,4 @@
|
|
||||||
obj-$(CONFIG_MTD_RBTX4939) += rbtx4939-flash.o
|
|
||||||
obj-$(CONFIG_MTD_VMU) += vmu-flash.o
|
|
||||||
obj-$(CONFIG_MTD_GPIO_ADDR) += gpio-addr-flash.o
|
|
||||||
+obj-$(CONFIG_MTD_LANTIQ) += lantiq-flash.o
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/drivers/mtd/maps/lantiq-flash.c
|
|
||||||
@@ -0,0 +1,251 @@
|
|
||||||
+/*
|
|
||||||
+ * 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) 2004 Liu Peng Infineon IFAP DC COM CPE
|
|
||||||
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#include <linux/module.h>
|
|
||||||
+#include <linux/types.h>
|
|
||||||
+#include <linux/kernel.h>
|
|
||||||
+#include <linux/io.h>
|
|
||||||
+#include <linux/slab.h>
|
|
||||||
+#include <linux/init.h>
|
|
||||||
+#include <linux/mtd/mtd.h>
|
|
||||||
+#include <linux/mtd/map.h>
|
|
||||||
+#include <linux/mtd/partitions.h>
|
|
||||||
+#include <linux/mtd/cfi.h>
|
|
||||||
+#include <linux/platform_device.h>
|
|
||||||
+#include <linux/mtd/physmap.h>
|
|
||||||
+
|
|
||||||
+#include <lantiq_soc.h>
|
|
||||||
+#include <lantiq_platform.h>
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * The NOR flash is connected to the same external bus unit (EBU) as PCI.
|
|
||||||
+ * To make PCI work we need to enable the endianness swapping for the address
|
|
||||||
+ * written to the EBU. This endianness swapping works for PCI correctly but
|
|
||||||
+ * fails for attached NOR devices. To workaround this we need to use a complex
|
|
||||||
+ * map. The workaround involves swapping all addresses whilst probing the chip.
|
|
||||||
+ * Once probing is complete we stop swapping the addresses but swizzle the
|
|
||||||
+ * unlock addresses to ensure that access to the NOR device works correctly.
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+enum {
|
|
||||||
+ LTQ_NOR_PROBING,
|
|
||||||
+ LTQ_NOR_NORMAL
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+struct ltq_mtd {
|
|
||||||
+ struct resource *res;
|
|
||||||
+ struct mtd_info *mtd;
|
|
||||||
+ struct map_info *map;
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static char ltq_map_name[] = "ltq_nor";
|
|
||||||
+
|
|
||||||
+static map_word
|
|
||||||
+ltq_read16(struct map_info *map, unsigned long adr)
|
|
||||||
+{
|
|
||||||
+ unsigned long flags;
|
|
||||||
+ map_word temp;
|
|
||||||
+
|
|
||||||
+ if (map->map_priv_1 == LTQ_NOR_PROBING)
|
|
||||||
+ adr ^= 2;
|
|
||||||
+ spin_lock_irqsave(&ebu_lock, flags);
|
|
||||||
+ temp.x[0] = *(u16 *)(map->virt + adr);
|
|
||||||
+ spin_unlock_irqrestore(&ebu_lock, flags);
|
|
||||||
+ return temp;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+ltq_write16(struct map_info *map, map_word d, unsigned long adr)
|
|
||||||
+{
|
|
||||||
+ unsigned long flags;
|
|
||||||
+
|
|
||||||
+ if (map->map_priv_1 == LTQ_NOR_PROBING)
|
|
||||||
+ adr ^= 2;
|
|
||||||
+ spin_lock_irqsave(&ebu_lock, flags);
|
|
||||||
+ *(u16 *)(map->virt + adr) = d.x[0];
|
|
||||||
+ spin_unlock_irqrestore(&ebu_lock, flags);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * The following 2 functions copy data between iomem and a cached memory
|
|
||||||
+ * section. As memcpy() makes use of pre-fetching we cannot use it here.
|
|
||||||
+ * The normal alternative of using memcpy_{to,from}io also makes use of
|
|
||||||
+ * memcpy() on MIPS so it is not applicable either. We are therefore stuck
|
|
||||||
+ * with having to use our own loop.
|
|
||||||
+ */
|
|
||||||
+static void
|
|
||||||
+ltq_copy_from(struct map_info *map, void *to,
|
|
||||||
+ unsigned long from, ssize_t len)
|
|
||||||
+{
|
|
||||||
+ unsigned char *f = (unsigned char *)map->virt + from;
|
|
||||||
+ unsigned char *t = (unsigned char *)to;
|
|
||||||
+ unsigned long flags;
|
|
||||||
+
|
|
||||||
+ spin_lock_irqsave(&ebu_lock, flags);
|
|
||||||
+ while (len--)
|
|
||||||
+ *t++ = *f++;
|
|
||||||
+ spin_unlock_irqrestore(&ebu_lock, flags);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+ltq_copy_to(struct map_info *map, unsigned long to,
|
|
||||||
+ const void *from, ssize_t len)
|
|
||||||
+{
|
|
||||||
+ unsigned char *f = (unsigned char *)from;
|
|
||||||
+ unsigned char *t = (unsigned char *)map->virt + to;
|
|
||||||
+ unsigned long flags;
|
|
||||||
+
|
|
||||||
+ spin_lock_irqsave(&ebu_lock, flags);
|
|
||||||
+ while (len--)
|
|
||||||
+ *t++ = *f++;
|
|
||||||
+ spin_unlock_irqrestore(&ebu_lock, flags);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static const char const *part_probe_types[] = { "cmdlinepart", NULL };
|
|
||||||
+
|
|
||||||
+static int __init
|
|
||||||
+ltq_mtd_probe(struct platform_device *pdev)
|
|
||||||
+{
|
|
||||||
+ struct physmap_flash_data *ltq_mtd_data = dev_get_platdata(&pdev->dev);
|
|
||||||
+ struct ltq_mtd *ltq_mtd;
|
|
||||||
+ struct mtd_partition *parts;
|
|
||||||
+ struct resource *res;
|
|
||||||
+ int nr_parts = 0;
|
|
||||||
+ struct cfi_private *cfi;
|
|
||||||
+ int err;
|
|
||||||
+
|
|
||||||
+ ltq_mtd = kzalloc(sizeof(struct ltq_mtd), GFP_KERNEL);
|
|
||||||
+ platform_set_drvdata(pdev, ltq_mtd);
|
|
||||||
+
|
|
||||||
+ ltq_mtd->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
||||||
+ if (!ltq_mtd->res) {
|
|
||||||
+ dev_err(&pdev->dev, "failed to get memory resource");
|
|
||||||
+ err = -ENOENT;
|
|
||||||
+ goto err_out;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ res = devm_request_mem_region(&pdev->dev, ltq_mtd->res->start,
|
|
||||||
+ resource_size(ltq_mtd->res), dev_name(&pdev->dev));
|
|
||||||
+ if (!ltq_mtd->res) {
|
|
||||||
+ dev_err(&pdev->dev, "failed to request mem resource");
|
|
||||||
+ err = -EBUSY;
|
|
||||||
+ goto err_out;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ ltq_mtd->map = kzalloc(sizeof(struct map_info), GFP_KERNEL);
|
|
||||||
+ ltq_mtd->map->phys = res->start;
|
|
||||||
+ ltq_mtd->map->size = resource_size(res);
|
|
||||||
+ ltq_mtd->map->virt = devm_ioremap_nocache(&pdev->dev,
|
|
||||||
+ ltq_mtd->map->phys, ltq_mtd->map->size);
|
|
||||||
+ if (!ltq_mtd->map->virt) {
|
|
||||||
+ dev_err(&pdev->dev, "failed to ioremap!\n");
|
|
||||||
+ err = -ENOMEM;
|
|
||||||
+ goto err_free;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ ltq_mtd->map->name = ltq_map_name;
|
|
||||||
+ ltq_mtd->map->bankwidth = 2;
|
|
||||||
+ ltq_mtd->map->read = ltq_read16;
|
|
||||||
+ ltq_mtd->map->write = ltq_write16;
|
|
||||||
+ ltq_mtd->map->copy_from = ltq_copy_from;
|
|
||||||
+ ltq_mtd->map->copy_to = ltq_copy_to;
|
|
||||||
+
|
|
||||||
+ ltq_mtd->map->map_priv_1 = LTQ_NOR_PROBING;
|
|
||||||
+ ltq_mtd->mtd = do_map_probe("cfi_probe", ltq_mtd->map);
|
|
||||||
+ ltq_mtd->map->map_priv_1 = LTQ_NOR_NORMAL;
|
|
||||||
+
|
|
||||||
+ if (!ltq_mtd->mtd) {
|
|
||||||
+ dev_err(&pdev->dev, "probing failed\n");
|
|
||||||
+ err = -ENXIO;
|
|
||||||
+ goto err_unmap;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ ltq_mtd->mtd->owner = THIS_MODULE;
|
|
||||||
+
|
|
||||||
+ cfi = ltq_mtd->map->fldrv_priv;
|
|
||||||
+ cfi->addr_unlock1 ^= 1;
|
|
||||||
+ cfi->addr_unlock2 ^= 1;
|
|
||||||
+
|
|
||||||
+ nr_parts = parse_mtd_partitions(ltq_mtd->mtd,
|
|
||||||
+ part_probe_types, &parts, 0);
|
|
||||||
+ if (nr_parts > 0) {
|
|
||||||
+ dev_info(&pdev->dev,
|
|
||||||
+ "using %d partitions from cmdline", nr_parts);
|
|
||||||
+ } else {
|
|
||||||
+ nr_parts = ltq_mtd_data->nr_parts;
|
|
||||||
+ parts = ltq_mtd_data->parts;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ err = add_mtd_partitions(ltq_mtd->mtd, parts, nr_parts);
|
|
||||||
+ if (err) {
|
|
||||||
+ dev_err(&pdev->dev, "failed to add partitions\n");
|
|
||||||
+ goto err_destroy;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+
|
|
||||||
+err_destroy:
|
|
||||||
+ map_destroy(ltq_mtd->mtd);
|
|
||||||
+err_unmap:
|
|
||||||
+ iounmap(ltq_mtd->map->virt);
|
|
||||||
+err_free:
|
|
||||||
+ kfree(ltq_mtd->map);
|
|
||||||
+err_out:
|
|
||||||
+ kfree(ltq_mtd);
|
|
||||||
+ return err;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int __devexit
|
|
||||||
+ltq_mtd_remove(struct platform_device *pdev)
|
|
||||||
+{
|
|
||||||
+ struct ltq_mtd *ltq_mtd = platform_get_drvdata(pdev);
|
|
||||||
+
|
|
||||||
+ if (ltq_mtd) {
|
|
||||||
+ if (ltq_mtd->mtd) {
|
|
||||||
+ del_mtd_partitions(ltq_mtd->mtd);
|
|
||||||
+ map_destroy(ltq_mtd->mtd);
|
|
||||||
+ }
|
|
||||||
+ if (ltq_mtd->map->virt)
|
|
||||||
+ iounmap(ltq_mtd->map->virt);
|
|
||||||
+ kfree(ltq_mtd->map);
|
|
||||||
+ kfree(ltq_mtd);
|
|
||||||
+ }
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static struct platform_driver ltq_mtd_driver = {
|
|
||||||
+ .remove = __devexit_p(ltq_mtd_remove),
|
|
||||||
+ .driver = {
|
|
||||||
+ .name = "ltq_nor",
|
|
||||||
+ .owner = THIS_MODULE,
|
|
||||||
+ },
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static int __init
|
|
||||||
+init_ltq_mtd(void)
|
|
||||||
+{
|
|
||||||
+ int ret = platform_driver_probe(<q_mtd_driver, ltq_mtd_probe);
|
|
||||||
+
|
|
||||||
+ if (ret)
|
|
||||||
+ pr_err("ltq_nor: error registering platform driver");
|
|
||||||
+ return ret;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void __exit
|
|
||||||
+exit_ltq_mtd(void)
|
|
||||||
+{
|
|
||||||
+ platform_driver_unregister(<q_mtd_driver);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+module_init(init_ltq_mtd);
|
|
||||||
+module_exit(exit_ltq_mtd);
|
|
||||||
+
|
|
||||||
+MODULE_LICENSE("GPL");
|
|
||||||
+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
|
|
||||||
+MODULE_DESCRIPTION("Lantiq SoC NOR");
|
|
@ -1,338 +0,0 @@ |
|||||||
From 09e57348261c1ae0ff89c68679126fc76a28b2a2 Mon Sep 17 00:00:00 2001
|
|
||||||
From: John Crispin <blogic@openwrt.org>
|
|
||||||
Date: Wed, 30 Mar 2011 09:27:53 +0200
|
|
||||||
Subject: [PATCH 05/13] MIPS: Lantiq: Add platform device support
|
|
||||||
|
|
||||||
This patch adds the wrappers for registering our platform devices.
|
|
||||||
|
|
||||||
Signed-off-by: John Crispin <blogic@openwrt.org>
|
|
||||||
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
|
|
||||||
Cc: linux-mips@linux-mips.org
|
|
||||||
Patchwork: https://patchwork.linux-mips.org/patch/2254/
|
|
||||||
Patchwork: https://patchwork.linux-mips.org/patch/2360/
|
|
||||||
Patchwork: https://patchwork.linux-mips.org/patch/2359/
|
|
||||||
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
|
|
||||||
---
|
|
||||||
arch/mips/lantiq/Makefile | 2 +-
|
|
||||||
arch/mips/lantiq/devices.c | 122 +++++++++++++++++++++++++++++++++++++++
|
|
||||||
arch/mips/lantiq/devices.h | 23 +++++++
|
|
||||||
arch/mips/lantiq/xway/Makefile | 2 +-
|
|
||||||
arch/mips/lantiq/xway/devices.c | 98 +++++++++++++++++++++++++++++++
|
|
||||||
arch/mips/lantiq/xway/devices.h | 18 ++++++
|
|
||||||
6 files changed, 263 insertions(+), 2 deletions(-)
|
|
||||||
create mode 100644 arch/mips/lantiq/devices.c
|
|
||||||
create mode 100644 arch/mips/lantiq/devices.h
|
|
||||||
create mode 100644 arch/mips/lantiq/xway/devices.c
|
|
||||||
create mode 100644 arch/mips/lantiq/xway/devices.h
|
|
||||||
|
|
||||||
diff --git a/arch/mips/lantiq/Makefile b/arch/mips/lantiq/Makefile
|
|
||||||
index a268391..e5dae0e 100644
|
|
||||||
--- 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
|
|
||||||
+obj-y := irq.o setup.o clk.o prom.o devices.o
|
|
||||||
|
|
||||||
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
|
|
||||||
|
|
||||||
diff --git a/arch/mips/lantiq/devices.c b/arch/mips/lantiq/devices.c
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000..7b82c34
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/arch/mips/lantiq/devices.c
|
|
||||||
@@ -0,0 +1,122 @@
|
|
||||||
+/*
|
|
||||||
+ * 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/module.h>
|
|
||||||
+#include <linux/types.h>
|
|
||||||
+#include <linux/string.h>
|
|
||||||
+#include <linux/kernel.h>
|
|
||||||
+#include <linux/reboot.h>
|
|
||||||
+#include <linux/platform_device.h>
|
|
||||||
+#include <linux/leds.h>
|
|
||||||
+#include <linux/etherdevice.h>
|
|
||||||
+#include <linux/reboot.h>
|
|
||||||
+#include <linux/time.h>
|
|
||||||
+#include <linux/io.h>
|
|
||||||
+#include <linux/gpio.h>
|
|
||||||
+#include <linux/leds.h>
|
|
||||||
+
|
|
||||||
+#include <asm/bootinfo.h>
|
|
||||||
+#include <asm/irq.h>
|
|
||||||
+
|
|
||||||
+#include <lantiq_soc.h>
|
|
||||||
+
|
|
||||||
+#include "devices.h"
|
|
||||||
+
|
|
||||||
+/* nor flash */
|
|
||||||
+static struct resource ltq_nor_resource = {
|
|
||||||
+ .name = "nor",
|
|
||||||
+ .start = LTQ_FLASH_START,
|
|
||||||
+ .end = LTQ_FLASH_START + LTQ_FLASH_MAX - 1,
|
|
||||||
+ .flags = IORESOURCE_MEM,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static struct platform_device ltq_nor = {
|
|
||||||
+ .name = "ltq_nor",
|
|
||||||
+ .resource = <q_nor_resource,
|
|
||||||
+ .num_resources = 1,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+void __init ltq_register_nor(struct physmap_flash_data *data)
|
|
||||||
+{
|
|
||||||
+ ltq_nor.dev.platform_data = data;
|
|
||||||
+ platform_device_register(<q_nor);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+/* watchdog */
|
|
||||||
+static struct resource ltq_wdt_resource = {
|
|
||||||
+ .name = "watchdog",
|
|
||||||
+ .start = LTQ_WDT_BASE_ADDR,
|
|
||||||
+ .end = LTQ_WDT_BASE_ADDR + LTQ_WDT_SIZE - 1,
|
|
||||||
+ .flags = IORESOURCE_MEM,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+void __init ltq_register_wdt(void)
|
|
||||||
+{
|
|
||||||
+ platform_device_register_simple("ltq_wdt", 0, <q_wdt_resource, 1);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+/* asc ports */
|
|
||||||
+static struct resource ltq_asc0_resources[] = {
|
|
||||||
+ {
|
|
||||||
+ .name = "asc0",
|
|
||||||
+ .start = LTQ_ASC0_BASE_ADDR,
|
|
||||||
+ .end = LTQ_ASC0_BASE_ADDR + LTQ_ASC_SIZE - 1,
|
|
||||||
+ .flags = IORESOURCE_MEM,
|
|
||||||
+ },
|
|
||||||
+ IRQ_RES(tx, LTQ_ASC_TIR(0)),
|
|
||||||
+ IRQ_RES(rx, LTQ_ASC_RIR(0)),
|
|
||||||
+ IRQ_RES(err, LTQ_ASC_EIR(0)),
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static struct resource ltq_asc1_resources[] = {
|
|
||||||
+ {
|
|
||||||
+ .name = "asc1",
|
|
||||||
+ .start = LTQ_ASC1_BASE_ADDR,
|
|
||||||
+ .end = LTQ_ASC1_BASE_ADDR + LTQ_ASC_SIZE - 1,
|
|
||||||
+ .flags = IORESOURCE_MEM,
|
|
||||||
+ },
|
|
||||||
+ IRQ_RES(tx, LTQ_ASC_TIR(1)),
|
|
||||||
+ IRQ_RES(rx, LTQ_ASC_RIR(1)),
|
|
||||||
+ IRQ_RES(err, LTQ_ASC_EIR(1)),
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+void __init ltq_register_asc(int port)
|
|
||||||
+{
|
|
||||||
+ switch (port) {
|
|
||||||
+ case 0:
|
|
||||||
+ platform_device_register_simple("ltq_asc", 0,
|
|
||||||
+ ltq_asc0_resources, ARRAY_SIZE(ltq_asc0_resources));
|
|
||||||
+ break;
|
|
||||||
+ case 1:
|
|
||||||
+ platform_device_register_simple("ltq_asc", 1,
|
|
||||||
+ ltq_asc1_resources, ARRAY_SIZE(ltq_asc1_resources));
|
|
||||||
+ break;
|
|
||||||
+ default:
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+#ifdef CONFIG_PCI
|
|
||||||
+/* pci */
|
|
||||||
+static struct platform_device ltq_pci = {
|
|
||||||
+ .name = "ltq_pci",
|
|
||||||
+ .num_resources = 0,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+void __init ltq_register_pci(struct ltq_pci_data *data)
|
|
||||||
+{
|
|
||||||
+ ltq_pci.dev.platform_data = data;
|
|
||||||
+ platform_device_register(<q_pci);
|
|
||||||
+}
|
|
||||||
+#else
|
|
||||||
+void __init ltq_register_pci(struct ltq_pci_data *data)
|
|
||||||
+{
|
|
||||||
+ pr_err("kernel is compiled without PCI support\n");
|
|
||||||
+}
|
|
||||||
+#endif
|
|
||||||
diff --git a/arch/mips/lantiq/devices.h b/arch/mips/lantiq/devices.h
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000..2947bb1
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/arch/mips/lantiq/devices.h
|
|
||||||
@@ -0,0 +1,23 @@
|
|
||||||
+/*
|
|
||||||
+ * 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_DEVICES_H__
|
|
||||||
+#define _LTQ_DEVICES_H__
|
|
||||||
+
|
|
||||||
+#include <lantiq_platform.h>
|
|
||||||
+#include <linux/mtd/physmap.h>
|
|
||||||
+
|
|
||||||
+#define IRQ_RES(resname, irq) \
|
|
||||||
+ {.name = #resname, .start = (irq), .flags = IORESOURCE_IRQ}
|
|
||||||
+
|
|
||||||
+extern void ltq_register_nor(struct physmap_flash_data *data);
|
|
||||||
+extern void ltq_register_wdt(void);
|
|
||||||
+extern void ltq_register_asc(int port);
|
|
||||||
+extern void ltq_register_pci(struct ltq_pci_data *data);
|
|
||||||
+
|
|
||||||
+#endif
|
|
||||||
diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile
|
|
||||||
index 9c85ff9..74ce438 100644
|
|
||||||
--- 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
|
|
||||||
+obj-y := pmu.o ebu.o reset.o gpio.o devices.o
|
|
||||||
|
|
||||||
obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o
|
|
||||||
obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o
|
|
||||||
diff --git a/arch/mips/lantiq/xway/devices.c b/arch/mips/lantiq/xway/devices.c
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000..a71b3b5
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/arch/mips/lantiq/xway/devices.c
|
|
||||||
@@ -0,0 +1,98 @@
|
|
||||||
+/*
|
|
||||||
+ * 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/module.h>
|
|
||||||
+#include <linux/types.h>
|
|
||||||
+#include <linux/string.h>
|
|
||||||
+#include <linux/mtd/physmap.h>
|
|
||||||
+#include <linux/kernel.h>
|
|
||||||
+#include <linux/reboot.h>
|
|
||||||
+#include <linux/platform_device.h>
|
|
||||||
+#include <linux/leds.h>
|
|
||||||
+#include <linux/etherdevice.h>
|
|
||||||
+#include <linux/reboot.h>
|
|
||||||
+#include <linux/time.h>
|
|
||||||
+#include <linux/io.h>
|
|
||||||
+#include <linux/gpio.h>
|
|
||||||
+#include <linux/leds.h>
|
|
||||||
+
|
|
||||||
+#include <asm/bootinfo.h>
|
|
||||||
+#include <asm/irq.h>
|
|
||||||
+
|
|
||||||
+#include <lantiq_soc.h>
|
|
||||||
+#include <lantiq_irq.h>
|
|
||||||
+#include <lantiq_platform.h>
|
|
||||||
+
|
|
||||||
+#include "devices.h"
|
|
||||||
+
|
|
||||||
+/* gpio */
|
|
||||||
+static struct resource ltq_gpio_resource[] = {
|
|
||||||
+ {
|
|
||||||
+ .name = "gpio0",
|
|
||||||
+ .start = LTQ_GPIO0_BASE_ADDR,
|
|
||||||
+ .end = LTQ_GPIO0_BASE_ADDR + LTQ_GPIO_SIZE - 1,
|
|
||||||
+ .flags = IORESOURCE_MEM,
|
|
||||||
+ }, {
|
|
||||||
+ .name = "gpio1",
|
|
||||||
+ .start = LTQ_GPIO1_BASE_ADDR,
|
|
||||||
+ .end = LTQ_GPIO1_BASE_ADDR + LTQ_GPIO_SIZE - 1,
|
|
||||||
+ .flags = IORESOURCE_MEM,
|
|
||||||
+ }, {
|
|
||||||
+ .name = "gpio2",
|
|
||||||
+ .start = LTQ_GPIO2_BASE_ADDR,
|
|
||||||
+ .end = LTQ_GPIO2_BASE_ADDR + LTQ_GPIO_SIZE - 1,
|
|
||||||
+ .flags = IORESOURCE_MEM,
|
|
||||||
+ }
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+void __init ltq_register_gpio(void)
|
|
||||||
+{
|
|
||||||
+ platform_device_register_simple("ltq_gpio", 0,
|
|
||||||
+ <q_gpio_resource[0], 1);
|
|
||||||
+ platform_device_register_simple("ltq_gpio", 1,
|
|
||||||
+ <q_gpio_resource[1], 1);
|
|
||||||
+
|
|
||||||
+ /* AR9 and VR9 have an extra gpio block */
|
|
||||||
+ if (ltq_is_ar9() || ltq_is_vr9()) {
|
|
||||||
+ platform_device_register_simple("ltq_gpio", 2,
|
|
||||||
+ <q_gpio_resource[2], 1);
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+/* serial to parallel conversion */
|
|
||||||
+static struct resource ltq_stp_resource = {
|
|
||||||
+ .name = "stp",
|
|
||||||
+ .start = LTQ_STP_BASE_ADDR,
|
|
||||||
+ .end = LTQ_STP_BASE_ADDR + LTQ_STP_SIZE - 1,
|
|
||||||
+ .flags = IORESOURCE_MEM,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+void __init ltq_register_gpio_stp(void)
|
|
||||||
+{
|
|
||||||
+ platform_device_register_simple("ltq_stp", 0, <q_stp_resource, 1);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+/* asc ports - amazon se has its own serial mapping */
|
|
||||||
+static struct resource ltq_ase_asc_resources[] = {
|
|
||||||
+ {
|
|
||||||
+ .name = "asc0",
|
|
||||||
+ .start = LTQ_ASC1_BASE_ADDR,
|
|
||||||
+ .end = LTQ_ASC1_BASE_ADDR + LTQ_ASC_SIZE - 1,
|
|
||||||
+ .flags = IORESOURCE_MEM,
|
|
||||||
+ },
|
|
||||||
+ IRQ_RES(tx, LTQ_ASC_ASE_TIR),
|
|
||||||
+ IRQ_RES(rx, LTQ_ASC_ASE_RIR),
|
|
||||||
+ IRQ_RES(err, LTQ_ASC_ASE_EIR),
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+void __init ltq_register_ase_asc(void)
|
|
||||||
+{
|
|
||||||
+ platform_device_register_simple("ltq_asc", 0,
|
|
||||||
+ ltq_ase_asc_resources, ARRAY_SIZE(ltq_ase_asc_resources));
|
|
||||||
+}
|
|
||||||
diff --git a/arch/mips/lantiq/xway/devices.h b/arch/mips/lantiq/xway/devices.h
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000..51f56b5
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/arch/mips/lantiq/xway/devices.h
|
|
||||||
@@ -0,0 +1,18 @@
|
|
||||||
+/*
|
|
||||||
+ * 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_DEVICES_XWAY_H__
|
|
||||||
+#define _LTQ_DEVICES_XWAY_H__
|
|
||||||
+
|
|
||||||
+#include "../devices.h"
|
|
||||||
+
|
|
||||||
+extern void ltq_register_gpio(void);
|
|
||||||
+extern void ltq_register_gpio_stp(void);
|
|
||||||
+extern void ltq_register_ase_asc(void);
|
|
||||||
+
|
|
||||||
+#endif
|
|
||||||
--
|
|
||||||
1.7.2.3
|
|
||||||
|
|
@ -1,170 +0,0 @@ |
|||||||
From 52a5369d1067d4feddbfa7ff4486a77ac9a2971e Mon Sep 17 00:00:00 2001
|
|
||||||
From: John Crispin <blogic@openwrt.org>
|
|
||||||
Date: Wed, 30 Mar 2011 09:27:54 +0200
|
|
||||||
Subject: [PATCH 06/13] MIPS: Lantiq: Add mips_machine support
|
|
||||||
|
|
||||||
This patch adds support for Gabor's mips_machine patch.
|
|
||||||
|
|
||||||
Signed-off-by: John Crispin <blogic@openwrt.org>
|
|
||||||
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
|
|
||||||
Cc: Gabor Juhos <juhosg@openwrt.org>
|
|
||||||
Cc: linux-mips@linux-mips.org
|
|
||||||
Patchwork: https://patchwork.linux-mips.org/patch/2251/
|
|
||||||
Patchwork: https://patchwork.linux-mips.org/patch/2358/
|
|
||||||
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
|
|
||||||
---
|
|
||||||
arch/mips/Kconfig | 1 +
|
|
||||||
arch/mips/lantiq/machtypes.h | 18 ++++++++++++++++++
|
|
||||||
arch/mips/lantiq/prom.h | 1 +
|
|
||||||
arch/mips/lantiq/setup.c | 25 +++++++++++++++++++++++++
|
|
||||||
arch/mips/lantiq/xway/Makefile | 4 ++--
|
|
||||||
arch/mips/lantiq/xway/setup-ase.c | 19 +++++++++++++++++++
|
|
||||||
arch/mips/lantiq/xway/setup-xway.c | 20 ++++++++++++++++++++
|
|
||||||
7 files changed, 86 insertions(+), 2 deletions(-)
|
|
||||||
create mode 100644 arch/mips/lantiq/machtypes.h
|
|
||||||
create mode 100644 arch/mips/lantiq/xway/setup-ase.c
|
|
||||||
create mode 100644 arch/mips/lantiq/xway/setup-xway.c
|
|
||||||
|
|
||||||
--- a/arch/mips/Kconfig
|
|
||||||
+++ b/arch/mips/Kconfig
|
|
||||||
@@ -190,6 +190,7 @@
|
|
||||||
select SWAP_IO_SPACE
|
|
||||||
select BOOT_RAW
|
|
||||||
select HAVE_CLK
|
|
||||||
+ select MIPS_MACHINE
|
|
||||||
|
|
||||||
config LASAT
|
|
||||||
bool "LASAT Networks platforms"
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/arch/mips/lantiq/machtypes.h
|
|
||||||
@@ -0,0 +1,18 @@
|
|
||||||
+/*
|
|
||||||
+ * 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 _LANTIQ_MACH_H__
|
|
||||||
+#define _LANTIQ_MACH_H__
|
|
||||||
+
|
|
||||||
+#include <asm/mips_machine.h>
|
|
||||||
+
|
|
||||||
+enum lantiq_mach_type {
|
|
||||||
+ LTQ_MACH_GENERIC = 0,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+#endif
|
|
||||||
--- a/arch/mips/lantiq/prom.h
|
|
||||||
+++ b/arch/mips/lantiq/prom.h
|
|
||||||
@@ -20,5 +20,6 @@
|
|
||||||
};
|
|
||||||
|
|
||||||
extern void ltq_soc_detect(struct ltq_soc_info *i);
|
|
||||||
+extern void ltq_soc_setup(void);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
--- a/arch/mips/lantiq/setup.c
|
|
||||||
+++ b/arch/mips/lantiq/setup.c
|
|
||||||
@@ -14,6 +14,12 @@
|
|
||||||
|
|
||||||
#include <lantiq_soc.h>
|
|
||||||
|
|
||||||
+#include "machtypes.h"
|
|
||||||
+#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 */
|
|
||||||
@@ -32,10 +38,32 @@
|
|
||||||
if (!strncmp(e, "memsize=", 8)) {
|
|
||||||
e += 8;
|
|
||||||
if (strict_strtoul(e, 0, &memsize))
|
|
||||||
- pr_warn("bad memsize specified\n");
|
|
||||||
+ pr_warning("bad memsize specified\n");
|
|
||||||
}
|
|
||||||
envp++;
|
|
||||||
}
|
|
||||||
memsize *= 1024 * 1024;
|
|
||||||
add_memory_region(0x00000000, memsize, BOOT_MEM_RAM);
|
|
||||||
+ physical_memsize = memsize;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int __init
|
|
||||||
+lantiq_setup(void)
|
|
||||||
+{
|
|
||||||
+ ltq_soc_setup();
|
|
||||||
+ mips_machine_setup();
|
|
||||||
+ return 0;
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+arch_initcall(lantiq_setup);
|
|
||||||
+
|
|
||||||
+static void __init
|
|
||||||
+lantiq_generic_init(void)
|
|
||||||
+{
|
|
||||||
+ /* Nothing to do */
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+MIPS_MACHINE(LTQ_MACH_GENERIC,
|
|
||||||
+ "Generic",
|
|
||||||
+ "Generic Lantiq based board",
|
|
||||||
+ lantiq_generic_init);
|
|
||||||
--- 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 devices.o
|
|
||||||
|
|
||||||
-obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o
|
|
||||||
-obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.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
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/arch/mips/lantiq/xway/setup-ase.c
|
|
||||||
@@ -0,0 +1,19 @@
|
|
||||||
+/*
|
|
||||||
+ * 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 John Crispin <blogic@openwrt.org>
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#include <lantiq_soc.h>
|
|
||||||
+
|
|
||||||
+#include "../prom.h"
|
|
||||||
+#include "devices.h"
|
|
||||||
+
|
|
||||||
+void __init ltq_soc_setup(void)
|
|
||||||
+{
|
|
||||||
+ ltq_register_ase_asc();
|
|
||||||
+ ltq_register_gpio();
|
|
||||||
+ ltq_register_wdt();
|
|
||||||
+}
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/arch/mips/lantiq/xway/setup-xway.c
|
|
||||||
@@ -0,0 +1,20 @@
|
|
||||||
+/*
|
|
||||||
+ * 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 John Crispin <blogic@openwrt.org>
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#include <lantiq_soc.h>
|
|
||||||
+
|
|
||||||
+#include "../prom.h"
|
|
||||||
+#include "devices.h"
|
|
||||||
+
|
|
||||||
+void __init ltq_soc_setup(void)
|
|
||||||
+{
|
|
||||||
+ ltq_register_asc(0);
|
|
||||||
+ ltq_register_asc(1);
|
|
||||||
+ ltq_register_gpio();
|
|
||||||
+ ltq_register_wdt();
|
|
||||||
+}
|
|
@ -1,230 +0,0 @@ |
|||||||
From ab2182fc419548455d03979683eb0e92c372ed79 Mon Sep 17 00:00:00 2001
|
|
||||||
From: John Crispin <blogic@openwrt.org>
|
|
||||||
Date: Wed, 30 Mar 2011 09:27:55 +0200
|
|
||||||
Subject: [PATCH 07/13] MIPS: Lantiq: Add machtypes for lantiq eval kits
|
|
||||||
|
|
||||||
This patch adds mach specific code for the Lantiq EASY50712/50601 evaluation
|
|
||||||
boards
|
|
||||||
|
|
||||||
Signed-off-by: John Crispin <blogic@openwrt.org>
|
|
||||||
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
|
|
||||||
Cc: linux-mips@linux-mips.org
|
|
||||||
Patchwork: https://patchwork.linux-mips.org/patch/2255/
|
|
||||||
Patchwork: https://patchwork.linux-mips.org/patch/2361/
|
|
||||||
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
|
|
||||||
---
|
|
||||||
arch/mips/lantiq/Kconfig | 2 +
|
|
||||||
arch/mips/lantiq/machtypes.h | 2 +
|
|
||||||
arch/mips/lantiq/xway/Kconfig | 23 +++++++++++
|
|
||||||
arch/mips/lantiq/xway/Makefile | 3 +
|
|
||||||
arch/mips/lantiq/xway/mach-easy50601.c | 57 ++++++++++++++++++++++++++
|
|
||||||
arch/mips/lantiq/xway/mach-easy50712.c | 68 ++++++++++++++++++++++++++++++++
|
|
||||||
6 files changed, 155 insertions(+), 0 deletions(-)
|
|
||||||
create mode 100644 arch/mips/lantiq/xway/Kconfig
|
|
||||||
create mode 100644 arch/mips/lantiq/xway/mach-easy50601.c
|
|
||||||
create mode 100644 arch/mips/lantiq/xway/mach-easy50712.c
|
|
||||||
|
|
||||||
diff --git a/arch/mips/lantiq/Kconfig b/arch/mips/lantiq/Kconfig
|
|
||||||
index 2780461..3fccf21 100644
|
|
||||||
--- a/arch/mips/lantiq/Kconfig
|
|
||||||
+++ b/arch/mips/lantiq/Kconfig
|
|
||||||
@@ -18,4 +18,6 @@ config SOC_XWAY
|
|
||||||
select HW_HAS_PCI
|
|
||||||
endchoice
|
|
||||||
|
|
||||||
+source "arch/mips/lantiq/xway/Kconfig"
|
|
||||||
+
|
|
||||||
endif
|
|
||||||
diff --git a/arch/mips/lantiq/machtypes.h b/arch/mips/lantiq/machtypes.h
|
|
||||||
index ffcacfc..7e01b8c 100644
|
|
||||||
--- a/arch/mips/lantiq/machtypes.h
|
|
||||||
+++ b/arch/mips/lantiq/machtypes.h
|
|
||||||
@@ -13,6 +13,8 @@
|
|
||||||
|
|
||||||
enum lantiq_mach_type {
|
|
||||||
LTQ_MACH_GENERIC = 0,
|
|
||||||
+ LTQ_MACH_EASY50712, /* Danube evaluation board */
|
|
||||||
+ LTQ_MACH_EASY50601, /* Amazon SE evaluation board */
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
diff --git a/arch/mips/lantiq/xway/Kconfig b/arch/mips/lantiq/xway/Kconfig
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000..2b857de
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/arch/mips/lantiq/xway/Kconfig
|
|
||||||
@@ -0,0 +1,23 @@
|
|
||||||
+if SOC_XWAY
|
|
||||||
+
|
|
||||||
+menu "MIPS Machine"
|
|
||||||
+
|
|
||||||
+config LANTIQ_MACH_EASY50712
|
|
||||||
+ bool "Easy50712 - Danube"
|
|
||||||
+ default y
|
|
||||||
+
|
|
||||||
+endmenu
|
|
||||||
+
|
|
||||||
+endif
|
|
||||||
+
|
|
||||||
+if SOC_AMAZON_SE
|
|
||||||
+
|
|
||||||
+menu "MIPS Machine"
|
|
||||||
+
|
|
||||||
+config LANTIQ_MACH_EASY50601
|
|
||||||
+ bool "Easy50601 - Amazon SE"
|
|
||||||
+ default y
|
|
||||||
+
|
|
||||||
+endmenu
|
|
||||||
+
|
|
||||||
+endif
|
|
||||||
diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile
|
|
||||||
index 8c06a97..b1d3640 100644
|
|
||||||
--- a/arch/mips/lantiq/xway/Makefile
|
|
||||||
+++ b/arch/mips/lantiq/xway/Makefile
|
|
||||||
@@ -2,3 +2,6 @@ obj-y := pmu.o ebu.o reset.o gpio.o devices.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
|
|
||||||
+
|
|
||||||
+obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o
|
|
||||||
+obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o
|
|
||||||
diff --git a/arch/mips/lantiq/xway/mach-easy50601.c b/arch/mips/lantiq/xway/mach-easy50601.c
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000..d5aaf63
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/arch/mips/lantiq/xway/mach-easy50601.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 <lantiq.h>
|
|
||||||
+
|
|
||||||
+#include "../machtypes.h"
|
|
||||||
+#include "devices.h"
|
|
||||||
+
|
|
||||||
+static struct mtd_partition easy50601_partitions[] = {
|
|
||||||
+ {
|
|
||||||
+ .name = "uboot",
|
|
||||||
+ .offset = 0x0,
|
|
||||||
+ .size = 0x10000,
|
|
||||||
+ },
|
|
||||||
+ {
|
|
||||||
+ .name = "uboot_env",
|
|
||||||
+ .offset = 0x10000,
|
|
||||||
+ .size = 0x10000,
|
|
||||||
+ },
|
|
||||||
+ {
|
|
||||||
+ .name = "linux",
|
|
||||||
+ .offset = 0x20000,
|
|
||||||
+ .size = 0xE0000,
|
|
||||||
+ },
|
|
||||||
+ {
|
|
||||||
+ .name = "rootfs",
|
|
||||||
+ .offset = 0x100000,
|
|
||||||
+ .size = 0x300000,
|
|
||||||
+ },
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static struct physmap_flash_data easy50601_flash_data = {
|
|
||||||
+ .nr_parts = ARRAY_SIZE(easy50601_partitions),
|
|
||||||
+ .parts = easy50601_partitions,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static void __init easy50601_init(void)
|
|
||||||
+{
|
|
||||||
+ ltq_register_nor(&easy50601_flash_data);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+MIPS_MACHINE(LTQ_MACH_EASY50601,
|
|
||||||
+ "EASY50601",
|
|
||||||
+ "EASY50601 Eval Board",
|
|
||||||
+ easy50601_init);
|
|
||||||
diff --git a/arch/mips/lantiq/xway/mach-easy50712.c b/arch/mips/lantiq/xway/mach-easy50712.c
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000..e5e7e09
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/arch/mips/lantiq/xway/mach-easy50712.c
|
|
||||||
@@ -0,0 +1,68 @@
|
|
||||||
+/*
|
|
||||||
+ * 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 <lantiq_soc.h>
|
|
||||||
+#include <irq.h>
|
|
||||||
+
|
|
||||||
+#include "../machtypes.h"
|
|
||||||
+#include "devices.h"
|
|
||||||
+
|
|
||||||
+static struct mtd_partition easy50712_partitions[] = {
|
|
||||||
+ {
|
|
||||||
+ .name = "uboot",
|
|
||||||
+ .offset = 0x0,
|
|
||||||
+ .size = 0x10000,
|
|
||||||
+ },
|
|
||||||
+ {
|
|
||||||
+ .name = "uboot_env",
|
|
||||||
+ .offset = 0x10000,
|
|
||||||
+ .size = 0x10000,
|
|
||||||
+ },
|
|
||||||
+ {
|
|
||||||
+ .name = "linux",
|
|
||||||
+ .offset = 0x20000,
|
|
||||||
+ .size = 0xe0000,
|
|
||||||
+ },
|
|
||||||
+ {
|
|
||||||
+ .name = "rootfs",
|
|
||||||
+ .offset = 0x100000,
|
|
||||||
+ .size = 0x300000,
|
|
||||||
+ },
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static struct physmap_flash_data easy50712_flash_data = {
|
|
||||||
+ .nr_parts = ARRAY_SIZE(easy50712_partitions),
|
|
||||||
+ .parts = easy50712_partitions,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+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 void __init easy50712_init(void)
|
|
||||||
+{
|
|
||||||
+ ltq_register_gpio_stp();
|
|
||||||
+ ltq_register_nor(&easy50712_flash_data);
|
|
||||||
+ ltq_register_pci(<q_pci_data);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+MIPS_MACHINE(LTQ_MACH_EASY50712,
|
|
||||||
+ "EASY50712",
|
|
||||||
+ "EASY50712 Eval Board",
|
|
||||||
+ easy50712_init);
|
|
||||||
--
|
|
||||||
1.7.2.3
|
|
||||||
|
|
@ -1,330 +0,0 @@ |
|||||||
From f9391211e47cdcc31f341d710efef4b3b46c333d Mon Sep 17 00:00:00 2001
|
|
||||||
From: John Crispin <blogic@openwrt.org>
|
|
||||||
Date: Wed, 30 Mar 2011 09:27:56 +0200
|
|
||||||
Subject: [PATCH 08/13] MIPS: Lantiq: Add more gpio drivers
|
|
||||||
|
|
||||||
The XWAY family allows to extend the number of gpios by using shift registers or latches. This patch adds the 2 drivers needed for this. The extended gpios are output only.
|
|
||||||
|
|
||||||
[ralf@linux-mips.org: Fixed ltq_stp_probe section() attributes.]
|
|
||||||
|
|
||||||
Signed-off-by: John Crispin <blogic@openwrt.org>
|
|
||||||
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
|
|
||||||
Cc: linux-mips@linux-mips.org
|
|
||||||
Patchwork: https://patchwork.linux-mips.org/patch/2258/
|
|
||||||
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
|
|
||||||
---
|
|
||||||
arch/mips/lantiq/xway/Makefile | 2 +-
|
|
||||||
arch/mips/lantiq/xway/gpio_ebu.c | 126 ++++++++++++++++++++++++++++++
|
|
||||||
arch/mips/lantiq/xway/gpio_stp.c | 157 ++++++++++++++++++++++++++++++++++++++
|
|
||||||
3 files changed, 284 insertions(+), 1 deletions(-)
|
|
||||||
create mode 100644 arch/mips/lantiq/xway/gpio_ebu.c
|
|
||||||
create mode 100644 arch/mips/lantiq/xway/gpio_stp.c
|
|
||||||
|
|
||||||
diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile
|
|
||||||
index b1d3640..6b5e07e 100644
|
|
||||||
--- 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 devices.o
|
|
||||||
+obj-y := pmu.o ebu.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.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
|
|
||||||
diff --git a/arch/mips/lantiq/xway/gpio_ebu.c b/arch/mips/lantiq/xway/gpio_ebu.c
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000..a479355
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/arch/mips/lantiq/xway/gpio_ebu.c
|
|
||||||
@@ -0,0 +1,126 @@
|
|
||||||
+/*
|
|
||||||
+ * 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/module.h>
|
|
||||||
+#include <linux/types.h>
|
|
||||||
+#include <linux/platform_device.h>
|
|
||||||
+#include <linux/mutex.h>
|
|
||||||
+#include <linux/gpio.h>
|
|
||||||
+#include <linux/io.h>
|
|
||||||
+
|
|
||||||
+#include <lantiq_soc.h>
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * By attaching hardware latches to the EBU it is possible to create output
|
|
||||||
+ * only gpios. This driver configures a special memory address, which when
|
|
||||||
+ * written to outputs 16 bit to the latches.
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#define LTQ_EBU_BUSCON 0x1e7ff /* 16 bit access, slowest timing */
|
|
||||||
+#define LTQ_EBU_WP 0x80000000 /* write protect bit */
|
|
||||||
+
|
|
||||||
+/* we keep a shadow value of the last value written to the ebu */
|
|
||||||
+static int ltq_ebu_gpio_shadow = 0x0;
|
|
||||||
+static void __iomem *ltq_ebu_gpio_membase;
|
|
||||||
+
|
|
||||||
+static void ltq_ebu_apply(void)
|
|
||||||
+{
|
|
||||||
+ unsigned long flags;
|
|
||||||
+
|
|
||||||
+ spin_lock_irqsave(&ebu_lock, flags);
|
|
||||||
+ ltq_ebu_w32(LTQ_EBU_BUSCON, LTQ_EBU_BUSCON1);
|
|
||||||
+ *((__u16 *)ltq_ebu_gpio_membase) = ltq_ebu_gpio_shadow;
|
|
||||||
+ ltq_ebu_w32(LTQ_EBU_BUSCON | LTQ_EBU_WP, LTQ_EBU_BUSCON1);
|
|
||||||
+ spin_unlock_irqrestore(&ebu_lock, flags);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void ltq_ebu_set(struct gpio_chip *chip, unsigned offset, int value)
|
|
||||||
+{
|
|
||||||
+ if (value)
|
|
||||||
+ ltq_ebu_gpio_shadow |= (1 << offset);
|
|
||||||
+ else
|
|
||||||
+ ltq_ebu_gpio_shadow &= ~(1 << offset);
|
|
||||||
+ ltq_ebu_apply();
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int ltq_ebu_direction_output(struct gpio_chip *chip, unsigned offset,
|
|
||||||
+ int value)
|
|
||||||
+{
|
|
||||||
+ ltq_ebu_set(chip, offset, value);
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static struct gpio_chip ltq_ebu_chip = {
|
|
||||||
+ .label = "ltq_ebu",
|
|
||||||
+ .direction_output = ltq_ebu_direction_output,
|
|
||||||
+ .set = ltq_ebu_set,
|
|
||||||
+ .base = 72,
|
|
||||||
+ .ngpio = 16,
|
|
||||||
+ .can_sleep = 1,
|
|
||||||
+ .owner = THIS_MODULE,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static int ltq_ebu_probe(struct platform_device *pdev)
|
|
||||||
+{
|
|
||||||
+ int ret = 0;
|
|
||||||
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
||||||
+
|
|
||||||
+ if (!res) {
|
|
||||||
+ dev_err(&pdev->dev, "failed to get memory resource\n");
|
|
||||||
+ return -ENOENT;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ res = devm_request_mem_region(&pdev->dev, res->start,
|
|
||||||
+ resource_size(res), dev_name(&pdev->dev));
|
|
||||||
+ if (!res) {
|
|
||||||
+ dev_err(&pdev->dev, "failed to request memory resource\n");
|
|
||||||
+ return -EBUSY;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ ltq_ebu_gpio_membase = devm_ioremap_nocache(&pdev->dev, res->start,
|
|
||||||
+ resource_size(res));
|
|
||||||
+ if (!ltq_ebu_gpio_membase) {
|
|
||||||
+ dev_err(&pdev->dev, "Failed to ioremap mem region\n");
|
|
||||||
+ return -ENOMEM;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* grab the default shadow value passed form the platform code */
|
|
||||||
+ ltq_ebu_gpio_shadow = (unsigned int) pdev->dev.platform_data;
|
|
||||||
+
|
|
||||||
+ /* tell the ebu controller which memory address we will be using */
|
|
||||||
+ ltq_ebu_w32(pdev->resource->start | 0x1, LTQ_EBU_ADDRSEL1);
|
|
||||||
+
|
|
||||||
+ /* write protect the region */
|
|
||||||
+ ltq_ebu_w32(LTQ_EBU_BUSCON | LTQ_EBU_WP, LTQ_EBU_BUSCON1);
|
|
||||||
+
|
|
||||||
+ ret = gpiochip_add(<q_ebu_chip);
|
|
||||||
+ if (!ret)
|
|
||||||
+ ltq_ebu_apply();
|
|
||||||
+ return ret;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static struct platform_driver ltq_ebu_driver = {
|
|
||||||
+ .probe = ltq_ebu_probe,
|
|
||||||
+ .driver = {
|
|
||||||
+ .name = "ltq_ebu",
|
|
||||||
+ .owner = THIS_MODULE,
|
|
||||||
+ },
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static int __init ltq_ebu_init(void)
|
|
||||||
+{
|
|
||||||
+ int ret = platform_driver_register(<q_ebu_driver);
|
|
||||||
+
|
|
||||||
+ if (ret)
|
|
||||||
+ pr_info("ltq_ebu : Error registering platfom driver!");
|
|
||||||
+ return ret;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+postcore_initcall(ltq_ebu_init);
|
|
||||||
diff --git a/arch/mips/lantiq/xway/gpio_stp.c b/arch/mips/lantiq/xway/gpio_stp.c
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000..67d59d6
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/arch/mips/lantiq/xway/gpio_stp.c
|
|
||||||
@@ -0,0 +1,157 @@
|
|
||||||
+/*
|
|
||||||
+ * 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) 2007 John Crispin <blogic@openwrt.org>
|
|
||||||
+ *
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#include <linux/slab.h>
|
|
||||||
+#include <linux/init.h>
|
|
||||||
+#include <linux/module.h>
|
|
||||||
+#include <linux/types.h>
|
|
||||||
+#include <linux/platform_device.h>
|
|
||||||
+#include <linux/mutex.h>
|
|
||||||
+#include <linux/io.h>
|
|
||||||
+#include <linux/gpio.h>
|
|
||||||
+
|
|
||||||
+#include <lantiq_soc.h>
|
|
||||||
+
|
|
||||||
+#define LTQ_STP_CON0 0x00
|
|
||||||
+#define LTQ_STP_CON1 0x04
|
|
||||||
+#define LTQ_STP_CPU0 0x08
|
|
||||||
+#define LTQ_STP_CPU1 0x0C
|
|
||||||
+#define LTQ_STP_AR 0x10
|
|
||||||
+
|
|
||||||
+#define LTQ_STP_CON_SWU (1 << 31)
|
|
||||||
+#define LTQ_STP_2HZ 0
|
|
||||||
+#define LTQ_STP_4HZ (1 << 23)
|
|
||||||
+#define LTQ_STP_8HZ (2 << 23)
|
|
||||||
+#define LTQ_STP_10HZ (3 << 23)
|
|
||||||
+#define LTQ_STP_SPEED_MASK (0xf << 23)
|
|
||||||
+#define LTQ_STP_UPD_FPI (1 << 31)
|
|
||||||
+#define LTQ_STP_UPD_MASK (3 << 30)
|
|
||||||
+#define LTQ_STP_ADSL_SRC (3 << 24)
|
|
||||||
+
|
|
||||||
+#define LTQ_STP_GROUP0 (1 << 0)
|
|
||||||
+
|
|
||||||
+#define LTQ_STP_RISING 0
|
|
||||||
+#define LTQ_STP_FALLING (1 << 26)
|
|
||||||
+#define LTQ_STP_EDGE_MASK (1 << 26)
|
|
||||||
+
|
|
||||||
+#define ltq_stp_r32(reg) __raw_readl(ltq_stp_membase + reg)
|
|
||||||
+#define ltq_stp_w32(val, reg) __raw_writel(val, ltq_stp_membase + reg)
|
|
||||||
+#define ltq_stp_w32_mask(clear, set, reg) \
|
|
||||||
+ ltq_w32((ltq_r32(ltq_stp_membase + reg) & ~(clear)) | (set), \
|
|
||||||
+ ltq_stp_membase + (reg))
|
|
||||||
+
|
|
||||||
+static int ltq_stp_shadow = 0xffff;
|
|
||||||
+static void __iomem *ltq_stp_membase;
|
|
||||||
+
|
|
||||||
+static void ltq_stp_set(struct gpio_chip *chip, unsigned offset, int value)
|
|
||||||
+{
|
|
||||||
+ if (value)
|
|
||||||
+ ltq_stp_shadow |= (1 << offset);
|
|
||||||
+ else
|
|
||||||
+ ltq_stp_shadow &= ~(1 << offset);
|
|
||||||
+ ltq_stp_w32(ltq_stp_shadow, LTQ_STP_CPU0);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int ltq_stp_direction_output(struct gpio_chip *chip, unsigned offset,
|
|
||||||
+ int value)
|
|
||||||
+{
|
|
||||||
+ ltq_stp_set(chip, offset, value);
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static struct gpio_chip ltq_stp_chip = {
|
|
||||||
+ .label = "ltq_stp",
|
|
||||||
+ .direction_output = ltq_stp_direction_output,
|
|
||||||
+ .set = ltq_stp_set,
|
|
||||||
+ .base = 48,
|
|
||||||
+ .ngpio = 24,
|
|
||||||
+ .can_sleep = 1,
|
|
||||||
+ .owner = THIS_MODULE,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static int ltq_stp_hw_init(void)
|
|
||||||
+{
|
|
||||||
+ /* the 3 pins used to control the external stp */
|
|
||||||
+ ltq_gpio_request(4, 1, 0, 1, "stp-st");
|
|
||||||
+ ltq_gpio_request(5, 1, 0, 1, "stp-d");
|
|
||||||
+ ltq_gpio_request(6, 1, 0, 1, "stp-sh");
|
|
||||||
+
|
|
||||||
+ /* sane defaults */
|
|
||||||
+ ltq_stp_w32(0, LTQ_STP_AR);
|
|
||||||
+ ltq_stp_w32(0, LTQ_STP_CPU0);
|
|
||||||
+ ltq_stp_w32(0, LTQ_STP_CPU1);
|
|
||||||
+ ltq_stp_w32(LTQ_STP_CON_SWU, LTQ_STP_CON0);
|
|
||||||
+ ltq_stp_w32(0, LTQ_STP_CON1);
|
|
||||||
+
|
|
||||||
+ /* rising or falling edge */
|
|
||||||
+ ltq_stp_w32_mask(LTQ_STP_EDGE_MASK, LTQ_STP_FALLING, LTQ_STP_CON0);
|
|
||||||
+
|
|
||||||
+ /* per default stp 15-0 are set */
|
|
||||||
+ ltq_stp_w32_mask(0, LTQ_STP_GROUP0, LTQ_STP_CON1);
|
|
||||||
+
|
|
||||||
+ /* stp are update periodically by the FPI bus */
|
|
||||||
+ ltq_stp_w32_mask(LTQ_STP_UPD_MASK, LTQ_STP_UPD_FPI, LTQ_STP_CON1);
|
|
||||||
+
|
|
||||||
+ /* set stp update speed */
|
|
||||||
+ ltq_stp_w32_mask(LTQ_STP_SPEED_MASK, LTQ_STP_8HZ, LTQ_STP_CON1);
|
|
||||||
+
|
|
||||||
+ /* tell the hardware that pin (led) 0 and 1 are controlled
|
|
||||||
+ * by the dsl arc
|
|
||||||
+ */
|
|
||||||
+ ltq_stp_w32_mask(0, LTQ_STP_ADSL_SRC, LTQ_STP_CON0);
|
|
||||||
+
|
|
||||||
+ ltq_pmu_enable(PMU_LED);
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int __devinit ltq_stp_probe(struct platform_device *pdev)
|
|
||||||
+{
|
|
||||||
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
||||||
+ int ret = 0;
|
|
||||||
+
|
|
||||||
+ if (!res)
|
|
||||||
+ return -ENOENT;
|
|
||||||
+ res = devm_request_mem_region(&pdev->dev, res->start,
|
|
||||||
+ resource_size(res), dev_name(&pdev->dev));
|
|
||||||
+ if (!res) {
|
|
||||||
+ dev_err(&pdev->dev, "failed to request STP memory\n");
|
|
||||||
+ return -EBUSY;
|
|
||||||
+ }
|
|
||||||
+ ltq_stp_membase = devm_ioremap_nocache(&pdev->dev, res->start,
|
|
||||||
+ resource_size(res));
|
|
||||||
+ if (!ltq_stp_membase) {
|
|
||||||
+ dev_err(&pdev->dev, "failed to remap STP memory\n");
|
|
||||||
+ return -ENOMEM;
|
|
||||||
+ }
|
|
||||||
+ ret = gpiochip_add(<q_stp_chip);
|
|
||||||
+ if (!ret)
|
|
||||||
+ ret = ltq_stp_hw_init();
|
|
||||||
+
|
|
||||||
+ return ret;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static struct platform_driver ltq_stp_driver = {
|
|
||||||
+ .probe = ltq_stp_probe,
|
|
||||||
+ .driver = {
|
|
||||||
+ .name = "ltq_stp",
|
|
||||||
+ .owner = THIS_MODULE,
|
|
||||||
+ },
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+int __init ltq_stp_init(void)
|
|
||||||
+{
|
|
||||||
+ int ret = platform_driver_register(<q_stp_driver);
|
|
||||||
+
|
|
||||||
+ if (ret)
|
|
||||||
+ pr_info("ltq_stp: error registering platfom driver");
|
|
||||||
+ return ret;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+postcore_initcall(ltq_stp_init);
|
|
||||||
--
|
|
||||||
1.7.2.3
|
|
||||||
|
|
@ -1,804 +0,0 @@ |
|||||||
From 1d2b44b1afa3ef081cd817dbf947d48eb8f5d21a Mon Sep 17 00:00:00 2001
|
|
||||||
From: John Crispin <blogic@openwrt.org>
|
|
||||||
Date: Tue, 5 Apr 2011 14:10:57 +0200
|
|
||||||
Subject: [PATCH 09/13] SERIAL: Lantiq: Add driver for MIPS Lantiq SOCs.
|
|
||||||
|
|
||||||
Signed-off-by: John Crispin <blogic@openwrt.org>
|
|
||||||
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
|
|
||||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
|
||||||
Cc: alan@lxorguk.ukuu.org.uk
|
|
||||||
Cc: linux-mips@linux-mips.org
|
|
||||||
Cc: linux-serial@vger.kernel.org
|
|
||||||
Patchwork: https://patchwork.linux-mips.org/patch/2269/
|
|
||||||
Acked-by: Alan Cox <alan@linux.intel.com>
|
|
||||||
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
|
|
||||||
---
|
|
||||||
drivers/tty/serial/Kconfig | 8 +
|
|
||||||
drivers/tty/serial/Makefile | 1 +
|
|
||||||
drivers/tty/serial/lantiq.c | 756 +++++++++++++++++++++++++++++++++++++++++++
|
|
||||||
3 files changed, 765 insertions(+), 0 deletions(-)
|
|
||||||
create mode 100644 drivers/tty/serial/lantiq.c
|
|
||||||
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/drivers/serial/lantiq.c
|
|
||||||
@@ -0,0 +1,756 @@
|
|
||||||
+/*
|
|
||||||
+ * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
|
|
||||||
+ *
|
|
||||||
+ * 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.
|
|
||||||
+ *
|
|
||||||
+ * 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
|
|
||||||
+ *
|
|
||||||
+ * Copyright (C) 2004 Infineon IFAP DC COM CPE
|
|
||||||
+ * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
|
|
||||||
+ * Copyright (C) 2007 John Crispin <blogic@openwrt.org>
|
|
||||||
+ * Copyright (C) 2010 Thomas Langer, <thomas.langer@lantiq.com>
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#include <linux/slab.h>
|
|
||||||
+#include <linux/module.h>
|
|
||||||
+#include <linux/ioport.h>
|
|
||||||
+#include <linux/init.h>
|
|
||||||
+#include <linux/console.h>
|
|
||||||
+#include <linux/sysrq.h>
|
|
||||||
+#include <linux/device.h>
|
|
||||||
+#include <linux/tty.h>
|
|
||||||
+#include <linux/tty_flip.h>
|
|
||||||
+#include <linux/serial_core.h>
|
|
||||||
+#include <linux/serial.h>
|
|
||||||
+#include <linux/platform_device.h>
|
|
||||||
+#include <linux/io.h>
|
|
||||||
+#include <linux/clk.h>
|
|
||||||
+
|
|
||||||
+#include <lantiq_soc.h>
|
|
||||||
+
|
|
||||||
+#define PORT_LTQ_ASC 111
|
|
||||||
+#define MAXPORTS 2
|
|
||||||
+#define UART_DUMMY_UER_RX 1
|
|
||||||
+#define DRVNAME "ltq_asc"
|
|
||||||
+#ifdef __BIG_ENDIAN
|
|
||||||
+#define LTQ_ASC_TBUF (0x0020 + 3)
|
|
||||||
+#define LTQ_ASC_RBUF (0x0024 + 3)
|
|
||||||
+#else
|
|
||||||
+#define LTQ_ASC_TBUF 0x0020
|
|
||||||
+#define LTQ_ASC_RBUF 0x0024
|
|
||||||
+#endif
|
|
||||||
+#define LTQ_ASC_FSTAT 0x0048
|
|
||||||
+#define LTQ_ASC_WHBSTATE 0x0018
|
|
||||||
+#define LTQ_ASC_STATE 0x0014
|
|
||||||
+#define LTQ_ASC_IRNCR 0x00F8
|
|
||||||
+#define LTQ_ASC_CLC 0x0000
|
|
||||||
+#define LTQ_ASC_ID 0x0008
|
|
||||||
+#define LTQ_ASC_PISEL 0x0004
|
|
||||||
+#define LTQ_ASC_TXFCON 0x0044
|
|
||||||
+#define LTQ_ASC_RXFCON 0x0040
|
|
||||||
+#define LTQ_ASC_CON 0x0010
|
|
||||||
+#define LTQ_ASC_BG 0x0050
|
|
||||||
+#define LTQ_ASC_IRNREN 0x00F4
|
|
||||||
+
|
|
||||||
+#define ASC_IRNREN_TX 0x1
|
|
||||||
+#define ASC_IRNREN_RX 0x2
|
|
||||||
+#define ASC_IRNREN_ERR 0x4
|
|
||||||
+#define ASC_IRNREN_TX_BUF 0x8
|
|
||||||
+#define ASC_IRNCR_TIR 0x1
|
|
||||||
+#define ASC_IRNCR_RIR 0x2
|
|
||||||
+#define ASC_IRNCR_EIR 0x4
|
|
||||||
+
|
|
||||||
+#define ASCOPT_CSIZE 0x3
|
|
||||||
+#define TXFIFO_FL 1
|
|
||||||
+#define RXFIFO_FL 1
|
|
||||||
+#define ASCCLC_DISS 0x2
|
|
||||||
+#define ASCCLC_RMCMASK 0x0000FF00
|
|
||||||
+#define ASCCLC_RMCOFFSET 8
|
|
||||||
+#define ASCCON_M_8ASYNC 0x0
|
|
||||||
+#define ASCCON_M_7ASYNC 0x2
|
|
||||||
+#define ASCCON_ODD 0x00000020
|
|
||||||
+#define ASCCON_STP 0x00000080
|
|
||||||
+#define ASCCON_BRS 0x00000100
|
|
||||||
+#define ASCCON_FDE 0x00000200
|
|
||||||
+#define ASCCON_R 0x00008000
|
|
||||||
+#define ASCCON_FEN 0x00020000
|
|
||||||
+#define ASCCON_ROEN 0x00080000
|
|
||||||
+#define ASCCON_TOEN 0x00100000
|
|
||||||
+#define ASCSTATE_PE 0x00010000
|
|
||||||
+#define ASCSTATE_FE 0x00020000
|
|
||||||
+#define ASCSTATE_ROE 0x00080000
|
|
||||||
+#define ASCSTATE_ANY (ASCSTATE_ROE|ASCSTATE_PE|ASCSTATE_FE)
|
|
||||||
+#define ASCWHBSTATE_CLRREN 0x00000001
|
|
||||||
+#define ASCWHBSTATE_SETREN 0x00000002
|
|
||||||
+#define ASCWHBSTATE_CLRPE 0x00000004
|
|
||||||
+#define ASCWHBSTATE_CLRFE 0x00000008
|
|
||||||
+#define ASCWHBSTATE_CLRROE 0x00000020
|
|
||||||
+#define ASCTXFCON_TXFEN 0x0001
|
|
||||||
+#define ASCTXFCON_TXFFLU 0x0002
|
|
||||||
+#define ASCTXFCON_TXFITLMASK 0x3F00
|
|
||||||
+#define ASCTXFCON_TXFITLOFF 8
|
|
||||||
+#define ASCRXFCON_RXFEN 0x0001
|
|
||||||
+#define ASCRXFCON_RXFFLU 0x0002
|
|
||||||
+#define ASCRXFCON_RXFITLMASK 0x3F00
|
|
||||||
+#define ASCRXFCON_RXFITLOFF 8
|
|
||||||
+#define ASCFSTAT_RXFFLMASK 0x003F
|
|
||||||
+#define ASCFSTAT_TXFFLMASK 0x3F00
|
|
||||||
+#define ASCFSTAT_TXFREEMASK 0x3F000000
|
|
||||||
+#define ASCFSTAT_TXFREEOFF 24
|
|
||||||
+
|
|
||||||
+static void lqasc_tx_chars(struct uart_port *port);
|
|
||||||
+static struct ltq_uart_port *lqasc_port[MAXPORTS];
|
|
||||||
+static struct uart_driver lqasc_reg;
|
|
||||||
+static DEFINE_SPINLOCK(ltq_asc_lock);
|
|
||||||
+
|
|
||||||
+struct ltq_uart_port {
|
|
||||||
+ struct uart_port port;
|
|
||||||
+ struct clk *clk;
|
|
||||||
+ unsigned int tx_irq;
|
|
||||||
+ unsigned int rx_irq;
|
|
||||||
+ unsigned int err_irq;
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static inline struct
|
|
||||||
+ltq_uart_port *to_ltq_uart_port(struct uart_port *port)
|
|
||||||
+{
|
|
||||||
+ return container_of(port, struct ltq_uart_port, port);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+lqasc_stop_tx(struct uart_port *port)
|
|
||||||
+{
|
|
||||||
+ return;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+lqasc_start_tx(struct uart_port *port)
|
|
||||||
+{
|
|
||||||
+ unsigned long flags;
|
|
||||||
+ spin_lock_irqsave(<q_asc_lock, flags);
|
|
||||||
+ lqasc_tx_chars(port);
|
|
||||||
+ spin_unlock_irqrestore(<q_asc_lock, flags);
|
|
||||||
+ return;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+lqasc_stop_rx(struct uart_port *port)
|
|
||||||
+{
|
|
||||||
+ ltq_w32(ASCWHBSTATE_CLRREN, port->membase + LTQ_ASC_WHBSTATE);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+lqasc_enable_ms(struct uart_port *port)
|
|
||||||
+{
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int
|
|
||||||
+lqasc_rx_chars(struct uart_port *port)
|
|
||||||
+{
|
|
||||||
+ struct tty_struct *tty = tty_port_tty_get(&port->state->port);
|
|
||||||
+ unsigned int ch = 0, rsr = 0, fifocnt;
|
|
||||||
+
|
|
||||||
+ if (!tty) {
|
|
||||||
+ dev_dbg(port->dev, "%s:tty is busy now", __func__);
|
|
||||||
+ return -EBUSY;
|
|
||||||
+ }
|
|
||||||
+ fifocnt =
|
|
||||||
+ ltq_r32(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_RXFFLMASK;
|
|
||||||
+ while (fifocnt--) {
|
|
||||||
+ u8 flag = TTY_NORMAL;
|
|
||||||
+ ch = ltq_r8(port->membase + LTQ_ASC_RBUF);
|
|
||||||
+ rsr = (ltq_r32(port->membase + LTQ_ASC_STATE)
|
|
||||||
+ & ASCSTATE_ANY) | UART_DUMMY_UER_RX;
|
|
||||||
+ tty_flip_buffer_push(tty);
|
|
||||||
+ port->icount.rx++;
|
|
||||||
+
|
|
||||||
+ /*
|
|
||||||
+ * Note that the error handling code is
|
|
||||||
+ * out of the main execution path
|
|
||||||
+ */
|
|
||||||
+ if (rsr & ASCSTATE_ANY) {
|
|
||||||
+ if (rsr & ASCSTATE_PE) {
|
|
||||||
+ port->icount.parity++;
|
|
||||||
+ ltq_w32_mask(0, ASCWHBSTATE_CLRPE,
|
|
||||||
+ port->membase + LTQ_ASC_WHBSTATE);
|
|
||||||
+ } else if (rsr & ASCSTATE_FE) {
|
|
||||||
+ port->icount.frame++;
|
|
||||||
+ ltq_w32_mask(0, ASCWHBSTATE_CLRFE,
|
|
||||||
+ port->membase + LTQ_ASC_WHBSTATE);
|
|
||||||
+ }
|
|
||||||
+ if (rsr & ASCSTATE_ROE) {
|
|
||||||
+ port->icount.overrun++;
|
|
||||||
+ ltq_w32_mask(0, ASCWHBSTATE_CLRROE,
|
|
||||||
+ port->membase + LTQ_ASC_WHBSTATE);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ rsr &= port->read_status_mask;
|
|
||||||
+
|
|
||||||
+ if (rsr & ASCSTATE_PE)
|
|
||||||
+ flag = TTY_PARITY;
|
|
||||||
+ else if (rsr & ASCSTATE_FE)
|
|
||||||
+ flag = TTY_FRAME;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if ((rsr & port->ignore_status_mask) == 0)
|
|
||||||
+ tty_insert_flip_char(tty, ch, flag);
|
|
||||||
+
|
|
||||||
+ if (rsr & ASCSTATE_ROE)
|
|
||||||
+ /*
|
|
||||||
+ * Overrun is special, since it's reported
|
|
||||||
+ * immediately, and doesn't affect the current
|
|
||||||
+ * character
|
|
||||||
+ */
|
|
||||||
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
|
|
||||||
+ }
|
|
||||||
+ if (ch != 0)
|
|
||||||
+ tty_flip_buffer_push(tty);
|
|
||||||
+ tty_kref_put(tty);
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+lqasc_tx_chars(struct uart_port *port)
|
|
||||||
+{
|
|
||||||
+ struct circ_buf *xmit = &port->state->xmit;
|
|
||||||
+ if (uart_tx_stopped(port)) {
|
|
||||||
+ lqasc_stop_tx(port);
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ while (((ltq_r32(port->membase + LTQ_ASC_FSTAT) &
|
|
||||||
+ ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF) != 0) {
|
|
||||||
+ if (port->x_char) {
|
|
||||||
+ ltq_w8(port->x_char, port->membase + LTQ_ASC_TBUF);
|
|
||||||
+ port->icount.tx++;
|
|
||||||
+ port->x_char = 0;
|
|
||||||
+ continue;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (uart_circ_empty(xmit))
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
+ ltq_w8(port->state->xmit.buf[port->state->xmit.tail],
|
|
||||||
+ port->membase + LTQ_ASC_TBUF);
|
|
||||||
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
|
||||||
+ port->icount.tx++;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
|
||||||
+ uart_write_wakeup(port);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static irqreturn_t
|
|
||||||
+lqasc_tx_int(int irq, void *_port)
|
|
||||||
+{
|
|
||||||
+ unsigned long flags;
|
|
||||||
+ struct uart_port *port = (struct uart_port *)_port;
|
|
||||||
+ spin_lock_irqsave(<q_asc_lock, flags);
|
|
||||||
+ ltq_w32(ASC_IRNCR_TIR, port->membase + LTQ_ASC_IRNCR);
|
|
||||||
+ spin_unlock_irqrestore(<q_asc_lock, flags);
|
|
||||||
+ lqasc_start_tx(port);
|
|
||||||
+ return IRQ_HANDLED;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static irqreturn_t
|
|
||||||
+lqasc_err_int(int irq, void *_port)
|
|
||||||
+{
|
|
||||||
+ unsigned long flags;
|
|
||||||
+ struct uart_port *port = (struct uart_port *)_port;
|
|
||||||
+ spin_lock_irqsave(<q_asc_lock, flags);
|
|
||||||
+ /* clear any pending interrupts */
|
|
||||||
+ ltq_w32_mask(0, ASCWHBSTATE_CLRPE | ASCWHBSTATE_CLRFE |
|
|
||||||
+ ASCWHBSTATE_CLRROE, port->membase + LTQ_ASC_WHBSTATE);
|
|
||||||
+ spin_unlock_irqrestore(<q_asc_lock, flags);
|
|
||||||
+ return IRQ_HANDLED;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static irqreturn_t
|
|
||||||
+lqasc_rx_int(int irq, void *_port)
|
|
||||||
+{
|
|
||||||
+ unsigned long flags;
|
|
||||||
+ struct uart_port *port = (struct uart_port *)_port;
|
|
||||||
+ spin_lock_irqsave(<q_asc_lock, flags);
|
|
||||||
+ ltq_w32(ASC_IRNCR_RIR, port->membase + LTQ_ASC_IRNCR);
|
|
||||||
+ lqasc_rx_chars(port);
|
|
||||||
+ spin_unlock_irqrestore(<q_asc_lock, flags);
|
|
||||||
+ return IRQ_HANDLED;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static unsigned int
|
|
||||||
+lqasc_tx_empty(struct uart_port *port)
|
|
||||||
+{
|
|
||||||
+ int status;
|
|
||||||
+ status = ltq_r32(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_TXFFLMASK;
|
|
||||||
+ return status ? 0 : TIOCSER_TEMT;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static unsigned int
|
|
||||||
+lqasc_get_mctrl(struct uart_port *port)
|
|
||||||
+{
|
|
||||||
+ return TIOCM_CTS | TIOCM_CAR | TIOCM_DSR;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+lqasc_set_mctrl(struct uart_port *port, u_int mctrl)
|
|
||||||
+{
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+lqasc_break_ctl(struct uart_port *port, int break_state)
|
|
||||||
+{
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int
|
|
||||||
+lqasc_startup(struct uart_port *port)
|
|
||||||
+{
|
|
||||||
+ struct ltq_uart_port *ltq_port = to_ltq_uart_port(port);
|
|
||||||
+ int retval;
|
|
||||||
+
|
|
||||||
+ port->uartclk = clk_get_rate(ltq_port->clk);
|
|
||||||
+
|
|
||||||
+ ltq_w32_mask(ASCCLC_DISS | ASCCLC_RMCMASK, (1 << ASCCLC_RMCOFFSET),
|
|
||||||
+ port->membase + LTQ_ASC_CLC);
|
|
||||||
+
|
|
||||||
+ ltq_w32(0, port->membase + LTQ_ASC_PISEL);
|
|
||||||
+ ltq_w32(
|
|
||||||
+ ((TXFIFO_FL << ASCTXFCON_TXFITLOFF) & ASCTXFCON_TXFITLMASK) |
|
|
||||||
+ ASCTXFCON_TXFEN | ASCTXFCON_TXFFLU,
|
|
||||||
+ port->membase + LTQ_ASC_TXFCON);
|
|
||||||
+ ltq_w32(
|
|
||||||
+ ((RXFIFO_FL << ASCRXFCON_RXFITLOFF) & ASCRXFCON_RXFITLMASK)
|
|
||||||
+ | ASCRXFCON_RXFEN | ASCRXFCON_RXFFLU,
|
|
||||||
+ port->membase + LTQ_ASC_RXFCON);
|
|
||||||
+ /* make sure other settings are written to hardware before
|
|
||||||
+ * setting enable bits
|
|
||||||
+ */
|
|
||||||
+ wmb();
|
|
||||||
+ ltq_w32_mask(0, ASCCON_M_8ASYNC | ASCCON_FEN | ASCCON_TOEN |
|
|
||||||
+ ASCCON_ROEN, port->membase + LTQ_ASC_CON);
|
|
||||||
+
|
|
||||||
+ retval = request_irq(ltq_port->tx_irq, lqasc_tx_int,
|
|
||||||
+ IRQF_DISABLED, "asc_tx", port);
|
|
||||||
+ if (retval) {
|
|
||||||
+ pr_err("failed to request lqasc_tx_int\n");
|
|
||||||
+ return retval;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ retval = request_irq(ltq_port->rx_irq, lqasc_rx_int,
|
|
||||||
+ IRQF_DISABLED, "asc_rx", port);
|
|
||||||
+ if (retval) {
|
|
||||||
+ pr_err("failed to request lqasc_rx_int\n");
|
|
||||||
+ goto err1;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ retval = request_irq(ltq_port->err_irq, lqasc_err_int,
|
|
||||||
+ IRQF_DISABLED, "asc_err", port);
|
|
||||||
+ if (retval) {
|
|
||||||
+ pr_err("failed to request lqasc_err_int\n");
|
|
||||||
+ goto err2;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ ltq_w32(ASC_IRNREN_RX | ASC_IRNREN_ERR | ASC_IRNREN_TX,
|
|
||||||
+ port->membase + LTQ_ASC_IRNREN);
|
|
||||||
+ return 0;
|
|
||||||
+
|
|
||||||
+err2:
|
|
||||||
+ free_irq(ltq_port->rx_irq, port);
|
|
||||||
+err1:
|
|
||||||
+ free_irq(ltq_port->tx_irq, port);
|
|
||||||
+ return retval;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+lqasc_shutdown(struct uart_port *port)
|
|
||||||
+{
|
|
||||||
+ struct ltq_uart_port *ltq_port = to_ltq_uart_port(port);
|
|
||||||
+ free_irq(ltq_port->tx_irq, port);
|
|
||||||
+ free_irq(ltq_port->rx_irq, port);
|
|
||||||
+ free_irq(ltq_port->err_irq, port);
|
|
||||||
+
|
|
||||||
+ ltq_w32(0, port->membase + LTQ_ASC_CON);
|
|
||||||
+ ltq_w32_mask(ASCRXFCON_RXFEN, ASCRXFCON_RXFFLU,
|
|
||||||
+ port->membase + LTQ_ASC_RXFCON);
|
|
||||||
+ ltq_w32_mask(ASCTXFCON_TXFEN, ASCTXFCON_TXFFLU,
|
|
||||||
+ port->membase + LTQ_ASC_TXFCON);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+lqasc_set_termios(struct uart_port *port,
|
|
||||||
+ struct ktermios *new, struct ktermios *old)
|
|
||||||
+{
|
|
||||||
+ unsigned int cflag;
|
|
||||||
+ unsigned int iflag;
|
|
||||||
+ unsigned int divisor;
|
|
||||||
+ unsigned int baud;
|
|
||||||
+ unsigned int con = 0;
|
|
||||||
+ unsigned long flags;
|
|
||||||
+
|
|
||||||
+ cflag = new->c_cflag;
|
|
||||||
+ iflag = new->c_iflag;
|
|
||||||
+
|
|
||||||
+ switch (cflag & CSIZE) {
|
|
||||||
+ case CS7:
|
|
||||||
+ con = ASCCON_M_7ASYNC;
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
+ case CS5:
|
|
||||||
+ case CS6:
|
|
||||||
+ default:
|
|
||||||
+ new->c_cflag &= ~ CSIZE;
|
|
||||||
+ new->c_cflag |= CS8;
|
|
||||||
+ con = ASCCON_M_8ASYNC;
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ cflag &= ~CMSPAR; /* Mark/Space parity is not supported */
|
|
||||||
+
|
|
||||||
+ if (cflag & CSTOPB)
|
|
||||||
+ con |= ASCCON_STP;
|
|
||||||
+
|
|
||||||
+ if (cflag & PARENB) {
|
|
||||||
+ if (!(cflag & PARODD))
|
|
||||||
+ con &= ~ASCCON_ODD;
|
|
||||||
+ else
|
|
||||||
+ con |= ASCCON_ODD;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ port->read_status_mask = ASCSTATE_ROE;
|
|
||||||
+ if (iflag & INPCK)
|
|
||||||
+ port->read_status_mask |= ASCSTATE_FE | ASCSTATE_PE;
|
|
||||||
+
|
|
||||||
+ port->ignore_status_mask = 0;
|
|
||||||
+ if (iflag & IGNPAR)
|
|
||||||
+ port->ignore_status_mask |= ASCSTATE_FE | ASCSTATE_PE;
|
|
||||||
+
|
|
||||||
+ if (iflag & IGNBRK) {
|
|
||||||
+ /*
|
|
||||||
+ * If we're ignoring parity and break indicators,
|
|
||||||
+ * ignore overruns too (for real raw support).
|
|
||||||
+ */
|
|
||||||
+ if (iflag & IGNPAR)
|
|
||||||
+ port->ignore_status_mask |= ASCSTATE_ROE;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if ((cflag & CREAD) == 0)
|
|
||||||
+ port->ignore_status_mask |= UART_DUMMY_UER_RX;
|
|
||||||
+
|
|
||||||
+ /* set error signals - framing, parity and overrun, enable receiver */
|
|
||||||
+ con |= ASCCON_FEN | ASCCON_TOEN | ASCCON_ROEN;
|
|
||||||
+
|
|
||||||
+ spin_lock_irqsave(<q_asc_lock, flags);
|
|
||||||
+
|
|
||||||
+ /* set up CON */
|
|
||||||
+ ltq_w32_mask(0, con, port->membase + LTQ_ASC_CON);
|
|
||||||
+
|
|
||||||
+ /* Set baud rate - take a divider of 2 into account */
|
|
||||||
+ baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16);
|
|
||||||
+ divisor = uart_get_divisor(port, baud);
|
|
||||||
+ divisor = divisor / 2 - 1;
|
|
||||||
+
|
|
||||||
+ /* disable the baudrate generator */
|
|
||||||
+ ltq_w32_mask(ASCCON_R, 0, port->membase + LTQ_ASC_CON);
|
|
||||||
+
|
|
||||||
+ /* make sure the fractional divider is off */
|
|
||||||
+ ltq_w32_mask(ASCCON_FDE, 0, port->membase + LTQ_ASC_CON);
|
|
||||||
+
|
|
||||||
+ /* set up to use divisor of 2 */
|
|
||||||
+ ltq_w32_mask(ASCCON_BRS, 0, port->membase + LTQ_ASC_CON);
|
|
||||||
+
|
|
||||||
+ /* now we can write the new baudrate into the register */
|
|
||||||
+ ltq_w32(divisor, port->membase + LTQ_ASC_BG);
|
|
||||||
+
|
|
||||||
+ /* turn the baudrate generator back on */
|
|
||||||
+ ltq_w32_mask(0, ASCCON_R, port->membase + LTQ_ASC_CON);
|
|
||||||
+
|
|
||||||
+ /* enable rx */
|
|
||||||
+ ltq_w32(ASCWHBSTATE_SETREN, port->membase + LTQ_ASC_WHBSTATE);
|
|
||||||
+
|
|
||||||
+ spin_unlock_irqrestore(<q_asc_lock, flags);
|
|
||||||
+
|
|
||||||
+ /* Don't rewrite B0 */
|
|
||||||
+ if (tty_termios_baud_rate(new))
|
|
||||||
+ tty_termios_encode_baud_rate(new, baud, baud);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static const char*
|
|
||||||
+lqasc_type(struct uart_port *port)
|
|
||||||
+{
|
|
||||||
+ if (port->type == PORT_LTQ_ASC)
|
|
||||||
+ return DRVNAME;
|
|
||||||
+ else
|
|
||||||
+ return NULL;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+lqasc_release_port(struct uart_port *port)
|
|
||||||
+{
|
|
||||||
+ if (port->flags & UPF_IOREMAP) {
|
|
||||||
+ iounmap(port->membase);
|
|
||||||
+ port->membase = NULL;
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int
|
|
||||||
+lqasc_request_port(struct uart_port *port)
|
|
||||||
+{
|
|
||||||
+ struct platform_device *pdev = to_platform_device(port->dev);
|
|
||||||
+ struct resource *res;
|
|
||||||
+ int size;
|
|
||||||
+
|
|
||||||
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
||||||
+ if (!res) {
|
|
||||||
+ dev_err(&pdev->dev, "cannot obtain I/O memory region");
|
|
||||||
+ return -ENODEV;
|
|
||||||
+ }
|
|
||||||
+ size = resource_size(res);
|
|
||||||
+
|
|
||||||
+ res = devm_request_mem_region(&pdev->dev, res->start,
|
|
||||||
+ size, dev_name(&pdev->dev));
|
|
||||||
+ if (!res) {
|
|
||||||
+ dev_err(&pdev->dev, "cannot request I/O memory region");
|
|
||||||
+ return -EBUSY;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (port->flags & UPF_IOREMAP) {
|
|
||||||
+ port->membase = devm_ioremap_nocache(&pdev->dev,
|
|
||||||
+ port->mapbase, size);
|
|
||||||
+ if (port->membase == NULL)
|
|
||||||
+ return -ENOMEM;
|
|
||||||
+ }
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+lqasc_config_port(struct uart_port *port, int flags)
|
|
||||||
+{
|
|
||||||
+ if (flags & UART_CONFIG_TYPE) {
|
|
||||||
+ port->type = PORT_LTQ_ASC;
|
|
||||||
+ lqasc_request_port(port);
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int
|
|
||||||
+lqasc_verify_port(struct uart_port *port,
|
|
||||||
+ struct serial_struct *ser)
|
|
||||||
+{
|
|
||||||
+ int ret = 0;
|
|
||||||
+ if (ser->type != PORT_UNKNOWN && ser->type != PORT_LTQ_ASC)
|
|
||||||
+ ret = -EINVAL;
|
|
||||||
+ if (ser->irq < 0 || ser->irq >= NR_IRQS)
|
|
||||||
+ ret = -EINVAL;
|
|
||||||
+ if (ser->baud_base < 9600)
|
|
||||||
+ ret = -EINVAL;
|
|
||||||
+ return ret;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static struct uart_ops lqasc_pops = {
|
|
||||||
+ .tx_empty = lqasc_tx_empty,
|
|
||||||
+ .set_mctrl = lqasc_set_mctrl,
|
|
||||||
+ .get_mctrl = lqasc_get_mctrl,
|
|
||||||
+ .stop_tx = lqasc_stop_tx,
|
|
||||||
+ .start_tx = lqasc_start_tx,
|
|
||||||
+ .stop_rx = lqasc_stop_rx,
|
|
||||||
+ .enable_ms = lqasc_enable_ms,
|
|
||||||
+ .break_ctl = lqasc_break_ctl,
|
|
||||||
+ .startup = lqasc_startup,
|
|
||||||
+ .shutdown = lqasc_shutdown,
|
|
||||||
+ .set_termios = lqasc_set_termios,
|
|
||||||
+ .type = lqasc_type,
|
|
||||||
+ .release_port = lqasc_release_port,
|
|
||||||
+ .request_port = lqasc_request_port,
|
|
||||||
+ .config_port = lqasc_config_port,
|
|
||||||
+ .verify_port = lqasc_verify_port,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+lqasc_console_putchar(struct uart_port *port, int ch)
|
|
||||||
+{
|
|
||||||
+ int fifofree;
|
|
||||||
+
|
|
||||||
+ if (!port->membase)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ do {
|
|
||||||
+ fifofree = (ltq_r32(port->membase + LTQ_ASC_FSTAT)
|
|
||||||
+ & ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF;
|
|
||||||
+ } while (fifofree == 0);
|
|
||||||
+ ltq_w8(ch, port->membase + LTQ_ASC_TBUF);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+lqasc_console_write(struct console *co, const char *s, u_int count)
|
|
||||||
+{
|
|
||||||
+ struct ltq_uart_port *ltq_port;
|
|
||||||
+ struct uart_port *port;
|
|
||||||
+ unsigned long flags;
|
|
||||||
+
|
|
||||||
+ if (co->index >= MAXPORTS)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ ltq_port = lqasc_port[co->index];
|
|
||||||
+ if (!ltq_port)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ port = <q_port->port;
|
|
||||||
+
|
|
||||||
+ spin_lock_irqsave(<q_asc_lock, flags);
|
|
||||||
+ uart_console_write(port, s, count, lqasc_console_putchar);
|
|
||||||
+ spin_unlock_irqrestore(<q_asc_lock, flags);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int __init
|
|
||||||
+lqasc_console_setup(struct console *co, char *options)
|
|
||||||
+{
|
|
||||||
+ struct ltq_uart_port *ltq_port;
|
|
||||||
+ struct uart_port *port;
|
|
||||||
+ int baud = 115200;
|
|
||||||
+ int bits = 8;
|
|
||||||
+ int parity = 'n';
|
|
||||||
+ int flow = 'n';
|
|
||||||
+
|
|
||||||
+ if (co->index >= MAXPORTS)
|
|
||||||
+ return -ENODEV;
|
|
||||||
+
|
|
||||||
+ ltq_port = lqasc_port[co->index];
|
|
||||||
+ if (!ltq_port)
|
|
||||||
+ return -ENODEV;
|
|
||||||
+
|
|
||||||
+ port = <q_port->port;
|
|
||||||
+
|
|
||||||
+ port->uartclk = clk_get_rate(ltq_port->clk);
|
|
||||||
+
|
|
||||||
+ if (options)
|
|
||||||
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
|
|
||||||
+ return uart_set_options(port, co, baud, parity, bits, flow);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static struct console lqasc_console = {
|
|
||||||
+ .name = "ttyLTQ",
|
|
||||||
+ .write = lqasc_console_write,
|
|
||||||
+ .device = uart_console_device,
|
|
||||||
+ .setup = lqasc_console_setup,
|
|
||||||
+ .flags = CON_PRINTBUFFER,
|
|
||||||
+ .index = -1,
|
|
||||||
+ .data = &lqasc_reg,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static int __init
|
|
||||||
+lqasc_console_init(void)
|
|
||||||
+{
|
|
||||||
+ register_console(&lqasc_console);
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+console_initcall(lqasc_console_init);
|
|
||||||
+
|
|
||||||
+static struct uart_driver lqasc_reg = {
|
|
||||||
+ .owner = THIS_MODULE,
|
|
||||||
+ .driver_name = DRVNAME,
|
|
||||||
+ .dev_name = "ttyLTQ",
|
|
||||||
+ .major = 0,
|
|
||||||
+ .minor = 0,
|
|
||||||
+ .nr = MAXPORTS,
|
|
||||||
+ .cons = &lqasc_console,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static int __init
|
|
||||||
+lqasc_probe(struct platform_device *pdev)
|
|
||||||
+{
|
|
||||||
+ struct ltq_uart_port *ltq_port;
|
|
||||||
+ struct uart_port *port;
|
|
||||||
+ struct resource *mmres, *irqres;
|
|
||||||
+ int tx_irq, rx_irq, err_irq;
|
|
||||||
+ struct clk *clk;
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
||||||
+ irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
|
||||||
+ if (!mmres || !irqres)
|
|
||||||
+ return -ENODEV;
|
|
||||||
+
|
|
||||||
+ if (pdev->id >= MAXPORTS)
|
|
||||||
+ return -EBUSY;
|
|
||||||
+
|
|
||||||
+ if (lqasc_port[pdev->id] != NULL)
|
|
||||||
+ return -EBUSY;
|
|
||||||
+
|
|
||||||
+ clk = clk_get(&pdev->dev, "fpi");
|
|
||||||
+ if (IS_ERR(clk)) {
|
|
||||||
+ pr_err("failed to get fpi clk\n");
|
|
||||||
+ return -ENOENT;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ tx_irq = platform_get_irq_byname(pdev, "tx");
|
|
||||||
+ rx_irq = platform_get_irq_byname(pdev, "rx");
|
|
||||||
+ err_irq = platform_get_irq_byname(pdev, "err");
|
|
||||||
+ if ((tx_irq < 0) | (rx_irq < 0) | (err_irq < 0))
|
|
||||||
+ return -ENODEV;
|
|
||||||
+
|
|
||||||
+ ltq_port = kzalloc(sizeof(struct ltq_uart_port), GFP_KERNEL);
|
|
||||||
+ if (!ltq_port)
|
|
||||||
+ return -ENOMEM;
|
|
||||||
+
|
|
||||||
+ port = <q_port->port;
|
|
||||||
+
|
|
||||||
+ port->iotype = SERIAL_IO_MEM;
|
|
||||||
+ port->flags = ASYNC_BOOT_AUTOCONF | UPF_IOREMAP;
|
|
||||||
+ port->ops = &lqasc_pops;
|
|
||||||
+ port->fifosize = 16;
|
|
||||||
+ port->type = PORT_LTQ_ASC,
|
|
||||||
+ port->line = pdev->id;
|
|
||||||
+ port->dev = &pdev->dev;
|
|
||||||
+
|
|
||||||
+ port->irq = tx_irq; /* unused, just to be backward-compatibe */
|
|
||||||
+ port->mapbase = mmres->start;
|
|
||||||
+
|
|
||||||
+ ltq_port->clk = clk;
|
|
||||||
+
|
|
||||||
+ ltq_port->tx_irq = tx_irq;
|
|
||||||
+ ltq_port->rx_irq = rx_irq;
|
|
||||||
+ ltq_port->err_irq = err_irq;
|
|
||||||
+
|
|
||||||
+ lqasc_port[pdev->id] = ltq_port;
|
|
||||||
+ platform_set_drvdata(pdev, ltq_port);
|
|
||||||
+
|
|
||||||
+ ret = uart_add_one_port(&lqasc_reg, port);
|
|
||||||
+
|
|
||||||
+ return ret;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static struct platform_driver lqasc_driver = {
|
|
||||||
+ .driver = {
|
|
||||||
+ .name = DRVNAME,
|
|
||||||
+ .owner = THIS_MODULE,
|
|
||||||
+ },
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+int __init
|
|
||||||
+init_lqasc(void)
|
|
||||||
+{
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ ret = uart_register_driver(&lqasc_reg);
|
|
||||||
+ if (ret != 0)
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+ ret = platform_driver_probe(&lqasc_driver, lqasc_probe);
|
|
||||||
+ if (ret != 0)
|
|
||||||
+ uart_unregister_driver(&lqasc_reg);
|
|
||||||
+
|
|
||||||
+ return ret;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+module_init(init_lqasc);
|
|
||||||
+
|
|
||||||
+MODULE_DESCRIPTION("Lantiq serial port driver");
|
|
||||||
+MODULE_LICENSE("GPL");
|
|
||||||
--- a/drivers/serial/Kconfig
|
|
||||||
+++ b/drivers/serial/Kconfig
|
|
||||||
@@ -1383,6 +1383,14 @@
|
|
||||||
help
|
|
||||||
Support for Console on the NWP serial ports.
|
|
||||||
|
|
||||||
+config SERIAL_LANTIQ
|
|
||||||
+ bool "Lantiq serial driver"
|
|
||||||
+ depends on LANTIQ
|
|
||||||
+ select SERIAL_CORE
|
|
||||||
+ select SERIAL_CORE_CONSOLE
|
|
||||||
+ help
|
|
||||||
+ Support for console and UART on Lantiq SoCs.
|
|
||||||
+
|
|
||||||
config SERIAL_QE
|
|
||||||
tristate "Freescale QUICC Engine serial port support"
|
|
||||||
depends on QUICC_ENGINE
|
|
||||||
--- a/drivers/serial/Makefile
|
|
||||||
+++ b/drivers/serial/Makefile
|
|
||||||
@@ -81,3 +81,4 @@
|
|
||||||
obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
|
|
||||||
obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
|
|
||||||
obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o
|
|
||||||
+obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o
|
|
@ -1,387 +0,0 @@ |
|||||||
From bd620ec1ca053bab8ce2562968700e6f80e4ff83 Mon Sep 17 00:00:00 2001
|
|
||||||
From: John Crispin <blogic@openwrt.org>
|
|
||||||
Date: Fri, 6 May 2011 00:10:00 +0200
|
|
||||||
Subject: [PATCH 10/13] MIPS: Lantiq: Add DMA support
|
|
||||||
|
|
||||||
This patch adds support for the DMA engine found inside the XWAY family of
|
|
||||||
SoCs. The engine has 5 ports and 20 channels.
|
|
||||||
|
|
||||||
Signed-off-by: John Crispin <blogic@openwrt.org>
|
|
||||||
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
|
|
||||||
Cc: linux-mips@linux-mips.org
|
|
||||||
Patchwork: https://patchwork.linux-mips.org/patch/2355/
|
|
||||||
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
|
|
||||||
---
|
|
||||||
.../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 3 +-
|
|
||||||
arch/mips/include/asm/mach-lantiq/xway/xway_dma.h | 60 +++++
|
|
||||||
arch/mips/lantiq/xway/Makefile | 2 +-
|
|
||||||
arch/mips/lantiq/xway/devices.h | 1 +
|
|
||||||
arch/mips/lantiq/xway/dma.c | 253 ++++++++++++++++++++
|
|
||||||
5 files changed, 317 insertions(+), 2 deletions(-)
|
|
||||||
create mode 100644 arch/mips/include/asm/mach-lantiq/xway/xway_dma.h
|
|
||||||
create mode 100644 arch/mips/lantiq/xway/dma.c
|
|
||||||
|
|
||||||
diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
|
|
||||||
index 343e82c..4827afb 100644
|
|
||||||
--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
|
|
||||||
+++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
|
|
||||||
@@ -86,7 +86,8 @@
|
|
||||||
#define LTQ_PPE32_SIZE 0x40000
|
|
||||||
|
|
||||||
/* DMA */
|
|
||||||
-#define LTQ_DMA_BASE_ADDR 0xBE104100
|
|
||||||
+#define LTQ_DMA_BASE_ADDR 0x1E104100
|
|
||||||
+#define LTQ_DMA_SIZE 0x800
|
|
||||||
|
|
||||||
/* PCI */
|
|
||||||
#define PCI_CR_BASE_ADDR 0x1E105400
|
|
||||||
diff --git a/arch/mips/include/asm/mach-lantiq/xway/xway_dma.h b/arch/mips/include/asm/mach-lantiq/xway/xway_dma.h
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000..872943a
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/arch/mips/include/asm/mach-lantiq/xway/xway_dma.h
|
|
||||||
@@ -0,0 +1,60 @@
|
|
||||||
+/*
|
|
||||||
+ * 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.
|
|
||||||
+ *
|
|
||||||
+ * 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.
|
|
||||||
+ *
|
|
||||||
+ * Copyright (C) 2011 John Crispin <blogic@openwrt.org>
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#ifndef LTQ_DMA_H__
|
|
||||||
+#define LTQ_DMA_H__
|
|
||||||
+
|
|
||||||
+#define LTQ_DESC_SIZE 0x08 /* each descriptor is 64bit */
|
|
||||||
+#define LTQ_DESC_NUM 0x40 /* 64 descriptors / channel */
|
|
||||||
+
|
|
||||||
+#define LTQ_DMA_OWN BIT(31) /* owner bit */
|
|
||||||
+#define LTQ_DMA_C BIT(30) /* complete bit */
|
|
||||||
+#define LTQ_DMA_SOP BIT(29) /* start of packet */
|
|
||||||
+#define LTQ_DMA_EOP BIT(28) /* end of packet */
|
|
||||||
+#define LTQ_DMA_TX_OFFSET(x) ((x & 0x1f) << 23) /* data bytes offset */
|
|
||||||
+#define LTQ_DMA_RX_OFFSET(x) ((x & 0x7) << 23) /* data bytes offset */
|
|
||||||
+#define LTQ_DMA_SIZE_MASK (0xffff) /* the size field is 16 bit */
|
|
||||||
+
|
|
||||||
+struct ltq_dma_desc {
|
|
||||||
+ u32 ctl;
|
|
||||||
+ u32 addr;
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+struct ltq_dma_channel {
|
|
||||||
+ int nr; /* the channel number */
|
|
||||||
+ int irq; /* the mapped irq */
|
|
||||||
+ int desc; /* the current descriptor */
|
|
||||||
+ struct ltq_dma_desc *desc_base; /* the descriptor base */
|
|
||||||
+ int phys; /* physical addr */
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+enum {
|
|
||||||
+ DMA_PORT_ETOP = 0,
|
|
||||||
+ DMA_PORT_DEU,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+extern void ltq_dma_enable_irq(struct ltq_dma_channel *ch);
|
|
||||||
+extern void ltq_dma_disable_irq(struct ltq_dma_channel *ch);
|
|
||||||
+extern void ltq_dma_ack_irq(struct ltq_dma_channel *ch);
|
|
||||||
+extern void ltq_dma_open(struct ltq_dma_channel *ch);
|
|
||||||
+extern void ltq_dma_close(struct ltq_dma_channel *ch);
|
|
||||||
+extern void ltq_dma_alloc_tx(struct ltq_dma_channel *ch);
|
|
||||||
+extern void ltq_dma_alloc_rx(struct ltq_dma_channel *ch);
|
|
||||||
+extern void ltq_dma_free(struct ltq_dma_channel *ch);
|
|
||||||
+extern void ltq_dma_init_port(int p);
|
|
||||||
+
|
|
||||||
+#endif
|
|
||||||
diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile
|
|
||||||
index 6b5e07e..c517f2e 100644
|
|
||||||
--- 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
|
|
||||||
+obj-y := pmu.o ebu.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.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
|
|
||||||
diff --git a/arch/mips/lantiq/xway/devices.h b/arch/mips/lantiq/xway/devices.h
|
|
||||||
index 51f56b5..d573084 100644
|
|
||||||
--- a/arch/mips/lantiq/xway/devices.h
|
|
||||||
+++ b/arch/mips/lantiq/xway/devices.h
|
|
||||||
@@ -10,6 +10,7 @@
|
|
||||||
#define _LTQ_DEVICES_XWAY_H__
|
|
||||||
|
|
||||||
#include "../devices.h"
|
|
||||||
+#include <linux/phy.h>
|
|
||||||
|
|
||||||
extern void ltq_register_gpio(void);
|
|
||||||
extern void ltq_register_gpio_stp(void);
|
|
||||||
diff --git a/arch/mips/lantiq/xway/dma.c b/arch/mips/lantiq/xway/dma.c
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000..4278a45
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/arch/mips/lantiq/xway/dma.c
|
|
||||||
@@ -0,0 +1,253 @@
|
|
||||||
+/*
|
|
||||||
+ * 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.
|
|
||||||
+ *
|
|
||||||
+ * 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.
|
|
||||||
+ *
|
|
||||||
+ * Copyright (C) 2011 John Crispin <blogic@openwrt.org>
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#include <linux/init.h>
|
|
||||||
+#include <linux/platform_device.h>
|
|
||||||
+#include <linux/io.h>
|
|
||||||
+#include <linux/dma-mapping.h>
|
|
||||||
+
|
|
||||||
+#include <lantiq_soc.h>
|
|
||||||
+#include <xway_dma.h>
|
|
||||||
+
|
|
||||||
+#define LTQ_DMA_CTRL 0x10
|
|
||||||
+#define LTQ_DMA_CPOLL 0x14
|
|
||||||
+#define LTQ_DMA_CS 0x18
|
|
||||||
+#define LTQ_DMA_CCTRL 0x1C
|
|
||||||
+#define LTQ_DMA_CDBA 0x20
|
|
||||||
+#define LTQ_DMA_CDLEN 0x24
|
|
||||||
+#define LTQ_DMA_CIS 0x28
|
|
||||||
+#define LTQ_DMA_CIE 0x2C
|
|
||||||
+#define LTQ_DMA_PS 0x40
|
|
||||||
+#define LTQ_DMA_PCTRL 0x44
|
|
||||||
+#define LTQ_DMA_IRNEN 0xf4
|
|
||||||
+
|
|
||||||
+#define DMA_DESCPT BIT(3) /* descriptor complete irq */
|
|
||||||
+#define DMA_TX BIT(8) /* TX channel direction */
|
|
||||||
+#define DMA_CHAN_ON BIT(0) /* channel on / off bit */
|
|
||||||
+#define DMA_PDEN BIT(6) /* enable packet drop */
|
|
||||||
+#define DMA_CHAN_RST BIT(1) /* channel on / off bit */
|
|
||||||
+#define DMA_RESET BIT(0) /* channel on / off bit */
|
|
||||||
+#define DMA_IRQ_ACK 0x7e /* IRQ status register */
|
|
||||||
+#define DMA_POLL BIT(31) /* turn on channel polling */
|
|
||||||
+#define DMA_CLK_DIV4 BIT(6) /* polling clock divider */
|
|
||||||
+#define DMA_2W_BURST BIT(1) /* 2 word burst length */
|
|
||||||
+#define DMA_MAX_CHANNEL 20 /* the soc has 20 channels */
|
|
||||||
+#define DMA_ETOP_ENDIANESS (0xf << 8) /* endianess swap etop channels */
|
|
||||||
+#define DMA_WEIGHT (BIT(17) | BIT(16)) /* default channel wheight */
|
|
||||||
+
|
|
||||||
+#define ltq_dma_r32(x) ltq_r32(ltq_dma_membase + (x))
|
|
||||||
+#define ltq_dma_w32(x, y) ltq_w32(x, ltq_dma_membase + (y))
|
|
||||||
+#define ltq_dma_w32_mask(x, y, z) ltq_w32_mask(x, y, \
|
|
||||||
+ ltq_dma_membase + (z))
|
|
||||||
+
|
|
||||||
+static struct resource ltq_dma_resource = {
|
|
||||||
+ .name = "dma",
|
|
||||||
+ .start = LTQ_DMA_BASE_ADDR,
|
|
||||||
+ .end = LTQ_DMA_BASE_ADDR + LTQ_DMA_SIZE - 1,
|
|
||||||
+ .flags = IORESOURCE_MEM,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static void __iomem *ltq_dma_membase;
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+ltq_dma_enable_irq(struct ltq_dma_channel *ch)
|
|
||||||
+{
|
|
||||||
+ unsigned long flags;
|
|
||||||
+
|
|
||||||
+ local_irq_save(flags);
|
|
||||||
+ ltq_dma_w32(ch->nr, LTQ_DMA_CS);
|
|
||||||
+ ltq_dma_w32_mask(0, 1 << ch->nr, LTQ_DMA_IRNEN);
|
|
||||||
+ local_irq_restore(flags);
|
|
||||||
+}
|
|
||||||
+EXPORT_SYMBOL_GPL(ltq_dma_enable_irq);
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+ltq_dma_disable_irq(struct ltq_dma_channel *ch)
|
|
||||||
+{
|
|
||||||
+ unsigned long flags;
|
|
||||||
+
|
|
||||||
+ local_irq_save(flags);
|
|
||||||
+ ltq_dma_w32(ch->nr, LTQ_DMA_CS);
|
|
||||||
+ ltq_dma_w32_mask(1 << ch->nr, 0, LTQ_DMA_IRNEN);
|
|
||||||
+ local_irq_restore(flags);
|
|
||||||
+}
|
|
||||||
+EXPORT_SYMBOL_GPL(ltq_dma_disable_irq);
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+ltq_dma_ack_irq(struct ltq_dma_channel *ch)
|
|
||||||
+{
|
|
||||||
+ unsigned long flags;
|
|
||||||
+
|
|
||||||
+ local_irq_save(flags);
|
|
||||||
+ ltq_dma_w32(ch->nr, LTQ_DMA_CS);
|
|
||||||
+ ltq_dma_w32(DMA_IRQ_ACK, LTQ_DMA_CIS);
|
|
||||||
+ local_irq_restore(flags);
|
|
||||||
+}
|
|
||||||
+EXPORT_SYMBOL_GPL(ltq_dma_ack_irq);
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+ltq_dma_open(struct ltq_dma_channel *ch)
|
|
||||||
+{
|
|
||||||
+ unsigned long flag;
|
|
||||||
+
|
|
||||||
+ local_irq_save(flag);
|
|
||||||
+ ltq_dma_w32(ch->nr, LTQ_DMA_CS);
|
|
||||||
+ ltq_dma_w32_mask(0, DMA_CHAN_ON, LTQ_DMA_CCTRL);
|
|
||||||
+ ltq_dma_enable_irq(ch);
|
|
||||||
+ local_irq_restore(flag);
|
|
||||||
+}
|
|
||||||
+EXPORT_SYMBOL_GPL(ltq_dma_open);
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+ltq_dma_close(struct ltq_dma_channel *ch)
|
|
||||||
+{
|
|
||||||
+ unsigned long flag;
|
|
||||||
+
|
|
||||||
+ local_irq_save(flag);
|
|
||||||
+ ltq_dma_w32(ch->nr, LTQ_DMA_CS);
|
|
||||||
+ ltq_dma_w32_mask(DMA_CHAN_ON, 0, LTQ_DMA_CCTRL);
|
|
||||||
+ ltq_dma_disable_irq(ch);
|
|
||||||
+ local_irq_restore(flag);
|
|
||||||
+}
|
|
||||||
+EXPORT_SYMBOL_GPL(ltq_dma_close);
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+ltq_dma_alloc(struct ltq_dma_channel *ch)
|
|
||||||
+{
|
|
||||||
+ unsigned long flags;
|
|
||||||
+
|
|
||||||
+ ch->desc = 0;
|
|
||||||
+ ch->desc_base = dma_alloc_coherent(NULL,
|
|
||||||
+ LTQ_DESC_NUM * LTQ_DESC_SIZE,
|
|
||||||
+ &ch->phys, GFP_ATOMIC);
|
|
||||||
+ memset(ch->desc_base, 0, LTQ_DESC_NUM * LTQ_DESC_SIZE);
|
|
||||||
+
|
|
||||||
+ local_irq_save(flags);
|
|
||||||
+ ltq_dma_w32(ch->nr, LTQ_DMA_CS);
|
|
||||||
+ ltq_dma_w32(ch->phys, LTQ_DMA_CDBA);
|
|
||||||
+ ltq_dma_w32(LTQ_DESC_NUM, LTQ_DMA_CDLEN);
|
|
||||||
+ ltq_dma_w32_mask(DMA_CHAN_ON, 0, LTQ_DMA_CCTRL);
|
|
||||||
+ wmb();
|
|
||||||
+ ltq_dma_w32_mask(0, DMA_CHAN_RST, LTQ_DMA_CCTRL);
|
|
||||||
+ while (ltq_dma_r32(LTQ_DMA_CCTRL) & DMA_CHAN_RST)
|
|
||||||
+ ;
|
|
||||||
+ local_irq_restore(flags);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+ltq_dma_alloc_tx(struct ltq_dma_channel *ch)
|
|
||||||
+{
|
|
||||||
+ unsigned long flags;
|
|
||||||
+
|
|
||||||
+ ltq_dma_alloc(ch);
|
|
||||||
+
|
|
||||||
+ local_irq_save(flags);
|
|
||||||
+ ltq_dma_w32(DMA_DESCPT, LTQ_DMA_CIE);
|
|
||||||
+ ltq_dma_w32_mask(0, 1 << ch->nr, LTQ_DMA_IRNEN);
|
|
||||||
+ ltq_dma_w32(DMA_WEIGHT | DMA_TX, LTQ_DMA_CCTRL);
|
|
||||||
+ local_irq_restore(flags);
|
|
||||||
+}
|
|
||||||
+EXPORT_SYMBOL_GPL(ltq_dma_alloc_tx);
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+ltq_dma_alloc_rx(struct ltq_dma_channel *ch)
|
|
||||||
+{
|
|
||||||
+ unsigned long flags;
|
|
||||||
+
|
|
||||||
+ ltq_dma_alloc(ch);
|
|
||||||
+
|
|
||||||
+ local_irq_save(flags);
|
|
||||||
+ ltq_dma_w32(DMA_DESCPT, LTQ_DMA_CIE);
|
|
||||||
+ ltq_dma_w32_mask(0, 1 << ch->nr, LTQ_DMA_IRNEN);
|
|
||||||
+ ltq_dma_w32(DMA_WEIGHT, LTQ_DMA_CCTRL);
|
|
||||||
+ local_irq_restore(flags);
|
|
||||||
+}
|
|
||||||
+EXPORT_SYMBOL_GPL(ltq_dma_alloc_rx);
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+ltq_dma_free(struct ltq_dma_channel *ch)
|
|
||||||
+{
|
|
||||||
+ if (!ch->desc_base)
|
|
||||||
+ return;
|
|
||||||
+ ltq_dma_close(ch);
|
|
||||||
+ dma_free_coherent(NULL, LTQ_DESC_NUM * LTQ_DESC_SIZE,
|
|
||||||
+ ch->desc_base, ch->phys);
|
|
||||||
+}
|
|
||||||
+EXPORT_SYMBOL_GPL(ltq_dma_free);
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+ltq_dma_init_port(int p)
|
|
||||||
+{
|
|
||||||
+ ltq_dma_w32(p, LTQ_DMA_PS);
|
|
||||||
+ switch (p) {
|
|
||||||
+ case DMA_PORT_ETOP:
|
|
||||||
+ /*
|
|
||||||
+ * Tell the DMA engine to swap the endianess of data frames and
|
|
||||||
+ * drop packets if the channel arbitration fails.
|
|
||||||
+ */
|
|
||||||
+ ltq_dma_w32_mask(0, DMA_ETOP_ENDIANESS | DMA_PDEN,
|
|
||||||
+ LTQ_DMA_PCTRL);
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
+ case DMA_PORT_DEU:
|
|
||||||
+ ltq_dma_w32((DMA_2W_BURST << 4) | (DMA_2W_BURST << 2),
|
|
||||||
+ LTQ_DMA_PCTRL);
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
+ default:
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+EXPORT_SYMBOL_GPL(ltq_dma_init_port);
|
|
||||||
+
|
|
||||||
+int __init
|
|
||||||
+ltq_dma_init(void)
|
|
||||||
+{
|
|
||||||
+ int i;
|
|
||||||
+
|
|
||||||
+ /* insert and request the memory region */
|
|
||||||
+ if (insert_resource(&iomem_resource, <q_dma_resource) < 0)
|
|
||||||
+ panic("Failed to insert dma memory\n");
|
|
||||||
+
|
|
||||||
+ if (request_mem_region(ltq_dma_resource.start,
|
|
||||||
+ resource_size(<q_dma_resource), "dma") < 0)
|
|
||||||
+ panic("Failed to request dma memory\n");
|
|
||||||
+
|
|
||||||
+ /* remap dma register range */
|
|
||||||
+ ltq_dma_membase = ioremap_nocache(ltq_dma_resource.start,
|
|
||||||
+ resource_size(<q_dma_resource));
|
|
||||||
+ if (!ltq_dma_membase)
|
|
||||||
+ panic("Failed to remap dma memory\n");
|
|
||||||
+
|
|
||||||
+ /* power up and reset the dma engine */
|
|
||||||
+ ltq_pmu_enable(PMU_DMA);
|
|
||||||
+ ltq_dma_w32_mask(0, DMA_RESET, LTQ_DMA_CTRL);
|
|
||||||
+
|
|
||||||
+ /* disable all interrupts */
|
|
||||||
+ ltq_dma_w32(0, LTQ_DMA_IRNEN);
|
|
||||||
+
|
|
||||||
+ /* reset/configure each channel */
|
|
||||||
+ for (i = 0; i < DMA_MAX_CHANNEL; i++) {
|
|
||||||
+ ltq_dma_w32(i, LTQ_DMA_CS);
|
|
||||||
+ ltq_dma_w32(DMA_CHAN_RST, LTQ_DMA_CCTRL);
|
|
||||||
+ ltq_dma_w32(DMA_POLL | DMA_CLK_DIV4, LTQ_DMA_CPOLL);
|
|
||||||
+ ltq_dma_w32_mask(DMA_CHAN_ON, 0, LTQ_DMA_CCTRL);
|
|
||||||
+ }
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+postcore_initcall(ltq_dma_init);
|
|
||||||
--
|
|
||||||
1.7.2.3
|
|
||||||
|
|
@ -1,943 +0,0 @@ |
|||||||
From 435de86088af82496bcba69165cd7422bb4622ec Mon Sep 17 00:00:00 2001
|
|
||||||
From: John Crispin <blogic@openwrt.org>
|
|
||||||
Date: Fri, 6 May 2011 00:10:01 +0200
|
|
||||||
Subject: [PATCH 11/13] MIPS: Lantiq: Add ethernet driver
|
|
||||||
|
|
||||||
This patch adds the driver for the ETOP Packet Processing Engine (PPE32)
|
|
||||||
found inside the XWAY family of Lantiq MIPS SoCs. This driver makes 100MBit
|
|
||||||
ethernet work. Support for all 8 dma channels, gbit and the embedded switch
|
|
||||||
found on the ar9/vr9 still needs to be implemented.
|
|
||||||
|
|
||||||
Signed-off-by: John Crispin <blogic@openwrt.org>
|
|
||||||
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
|
|
||||||
Cc: linux-mips@linux-mips.org
|
|
||||||
Cc: netdev@vger.kernel.org
|
|
||||||
Patchwork: https://patchwork.linux-mips.org/patch/2357/
|
|
||||||
Acked-by: David S. Miller <davem@davemloft.net>
|
|
||||||
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
|
|
||||||
---
|
|
||||||
.../mips/include/asm/mach-lantiq/lantiq_platform.h | 7 +
|
|
||||||
.../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 4 +-
|
|
||||||
arch/mips/lantiq/xway/devices.c | 23 +
|
|
||||||
arch/mips/lantiq/xway/devices.h | 1 +
|
|
||||||
drivers/net/Kconfig | 7 +
|
|
||||||
drivers/net/Makefile | 1 +
|
|
||||||
drivers/net/lantiq_etop.c | 805 ++++++++++++++++++++
|
|
||||||
7 files changed, 846 insertions(+), 2 deletions(-)
|
|
||||||
create mode 100644 drivers/net/lantiq_etop.c
|
|
||||||
|
|
||||||
--- a/arch/mips/include/asm/mach-lantiq/lantiq_platform.h
|
|
||||||
+++ b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h
|
|
||||||
@@ -10,6 +10,7 @@
|
|
||||||
#define _LANTIQ_PLATFORM_H__
|
|
||||||
|
|
||||||
#include <linux/mtd/partitions.h>
|
|
||||||
+#include <linux/socket.h>
|
|
||||||
|
|
||||||
/* struct used to pass info to the pci core */
|
|
||||||
enum {
|
|
||||||
@@ -43,4 +44,10 @@
|
|
||||||
int irq[16];
|
|
||||||
};
|
|
||||||
|
|
||||||
+/* struct used to pass info to network drivers */
|
|
||||||
+struct ltq_eth_data {
|
|
||||||
+ struct sockaddr mac;
|
|
||||||
+ int mii_mode;
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
#endif
|
|
||||||
--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
|
|
||||||
+++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
|
|
||||||
@@ -82,8 +82,8 @@
|
|
||||||
#define PMU_SWITCH 0x10000000
|
|
||||||
|
|
||||||
/* ETOP - ethernet */
|
|
||||||
-#define LTQ_PPE32_BASE_ADDR 0xBE180000
|
|
||||||
-#define LTQ_PPE32_SIZE 0x40000
|
|
||||||
+#define LTQ_ETOP_BASE_ADDR 0x1E180000
|
|
||||||
+#define LTQ_ETOP_SIZE 0x40000
|
|
||||||
|
|
||||||
/* DMA */
|
|
||||||
#define LTQ_DMA_BASE_ADDR 0x1E104100
|
|
||||||
--- a/arch/mips/lantiq/xway/devices.c
|
|
||||||
+++ b/arch/mips/lantiq/xway/devices.c
|
|
||||||
@@ -96,3 +96,26 @@
|
|
||||||
platform_device_register_simple("ltq_asc", 0,
|
|
||||||
ltq_ase_asc_resources, ARRAY_SIZE(ltq_ase_asc_resources));
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+/* ethernet */
|
|
||||||
+static struct resource ltq_etop_resources = {
|
|
||||||
+ .name = "etop",
|
|
||||||
+ .start = LTQ_ETOP_BASE_ADDR,
|
|
||||||
+ .end = LTQ_ETOP_BASE_ADDR + LTQ_ETOP_SIZE - 1,
|
|
||||||
+ .flags = IORESOURCE_MEM,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static struct platform_device ltq_etop = {
|
|
||||||
+ .name = "ltq_etop",
|
|
||||||
+ .resource = <q_etop_resources,
|
|
||||||
+ .num_resources = 1,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+void __init
|
|
||||||
+ltq_register_etop(struct ltq_eth_data *eth)
|
|
||||||
+{
|
|
||||||
+ if (eth) {
|
|
||||||
+ ltq_etop.dev.platform_data = eth;
|
|
||||||
+ platform_device_register(<q_etop);
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
--- a/arch/mips/lantiq/xway/devices.h
|
|
||||||
+++ b/arch/mips/lantiq/xway/devices.h
|
|
||||||
@@ -15,5 +15,6 @@
|
|
||||||
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);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
--- a/drivers/net/Kconfig
|
|
||||||
+++ b/drivers/net/Kconfig
|
|
||||||
@@ -1951,6 +1951,13 @@
|
|
||||||
This driver supports the ethernet MACs in the Broadcom 63xx
|
|
||||||
MIPS chipset family (BCM63XX).
|
|
||||||
|
|
||||||
+config LANTIQ_ETOP
|
|
||||||
+ tristate "Lantiq SoC ETOP driver"
|
|
||||||
+ depends on SOC_TYPE_XWAY
|
|
||||||
+ help
|
|
||||||
+ Support for the MII0 inside the Lantiq SoC
|
|
||||||
+
|
|
||||||
+
|
|
||||||
source "drivers/net/fs_enet/Kconfig"
|
|
||||||
|
|
||||||
endif # NET_ETHERNET
|
|
||||||
--- a/drivers/net/Makefile
|
|
||||||
+++ b/drivers/net/Makefile
|
|
||||||
@@ -246,6 +246,7 @@
|
|
||||||
obj-$(CONFIG_MLX4_CORE) += mlx4/
|
|
||||||
obj-$(CONFIG_ENC28J60) += enc28j60.o
|
|
||||||
obj-$(CONFIG_ETHOC) += ethoc.o
|
|
||||||
+obj-$(CONFIG_LANTIQ_ETOP) += lantiq_etop.o
|
|
||||||
|
|
||||||
obj-$(CONFIG_XTENSA_XT2000_SONIC) += xtsonic.o
|
|
||||||
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/drivers/net/lantiq_etop.c
|
|
||||||
@@ -0,0 +1,814 @@
|
|
||||||
+/*
|
|
||||||
+ * 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.
|
|
||||||
+ *
|
|
||||||
+ * 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.
|
|
||||||
+ *
|
|
||||||
+ * Copyright (C) 2011 John Crispin <blogic@openwrt.org>
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#include <linux/kernel.h>
|
|
||||||
+#include <linux/slab.h>
|
|
||||||
+#include <linux/errno.h>
|
|
||||||
+#include <linux/types.h>
|
|
||||||
+#include <linux/interrupt.h>
|
|
||||||
+#include <linux/uaccess.h>
|
|
||||||
+#include <linux/in.h>
|
|
||||||
+#include <linux/netdevice.h>
|
|
||||||
+#include <linux/etherdevice.h>
|
|
||||||
+#include <linux/phy.h>
|
|
||||||
+#include <linux/ip.h>
|
|
||||||
+#include <linux/tcp.h>
|
|
||||||
+#include <linux/skbuff.h>
|
|
||||||
+#include <linux/mm.h>
|
|
||||||
+#include <linux/platform_device.h>
|
|
||||||
+#include <linux/ethtool.h>
|
|
||||||
+#include <linux/init.h>
|
|
||||||
+#include <linux/delay.h>
|
|
||||||
+#include <linux/io.h>
|
|
||||||
+
|
|
||||||
+#include <asm/checksum.h>
|
|
||||||
+
|
|
||||||
+#include <lantiq_soc.h>
|
|
||||||
+#include <xway_dma.h>
|
|
||||||
+#include <lantiq_platform.h>
|
|
||||||
+
|
|
||||||
+#define LTQ_ETOP_MDIO 0x11804
|
|
||||||
+#define MDIO_REQUEST 0x80000000
|
|
||||||
+#define MDIO_READ 0x40000000
|
|
||||||
+#define MDIO_ADDR_MASK 0x1f
|
|
||||||
+#define MDIO_ADDR_OFFSET 0x15
|
|
||||||
+#define MDIO_REG_MASK 0x1f
|
|
||||||
+#define MDIO_REG_OFFSET 0x10
|
|
||||||
+#define MDIO_VAL_MASK 0xffff
|
|
||||||
+
|
|
||||||
+#define PPE32_CGEN 0x800
|
|
||||||
+#define LTQ_PPE32_ENET_MAC_CFG 0x1840
|
|
||||||
+
|
|
||||||
+#define LTQ_ETOP_ENETS0 0x11850
|
|
||||||
+#define LTQ_ETOP_MAC_DA0 0x1186C
|
|
||||||
+#define LTQ_ETOP_MAC_DA1 0x11870
|
|
||||||
+#define LTQ_ETOP_CFG 0x16020
|
|
||||||
+#define LTQ_ETOP_IGPLEN 0x16080
|
|
||||||
+
|
|
||||||
+#define MAX_DMA_CHAN 0x8
|
|
||||||
+#define MAX_DMA_CRC_LEN 0x4
|
|
||||||
+#define MAX_DMA_DATA_LEN 0x600
|
|
||||||
+
|
|
||||||
+#define ETOP_FTCU BIT(28)
|
|
||||||
+#define ETOP_MII_MASK 0xf
|
|
||||||
+#define ETOP_MII_NORMAL 0xd
|
|
||||||
+#define ETOP_MII_REVERSE 0xe
|
|
||||||
+#define ETOP_PLEN_UNDER 0x40
|
|
||||||
+#define ETOP_CGEN 0x800
|
|
||||||
+
|
|
||||||
+/* use 2 static channels for TX/RX */
|
|
||||||
+#define LTQ_ETOP_TX_CHANNEL 1
|
|
||||||
+#define LTQ_ETOP_RX_CHANNEL 6
|
|
||||||
+#define IS_TX(x) (x == LTQ_ETOP_TX_CHANNEL)
|
|
||||||
+#define IS_RX(x) (x == LTQ_ETOP_RX_CHANNEL)
|
|
||||||
+
|
|
||||||
+#define ltq_etop_r32(x) ltq_r32(ltq_etop_membase + (x))
|
|
||||||
+#define ltq_etop_w32(x, y) ltq_w32(x, ltq_etop_membase + (y))
|
|
||||||
+#define ltq_etop_w32_mask(x, y, z) \
|
|
||||||
+ ltq_w32_mask(x, y, ltq_etop_membase + (z))
|
|
||||||
+
|
|
||||||
+#define DRV_VERSION "1.0"
|
|
||||||
+
|
|
||||||
+#ifndef netdev_err
|
|
||||||
+#define netdev_err(a, b, ...) printk(b, ##__VA_ARGS__)
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
+#ifndef pr_warn
|
|
||||||
+#define pr_warn pr_warning
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
+static void __iomem *ltq_etop_membase;
|
|
||||||
+
|
|
||||||
+struct ltq_etop_chan {
|
|
||||||
+ int idx;
|
|
||||||
+ int tx_free;
|
|
||||||
+ struct net_device *netdev;
|
|
||||||
+ struct napi_struct napi;
|
|
||||||
+ struct ltq_dma_channel dma;
|
|
||||||
+ struct sk_buff *skb[LTQ_DESC_NUM];
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+struct ltq_etop_priv {
|
|
||||||
+ struct net_device *netdev;
|
|
||||||
+ struct ltq_eth_data *pldata;
|
|
||||||
+ struct resource *res;
|
|
||||||
+
|
|
||||||
+ struct mii_bus *mii_bus;
|
|
||||||
+ struct phy_device *phydev;
|
|
||||||
+
|
|
||||||
+ struct ltq_etop_chan ch[MAX_DMA_CHAN];
|
|
||||||
+ int tx_free[MAX_DMA_CHAN >> 1];
|
|
||||||
+
|
|
||||||
+ spinlock_t lock;
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static int
|
|
||||||
+ltq_etop_alloc_skb(struct ltq_etop_chan *ch)
|
|
||||||
+{
|
|
||||||
+ ch->skb[ch->dma.desc] = dev_alloc_skb(MAX_DMA_DATA_LEN);
|
|
||||||
+ if (!ch->skb[ch->dma.desc])
|
|
||||||
+ return -ENOMEM;
|
|
||||||
+ ch->dma.desc_base[ch->dma.desc].addr = dma_map_single(NULL,
|
|
||||||
+ ch->skb[ch->dma.desc]->data, MAX_DMA_DATA_LEN,
|
|
||||||
+ DMA_FROM_DEVICE);
|
|
||||||
+ ch->dma.desc_base[ch->dma.desc].addr =
|
|
||||||
+ CPHYSADDR(ch->skb[ch->dma.desc]->data);
|
|
||||||
+ ch->dma.desc_base[ch->dma.desc].ctl =
|
|
||||||
+ LTQ_DMA_OWN | LTQ_DMA_RX_OFFSET(NET_IP_ALIGN) |
|
|
||||||
+ MAX_DMA_DATA_LEN;
|
|
||||||
+ skb_reserve(ch->skb[ch->dma.desc], NET_IP_ALIGN);
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+ltq_etop_hw_receive(struct ltq_etop_chan *ch)
|
|
||||||
+{
|
|
||||||
+ struct ltq_etop_priv *priv = netdev_priv(ch->netdev);
|
|
||||||
+ struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc];
|
|
||||||
+ struct sk_buff *skb = ch->skb[ch->dma.desc];
|
|
||||||
+ int len = (desc->ctl & LTQ_DMA_SIZE_MASK) - MAX_DMA_CRC_LEN;
|
|
||||||
+ unsigned long flags;
|
|
||||||
+
|
|
||||||
+ spin_lock_irqsave(&priv->lock, flags);
|
|
||||||
+ if (ltq_etop_alloc_skb(ch)) {
|
|
||||||
+ netdev_err(ch->netdev,
|
|
||||||
+ "failed to allocate new rx buffer, stopping DMA\n");
|
|
||||||
+ ltq_dma_close(&ch->dma);
|
|
||||||
+ }
|
|
||||||
+ ch->dma.desc++;
|
|
||||||
+ ch->dma.desc %= LTQ_DESC_NUM;
|
|
||||||
+ spin_unlock_irqrestore(&priv->lock, flags);
|
|
||||||
+
|
|
||||||
+ skb_put(skb, len);
|
|
||||||
+ skb->dev = ch->netdev;
|
|
||||||
+ skb->protocol = eth_type_trans(skb, ch->netdev);
|
|
||||||
+ netif_receive_skb(skb);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int
|
|
||||||
+ltq_etop_poll_rx(struct napi_struct *napi, int budget)
|
|
||||||
+{
|
|
||||||
+ struct ltq_etop_chan *ch = container_of(napi,
|
|
||||||
+ struct ltq_etop_chan, napi);
|
|
||||||
+ int rx = 0;
|
|
||||||
+ int complete = 0;
|
|
||||||
+
|
|
||||||
+ while ((rx < budget) && !complete) {
|
|
||||||
+ struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc];
|
|
||||||
+
|
|
||||||
+ if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) == LTQ_DMA_C) {
|
|
||||||
+ ltq_etop_hw_receive(ch);
|
|
||||||
+ rx++;
|
|
||||||
+ } else {
|
|
||||||
+ complete = 1;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ if (complete || !rx) {
|
|
||||||
+ napi_complete(&ch->napi);
|
|
||||||
+ ltq_dma_ack_irq(&ch->dma);
|
|
||||||
+ }
|
|
||||||
+ return rx;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int
|
|
||||||
+ltq_etop_poll_tx(struct napi_struct *napi, int budget)
|
|
||||||
+{
|
|
||||||
+ struct ltq_etop_chan *ch =
|
|
||||||
+ container_of(napi, struct ltq_etop_chan, napi);
|
|
||||||
+ struct ltq_etop_priv *priv = netdev_priv(ch->netdev);
|
|
||||||
+ struct netdev_queue *txq =
|
|
||||||
+ netdev_get_tx_queue(ch->netdev, ch->idx >> 1);
|
|
||||||
+ unsigned long flags;
|
|
||||||
+
|
|
||||||
+ spin_lock_irqsave(&priv->lock, flags);
|
|
||||||
+ while ((ch->dma.desc_base[ch->tx_free].ctl &
|
|
||||||
+ (LTQ_DMA_OWN | LTQ_DMA_C)) == LTQ_DMA_C) {
|
|
||||||
+ dev_kfree_skb_any(ch->skb[ch->tx_free]);
|
|
||||||
+ ch->skb[ch->tx_free] = NULL;
|
|
||||||
+ memset(&ch->dma.desc_base[ch->tx_free], 0,
|
|
||||||
+ sizeof(struct ltq_dma_desc));
|
|
||||||
+ ch->tx_free++;
|
|
||||||
+ ch->tx_free %= LTQ_DESC_NUM;
|
|
||||||
+ }
|
|
||||||
+ spin_unlock_irqrestore(&priv->lock, flags);
|
|
||||||
+
|
|
||||||
+ if (netif_tx_queue_stopped(txq))
|
|
||||||
+ netif_tx_start_queue(txq);
|
|
||||||
+ napi_complete(&ch->napi);
|
|
||||||
+ ltq_dma_ack_irq(&ch->dma);
|
|
||||||
+ return 1;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static irqreturn_t
|
|
||||||
+ltq_etop_dma_irq(int irq, void *_priv)
|
|
||||||
+{
|
|
||||||
+ struct ltq_etop_priv *priv = _priv;
|
|
||||||
+ int ch = irq - LTQ_DMA_CH0_INT;
|
|
||||||
+
|
|
||||||
+ napi_schedule(&priv->ch[ch].napi);
|
|
||||||
+ return IRQ_HANDLED;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+ltq_etop_free_channel(struct net_device *dev, struct ltq_etop_chan *ch)
|
|
||||||
+{
|
|
||||||
+ struct ltq_etop_priv *priv = netdev_priv(dev);
|
|
||||||
+
|
|
||||||
+ ltq_dma_free(&ch->dma);
|
|
||||||
+ if (ch->dma.irq)
|
|
||||||
+ free_irq(ch->dma.irq, priv);
|
|
||||||
+ if (IS_RX(ch->idx)) {
|
|
||||||
+ int desc;
|
|
||||||
+ for (desc = 0; desc < LTQ_DESC_NUM; desc++)
|
|
||||||
+ dev_kfree_skb_any(ch->skb[ch->dma.desc]);
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+ltq_etop_hw_exit(struct net_device *dev)
|
|
||||||
+{
|
|
||||||
+ struct ltq_etop_priv *priv = netdev_priv(dev);
|
|
||||||
+ int i;
|
|
||||||
+
|
|
||||||
+ ltq_pmu_disable(PMU_PPE);
|
|
||||||
+ for (i = 0; i < MAX_DMA_CHAN; i++)
|
|
||||||
+ if (IS_TX(i) || IS_RX(i))
|
|
||||||
+ ltq_etop_free_channel(dev, &priv->ch[i]);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int
|
|
||||||
+ltq_etop_hw_init(struct net_device *dev)
|
|
||||||
+{
|
|
||||||
+ struct ltq_etop_priv *priv = netdev_priv(dev);
|
|
||||||
+ int i;
|
|
||||||
+
|
|
||||||
+ ltq_pmu_enable(PMU_PPE);
|
|
||||||
+
|
|
||||||
+ switch (priv->pldata->mii_mode) {
|
|
||||||
+ case PHY_INTERFACE_MODE_RMII:
|
|
||||||
+ ltq_etop_w32_mask(ETOP_MII_MASK,
|
|
||||||
+ ETOP_MII_REVERSE, LTQ_ETOP_CFG);
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
+ case PHY_INTERFACE_MODE_MII:
|
|
||||||
+ ltq_etop_w32_mask(ETOP_MII_MASK,
|
|
||||||
+ ETOP_MII_NORMAL, LTQ_ETOP_CFG);
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
+ default:
|
|
||||||
+ netdev_err(dev, "unknown mii mode %d\n",
|
|
||||||
+ priv->pldata->mii_mode);
|
|
||||||
+ return -ENOTSUPP;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* enable crc generation */
|
|
||||||
+ ltq_etop_w32(PPE32_CGEN, LTQ_PPE32_ENET_MAC_CFG);
|
|
||||||
+
|
|
||||||
+ ltq_dma_init_port(DMA_PORT_ETOP);
|
|
||||||
+
|
|
||||||
+ for (i = 0; i < MAX_DMA_CHAN; i++) {
|
|
||||||
+ int irq = LTQ_DMA_CH0_INT + i;
|
|
||||||
+ struct ltq_etop_chan *ch = &priv->ch[i];
|
|
||||||
+
|
|
||||||
+ ch->idx = ch->dma.nr = i;
|
|
||||||
+
|
|
||||||
+ if (IS_TX(i)) {
|
|
||||||
+ ltq_dma_alloc_tx(&ch->dma);
|
|
||||||
+ request_irq(irq, ltq_etop_dma_irq, IRQF_DISABLED,
|
|
||||||
+ "etop_tx", priv);
|
|
||||||
+ } else if (IS_RX(i)) {
|
|
||||||
+ ltq_dma_alloc_rx(&ch->dma);
|
|
||||||
+ for (ch->dma.desc = 0; ch->dma.desc < LTQ_DESC_NUM;
|
|
||||||
+ ch->dma.desc++)
|
|
||||||
+ if (ltq_etop_alloc_skb(ch))
|
|
||||||
+ return -ENOMEM;
|
|
||||||
+ ch->dma.desc = 0;
|
|
||||||
+ request_irq(irq, ltq_etop_dma_irq, IRQF_DISABLED,
|
|
||||||
+ "etop_rx", priv);
|
|
||||||
+ }
|
|
||||||
+ ch->dma.irq = irq;
|
|
||||||
+ }
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+ltq_etop_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
|
|
||||||
+{
|
|
||||||
+ strcpy(info->driver, "Lantiq ETOP");
|
|
||||||
+ strcpy(info->bus_info, "internal");
|
|
||||||
+ strcpy(info->version, DRV_VERSION);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int
|
|
||||||
+ltq_etop_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
|
|
||||||
+{
|
|
||||||
+ struct ltq_etop_priv *priv = netdev_priv(dev);
|
|
||||||
+
|
|
||||||
+ return phy_ethtool_gset(priv->phydev, cmd);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int
|
|
||||||
+ltq_etop_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
|
|
||||||
+{
|
|
||||||
+ struct ltq_etop_priv *priv = netdev_priv(dev);
|
|
||||||
+
|
|
||||||
+ return phy_ethtool_sset(priv->phydev, cmd);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int
|
|
||||||
+ltq_etop_nway_reset(struct net_device *dev)
|
|
||||||
+{
|
|
||||||
+ struct ltq_etop_priv *priv = netdev_priv(dev);
|
|
||||||
+
|
|
||||||
+ return phy_start_aneg(priv->phydev);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static const struct ethtool_ops ltq_etop_ethtool_ops = {
|
|
||||||
+ .get_drvinfo = ltq_etop_get_drvinfo,
|
|
||||||
+ .get_settings = ltq_etop_get_settings,
|
|
||||||
+ .set_settings = ltq_etop_set_settings,
|
|
||||||
+ .nway_reset = ltq_etop_nway_reset,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static int
|
|
||||||
+ltq_etop_mdio_wr(struct mii_bus *bus, int phy_addr, int phy_reg, u16 phy_data)
|
|
||||||
+{
|
|
||||||
+ u32 val = MDIO_REQUEST |
|
|
||||||
+ ((phy_addr & MDIO_ADDR_MASK) << MDIO_ADDR_OFFSET) |
|
|
||||||
+ ((phy_reg & MDIO_REG_MASK) << MDIO_REG_OFFSET) |
|
|
||||||
+ phy_data;
|
|
||||||
+
|
|
||||||
+ while (ltq_etop_r32(LTQ_ETOP_MDIO) & MDIO_REQUEST)
|
|
||||||
+ ;
|
|
||||||
+ ltq_etop_w32(val, LTQ_ETOP_MDIO);
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int
|
|
||||||
+ltq_etop_mdio_rd(struct mii_bus *bus, int phy_addr, int phy_reg)
|
|
||||||
+{
|
|
||||||
+ u32 val = MDIO_REQUEST | MDIO_READ |
|
|
||||||
+ ((phy_addr & MDIO_ADDR_MASK) << MDIO_ADDR_OFFSET) |
|
|
||||||
+ ((phy_reg & MDIO_REG_MASK) << MDIO_REG_OFFSET);
|
|
||||||
+
|
|
||||||
+ while (ltq_etop_r32(LTQ_ETOP_MDIO) & MDIO_REQUEST)
|
|
||||||
+ ;
|
|
||||||
+ ltq_etop_w32(val, LTQ_ETOP_MDIO);
|
|
||||||
+ while (ltq_etop_r32(LTQ_ETOP_MDIO) & MDIO_REQUEST)
|
|
||||||
+ ;
|
|
||||||
+ val = ltq_etop_r32(LTQ_ETOP_MDIO) & MDIO_VAL_MASK;
|
|
||||||
+ return val;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+ltq_etop_mdio_link(struct net_device *dev)
|
|
||||||
+{
|
|
||||||
+ /* nothing to do */
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int
|
|
||||||
+ltq_etop_mdio_probe(struct net_device *dev)
|
|
||||||
+{
|
|
||||||
+ struct ltq_etop_priv *priv = netdev_priv(dev);
|
|
||||||
+ struct phy_device *phydev = NULL;
|
|
||||||
+ int phy_addr;
|
|
||||||
+
|
|
||||||
+ for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
|
|
||||||
+ if (priv->mii_bus->phy_map[phy_addr]) {
|
|
||||||
+ phydev = priv->mii_bus->phy_map[phy_addr];
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (!phydev) {
|
|
||||||
+ netdev_err(dev, "no PHY found\n");
|
|
||||||
+ return -ENODEV;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ phydev = phy_connect(dev, dev_name(&phydev->dev), <q_etop_mdio_link,
|
|
||||||
+ 0, priv->pldata->mii_mode);
|
|
||||||
+
|
|
||||||
+ if (IS_ERR(phydev)) {
|
|
||||||
+ netdev_err(dev, "Could not attach to PHY\n");
|
|
||||||
+ return PTR_ERR(phydev);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ phydev->supported &= (SUPPORTED_10baseT_Half
|
|
||||||
+ | SUPPORTED_10baseT_Full
|
|
||||||
+ | SUPPORTED_100baseT_Half
|
|
||||||
+ | SUPPORTED_100baseT_Full
|
|
||||||
+ | SUPPORTED_Autoneg
|
|
||||||
+ | SUPPORTED_MII
|
|
||||||
+ | SUPPORTED_TP);
|
|
||||||
+
|
|
||||||
+ phydev->advertising = phydev->supported;
|
|
||||||
+ priv->phydev = phydev;
|
|
||||||
+ pr_info("%s: attached PHY [%s] (phy_addr=%s, irq=%d)\n",
|
|
||||||
+ dev->name, phydev->drv->name,
|
|
||||||
+ dev_name(&phydev->dev), phydev->irq);
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int
|
|
||||||
+ltq_etop_mdio_init(struct net_device *dev)
|
|
||||||
+{
|
|
||||||
+ struct ltq_etop_priv *priv = netdev_priv(dev);
|
|
||||||
+ int i;
|
|
||||||
+ int err;
|
|
||||||
+
|
|
||||||
+ priv->mii_bus = mdiobus_alloc();
|
|
||||||
+ if (!priv->mii_bus) {
|
|
||||||
+ netdev_err(dev, "failed to allocate mii bus\n");
|
|
||||||
+ err = -ENOMEM;
|
|
||||||
+ goto err_out;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ priv->mii_bus->priv = dev;
|
|
||||||
+ priv->mii_bus->read = ltq_etop_mdio_rd;
|
|
||||||
+ priv->mii_bus->write = ltq_etop_mdio_wr;
|
|
||||||
+ priv->mii_bus->name = "ltq_mii";
|
|
||||||
+ snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%x", 0);
|
|
||||||
+ priv->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
|
|
||||||
+ if (!priv->mii_bus->irq) {
|
|
||||||
+ err = -ENOMEM;
|
|
||||||
+ goto err_out_free_mdiobus;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ for (i = 0; i < PHY_MAX_ADDR; ++i)
|
|
||||||
+ priv->mii_bus->irq[i] = PHY_POLL;
|
|
||||||
+
|
|
||||||
+ if (mdiobus_register(priv->mii_bus)) {
|
|
||||||
+ err = -ENXIO;
|
|
||||||
+ goto err_out_free_mdio_irq;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (ltq_etop_mdio_probe(dev)) {
|
|
||||||
+ err = -ENXIO;
|
|
||||||
+ goto err_out_unregister_bus;
|
|
||||||
+ }
|
|
||||||
+ return 0;
|
|
||||||
+
|
|
||||||
+err_out_unregister_bus:
|
|
||||||
+ mdiobus_unregister(priv->mii_bus);
|
|
||||||
+err_out_free_mdio_irq:
|
|
||||||
+ kfree(priv->mii_bus->irq);
|
|
||||||
+err_out_free_mdiobus:
|
|
||||||
+ mdiobus_free(priv->mii_bus);
|
|
||||||
+err_out:
|
|
||||||
+ return err;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+ltq_etop_mdio_cleanup(struct net_device *dev)
|
|
||||||
+{
|
|
||||||
+ struct ltq_etop_priv *priv = netdev_priv(dev);
|
|
||||||
+
|
|
||||||
+ phy_disconnect(priv->phydev);
|
|
||||||
+ mdiobus_unregister(priv->mii_bus);
|
|
||||||
+ kfree(priv->mii_bus->irq);
|
|
||||||
+ mdiobus_free(priv->mii_bus);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int
|
|
||||||
+ltq_etop_open(struct net_device *dev)
|
|
||||||
+{
|
|
||||||
+ struct ltq_etop_priv *priv = netdev_priv(dev);
|
|
||||||
+ int i;
|
|
||||||
+
|
|
||||||
+ for (i = 0; i < MAX_DMA_CHAN; i++) {
|
|
||||||
+ struct ltq_etop_chan *ch = &priv->ch[i];
|
|
||||||
+
|
|
||||||
+ if (!IS_TX(i) && (!IS_RX(i)))
|
|
||||||
+ continue;
|
|
||||||
+ ltq_dma_open(&ch->dma);
|
|
||||||
+ napi_enable(&ch->napi);
|
|
||||||
+ }
|
|
||||||
+ phy_start(priv->phydev);
|
|
||||||
+ netif_tx_start_all_queues(dev);
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int
|
|
||||||
+ltq_etop_stop(struct net_device *dev)
|
|
||||||
+{
|
|
||||||
+ struct ltq_etop_priv *priv = netdev_priv(dev);
|
|
||||||
+ int i;
|
|
||||||
+
|
|
||||||
+ netif_tx_stop_all_queues(dev);
|
|
||||||
+ phy_stop(priv->phydev);
|
|
||||||
+ for (i = 0; i < MAX_DMA_CHAN; i++) {
|
|
||||||
+ struct ltq_etop_chan *ch = &priv->ch[i];
|
|
||||||
+
|
|
||||||
+ if (!IS_RX(i) && !IS_TX(i))
|
|
||||||
+ continue;
|
|
||||||
+ napi_disable(&ch->napi);
|
|
||||||
+ ltq_dma_close(&ch->dma);
|
|
||||||
+ }
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int
|
|
||||||
+ltq_etop_tx(struct sk_buff *skb, struct net_device *dev)
|
|
||||||
+{
|
|
||||||
+ int queue = skb_get_queue_mapping(skb);
|
|
||||||
+ struct netdev_queue *txq = netdev_get_tx_queue(dev, queue);
|
|
||||||
+ struct ltq_etop_priv *priv = netdev_priv(dev);
|
|
||||||
+ struct ltq_etop_chan *ch = &priv->ch[(queue << 1) | 1];
|
|
||||||
+ struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc];
|
|
||||||
+ int len;
|
|
||||||
+ unsigned long flags;
|
|
||||||
+ u32 byte_offset;
|
|
||||||
+
|
|
||||||
+ len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
|
|
||||||
+
|
|
||||||
+ if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) || ch->skb[ch->dma.desc]) {
|
|
||||||
+ dev_kfree_skb_any(skb);
|
|
||||||
+ netdev_err(dev, "tx ring full\n");
|
|
||||||
+ netif_tx_stop_queue(txq);
|
|
||||||
+ return NETDEV_TX_BUSY;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* dma needs to start on a 16 byte aligned address */
|
|
||||||
+ byte_offset = CPHYSADDR(skb->data) % 16;
|
|
||||||
+ ch->skb[ch->dma.desc] = skb;
|
|
||||||
+
|
|
||||||
+ dev->trans_start = jiffies;
|
|
||||||
+
|
|
||||||
+ spin_lock_irqsave(&priv->lock, flags);
|
|
||||||
+ desc->addr = ((unsigned int) dma_map_single(NULL, skb->data, len,
|
|
||||||
+ DMA_TO_DEVICE)) - byte_offset;
|
|
||||||
+ wmb();
|
|
||||||
+ desc->ctl = LTQ_DMA_OWN | LTQ_DMA_SOP | LTQ_DMA_EOP |
|
|
||||||
+ LTQ_DMA_TX_OFFSET(byte_offset) | (len & LTQ_DMA_SIZE_MASK);
|
|
||||||
+ ch->dma.desc++;
|
|
||||||
+ ch->dma.desc %= LTQ_DESC_NUM;
|
|
||||||
+ spin_unlock_irqrestore(&priv->lock, flags);
|
|
||||||
+
|
|
||||||
+ if (ch->dma.desc_base[ch->dma.desc].ctl & LTQ_DMA_OWN)
|
|
||||||
+ netif_tx_stop_queue(txq);
|
|
||||||
+
|
|
||||||
+ return NETDEV_TX_OK;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int
|
|
||||||
+ltq_etop_change_mtu(struct net_device *dev, int new_mtu)
|
|
||||||
+{
|
|
||||||
+ int ret = eth_change_mtu(dev, new_mtu);
|
|
||||||
+
|
|
||||||
+ if (!ret) {
|
|
||||||
+ struct ltq_etop_priv *priv = netdev_priv(dev);
|
|
||||||
+ unsigned long flags;
|
|
||||||
+
|
|
||||||
+ spin_lock_irqsave(&priv->lock, flags);
|
|
||||||
+ ltq_etop_w32((ETOP_PLEN_UNDER << 16) | new_mtu,
|
|
||||||
+ LTQ_ETOP_IGPLEN);
|
|
||||||
+ spin_unlock_irqrestore(&priv->lock, flags);
|
|
||||||
+ }
|
|
||||||
+ return ret;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int
|
|
||||||
+ltq_etop_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
|
|
||||||
+{
|
|
||||||
+ struct ltq_etop_priv *priv = netdev_priv(dev);
|
|
||||||
+ struct mii_ioctl_data *data = if_mii(rq);
|
|
||||||
+
|
|
||||||
+ /* TODO: mii-toll reports "No MII transceiver present!." ?!*/
|
|
||||||
+ return phy_mii_ioctl(priv->phydev, data, cmd);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int
|
|
||||||
+ltq_etop_set_mac_address(struct net_device *dev, void *p)
|
|
||||||
+{
|
|
||||||
+ int ret = eth_mac_addr(dev, p);
|
|
||||||
+
|
|
||||||
+ if (!ret) {
|
|
||||||
+ struct ltq_etop_priv *priv = netdev_priv(dev);
|
|
||||||
+ unsigned long flags;
|
|
||||||
+
|
|
||||||
+ /* store the mac for the unicast filter */
|
|
||||||
+ spin_lock_irqsave(&priv->lock, flags);
|
|
||||||
+ ltq_etop_w32(*((u32 *)dev->dev_addr), LTQ_ETOP_MAC_DA0);
|
|
||||||
+ ltq_etop_w32(*((u16 *)&dev->dev_addr[4]) << 16,
|
|
||||||
+ LTQ_ETOP_MAC_DA1);
|
|
||||||
+ spin_unlock_irqrestore(&priv->lock, flags);
|
|
||||||
+ }
|
|
||||||
+ return ret;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+ltq_etop_set_multicast_list(struct net_device *dev)
|
|
||||||
+{
|
|
||||||
+ struct ltq_etop_priv *priv = netdev_priv(dev);
|
|
||||||
+ unsigned long flags;
|
|
||||||
+
|
|
||||||
+ /* ensure that the unicast filter is not enabled in promiscious mode */
|
|
||||||
+ spin_lock_irqsave(&priv->lock, flags);
|
|
||||||
+ if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI))
|
|
||||||
+ ltq_etop_w32_mask(ETOP_FTCU, 0, LTQ_ETOP_ENETS0);
|
|
||||||
+ else
|
|
||||||
+ ltq_etop_w32_mask(0, ETOP_FTCU, LTQ_ETOP_ENETS0);
|
|
||||||
+ spin_unlock_irqrestore(&priv->lock, flags);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static u16
|
|
||||||
+ltq_etop_select_queue(struct net_device *dev, struct sk_buff *skb)
|
|
||||||
+{
|
|
||||||
+ /* we are currently only using the first queue */
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int
|
|
||||||
+ltq_etop_init(struct net_device *dev)
|
|
||||||
+{
|
|
||||||
+ struct ltq_etop_priv *priv = netdev_priv(dev);
|
|
||||||
+ struct sockaddr mac;
|
|
||||||
+ int err;
|
|
||||||
+
|
|
||||||
+ ether_setup(dev);
|
|
||||||
+ dev->watchdog_timeo = 10 * HZ;
|
|
||||||
+ err = ltq_etop_hw_init(dev);
|
|
||||||
+ if (err)
|
|
||||||
+ goto err_hw;
|
|
||||||
+ ltq_etop_change_mtu(dev, 1500);
|
|
||||||
+
|
|
||||||
+ memcpy(&mac, &priv->pldata->mac, sizeof(struct sockaddr));
|
|
||||||
+ if (!is_valid_ether_addr(mac.sa_data)) {
|
|
||||||
+ pr_warn("etop: invalid MAC, using random\n");
|
|
||||||
+ random_ether_addr(mac.sa_data);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ err = ltq_etop_set_mac_address(dev, &mac);
|
|
||||||
+ if (err)
|
|
||||||
+ goto err_netdev;
|
|
||||||
+ ltq_etop_set_multicast_list(dev);
|
|
||||||
+ err = ltq_etop_mdio_init(dev);
|
|
||||||
+ if (err)
|
|
||||||
+ goto err_netdev;
|
|
||||||
+ return 0;
|
|
||||||
+
|
|
||||||
+err_netdev:
|
|
||||||
+ unregister_netdev(dev);
|
|
||||||
+ free_netdev(dev);
|
|
||||||
+err_hw:
|
|
||||||
+ ltq_etop_hw_exit(dev);
|
|
||||||
+ return err;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+ltq_etop_tx_timeout(struct net_device *dev)
|
|
||||||
+{
|
|
||||||
+ int err;
|
|
||||||
+
|
|
||||||
+ ltq_etop_hw_exit(dev);
|
|
||||||
+ err = ltq_etop_hw_init(dev);
|
|
||||||
+ if (err)
|
|
||||||
+ goto err_hw;
|
|
||||||
+ dev->trans_start = jiffies;
|
|
||||||
+ netif_wake_queue(dev);
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+err_hw:
|
|
||||||
+ ltq_etop_hw_exit(dev);
|
|
||||||
+ netdev_err(dev, "failed to restart etop after TX timeout\n");
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static const struct net_device_ops ltq_eth_netdev_ops = {
|
|
||||||
+ .ndo_open = ltq_etop_open,
|
|
||||||
+ .ndo_stop = ltq_etop_stop,
|
|
||||||
+ .ndo_start_xmit = ltq_etop_tx,
|
|
||||||
+ .ndo_change_mtu = ltq_etop_change_mtu,
|
|
||||||
+ .ndo_do_ioctl = ltq_etop_ioctl,
|
|
||||||
+ .ndo_set_mac_address = ltq_etop_set_mac_address,
|
|
||||||
+ .ndo_validate_addr = eth_validate_addr,
|
|
||||||
+ .ndo_set_multicast_list = ltq_etop_set_multicast_list,
|
|
||||||
+ .ndo_select_queue = ltq_etop_select_queue,
|
|
||||||
+ .ndo_init = ltq_etop_init,
|
|
||||||
+ .ndo_tx_timeout = ltq_etop_tx_timeout,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static int __init
|
|
||||||
+ltq_etop_probe(struct platform_device *pdev)
|
|
||||||
+{
|
|
||||||
+ struct net_device *dev;
|
|
||||||
+ struct ltq_etop_priv *priv;
|
|
||||||
+ struct resource *res;
|
|
||||||
+ int err;
|
|
||||||
+ int i;
|
|
||||||
+
|
|
||||||
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
||||||
+ if (!res) {
|
|
||||||
+ dev_err(&pdev->dev, "failed to get etop resource\n");
|
|
||||||
+ err = -ENOENT;
|
|
||||||
+ goto err_out;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ res = devm_request_mem_region(&pdev->dev, res->start,
|
|
||||||
+ resource_size(res), dev_name(&pdev->dev));
|
|
||||||
+ if (!res) {
|
|
||||||
+ dev_err(&pdev->dev, "failed to request etop resource\n");
|
|
||||||
+ err = -EBUSY;
|
|
||||||
+ goto err_out;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ ltq_etop_membase = devm_ioremap_nocache(&pdev->dev,
|
|
||||||
+ res->start, resource_size(res));
|
|
||||||
+ if (!ltq_etop_membase) {
|
|
||||||
+ dev_err(&pdev->dev, "failed to remap etop engine %d\n",
|
|
||||||
+ pdev->id);
|
|
||||||
+ err = -ENOMEM;
|
|
||||||
+ goto err_out;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ dev = alloc_etherdev_mq(sizeof(struct ltq_etop_priv), 4);
|
|
||||||
+ strcpy(dev->name, "eth%d");
|
|
||||||
+ dev->netdev_ops = <q_eth_netdev_ops;
|
|
||||||
+ dev->ethtool_ops = <q_etop_ethtool_ops;
|
|
||||||
+ priv = netdev_priv(dev);
|
|
||||||
+ priv->res = res;
|
|
||||||
+ priv->pldata = dev_get_platdata(&pdev->dev);
|
|
||||||
+ priv->netdev = dev;
|
|
||||||
+ spin_lock_init(&priv->lock);
|
|
||||||
+
|
|
||||||
+ for (i = 0; i < MAX_DMA_CHAN; i++) {
|
|
||||||
+ if (IS_TX(i))
|
|
||||||
+ netif_napi_add(dev, &priv->ch[i].napi,
|
|
||||||
+ ltq_etop_poll_tx, 8);
|
|
||||||
+ else if (IS_RX(i))
|
|
||||||
+ netif_napi_add(dev, &priv->ch[i].napi,
|
|
||||||
+ ltq_etop_poll_rx, 32);
|
|
||||||
+ priv->ch[i].netdev = dev;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ err = register_netdev(dev);
|
|
||||||
+ if (err)
|
|
||||||
+ goto err_free;
|
|
||||||
+
|
|
||||||
+ platform_set_drvdata(pdev, dev);
|
|
||||||
+ return 0;
|
|
||||||
+
|
|
||||||
+err_free:
|
|
||||||
+ kfree(dev);
|
|
||||||
+err_out:
|
|
||||||
+ return err;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int __devexit
|
|
||||||
+ltq_etop_remove(struct platform_device *pdev)
|
|
||||||
+{
|
|
||||||
+ struct net_device *dev = platform_get_drvdata(pdev);
|
|
||||||
+
|
|
||||||
+ if (dev) {
|
|
||||||
+ netif_tx_stop_all_queues(dev);
|
|
||||||
+ ltq_etop_hw_exit(dev);
|
|
||||||
+ ltq_etop_mdio_cleanup(dev);
|
|
||||||
+ unregister_netdev(dev);
|
|
||||||
+ }
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static struct platform_driver ltq_mii_driver = {
|
|
||||||
+ .remove = __devexit_p(ltq_etop_remove),
|
|
||||||
+ .driver = {
|
|
||||||
+ .name = "ltq_etop",
|
|
||||||
+ .owner = THIS_MODULE,
|
|
||||||
+ },
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+int __init
|
|
||||||
+init_ltq_etop(void)
|
|
||||||
+{
|
|
||||||
+ int ret = platform_driver_probe(<q_mii_driver, ltq_etop_probe);
|
|
||||||
+
|
|
||||||
+ if (ret)
|
|
||||||
+ pr_err("ltq_etop: Error registering platfom driver!");
|
|
||||||
+ return ret;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void __exit
|
|
||||||
+exit_ltq_etop(void)
|
|
||||||
+{
|
|
||||||
+ platform_driver_unregister(<q_mii_driver);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+module_init(init_ltq_etop);
|
|
||||||
+module_exit(exit_ltq_etop);
|
|
||||||
+
|
|
||||||
+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
|
|
||||||
+MODULE_DESCRIPTION("Lantiq SoC ETOP");
|
|
||||||
+MODULE_LICENSE("GPL");
|
|
@ -1,50 +0,0 @@ |
|||||||
From 72a9b536ef81f06bb8042abee0410458f5df93d2 Mon Sep 17 00:00:00 2001
|
|
||||||
From: John Crispin <blogic@openwrt.org>
|
|
||||||
Date: Fri, 6 May 2011 00:10:02 +0200
|
|
||||||
Subject: [PATCH 12/13] MIPS: Lantiq: Add etop board support
|
|
||||||
|
|
||||||
Register the etop platform device inside the machtype specific init code.
|
|
||||||
|
|
||||||
Signed-off-by: John Crispin <blogic@openwrt.org>
|
|
||||||
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
|
|
||||||
Signed-off-by: David Daney <ddaney@caviumnetworks.com>
|
|
||||||
Cc: linux-mips@linux-mips.org
|
|
||||||
Patchwork: https://patchwork.linux-mips.org/patch/2356/
|
|
||||||
Patchwork: https://patchwork.linux-mips.org/patch/2370/
|
|
||||||
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
|
|
||||||
---
|
|
||||||
arch/mips/lantiq/xway/mach-easy50712.c | 6 ++++++
|
|
||||||
1 files changed, 6 insertions(+), 0 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/arch/mips/lantiq/xway/mach-easy50712.c b/arch/mips/lantiq/xway/mach-easy50712.c
|
|
||||||
index e5e7e09..ea5027b 100644
|
|
||||||
--- a/arch/mips/lantiq/xway/mach-easy50712.c
|
|
||||||
+++ b/arch/mips/lantiq/xway/mach-easy50712.c
|
|
||||||
@@ -12,6 +12,7 @@
|
|
||||||
#include <linux/mtd/partitions.h>
|
|
||||||
#include <linux/mtd/physmap.h>
|
|
||||||
#include <linux/input.h>
|
|
||||||
+#include <linux/phy.h>
|
|
||||||
|
|
||||||
#include <lantiq_soc.h>
|
|
||||||
#include <irq.h>
|
|
||||||
@@ -55,11 +56,16 @@ static struct ltq_pci_data ltq_pci_data = {
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
+static struct ltq_eth_data ltq_eth_data = {
|
|
||||||
+ .mii_mode = PHY_INTERFACE_MODE_MII,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
static void __init easy50712_init(void)
|
|
||||||
{
|
|
||||||
ltq_register_gpio_stp();
|
|
||||||
ltq_register_nor(&easy50712_flash_data);
|
|
||||||
ltq_register_pci(<q_pci_data);
|
|
||||||
+ ltq_register_etop(<q_eth_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
MIPS_MACHINE(LTQ_MACH_EASY50712,
|
|
||||||
--
|
|
||||||
1.7.2.3
|
|
||||||
|
|
@ -1,310 +0,0 @@ |
|||||||
From 3466449c8f455da0cb646231602e6af16190f592 Mon Sep 17 00:00:00 2001
|
|
||||||
From: John Crispin <blogic@openwrt.org>
|
|
||||||
Date: Thu, 5 May 2011 23:00:23 +0200
|
|
||||||
Subject: [PATCH 13/13] MIPS: Lantiq: Add watchdog support
|
|
||||||
|
|
||||||
This patch adds the driver for the watchdog found inside the Lantiq SoC family.
|
|
||||||
|
|
||||||
Signed-off-by: John Crispin <blogic@openwrt.org>
|
|
||||||
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
|
|
||||||
Cc: Wim Van Sebroeck <wim@iguana.be>
|
|
||||||
Cc: linux-mips@linux-mips.org
|
|
||||||
Cc: linux-watchdog@vger.kernel.org
|
|
||||||
Patchwork: https://patchwork.linux-mips.org/patch/2327/
|
|
||||||
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
|
|
||||||
---
|
|
||||||
drivers/watchdog/Kconfig | 6 +
|
|
||||||
drivers/watchdog/Makefile | 1 +
|
|
||||||
drivers/watchdog/lantiq_wdt.c | 261 +++++++++++++++++++++++++++++++++++++++++
|
|
||||||
3 files changed, 268 insertions(+), 0 deletions(-)
|
|
||||||
create mode 100644 drivers/watchdog/lantiq_wdt.c
|
|
||||||
|
|
||||||
--- a/drivers/watchdog/Kconfig
|
|
||||||
+++ b/drivers/watchdog/Kconfig
|
|
||||||
@@ -850,6 +850,12 @@
|
|
||||||
help
|
|
||||||
Hardware driver for the built-in watchdog timer on TXx9 MIPS SoCs.
|
|
||||||
|
|
||||||
+config LANTIQ_WDT
|
|
||||||
+ tristate "Lantiq SoC watchdog"
|
|
||||||
+ depends on LANTIQ
|
|
||||||
+ help
|
|
||||||
+ Hardware driver for the Lantiq SoC Watchdog Timer.
|
|
||||||
+
|
|
||||||
# PARISC Architecture
|
|
||||||
|
|
||||||
# POWERPC Architecture
|
|
||||||
--- a/drivers/watchdog/Makefile
|
|
||||||
+++ b/drivers/watchdog/Makefile
|
|
||||||
@@ -113,6 +113,7 @@
|
|
||||||
obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o
|
|
||||||
obj-$(CONFIG_AR7_WDT) += ar7_wdt.o
|
|
||||||
obj-$(CONFIG_TXX9_WDT) += txx9wdt.o
|
|
||||||
+obj-$(CONFIG_LANTIQ_WDT) += lantiq_wdt.o
|
|
||||||
|
|
||||||
# PARISC Architecture
|
|
||||||
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/drivers/watchdog/lantiq_wdt.c
|
|
||||||
@@ -0,0 +1,261 @@
|
|
||||||
+/*
|
|
||||||
+ * 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>
|
|
||||||
+ * Based on EP93xx wdt driver
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#include <linux/module.h>
|
|
||||||
+#include <linux/fs.h>
|
|
||||||
+#include <linux/miscdevice.h>
|
|
||||||
+#include <linux/watchdog.h>
|
|
||||||
+#include <linux/platform_device.h>
|
|
||||||
+#include <linux/uaccess.h>
|
|
||||||
+#include <linux/clk.h>
|
|
||||||
+#include <linux/io.h>
|
|
||||||
+
|
|
||||||
+#include <lantiq.h>
|
|
||||||
+
|
|
||||||
+/* Section 3.4 of the datasheet
|
|
||||||
+ * The password sequence protects the WDT control register from unintended
|
|
||||||
+ * write actions, which might cause malfunction of the WDT.
|
|
||||||
+ *
|
|
||||||
+ * essentially the following two magic passwords need to be written to allow
|
|
||||||
+ * IO access to the WDT core
|
|
||||||
+ */
|
|
||||||
+#define LTQ_WDT_PW1 0x00BE0000
|
|
||||||
+#define LTQ_WDT_PW2 0x00DC0000
|
|
||||||
+
|
|
||||||
+#define LTQ_WDT_CR 0x0 /* watchdog control register */
|
|
||||||
+#define LTQ_WDT_SR 0x8 /* watchdog status register */
|
|
||||||
+
|
|
||||||
+#define LTQ_WDT_SR_EN (0x1 << 31) /* enable bit */
|
|
||||||
+#define LTQ_WDT_SR_PWD (0x3 << 26) /* turn on power */
|
|
||||||
+#define LTQ_WDT_SR_CLKDIV (0x3 << 24) /* turn on clock and set */
|
|
||||||
+ /* divider to 0x40000 */
|
|
||||||
+#define LTQ_WDT_DIVIDER 0x40000
|
|
||||||
+#define LTQ_MAX_TIMEOUT ((1 << 16) - 1) /* the reload field is 16 bit */
|
|
||||||
+
|
|
||||||
+static int nowayout = WATCHDOG_NOWAYOUT;
|
|
||||||
+
|
|
||||||
+static void __iomem *ltq_wdt_membase;
|
|
||||||
+static unsigned long ltq_io_region_clk_rate;
|
|
||||||
+
|
|
||||||
+static unsigned long ltq_wdt_bootstatus;
|
|
||||||
+static unsigned long ltq_wdt_in_use;
|
|
||||||
+static int ltq_wdt_timeout = 30;
|
|
||||||
+static int ltq_wdt_ok_to_close;
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+ltq_wdt_enable(void)
|
|
||||||
+{
|
|
||||||
+ ltq_wdt_timeout = ltq_wdt_timeout *
|
|
||||||
+ (ltq_io_region_clk_rate / LTQ_WDT_DIVIDER) + 0x1000;
|
|
||||||
+ if (ltq_wdt_timeout > LTQ_MAX_TIMEOUT)
|
|
||||||
+ ltq_wdt_timeout = LTQ_MAX_TIMEOUT;
|
|
||||||
+
|
|
||||||
+ /* write the first password magic */
|
|
||||||
+ ltq_w32(LTQ_WDT_PW1, ltq_wdt_membase + LTQ_WDT_CR);
|
|
||||||
+ /* write the second magic plus the configuration and new timeout */
|
|
||||||
+ ltq_w32(LTQ_WDT_SR_EN | LTQ_WDT_SR_PWD | LTQ_WDT_SR_CLKDIV |
|
|
||||||
+ LTQ_WDT_PW2 | ltq_wdt_timeout, ltq_wdt_membase + LTQ_WDT_CR);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+ltq_wdt_disable(void)
|
|
||||||
+{
|
|
||||||
+ /* write the first password magic */
|
|
||||||
+ ltq_w32(LTQ_WDT_PW1, ltq_wdt_membase + LTQ_WDT_CR);
|
|
||||||
+ /* write the second password magic with no config
|
|
||||||
+ * this turns the watchdog off
|
|
||||||
+ */
|
|
||||||
+ ltq_w32(LTQ_WDT_PW2, ltq_wdt_membase + LTQ_WDT_CR);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static ssize_t
|
|
||||||
+ltq_wdt_write(struct file *file, const char __user *data,
|
|
||||||
+ size_t len, loff_t *ppos)
|
|
||||||
+{
|
|
||||||
+ if (len) {
|
|
||||||
+ if (!nowayout) {
|
|
||||||
+ size_t i;
|
|
||||||
+
|
|
||||||
+ ltq_wdt_ok_to_close = 0;
|
|
||||||
+ for (i = 0; i != len; i++) {
|
|
||||||
+ char c;
|
|
||||||
+
|
|
||||||
+ if (get_user(c, data + i))
|
|
||||||
+ return -EFAULT;
|
|
||||||
+ if (c == 'V')
|
|
||||||
+ ltq_wdt_ok_to_close = 1;
|
|
||||||
+ else
|
|
||||||
+ ltq_wdt_ok_to_close = 0;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ ltq_wdt_enable();
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return len;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static struct watchdog_info ident = {
|
|
||||||
+ .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
|
|
||||||
+ WDIOF_CARDRESET,
|
|
||||||
+ .identity = "ltq_wdt",
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static long
|
|
||||||
+ltq_wdt_ioctl(struct file *file,
|
|
||||||
+ unsigned int cmd, unsigned long arg)
|
|
||||||
+{
|
|
||||||
+ int ret = -ENOTTY;
|
|
||||||
+
|
|
||||||
+ switch (cmd) {
|
|
||||||
+ case WDIOC_GETSUPPORT:
|
|
||||||
+ ret = copy_to_user((struct watchdog_info __user *)arg, &ident,
|
|
||||||
+ sizeof(ident)) ? -EFAULT : 0;
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
+ case WDIOC_GETBOOTSTATUS:
|
|
||||||
+ ret = put_user(ltq_wdt_bootstatus, (int __user *)arg);
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
+ case WDIOC_GETSTATUS:
|
|
||||||
+ ret = put_user(0, (int __user *)arg);
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
+ case WDIOC_SETTIMEOUT:
|
|
||||||
+ ret = get_user(ltq_wdt_timeout, (int __user *)arg);
|
|
||||||
+ if (!ret)
|
|
||||||
+ ltq_wdt_enable();
|
|
||||||
+ /* intentional drop through */
|
|
||||||
+ case WDIOC_GETTIMEOUT:
|
|
||||||
+ ret = put_user(ltq_wdt_timeout, (int __user *)arg);
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
+ case WDIOC_KEEPALIVE:
|
|
||||||
+ ltq_wdt_enable();
|
|
||||||
+ ret = 0;
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+ return ret;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int
|
|
||||||
+ltq_wdt_open(struct inode *inode, struct file *file)
|
|
||||||
+{
|
|
||||||
+ if (test_and_set_bit(0, <q_wdt_in_use))
|
|
||||||
+ return -EBUSY;
|
|
||||||
+ ltq_wdt_in_use = 1;
|
|
||||||
+ ltq_wdt_enable();
|
|
||||||
+
|
|
||||||
+ return nonseekable_open(inode, file);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int
|
|
||||||
+ltq_wdt_release(struct inode *inode, struct file *file)
|
|
||||||
+{
|
|
||||||
+ if (ltq_wdt_ok_to_close)
|
|
||||||
+ ltq_wdt_disable();
|
|
||||||
+ else
|
|
||||||
+ pr_err("ltq_wdt: watchdog closed without warning\n");
|
|
||||||
+ ltq_wdt_ok_to_close = 0;
|
|
||||||
+ clear_bit(0, <q_wdt_in_use);
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static const struct file_operations ltq_wdt_fops = {
|
|
||||||
+ .owner = THIS_MODULE,
|
|
||||||
+ .write = ltq_wdt_write,
|
|
||||||
+ .unlocked_ioctl = ltq_wdt_ioctl,
|
|
||||||
+ .open = ltq_wdt_open,
|
|
||||||
+ .release = ltq_wdt_release,
|
|
||||||
+ .llseek = no_llseek,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static struct miscdevice ltq_wdt_miscdev = {
|
|
||||||
+ .minor = WATCHDOG_MINOR,
|
|
||||||
+ .name = "watchdog",
|
|
||||||
+ .fops = <q_wdt_fops,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static int __init
|
|
||||||
+ltq_wdt_probe(struct platform_device *pdev)
|
|
||||||
+{
|
|
||||||
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
||||||
+ struct clk *clk;
|
|
||||||
+
|
|
||||||
+ if (!res) {
|
|
||||||
+ dev_err(&pdev->dev, "cannot obtain I/O memory region");
|
|
||||||
+ return -ENOENT;
|
|
||||||
+ }
|
|
||||||
+ res = devm_request_mem_region(&pdev->dev, res->start,
|
|
||||||
+ resource_size(res), dev_name(&pdev->dev));
|
|
||||||
+ if (!res) {
|
|
||||||
+ dev_err(&pdev->dev, "cannot request I/O memory region");
|
|
||||||
+ return -EBUSY;
|
|
||||||
+ }
|
|
||||||
+ ltq_wdt_membase = devm_ioremap_nocache(&pdev->dev, res->start,
|
|
||||||
+ resource_size(res));
|
|
||||||
+ if (!ltq_wdt_membase) {
|
|
||||||
+ dev_err(&pdev->dev, "cannot remap I/O memory region\n");
|
|
||||||
+ return -ENOMEM;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* we do not need to enable the clock as it is always running */
|
|
||||||
+ clk = clk_get(&pdev->dev, "io");
|
|
||||||
+ WARN_ON(!clk);
|
|
||||||
+ ltq_io_region_clk_rate = clk_get_rate(clk);
|
|
||||||
+ clk_put(clk);
|
|
||||||
+
|
|
||||||
+ if (ltq_reset_cause() == LTQ_RST_CAUSE_WDTRST)
|
|
||||||
+ ltq_wdt_bootstatus = WDIOF_CARDRESET;
|
|
||||||
+
|
|
||||||
+ return misc_register(<q_wdt_miscdev);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int __devexit
|
|
||||||
+ltq_wdt_remove(struct platform_device *pdev)
|
|
||||||
+{
|
|
||||||
+ misc_deregister(<q_wdt_miscdev);
|
|
||||||
+
|
|
||||||
+ if (ltq_wdt_membase)
|
|
||||||
+ iounmap(ltq_wdt_membase);
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+static struct platform_driver ltq_wdt_driver = {
|
|
||||||
+ .remove = __devexit_p(ltq_wdt_remove),
|
|
||||||
+ .driver = {
|
|
||||||
+ .name = "ltq_wdt",
|
|
||||||
+ .owner = THIS_MODULE,
|
|
||||||
+ },
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static int __init
|
|
||||||
+init_ltq_wdt(void)
|
|
||||||
+{
|
|
||||||
+ return platform_driver_probe(<q_wdt_driver, ltq_wdt_probe);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void __exit
|
|
||||||
+exit_ltq_wdt(void)
|
|
||||||
+{
|
|
||||||
+ return platform_driver_unregister(<q_wdt_driver);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+module_init(init_ltq_wdt);
|
|
||||||
+module_exit(exit_ltq_wdt);
|
|
||||||
+
|
|
||||||
+module_param(nowayout, int, 0);
|
|
||||||
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
|
|
||||||
+
|
|
||||||
+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
|
|
||||||
+MODULE_DESCRIPTION("Lantiq SoC Watchdog");
|
|
||||||
+MODULE_LICENSE("GPL");
|
|
||||||
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
|
|
@ -1,32 +0,0 @@ |
|||||||
--- 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,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,829 +0,0 @@ |
|||||||
--- a/drivers/i2c/busses/Makefile
|
|
||||||
+++ b/drivers/i2c/busses/Makefile
|
|
||||||
@@ -74,6 +74,7 @@
|
|
||||||
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
|
|
||||||
|
|
||||||
ifeq ($(CONFIG_I2C_DEBUG_BUS),y)
|
|
||||||
EXTRA_CFLAGS += -DDEBUG
|
|
||||||
--- a/drivers/i2c/busses/Kconfig
|
|
||||||
+++ b/drivers/i2c/busses/Kconfig
|
|
||||||
@@ -278,6 +278,10 @@
|
|
||||||
|
|
||||||
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 *)®)[idx])
|
|
||||||
+#define reg_w32_table(val, reg, idx) reg_w32(val, &((uint32_t *)®)[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");
|
|
@ -1,497 +0,0 @@ |
|||||||
--- a/drivers/spi/Makefile
|
|
||||||
+++ b/drivers/spi/Makefile
|
|
||||||
@@ -16,6 +16,7 @@
|
|
||||||
obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o
|
|
||||||
obj-$(CONFIG_SPI_AU1550) += au1550_spi.o
|
|
||||||
obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o
|
|
||||||
+obj-$(CONFIG_SPI_FALCON) += spi_falcon.o
|
|
||||||
obj-$(CONFIG_SPI_GPIO) += spi_gpio.o
|
|
||||||
obj-$(CONFIG_SPI_GPIO_OLD) += spi_gpio_old.o
|
|
||||||
obj-$(CONFIG_SPI_IMX) += spi_imx.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 *)®)[idx])
|
|
||||||
+#define reg_w32_table(val, reg, idx) reg_w32(val, &((uint32_t *)®)[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
|
|
||||||
@@ -142,6 +142,10 @@
|
|
||||||
which interfaces to an LM70 temperature sensor using
|
|
||||||
a parallel port.
|
|
||||||
|
|
||||||
+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
|
|
@ -1,193 +0,0 @@ |
|||||||
--- 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_ */
|
|
@ -1,138 +0,0 @@ |
|||||||
--- /dev/null
|
|
||||||
+++ b/arch/mips/lantiq/falcon/mach-easy98020.c
|
|
||||||
@@ -0,0 +1,115 @@
|
|
||||||
+#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
|
|
||||||
+
|
|
||||||
+#ifdef CONFIG_MTD_PARTITIONS
|
|
||||||
+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)
|
|
||||||
+};
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
+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,
|
|
||||||
+#ifdef CONFIG_MTD_PARTITIONS
|
|
||||||
+ .platform_data = &easy98020_spi_flash_platform_data
|
|
||||||
+#endif
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+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 @@ config LANTIQ_MACH_EASY98000
|
|
||||||
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-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
|
|
||||||
+obj-$(CONFIG_LANTIQ_MACH_EASY98020) += mach-easy98020.o
|
|
@ -1,134 +0,0 @@ |
|||||||
--- /dev/null
|
|
||||||
+++ b/arch/mips/lantiq/falcon/mach-95C3AM1.c
|
|
||||||
@@ -0,0 +1,101 @@
|
|
||||||
+#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
|
|
||||||
+
|
|
||||||
+#ifdef CONFIG_MTD_PARTITIONS
|
|
||||||
+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)
|
|
||||||
+};
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
+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,
|
|
||||||
+#ifdef CONFIG_MTD_PARTITIONS
|
|
||||||
+ .platform_data = &board_95C3AM1_flash_platform_data
|
|
||||||
+#endif
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+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 @@ config LANTIQ_MACH_EASY98020
|
|
||||||
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) += a
|
|
||||||
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 @@ enum lantiq_mach_type {
|
|
||||||
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
|
|
@ -1,547 +0,0 @@ |
|||||||
--- 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(<q_eth_data.mac.sa_data,
|
|
||||||
+ (void *)KSEG1ADDR(LTQ_FLASH_START + ARV45XX_BRN_MAC), 6);
|
|
||||||
+ ltq_register_etop(<q_eth_data);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+arv75xx_register_ethernet(void)
|
|
||||||
+{
|
|
||||||
+#define ARV75XX_BRN_MAC 0x7f0016
|
|
||||||
+ memcpy_fromio(<q_eth_data.mac.sa_data,
|
|
||||||
+ (void *)KSEG1ADDR(LTQ_FLASH_START + ARV75XX_BRN_MAC), 6);
|
|
||||||
+ ltq_register_etop(<q_eth_data);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+bewan_register_ethernet(void)
|
|
||||||
+{
|
|
||||||
+#define BEWAN_BRN_MAC 0x3f0014
|
|
||||||
+ memcpy_fromio(<q_eth_data.mac.sa_data,
|
|
||||||
+ (void *)KSEG1ADDR(LTQ_FLASH_START + BEWAN_BRN_MAC), 6);
|
|
||||||
+ ltq_register_etop(<q_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(<q_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(<q_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(<q_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(<q_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(<q_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(<q_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(<q_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
|
|
||||||
@@ -21,6 +21,17 @@
|
|
||||||
LANTIQ_MACH_EASY98000SF, /* Falcon Eval Board, Serial 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
|
|
@ -1,116 +0,0 @@ |
|||||||
--- a/drivers/mtd/Kconfig
|
|
||||||
+++ b/drivers/mtd/Kconfig
|
|
||||||
@@ -63,6 +63,10 @@
|
|
||||||
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"
|
|
||||||
depends on MTD_PARTITIONS
|
|
||||||
--- a/drivers/mtd/mtdpart.c
|
|
||||||
+++ b/drivers/mtd/mtdpart.c
|
|
||||||
@@ -724,6 +724,82 @@
|
|
||||||
}
|
|
||||||
#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
|
|
||||||
@@ -748,6 +824,17 @@
|
|
||||||
if (!slave)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
+#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) {
|
|
@ -1,42 +0,0 @@ |
|||||||
--- a/arch/mips/mm/cache.c
|
|
||||||
+++ b/arch/mips/mm/cache.c
|
|
||||||
@@ -52,6 +52,8 @@
|
|
||||||
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
|
|
||||||
@@ -152,7 +152,7 @@
|
|
||||||
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
|
|
||||||
@@ -57,11 +57,17 @@
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
+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,
|
|
@ -1,56 +0,0 @@ |
|||||||
--- a/arch/mips/lantiq/prom.c
|
|
||||||
+++ b/arch/mips/lantiq/prom.c
|
|
||||||
@@ -39,20 +39,51 @@ 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;
|
|
||||||
char **argv = (char **) KSEG1ADDR(fw_arg1);
|
|
||||||
int i;
|
|
||||||
|
|
||||||
+ arcs_cmdline[0] = '\0';
|
|
||||||
+
|
|
||||||
for (i = 0; i < argc; i++) {
|
|
||||||
- char *p = (char *) KSEG1ADDR(argv[i]);
|
|
||||||
+ char *p = (char *) KSEG1ADDR(argv[i]);
|
|
||||||
|
|
||||||
- if (p && *p) {
|
|
||||||
+ if (CPHYSADDR(p) && *p) {
|
|
||||||
strlcat(arcs_cmdline, p, sizeof(arcs_cmdline));
|
|
||||||
strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+ prom_init_image_cmdline();
|
|
||||||
}
|
|
||||||
|
|
||||||
void __init prom_init(void)
|
|
@ -1,347 +0,0 @@ |
|||||||
--- /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 @@
|
|
||||||
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_IP_FIB_HASH) += fib_hash.o
|
|
||||||
obj-$(CONFIG_IP_FIB_TRIE) += fib_trie.o
|
|
||||||
obj-$(CONFIG_PROC_FS) += proc.o
|
|
||||||
--- a/net/ipv4/udp.c
|
|
||||||
+++ b/net/ipv4/udp.c
|
|
||||||
@@ -106,7 +106,11 @@
|
|
||||||
#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;
|
|
||||||
+
|
|
||||||
EXPORT_SYMBOL(udp_table);
|
|
||||||
|
|
||||||
int sysctl_udp_mem[3] __read_mostly;
|
|
||||||
@@ -591,7 +595,7 @@
|
|
||||||
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;
|
|
||||||
|
|
||||||
if (len > 0xFFFF)
|
|
||||||
return -EMSGSIZE;
|
|
||||||
@@ -753,6 +757,12 @@
|
|
||||||
|
|
||||||
do_append_data:
|
|
||||||
up->len += ulen;
|
|
||||||
+ /* 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;
|
|
||||||
err = ip_append_data(sk, getfrag, msg->msg_iov, ulen,
|
|
||||||
sizeof(struct udphdr), &ipc, &rt,
|
|
||||||
@@ -1283,6 +1293,7 @@
|
|
||||||
struct rtable *rt = skb_rtable(skb);
|
|
||||||
__be32 saddr, daddr;
|
|
||||||
struct net *net = dev_net(skb->dev);
|
|
||||||
+ int ret = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Validate the packet.
|
|
||||||
@@ -1315,7 +1326,16 @@
|
|
||||||
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
|
|
||||||
@@ -1610,7 +1630,7 @@
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
EXPORT_SYMBOL(udp_prot);
|
|
||||||
-
|
|
||||||
+EXPORT_SYMBOL(udp_rcv);
|
|
||||||
/* ------------------------------------------------------------------------ */
|
|
||||||
#ifdef CONFIG_PROC_FS
|
|
||||||
|
|
||||||
--- a/net/Kconfig
|
|
||||||
+++ b/net/Kconfig
|
|
||||||
@@ -72,6 +72,12 @@
|
|
||||||
|
|
||||||
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
@ -1,301 +0,0 @@ |
|||||||
--- a/arch/mips/Kconfig
|
|
||||||
+++ b/arch/mips/Kconfig
|
|
||||||
@@ -1653,6 +1653,28 @@
|
|
||||||
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
|
|
||||||
@@ -129,6 +129,13 @@
|
|
||||||
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)
|
|
||||||
@@ -867,6 +874,65 @@
|
|
||||||
/* 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
|
|
||||||
@@ -1348,6 +1348,106 @@
|
|
||||||
__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);
|
|
||||||
@@ -1367,6 +1467,78 @@
|
|
||||||
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();
|
|
||||||
|
|
@ -1,8 +0,0 @@ |
|||||||
--- 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
|
|
||||||
*
|
|
@ -1,119 +0,0 @@ |
|||||||
--- 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>
|
|
||||||
@@ -121,6 +122,8 @@ typedef struct board_info {
|
|
||||||
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;
|
|
||||||
@@ -790,12 +793,14 @@ static void dm9000_timeout(struct net_de
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
/* Save previous register address */
|
|
||||||
- reg_save = readb(db->io_addr);
|
|
||||||
spin_lock_irqsave(&db->lock, flags);
|
|
||||||
+ reg_save = readb(db->io_addr);
|
|
||||||
|
|
||||||
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;
|
|
||||||
netif_wake_queue(dev);
|
|
||||||
@@ -867,6 +872,12 @@ dm9000_start_xmit(struct sk_buff *skb, s
|
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1073,6 +1084,18 @@ static void dm9000_poll_controller(struc
|
|
||||||
}
|
|
||||||
#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.
|
|
||||||
@@ -1086,27 +1109,35 @@ dm9000_open(struct net_device *dev)
|
|
||||||
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");
|
|
||||||
+ if (irqflags == IRQF_TRIGGER_NONE)
|
|
||||||
+ dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n");
|
|
||||||
|
|
||||||
- irqflags |= IRQF_SHARED;
|
|
||||||
+ irqflags |= IRQF_SHARED;
|
|
||||||
|
|
||||||
- if (request_irq(dev->irq, &dm9000_interrupt, irqflags, dev->name, dev))
|
|
||||||
- return -EAGAIN;
|
|
||||||
+ if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev))
|
|
||||||
+ return -EAGAIN;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
/* Initialize DM9000 board */
|
|
||||||
dm9000_reset(db);
|
|
||||||
dm9000_init_dm9000(dev);
|
|
||||||
+ /* workaround: init a second time */
|
|
||||||
+ dm9000_reset(db);
|
|
||||||
+ dm9000_init_dm9000(dev);
|
|
||||||
|
|
||||||
/* Init driver variable */
|
|
||||||
db->dbug_cnt = 0;
|
|
||||||
|
|
||||||
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;
|
|
||||||
@@ -1303,6 +1334,7 @@ dm9000_probe(struct platform_device *pde
|
|
||||||
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);
|
|
@ -1,36 +0,0 @@ |
|||||||
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 @@
|
|
||||||
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
@ -1,49 +0,0 @@ |
|||||||
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.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,28 @@
|
|
||||||
platform_device_register(<q_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 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)
|
|
||||||
+{
|
|
||||||
+ spi_register_board_info(info, n);
|
|
||||||
+ ltq_spi.dev.platform_data = pdata;
|
|
||||||
+ platform_device_register(<q_spi);
|
|
||||||
+}
|
|
@ -1,41 +0,0 @@ |
|||||||
--- a/arch/mips/lantiq/xway/devices.c
|
|
||||||
+++ b/arch/mips/lantiq/xway/devices.c
|
|
||||||
@@ -121,6 +121,29 @@
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+/* 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 = <q_ebu_resource,
|
|
||||||
+ .num_resources = 1,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+void __init
|
|
||||||
+ltq_register_gpio_ebu(unsigned int value)
|
|
||||||
+{
|
|
||||||
+ ltq_ebu.dev.platform_data = (void*) value;
|
|
||||||
+ platform_device_register(<q_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,5 +16,6 @@
|
|
||||||
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_gpio_ebu(unsigned int value);
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,28 +0,0 @@ |
|||||||
--- a/arch/mips/lantiq/xway/devices.c
|
|
||||||
+++ b/arch/mips/lantiq/xway/devices.c
|
|
||||||
@@ -144,6 +144,16 @@
|
|
||||||
platform_device_register(<q_ebu);
|
|
||||||
}
|
|
||||||
|
|
||||||
+/* 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
|
|
||||||
@@ -17,5 +17,6 @@
|
|
||||||
extern void ltq_register_ase_asc(void);
|
|
||||||
extern void ltq_register_etop(struct ltq_eth_data *eth);
|
|
||||||
extern void ltq_register_gpio_ebu(unsigned int value);
|
|
||||||
+extern void ltq_register_madwifi_eep(void);
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,46 +0,0 @@ |
|||||||
--- a/arch/mips/lantiq/xway/devices.c
|
|
||||||
+++ b/arch/mips/lantiq/xway/devices.c
|
|
||||||
@@ -154,6 +154,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 *) <q_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(<q_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
|
|
||||||
@@ -11,6 +11,7 @@
|
|
||||||
|
|
||||||
#include "../devices.h"
|
|
||||||
#include <linux/phy.h>
|
|
||||||
+#include <linux/gpio_buttons.h>
|
|
||||||
|
|
||||||
extern void ltq_register_gpio(void);
|
|
||||||
extern void ltq_register_gpio_stp(void);
|
|
||||||
@@ -18,5 +19,6 @@
|
|
||||||
extern void ltq_register_etop(struct ltq_eth_data *eth);
|
|
||||||
extern void ltq_register_gpio_ebu(unsigned int value);
|
|
||||||
extern void ltq_register_madwifi_eep(void);
|
|
||||||
+extern void ltq_register_gpio_buttons(struct gpio_button *buttons, int cnt);
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,42 +0,0 @@ |
|||||||
--- 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
|
|
||||||
@@ -66,6 +66,7 @@
|
|
||||||
ltq_register_nor(&easy50712_flash_data);
|
|
||||||
ltq_register_pci(<q_pci_data);
|
|
||||||
ltq_register_etop(<q_eth_data);
|
|
||||||
+ ltq_register_tapi();
|
|
||||||
}
|
|
||||||
|
|
||||||
MIPS_MACHINE(LTQ_MACH_EASY50712,
|
|
@ -1,999 +0,0 @@ |
|||||||
--- /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(¶m, (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, ¶m.value);
|
|
||||||
+ if (!ret)
|
|
||||||
+ copy_to_user(&((struct gptu_ioctl_param *) arg)->
|
|
||||||
+ value, ¶m.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, ¶m.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
@ -1,95 +0,0 @@ |
|||||||
--- /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
|
|
||||||
|
|
@ -1,111 +0,0 @@ |
|||||||
--- a/arch/mips/lantiq/machtypes.h
|
|
||||||
+++ b/arch/mips/lantiq/machtypes.h
|
|
||||||
@@ -32,6 +32,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,4 +6,5 @@
|
|
||||||
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
|
|
||||||
obj-y += dev-dwc_otg.o
|
|
||||||
--- 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/gpio_buttons.h>
|
|
||||||
+#include <linux/spi/spi.h>
|
|
||||||
|
|
||||||
extern void ltq_register_gpio(void);
|
|
||||||
extern void ltq_register_gpio_stp(void);
|
|
||||||
@@ -20,5 +21,7 @@
|
|
||||||
extern void ltq_register_gpio_ebu(unsigned int value);
|
|
||||||
extern void ltq_register_madwifi_eep(void);
|
|
||||||
extern void ltq_register_gpio_buttons(struct gpio_button *buttons, int cnt);
|
|
||||||
+extern void ltq_register_spi(struct ltq_spi_platform_data *pdata,
|
|
||||||
+ struct spi_board_info const *info, unsigned n);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
--- /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(<q_pci_data);
|
|
||||||
+ ltq_register_etop(<q_eth_data);
|
|
||||||
+ ltq_register_spi(<q_spi_data, &spi_info, 1);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+MIPS_MACHINE(LANTIQ_MACH_DGN3500B,
|
|
||||||
+ "DGN3500B",
|
|
||||||
+ "Netgear DGN3500B",
|
|
||||||
+ dgn3500_init);
|
|
@ -1,14 +0,0 @@ |
|||||||
--- a/drivers/serial/lantiq.c
|
|
||||||
+++ b/drivers/serial/lantiq.c
|
|
||||||
@@ -478,8 +478,10 @@
|
|
||||||
spin_unlock_irqrestore(<q_asc_lock, flags);
|
|
||||||
|
|
||||||
/* Don't rewrite B0 */
|
|
||||||
- if (tty_termios_baud_rate(new))
|
|
||||||
+ if (tty_termios_baud_rate(new))
|
|
||||||
tty_termios_encode_baud_rate(new, baud, baud);
|
|
||||||
+
|
|
||||||
+ uart_update_timeout(port, cflag, baud);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char*
|
|
@ -1,26 +0,0 @@ |
|||||||
--- a/arch/mips/lantiq/early_printk.c
|
|
||||||
+++ b/arch/mips/lantiq/early_printk.c
|
|
||||||
@@ -20,7 +20,12 @@
|
|
||||||
#endif
|
|
||||||
#define ASC_BUF 1024
|
|
||||||
#define LTQ_ASC_FSTAT ((u32 *)(LTQ_ASC_BASE + 0x0048))
|
|
||||||
-#define LTQ_ASC_TBUF ((u32 *)(LTQ_ASC_BASE + 0x0020))
|
|
||||||
+#ifdef __BIG_ENDIAN
|
|
||||||
+#define LTQ_ASC_TBUF ((u8 *)(LTQ_ASC_BASE + 0x0023))
|
|
||||||
+#else
|
|
||||||
+#define LTQ_ASC_TBUF ((u8 *)(LTQ_ASC_BASE + 0x0020))
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
#define TXMASK 0x3F00
|
|
||||||
#define TXOFFSET 8
|
|
||||||
|
|
||||||
@@ -30,8 +35,6 @@ void prom_putchar(char c)
|
|
||||||
|
|
||||||
local_irq_save(flags);
|
|
||||||
do { } while ((ltq_r32(LTQ_ASC_FSTAT) & TXMASK) >> TXOFFSET);
|
|
||||||
- if (c == '\n')
|
|
||||||
- ltq_w32('\r', LTQ_ASC_TBUF);
|
|
||||||
- ltq_w32(c, LTQ_ASC_TBUF);
|
|
||||||
+ ltq_w8(c, LTQ_ASC_TBUF);
|
|
||||||
local_irq_restore(flags);
|
|
||||||
}
|
|
@ -1,76 +0,0 @@ |
|||||||
--- a/arch/mips/Makefile
|
|
||||||
+++ b/arch/mips/Makefile
|
|
||||||
@@ -179,6 +179,16 @@
|
|
||||||
#
|
|
||||||
|
|
||||||
#
|
|
||||||
+# Lantiq
|
|
||||||
+#
|
|
||||||
+
|
|
||||||
+core-$(CONFIG_LANTIQ) += arch/mips/lantiq/
|
|
||||||
+cflags-$(CONFIG_LANTIQ) += -I$(srctree)/arch/mips/include/asm/mach-lantiq
|
|
||||||
+load-$(CONFIG_LANTIQ) = 0xffffffff80002000
|
|
||||||
+cflags-$(CONFIG_SOC_TYPE_XWAY) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/xway
|
|
||||||
+cflags-$(CONFIG_SOC_FALCON) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/falcon
|
|
||||||
+
|
|
||||||
+#
|
|
||||||
# Texas Instruments AR7
|
|
||||||
#
|
|
||||||
core-$(CONFIG_AR7) += arch/mips/ar7/
|
|
||||||
--- a/include/linux/compiler.h
|
|
||||||
+++ b/include/linux/compiler.h
|
|
||||||
@@ -144,6 +144,11 @@
|
|
||||||
# define barrier() __memory_barrier()
|
|
||||||
#endif
|
|
||||||
|
|
||||||
+/* Unreachable code */
|
|
||||||
+#ifndef unreachable
|
|
||||||
+# define unreachable() do { } while (1)
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
#ifndef RELOC_HIDE
|
|
||||||
# define RELOC_HIDE(ptr, off) \
|
|
||||||
({ unsigned long __ptr; \
|
|
||||||
--- /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__ */
|
|
Loading…
Reference in new issue