diff options
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.patch | 1151 |
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, <q_ebu_resource) < 0) ++ panic("Failed to insert ebu memory\n"); ++ ++ if (request_mem_region(ltq_ebu_resource.start, ++ resource_size(<q_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(<q_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, <q_gpio_port[pdev->id]); ++ return gpiochip_add(<q_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(<q_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, <q_pmu_resource) < 0) ++ panic("Failed to insert pmu memory\n"); ++ ++ if (request_mem_region(ltq_pmu_resource.start, ++ resource_size(<q_pmu_resource), "pmu") < 0) ++ panic("Failed to request pmu memory\n"); ++ ++ ltq_pmu_membase = ioremap_nocache(ltq_pmu_resource.start, ++ resource_size(<q_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, <q_rcu_resource) < 0) ++ panic("Failed to insert rcu memory\n"); ++ ++ if (request_mem_region(ltq_rcu_resource.start, ++ resource_size(<q_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(<q_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); |