summaryrefslogtreecommitdiffstats
path: root/target/linux/lantiq/patches-2.6.39/0002-MIPS-Lantiq-add-SoC-specific-code-for-XWAY-family.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/lantiq/patches-2.6.39/0002-MIPS-Lantiq-add-SoC-specific-code-for-XWAY-family.patch')
-rw-r--r--target/linux/lantiq/patches-2.6.39/0002-MIPS-Lantiq-add-SoC-specific-code-for-XWAY-family.patch1151
1 files changed, 1151 insertions, 0 deletions
diff --git a/target/linux/lantiq/patches-2.6.39/0002-MIPS-Lantiq-add-SoC-specific-code-for-XWAY-family.patch b/target/linux/lantiq/patches-2.6.39/0002-MIPS-Lantiq-add-SoC-specific-code-for-XWAY-family.patch
new file mode 100644
index 0000000000..2f44b6659d
--- /dev/null
+++ b/target/linux/lantiq/patches-2.6.39/0002-MIPS-Lantiq-add-SoC-specific-code-for-XWAY-family.patch
@@ -0,0 +1,1151 @@
+From 36cc26a362c6ad64ba3d176809847ec60cc40859 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Wed, 30 Mar 2011 09:27:48 +0200
+Subject: [PATCH 02/13] MIPS: Lantiq: add SoC specific code for XWAY family
+
+Add support for the Lantiq XWAY family of Mips24KEc SoCs.
+
+* Danube (PSB50702)
+* Twinpass (PSB4000)
+* AR9 (PSB50802)
+* Amazon SE (PSB5061)
+
+The Amazon SE is a lightweight SoC and has no PCI as well as a different
+clock. We split the code out into seperate files to handle this.
+
+The GPIO pins on the SoCs are multi function and there are several bits
+we can use to configure the pins. To be as compatible as possible to
+GPIOLIB we add a function
+
+int ltq_gpio_request(unsigned int pin, unsigned int alt0,
+ unsigned int alt1, unsigned int dir, const char *name);
+
+which lets you configure the 2 "alternate function" bits. This way drivers like
+PCI can make use of GPIOLIB without a cubersome wrapper.
+
+The PLL code inside arch/mips/lantiq/xway/clk-xway.c is voodoo to me. It was
+taken from a 2.4.20 source tree and was never really changed by me since then.
+
+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/2249/
+Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
+---
+ arch/mips/Kconfig | 1 +
+ arch/mips/include/asm/mach-lantiq/xway/irq.h | 18 ++
+ .../mips/include/asm/mach-lantiq/xway/lantiq_irq.h | 66 ++++++
+ .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 140 ++++++++++++
+ arch/mips/lantiq/Kconfig | 21 ++
+ arch/mips/lantiq/Makefile | 2 +
+ arch/mips/lantiq/Platform | 1 +
+ arch/mips/lantiq/xway/Makefile | 4 +
+ arch/mips/lantiq/xway/clk-ase.c | 48 +++++
+ arch/mips/lantiq/xway/clk-xway.c | 223 ++++++++++++++++++++
+ arch/mips/lantiq/xway/ebu.c | 53 +++++
+ arch/mips/lantiq/xway/gpio.c | 195 +++++++++++++++++
+ arch/mips/lantiq/xway/pmu.c | 70 ++++++
+ arch/mips/lantiq/xway/prom-ase.c | 39 ++++
+ arch/mips/lantiq/xway/prom-xway.c | 54 +++++
+ arch/mips/lantiq/xway/reset.c | 91 ++++++++
+ 16 files changed, 1026 insertions(+), 0 deletions(-)
+ create mode 100644 arch/mips/include/asm/mach-lantiq/xway/irq.h
+ create mode 100644 arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h
+ create mode 100644 arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
+ create mode 100644 arch/mips/lantiq/Kconfig
+ create mode 100644 arch/mips/lantiq/xway/Makefile
+ create mode 100644 arch/mips/lantiq/xway/clk-ase.c
+ create mode 100644 arch/mips/lantiq/xway/clk-xway.c
+ create mode 100644 arch/mips/lantiq/xway/ebu.c
+ create mode 100644 arch/mips/lantiq/xway/gpio.c
+ create mode 100644 arch/mips/lantiq/xway/pmu.c
+ create mode 100644 arch/mips/lantiq/xway/prom-ase.c
+ create mode 100644 arch/mips/lantiq/xway/prom-xway.c
+ create mode 100644 arch/mips/lantiq/xway/reset.c
+
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -760,6 +760,7 @@
+ source "arch/mips/bcm63xx/Kconfig"
+ source "arch/mips/jazz/Kconfig"
+ source "arch/mips/jz4740/Kconfig"
++source "arch/mips/lantiq/Kconfig"
+ source "arch/mips/lasat/Kconfig"
+ source "arch/mips/pmc-sierra/Kconfig"
+ source "arch/mips/powertv/Kconfig"
+--- /dev/null
++++ b/arch/mips/include/asm/mach-lantiq/xway/irq.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_IRQ_H
++#define __LANTIQ_IRQ_H
++
++#include <lantiq_irq.h>
++
++#define NR_IRQS 256
++
++#include_next <irq.h>
++
++#endif
+--- /dev/null
++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h
+@@ -0,0 +1,66 @@
++/*
++ * 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_XWAY_IRQ_H__
++#define _LANTIQ_XWAY_IRQ_H__
++
++#define INT_NUM_IRQ0 8
++#define INT_NUM_IM0_IRL0 (INT_NUM_IRQ0 + 0)
++#define INT_NUM_IM1_IRL0 (INT_NUM_IRQ0 + 32)
++#define INT_NUM_IM2_IRL0 (INT_NUM_IRQ0 + 64)
++#define INT_NUM_IM3_IRL0 (INT_NUM_IRQ0 + 96)
++#define INT_NUM_IM4_IRL0 (INT_NUM_IRQ0 + 128)
++#define INT_NUM_IM_OFFSET (INT_NUM_IM1_IRL0 - INT_NUM_IM0_IRL0)
++
++#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)
++
++#define LTQ_ASC_ASE_TIR INT_NUM_IM2_IRL0
++#define LTQ_ASC_ASE_RIR (INT_NUM_IM2_IRL0 + 2)
++#define LTQ_ASC_ASE_EIR (INT_NUM_IM2_IRL0 + 3)
++
++#define LTQ_SSC_TIR (INT_NUM_IM0_IRL0 + 15)
++#define LTQ_SSC_RIR (INT_NUM_IM0_IRL0 + 14)
++#define LTQ_SSC_EIR (INT_NUM_IM0_IRL0 + 16)
++
++#define LTQ_MEI_DYING_GASP_INT (INT_NUM_IM1_IRL0 + 21)
++#define LTQ_MEI_INT (INT_NUM_IM1_IRL0 + 23)
++
++#define LTQ_TIMER6_INT (INT_NUM_IM1_IRL0 + 23)
++#define LTQ_USB_INT (INT_NUM_IM1_IRL0 + 22)
++#define LTQ_USB_OC_INT (INT_NUM_IM4_IRL0 + 23)
++
++#define MIPS_CPU_TIMER_IRQ 7
++
++#define LTQ_DMA_CH0_INT (INT_NUM_IM2_IRL0)
++#define LTQ_DMA_CH1_INT (INT_NUM_IM2_IRL0 + 1)
++#define LTQ_DMA_CH2_INT (INT_NUM_IM2_IRL0 + 2)
++#define LTQ_DMA_CH3_INT (INT_NUM_IM2_IRL0 + 3)
++#define LTQ_DMA_CH4_INT (INT_NUM_IM2_IRL0 + 4)
++#define LTQ_DMA_CH5_INT (INT_NUM_IM2_IRL0 + 5)
++#define LTQ_DMA_CH6_INT (INT_NUM_IM2_IRL0 + 6)
++#define LTQ_DMA_CH7_INT (INT_NUM_IM2_IRL0 + 7)
++#define LTQ_DMA_CH8_INT (INT_NUM_IM2_IRL0 + 8)
++#define LTQ_DMA_CH9_INT (INT_NUM_IM2_IRL0 + 9)
++#define LTQ_DMA_CH10_INT (INT_NUM_IM2_IRL0 + 10)
++#define LTQ_DMA_CH11_INT (INT_NUM_IM2_IRL0 + 11)
++#define LTQ_DMA_CH12_INT (INT_NUM_IM2_IRL0 + 25)
++#define LTQ_DMA_CH13_INT (INT_NUM_IM2_IRL0 + 26)
++#define LTQ_DMA_CH14_INT (INT_NUM_IM2_IRL0 + 27)
++#define LTQ_DMA_CH15_INT (INT_NUM_IM2_IRL0 + 28)
++#define LTQ_DMA_CH16_INT (INT_NUM_IM2_IRL0 + 29)
++#define LTQ_DMA_CH17_INT (INT_NUM_IM2_IRL0 + 30)
++#define LTQ_DMA_CH18_INT (INT_NUM_IM2_IRL0 + 16)
++#define LTQ_DMA_CH19_INT (INT_NUM_IM2_IRL0 + 21)
++
++#define LTQ_PPE_MBOX_INT (INT_NUM_IM2_IRL0 + 24)
++
++#define INT_NUM_IM4_IRL14 (INT_NUM_IM4_IRL0 + 14)
++
++#endif
+--- /dev/null
++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
+@@ -0,0 +1,140 @@
++/*
++ * 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_XWAY_H__
++#define _LTQ_XWAY_H__
++
++#ifdef CONFIG_SOC_TYPE_XWAY
++
++#include <lantiq.h>
++
++/* Chip IDs */
++#define SOC_ID_DANUBE1 0x129
++#define SOC_ID_DANUBE2 0x12B
++#define SOC_ID_TWINPASS 0x12D
++#define SOC_ID_AMAZON_SE 0x152
++#define SOC_ID_ARX188 0x16C
++#define SOC_ID_ARX168 0x16D
++#define SOC_ID_ARX182 0x16F
++
++/* SoC Types */
++#define SOC_TYPE_DANUBE 0x01
++#define SOC_TYPE_TWINPASS 0x02
++#define SOC_TYPE_AR9 0x03
++#define SOC_TYPE_VR9 0x04
++#define SOC_TYPE_AMAZON_SE 0x05
++
++/* ASC0/1 - serial port */
++#define LTQ_ASC0_BASE_ADDR 0x1E100400
++#define LTQ_ASC1_BASE_ADDR 0x1E100C00
++#define LTQ_ASC_SIZE 0x400
++
++/* RCU - reset control unit */
++#define LTQ_RCU_BASE_ADDR 0x1F203000
++#define LTQ_RCU_SIZE 0x1000
++
++/* GPTU - general purpose timer unit */
++#define LTQ_GPTU_BASE_ADDR 0x18000300
++#define LTQ_GPTU_SIZE 0x100
++
++/* EBU - external bus unit */
++#define LTQ_EBU_GPIO_START 0x14000000
++#define LTQ_EBU_GPIO_SIZE 0x1000
++
++#define LTQ_EBU_BASE_ADDR 0x1E105300
++#define LTQ_EBU_SIZE 0x100
++
++#define LTQ_EBU_BUSCON0 0x0060
++#define LTQ_EBU_PCC_CON 0x0090
++#define LTQ_EBU_PCC_IEN 0x00A4
++#define LTQ_EBU_PCC_ISTAT 0x00A0
++#define LTQ_EBU_BUSCON1 0x0064
++#define LTQ_EBU_ADDRSEL1 0x0024
++#define EBU_WRDIS 0x80000000
++
++/* CGU - clock generation unit */
++#define LTQ_CGU_BASE_ADDR 0x1F103000
++#define LTQ_CGU_SIZE 0x1000
++
++/* ICU - interrupt control unit */
++#define LTQ_ICU_BASE_ADDR 0x1F880200
++#define LTQ_ICU_SIZE 0x100
++
++/* EIU - external interrupt unit */
++#define LTQ_EIU_BASE_ADDR 0x1F101000
++#define LTQ_EIU_SIZE 0x1000
++
++/* PMU - power management unit */
++#define LTQ_PMU_BASE_ADDR 0x1F102000
++#define LTQ_PMU_SIZE 0x1000
++
++#define PMU_DMA 0x0020
++#define PMU_USB 0x8041
++#define PMU_LED 0x0800
++#define PMU_GPT 0x1000
++#define PMU_PPE 0x2000
++#define PMU_FPI 0x4000
++#define PMU_SWITCH 0x10000000
++
++/* ETOP - ethernet */
++#define LTQ_PPE32_BASE_ADDR 0xBE180000
++#define LTQ_PPE32_SIZE 0x40000
++
++/* DMA */
++#define LTQ_DMA_BASE_ADDR 0xBE104100
++
++/* PCI */
++#define PCI_CR_BASE_ADDR 0x1E105400
++#define PCI_CR_SIZE 0x400
++
++/* WDT */
++#define LTQ_WDT_BASE_ADDR 0x1F8803F0
++#define LTQ_WDT_SIZE 0x10
++
++/* STP - serial to parallel conversion unit */
++#define LTQ_STP_BASE_ADDR 0x1E100BB0
++#define LTQ_STP_SIZE 0x40
++
++/* GPIO */
++#define LTQ_GPIO0_BASE_ADDR 0x1E100B10
++#define LTQ_GPIO1_BASE_ADDR 0x1E100B40
++#define LTQ_GPIO2_BASE_ADDR 0x1E100B70
++#define LTQ_GPIO_SIZE 0x30
++
++/* SSC */
++#define LTQ_SSC_BASE_ADDR 0x1e100800
++#define LTQ_SSC_SIZE 0x100
++
++/* MEI - dsl core */
++#define LTQ_MEI_BASE_ADDR 0x1E116000
++
++/* DEU - data encryption unit */
++#define LTQ_DEU_BASE_ADDR 0x1E103100
++
++/* MPS - multi processor unit (voice) */
++#define LTQ_MPS_BASE_ADDR (KSEG1 + 0x1F107000)
++#define LTQ_MPS_CHIPID ((u32 *)(LTQ_MPS_BASE_ADDR + 0x0344))
++
++/* request a non-gpio and set the PIO config */
++extern int ltq_gpio_request(unsigned int pin, unsigned int alt0,
++ unsigned int alt1, unsigned int dir, const char *name);
++extern void ltq_pmu_enable(unsigned int module);
++extern void ltq_pmu_disable(unsigned int module);
++
++static inline int ltq_is_ar9(void)
++{
++ return (ltq_get_soc_type() == SOC_TYPE_AR9);
++}
++
++static inline int ltq_is_vr9(void)
++{
++ return (ltq_get_soc_type() == SOC_TYPE_VR9);
++}
++
++#endif /* CONFIG_SOC_TYPE_XWAY */
++#endif /* _LTQ_XWAY_H__ */
+--- /dev/null
++++ b/arch/mips/lantiq/Kconfig
+@@ -0,0 +1,21 @@
++if LANTIQ
++
++config SOC_TYPE_XWAY
++ bool
++ default n
++
++choice
++ prompt "SoC Type"
++ default SOC_XWAY
++
++config SOC_AMAZON_SE
++ bool "Amazon SE"
++ select SOC_TYPE_XWAY
++
++config SOC_XWAY
++ bool "XWAY"
++ select SOC_TYPE_XWAY
++ select HW_HAS_PCI
++endchoice
++
++endif
+--- a/arch/mips/lantiq/Makefile
++++ b/arch/mips/lantiq/Makefile
+@@ -7,3 +7,5 @@
+ obj-y := irq.o setup.o clk.o prom.o
+
+ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
++
++obj-$(CONFIG_SOC_TYPE_XWAY) += xway/
+--- a/arch/mips/lantiq/Platform
++++ b/arch/mips/lantiq/Platform
+@@ -5,3 +5,4 @@
+ platform-$(CONFIG_LANTIQ) += 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
+--- /dev/null
++++ b/arch/mips/lantiq/xway/Makefile
+@@ -0,0 +1,4 @@
++obj-y := pmu.o ebu.o reset.o gpio.o
++
++obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o
++obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o
+--- /dev/null
++++ b/arch/mips/lantiq/xway/clk-ase.c
+@@ -0,0 +1,48 @@
++/*
++ * 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 <linux/io.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/clk.h>
++
++#include <asm/time.h>
++#include <asm/irq.h>
++#include <asm/div64.h>
++
++#include <lantiq_soc.h>
++
++/* cgu registers */
++#define LTQ_CGU_SYS 0x0010
++
++unsigned int ltq_get_io_region_clock(void)
++{
++ return CLOCK_133M;
++}
++EXPORT_SYMBOL(ltq_get_io_region_clock);
++
++unsigned int ltq_get_fpi_bus_clock(int fpi)
++{
++ return CLOCK_133M;
++}
++EXPORT_SYMBOL(ltq_get_fpi_bus_clock);
++
++unsigned int ltq_get_cpu_hz(void)
++{
++ if (ltq_cgu_r32(LTQ_CGU_SYS) & (1 << 5))
++ return CLOCK_266M;
++ else
++ return CLOCK_133M;
++}
++EXPORT_SYMBOL(ltq_get_cpu_hz);
++
++unsigned int ltq_get_fpi_hz(void)
++{
++ return CLOCK_133M;
++}
++EXPORT_SYMBOL(ltq_get_fpi_hz);
+--- /dev/null
++++ b/arch/mips/lantiq/xway/clk-xway.c
+@@ -0,0 +1,223 @@
++/*
++ * 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/io.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/clk.h>
++
++#include <asm/time.h>
++#include <asm/irq.h>
++#include <asm/div64.h>
++
++#include <lantiq_soc.h>
++
++static unsigned int ltq_ram_clocks[] = {
++ CLOCK_167M, CLOCK_133M, CLOCK_111M, CLOCK_83M };
++#define DDR_HZ ltq_ram_clocks[ltq_cgu_r32(LTQ_CGU_SYS) & 0x3]
++
++#define BASIC_FREQUENCY_1 35328000
++#define BASIC_FREQUENCY_2 36000000
++#define BASIS_REQUENCY_USB 12000000
++
++#define GET_BITS(x, msb, lsb) \
++ (((x) & ((1 << ((msb) + 1)) - 1)) >> (lsb))
++
++#define LTQ_CGU_PLL0_CFG 0x0004
++#define LTQ_CGU_PLL1_CFG 0x0008
++#define LTQ_CGU_PLL2_CFG 0x000C
++#define LTQ_CGU_SYS 0x0010
++#define LTQ_CGU_UPDATE 0x0014
++#define LTQ_CGU_IF_CLK 0x0018
++#define LTQ_CGU_OSC_CON 0x001C
++#define LTQ_CGU_SMD 0x0020
++#define LTQ_CGU_CT1SR 0x0028
++#define LTQ_CGU_CT2SR 0x002C
++#define LTQ_CGU_PCMCR 0x0030
++#define LTQ_CGU_PCI_CR 0x0034
++#define LTQ_CGU_PD_PC 0x0038
++#define LTQ_CGU_FMR 0x003C
++
++#define CGU_PLL0_PHASE_DIVIDER_ENABLE \
++ (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 31))
++#define CGU_PLL0_BYPASS \
++ (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 30))
++#define CGU_PLL0_CFG_DSMSEL \
++ (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 28))
++#define CGU_PLL0_CFG_FRAC_EN \
++ (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 27))
++#define CGU_PLL1_SRC \
++ (ltq_cgu_r32(LTQ_CGU_PLL1_CFG) & (1 << 31))
++#define CGU_PLL2_PHASE_DIVIDER_ENABLE \
++ (ltq_cgu_r32(LTQ_CGU_PLL2_CFG) & (1 << 20))
++#define CGU_SYS_FPI_SEL (1 << 6)
++#define CGU_SYS_DDR_SEL 0x3
++#define CGU_PLL0_SRC (1 << 29)
++
++#define CGU_PLL0_CFG_PLLK GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 26, 17)
++#define CGU_PLL0_CFG_PLLN GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 12, 6)
++#define CGU_PLL0_CFG_PLLM GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 5, 2)
++#define CGU_PLL2_SRC GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL2_CFG), 18, 17)
++#define CGU_PLL2_CFG_INPUT_DIV GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL2_CFG), 16, 13)
++
++static unsigned int ltq_get_pll0_fdiv(void);
++
++static inline unsigned int get_input_clock(int pll)
++{
++ switch (pll) {
++ case 0:
++ if (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & CGU_PLL0_SRC)
++ return BASIS_REQUENCY_USB;
++ else if (CGU_PLL0_PHASE_DIVIDER_ENABLE)
++ return BASIC_FREQUENCY_1;
++ else
++ return BASIC_FREQUENCY_2;
++ case 1:
++ if (CGU_PLL1_SRC)
++ return BASIS_REQUENCY_USB;
++ else if (CGU_PLL0_PHASE_DIVIDER_ENABLE)
++ return BASIC_FREQUENCY_1;
++ else
++ return BASIC_FREQUENCY_2;
++ case 2:
++ switch (CGU_PLL2_SRC) {
++ case 0:
++ return ltq_get_pll0_fdiv();
++ case 1:
++ return CGU_PLL2_PHASE_DIVIDER_ENABLE ?
++ BASIC_FREQUENCY_1 :
++ BASIC_FREQUENCY_2;
++ case 2:
++ return BASIS_REQUENCY_USB;
++ }
++ default:
++ return 0;
++ }
++}
++
++static inline unsigned int cal_dsm(int pll, unsigned int num, unsigned int den)
++{
++ u64 res, clock = get_input_clock(pll);
++
++ res = num * clock;
++ do_div(res, den);
++ return res;
++}
++
++static inline unsigned int mash_dsm(int pll, unsigned int M, unsigned int N,
++ unsigned int K)
++{
++ unsigned int num = ((N + 1) << 10) + K;
++ unsigned int den = (M + 1) << 10;
++
++ return cal_dsm(pll, num, den);
++}
++
++static inline unsigned int ssff_dsm_1(int pll, unsigned int M, unsigned int N,
++ unsigned int K)
++{
++ unsigned int num = ((N + 1) << 11) + K + 512;
++ unsigned int den = (M + 1) << 11;
++
++ return cal_dsm(pll, num, den);
++}
++
++static inline unsigned int ssff_dsm_2(int pll, unsigned int M, unsigned int N,
++ unsigned int K)
++{
++ unsigned int num = K >= 512 ?
++ ((N + 1) << 12) + K - 512 : ((N + 1) << 12) + K + 3584;
++ unsigned int den = (M + 1) << 12;
++
++ return cal_dsm(pll, num, den);
++}
++
++static inline unsigned int dsm(int pll, unsigned int M, unsigned int N,
++ unsigned int K, unsigned int dsmsel, unsigned int phase_div_en)
++{
++ if (!dsmsel)
++ return mash_dsm(pll, M, N, K);
++ else if (!phase_div_en)
++ return mash_dsm(pll, M, N, K);
++ else
++ return ssff_dsm_2(pll, M, N, K);
++}
++
++static inline unsigned int ltq_get_pll0_fosc(void)
++{
++ if (CGU_PLL0_BYPASS)
++ return get_input_clock(0);
++ else
++ return !CGU_PLL0_CFG_FRAC_EN
++ ? dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN, 0,
++ CGU_PLL0_CFG_DSMSEL,
++ CGU_PLL0_PHASE_DIVIDER_ENABLE)
++ : dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN,
++ CGU_PLL0_CFG_PLLK, CGU_PLL0_CFG_DSMSEL,
++ CGU_PLL0_PHASE_DIVIDER_ENABLE);
++}
++
++static unsigned int ltq_get_pll0_fdiv(void)
++{
++ unsigned int div = CGU_PLL2_CFG_INPUT_DIV + 1;
++
++ return (ltq_get_pll0_fosc() + (div >> 1)) / div;
++}
++
++unsigned int ltq_get_io_region_clock(void)
++{
++ unsigned int ret = ltq_get_pll0_fosc();
++
++ switch (ltq_cgu_r32(LTQ_CGU_PLL2_CFG) & CGU_SYS_DDR_SEL) {
++ default:
++ case 0:
++ return (ret + 1) / 2;
++ case 1:
++ return (ret * 2 + 2) / 5;
++ case 2:
++ return (ret + 1) / 3;
++ case 3:
++ return (ret + 2) / 4;
++ }
++}
++EXPORT_SYMBOL(ltq_get_io_region_clock);
++
++unsigned int ltq_get_fpi_bus_clock(int fpi)
++{
++ unsigned int ret = ltq_get_io_region_clock();
++
++ if ((fpi == 2) && (ltq_cgu_r32(LTQ_CGU_SYS) & CGU_SYS_FPI_SEL))
++ ret >>= 1;
++ return ret;
++}
++EXPORT_SYMBOL(ltq_get_fpi_bus_clock);
++
++unsigned int ltq_get_cpu_hz(void)
++{
++ switch (ltq_cgu_r32(LTQ_CGU_SYS) & 0xc) {
++ case 0:
++ return CLOCK_333M;
++ case 4:
++ return DDR_HZ;
++ case 8:
++ return DDR_HZ << 1;
++ default:
++ return DDR_HZ >> 1;
++ }
++}
++EXPORT_SYMBOL(ltq_get_cpu_hz);
++
++unsigned int ltq_get_fpi_hz(void)
++{
++ unsigned int ddr_clock = DDR_HZ;
++
++ if (ltq_cgu_r32(LTQ_CGU_SYS) & 0x40)
++ return ddr_clock >> 1;
++ return ddr_clock;
++}
++EXPORT_SYMBOL(ltq_get_fpi_hz);
+--- /dev/null
++++ b/arch/mips/lantiq/xway/ebu.c
+@@ -0,0 +1,53 @@
++/*
++ * 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.
++ *
++ * EBU - the external bus unit attaches PCI, NOR and NAND
++ *
++ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/version.h>
++#include <linux/ioport.h>
++
++#include <lantiq_soc.h>
++
++/* all access to the ebu must be locked */
++DEFINE_SPINLOCK(ebu_lock);
++EXPORT_SYMBOL_GPL(ebu_lock);
++
++static struct resource ltq_ebu_resource = {
++ .name = "ebu",
++ .start = LTQ_EBU_BASE_ADDR,
++ .end = LTQ_EBU_BASE_ADDR + LTQ_EBU_SIZE - 1,
++ .flags = IORESOURCE_MEM,
++};
++
++/* remapped base addr of the clock unit and external bus unit */
++void __iomem *ltq_ebu_membase;
++
++static int __init lantiq_ebu_init(void)
++{
++ /* insert and request the memory region */
++ if (insert_resource(&iomem_resource, &ltq_ebu_resource) < 0)
++ panic("Failed to insert ebu memory\n");
++
++ if (request_mem_region(ltq_ebu_resource.start,
++ resource_size(&ltq_ebu_resource), "ebu") < 0)
++ panic("Failed to request ebu memory\n");
++
++ /* remap ebu register range */
++ ltq_ebu_membase = ioremap_nocache(ltq_ebu_resource.start,
++ resource_size(&ltq_ebu_resource));
++ if (!ltq_ebu_membase)
++ panic("Failed to remap ebu memory\n");
++
++ /* make sure to unprotect the memory region where flash is located */
++ ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_BUSCON0) & ~EBU_WRDIS, LTQ_EBU_BUSCON0);
++ return 0;
++}
++
++postcore_initcall(lantiq_ebu_init);
+--- /dev/null
++++ b/arch/mips/lantiq/xway/gpio.c
+@@ -0,0 +1,195 @@
++/*
++ * 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/slab.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/gpio.h>
++#include <linux/ioport.h>
++#include <linux/io.h>
++
++#include <lantiq_soc.h>
++
++#define LTQ_GPIO_OUT 0x00
++#define LTQ_GPIO_IN 0x04
++#define LTQ_GPIO_DIR 0x08
++#define LTQ_GPIO_ALTSEL0 0x0C
++#define LTQ_GPIO_ALTSEL1 0x10
++#define LTQ_GPIO_OD 0x14
++
++#define PINS_PER_PORT 16
++#define MAX_PORTS 3
++
++#define ltq_gpio_getbit(m, r, p) (!!(ltq_r32(m + r) & (1 << p)))
++#define ltq_gpio_setbit(m, r, p) ltq_w32_mask(0, (1 << p), m + r)
++#define ltq_gpio_clearbit(m, r, p) ltq_w32_mask((1 << p), 0, m + r)
++
++struct ltq_gpio {
++ void __iomem *membase;
++ struct gpio_chip chip;
++};
++
++static struct ltq_gpio ltq_gpio_port[MAX_PORTS];
++
++int gpio_to_irq(unsigned int gpio)
++{
++ return -EINVAL;
++}
++EXPORT_SYMBOL(gpio_to_irq);
++
++int irq_to_gpio(unsigned int gpio)
++{
++ return -EINVAL;
++}
++EXPORT_SYMBOL(irq_to_gpio);
++
++int ltq_gpio_request(unsigned int pin, unsigned int alt0,
++ unsigned int alt1, unsigned int dir, const char *name)
++{
++ int id = 0;
++
++ if (pin >= (MAX_PORTS * PINS_PER_PORT))
++ return -EINVAL;
++ if (gpio_request(pin, name)) {
++ pr_err("failed to setup lantiq gpio: %s\n", name);
++ return -EBUSY;
++ }
++ if (dir)
++ gpio_direction_output(pin, 1);
++ else
++ gpio_direction_input(pin);
++ while (pin >= PINS_PER_PORT) {
++ pin -= PINS_PER_PORT;
++ id++;
++ }
++ if (alt0)
++ ltq_gpio_setbit(ltq_gpio_port[id].membase,
++ LTQ_GPIO_ALTSEL0, pin);
++ else
++ ltq_gpio_clearbit(ltq_gpio_port[id].membase,
++ LTQ_GPIO_ALTSEL0, pin);
++ if (alt1)
++ ltq_gpio_setbit(ltq_gpio_port[id].membase,
++ LTQ_GPIO_ALTSEL1, pin);
++ else
++ ltq_gpio_clearbit(ltq_gpio_port[id].membase,
++ LTQ_GPIO_ALTSEL1, pin);
++ return 0;
++}
++EXPORT_SYMBOL(ltq_gpio_request);
++
++static void ltq_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
++{
++ struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
++
++ if (value)
++ ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_OUT, offset);
++ else
++ ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_OUT, offset);
++}
++
++static int ltq_gpio_get(struct gpio_chip *chip, unsigned int offset)
++{
++ struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
++
++ return ltq_gpio_getbit(ltq_gpio->membase, LTQ_GPIO_IN, offset);
++}
++
++static int ltq_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
++{
++ struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
++
++ ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_OD, offset);
++ ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_DIR, offset);
++
++ return 0;
++}
++
++static int ltq_gpio_direction_output(struct gpio_chip *chip,
++ unsigned int offset, int value)
++{
++ struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
++
++ ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_OD, offset);
++ ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_DIR, offset);
++ ltq_gpio_set(chip, offset, value);
++
++ return 0;
++}
++
++static int ltq_gpio_req(struct gpio_chip *chip, unsigned offset)
++{
++ struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
++
++ ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_ALTSEL0, offset);
++ ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_ALTSEL1, offset);
++ return 0;
++}
++
++static int ltq_gpio_probe(struct platform_device *pdev)
++{
++ struct resource *res;
++
++ if (pdev->id >= MAX_PORTS) {
++ dev_err(&pdev->dev, "invalid gpio port %d\n",
++ pdev->id);
++ return -EINVAL;
++ }
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!res) {
++ dev_err(&pdev->dev, "failed to get memory for gpio port %d\n",
++ pdev->id);
++ 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 for gpio port %d\n",
++ pdev->id);
++ return -EBUSY;
++ }
++ ltq_gpio_port[pdev->id].membase = devm_ioremap_nocache(&pdev->dev,
++ res->start, resource_size(res));
++ if (!ltq_gpio_port[pdev->id].membase) {
++ dev_err(&pdev->dev, "failed to remap memory for gpio port %d\n",
++ pdev->id);
++ return -ENOMEM;
++ }
++ ltq_gpio_port[pdev->id].chip.label = "ltq_gpio";
++ ltq_gpio_port[pdev->id].chip.direction_input = ltq_gpio_direction_input;
++ ltq_gpio_port[pdev->id].chip.direction_output =
++ ltq_gpio_direction_output;
++ ltq_gpio_port[pdev->id].chip.get = ltq_gpio_get;
++ ltq_gpio_port[pdev->id].chip.set = ltq_gpio_set;
++ ltq_gpio_port[pdev->id].chip.request = ltq_gpio_req;
++ ltq_gpio_port[pdev->id].chip.base = PINS_PER_PORT * pdev->id;
++ ltq_gpio_port[pdev->id].chip.ngpio = PINS_PER_PORT;
++ platform_set_drvdata(pdev, &ltq_gpio_port[pdev->id]);
++ return gpiochip_add(&ltq_gpio_port[pdev->id].chip);
++}
++
++static struct platform_driver
++ltq_gpio_driver = {
++ .probe = ltq_gpio_probe,
++ .driver = {
++ .name = "ltq_gpio",
++ .owner = THIS_MODULE,
++ },
++};
++
++int __init ltq_gpio_init(void)
++{
++ int ret = platform_driver_register(&ltq_gpio_driver);
++
++ if (ret)
++ pr_info("ltq_gpio : Error registering platfom driver!");
++ return ret;
++}
++
++postcore_initcall(ltq_gpio_init);
+--- /dev/null
++++ b/arch/mips/lantiq/xway/pmu.c
+@@ -0,0 +1,70 @@
++/*
++ * 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/version.h>
++#include <linux/ioport.h>
++
++#include <lantiq_soc.h>
++
++/* PMU - the power management unit allows us to turn part of the core
++ * on and off
++ */
++
++/* the enable / disable registers */
++#define LTQ_PMU_PWDCR 0x1C
++#define LTQ_PMU_PWDSR 0x20
++
++#define ltq_pmu_w32(x, y) ltq_w32((x), ltq_pmu_membase + (y))
++#define ltq_pmu_r32(x) ltq_r32(ltq_pmu_membase + (x))
++
++static struct resource ltq_pmu_resource = {
++ .name = "pmu",
++ .start = LTQ_PMU_BASE_ADDR,
++ .end = LTQ_PMU_BASE_ADDR + LTQ_PMU_SIZE - 1,
++ .flags = IORESOURCE_MEM,
++};
++
++static void __iomem *ltq_pmu_membase;
++
++void ltq_pmu_enable(unsigned int module)
++{
++ int err = 1000000;
++
++ ltq_pmu_w32(ltq_pmu_r32(LTQ_PMU_PWDCR) & ~module, LTQ_PMU_PWDCR);
++ do {} while (--err && (ltq_pmu_r32(LTQ_PMU_PWDSR) & module));
++
++ if (!err)
++ panic("activating PMU module failed!\n");
++}
++EXPORT_SYMBOL(ltq_pmu_enable);
++
++void ltq_pmu_disable(unsigned int module)
++{
++ ltq_pmu_w32(ltq_pmu_r32(LTQ_PMU_PWDCR) | module, LTQ_PMU_PWDCR);
++}
++EXPORT_SYMBOL(ltq_pmu_disable);
++
++int __init ltq_pmu_init(void)
++{
++ if (insert_resource(&iomem_resource, &ltq_pmu_resource) < 0)
++ panic("Failed to insert pmu memory\n");
++
++ if (request_mem_region(ltq_pmu_resource.start,
++ resource_size(&ltq_pmu_resource), "pmu") < 0)
++ panic("Failed to request pmu memory\n");
++
++ ltq_pmu_membase = ioremap_nocache(ltq_pmu_resource.start,
++ resource_size(&ltq_pmu_resource));
++ if (!ltq_pmu_membase)
++ panic("Failed to remap pmu memory\n");
++ return 0;
++}
++
++core_initcall(ltq_pmu_init);
+--- /dev/null
++++ b/arch/mips/lantiq/xway/prom-ase.c
+@@ -0,0 +1,39 @@
++/*
++ * 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_soc.h>
++
++#include "../prom.h"
++
++#define SOC_AMAZON_SE "Amazon_SE"
++
++#define PART_SHIFT 12
++#define PART_MASK 0x0FFFFFFF
++#define REV_SHIFT 28
++#define REV_MASK 0xF0000000
++
++void __init ltq_soc_detect(struct ltq_soc_info *i)
++{
++ i->partnum = (ltq_r32(LTQ_MPS_CHIPID) & PART_MASK) >> PART_SHIFT;
++ i->rev = (ltq_r32(LTQ_MPS_CHIPID) & REV_MASK) >> REV_SHIFT;
++ switch (i->partnum) {
++ case SOC_ID_AMAZON_SE:
++ i->name = SOC_AMAZON_SE;
++ i->type = SOC_TYPE_AMAZON_SE;
++ break;
++
++ default:
++ unreachable();
++ break;
++ }
++}
+--- /dev/null
++++ b/arch/mips/lantiq/xway/prom-xway.c
+@@ -0,0 +1,54 @@
++/*
++ * 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_soc.h>
++
++#include "../prom.h"
++
++#define SOC_DANUBE "Danube"
++#define SOC_TWINPASS "Twinpass"
++#define SOC_AR9 "AR9"
++
++#define PART_SHIFT 12
++#define PART_MASK 0x0FFFFFFF
++#define REV_SHIFT 28
++#define REV_MASK 0xF0000000
++
++void __init ltq_soc_detect(struct ltq_soc_info *i)
++{
++ i->partnum = (ltq_r32(LTQ_MPS_CHIPID) & PART_MASK) >> PART_SHIFT;
++ i->rev = (ltq_r32(LTQ_MPS_CHIPID) & REV_MASK) >> REV_SHIFT;
++ switch (i->partnum) {
++ case SOC_ID_DANUBE1:
++ case SOC_ID_DANUBE2:
++ i->name = SOC_DANUBE;
++ i->type = SOC_TYPE_DANUBE;
++ break;
++
++ case SOC_ID_TWINPASS:
++ i->name = SOC_TWINPASS;
++ i->type = SOC_TYPE_DANUBE;
++ break;
++
++ case SOC_ID_ARX188:
++ case SOC_ID_ARX168:
++ case SOC_ID_ARX182:
++ i->name = SOC_AR9;
++ i->type = SOC_TYPE_AR9;
++ break;
++
++ default:
++ unreachable();
++ break;
++ }
++}
+--- /dev/null
++++ b/arch/mips/lantiq/xway/reset.c
+@@ -0,0 +1,91 @@
++/*
++ * 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/io.h>
++#include <linux/ioport.h>
++#include <linux/pm.h>
++#include <linux/module.h>
++#include <asm/reboot.h>
++
++#include <lantiq_soc.h>
++
++#define ltq_rcu_w32(x, y) ltq_w32((x), ltq_rcu_membase + (y))
++#define ltq_rcu_r32(x) ltq_r32(ltq_rcu_membase + (x))
++
++/* register definitions */
++#define LTQ_RCU_RST 0x0010
++#define LTQ_RCU_RST_ALL 0x40000000
++
++#define LTQ_RCU_RST_STAT 0x0014
++#define LTQ_RCU_STAT_SHIFT 26
++
++static struct resource ltq_rcu_resource = {
++ .name = "rcu",
++ .start = LTQ_RCU_BASE_ADDR,
++ .end = LTQ_RCU_BASE_ADDR + LTQ_RCU_SIZE - 1,
++ .flags = IORESOURCE_MEM,
++};
++
++/* remapped base addr of the reset control unit */
++static void __iomem *ltq_rcu_membase;
++
++/* This function is used by the watchdog driver */
++int ltq_reset_cause(void)
++{
++ u32 val = ltq_rcu_r32(LTQ_RCU_RST_STAT);
++ return val >> LTQ_RCU_STAT_SHIFT;
++}
++EXPORT_SYMBOL_GPL(ltq_reset_cause);
++
++static void ltq_machine_restart(char *command)
++{
++ pr_notice("System restart\n");
++ local_irq_disable();
++ ltq_rcu_w32(ltq_rcu_r32(LTQ_RCU_RST) | LTQ_RCU_RST_ALL, LTQ_RCU_RST);
++ unreachable();
++}
++
++static void ltq_machine_halt(void)
++{
++ pr_notice("System halted.\n");
++ local_irq_disable();
++ unreachable();
++}
++
++static void ltq_machine_power_off(void)
++{
++ pr_notice("Please turn off the power now.\n");
++ local_irq_disable();
++ unreachable();
++}
++
++static int __init mips_reboot_setup(void)
++{
++ /* insert and request the memory region */
++ if (insert_resource(&iomem_resource, &ltq_rcu_resource) < 0)
++ panic("Failed to insert rcu memory\n");
++
++ if (request_mem_region(ltq_rcu_resource.start,
++ resource_size(&ltq_rcu_resource), "rcu") < 0)
++ panic("Failed to request rcu memory\n");
++
++ /* remap rcu register range */
++ ltq_rcu_membase = ioremap_nocache(ltq_rcu_resource.start,
++ resource_size(&ltq_rcu_resource));
++ if (!ltq_rcu_membase)
++ panic("Failed to remap rcu memory\n");
++
++ _machine_restart = ltq_machine_restart;
++ _machine_halt = ltq_machine_halt;
++ pm_power_off = ltq_machine_power_off;
++
++ return 0;
++}
++
++arch_initcall(mips_reboot_setup);