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 lq_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@xxxxxxxxxxx> Signed-off-by: Ralph Hempel <ralph.hempel@xxxxxxxxxx> Cc: linux-mips@xxxxxxxxxxxxxx --- arch/mips/Kconfig | 1 + arch/mips/include/asm/mach-lantiq/xway/irq.h | 18 ++ .../mips/include/asm/mach-lantiq/xway/lantiq_irq.h | 62 ++++++ .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 119 +++++++++++ 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 | 53 +++++ arch/mips/lantiq/xway/clk-xway.c | 221 ++++++++++++++++++++ arch/mips/lantiq/xway/gpio.c | 205 ++++++++++++++++++ arch/mips/lantiq/xway/pmu.c | 36 ++++ arch/mips/lantiq/xway/prom-ase.c | 41 ++++ arch/mips/lantiq/xway/prom-xway.c | 56 +++++ arch/mips/lantiq/xway/reset.c | 53 +++++ 15 files changed, 893 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/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 diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index a2396f1..9d3fd89 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -736,6 +736,7 @@ source "arch/mips/alchemy/Kconfig" 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" diff --git a/arch/mips/include/asm/mach-lantiq/xway/irq.h b/arch/mips/include/asm/mach-lantiq/xway/irq.h new file mode 100644 index 0000000..a1471d2 --- /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@xxxxxxxxxxx> + */ + +#ifndef __LANTIQ_IRQ_H +#define __LANTIQ_IRQ_H + +#include <lantiq_irq.h> + +#define NR_IRQS 256 + +#include_next <irq.h> + +#endif diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h new file mode 100644 index 0000000..2d29e77 --- /dev/null +++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h @@ -0,0 +1,62 @@ +/* + * 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@xxxxxxxxxxx> + */ + +#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_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 diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h new file mode 100644 index 0000000..74beeb7 --- /dev/null +++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h @@ -0,0 +1,119 @@ +/* + * 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@xxxxxxxxxxx> + */ + +#ifdef CONFIG_SOC_TYPE_XWAY + +#ifndef _LTQ_XWAY_H__ +#define _LTQ_XWAY_H__ + +#include <lantiq.h> + +/* 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 int ltq_gpio_setconfig(unsigned int pin, + unsigned int reg, unsigned int val); + +extern void ltq_pmu_enable(unsigned int module); +extern void ltq_pmu_disable(unsigned int module); + +/*------------ 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_AMAZON_SE 0x04 + +/*------------ ASC0/1 */ +#define LTQ_ASC0_BASE 0x1E100400 +#define LTQ_ASC1_BASE 0x1E100C00 +#define LTQ_ASC_SIZE 0x400 + +/*------------ RCU */ +#define LTQ_RCU_BASE_ADDR 0xBF203000 + +/*------------ GPTU */ +#define LTQ_GPTU_BASE_ADDR 0xB8000300 + +/*------------ EBU */ +#define LTQ_EBU_GPIO_START 0x14000000 +#define LTQ_EBU_GPIO_SIZE 0x1000 + +#define LTQ_EBU_BASE_ADDR 0xBE105300 + +#define LTQ_EBU_BUSCON0 ((u32 *)(LTQ_EBU_BASE_ADDR + 0x0060)) +#define LTQ_EBU_PCC_CON ((u32 *)(LTQ_EBU_BASE_ADDR + 0x0090)) +#define LTQ_EBU_PCC_IEN ((u32 *)(LTQ_EBU_BASE_ADDR + 0x00A4)) +#define LTQ_EBU_PCC_ISTAT ((u32 *)(LTQ_EBU_BASE_ADDR + 0x00A0)) +#define LTQ_EBU_BUSCON1 ((u32 *)(LTQ_EBU_BASE_ADDR + 0x0064)) +#define LTQ_EBU_ADDRSEL1 ((u32 *)(LTQ_EBU_BASE_ADDR + 0x0024)) + +#define EBU_WRDIS 0x80000000 + +/*------------ CGU */ +#define LTQ_CGU_BASE_ADDR (KSEG1 + 0x1F103000) + +/*------------ PMU */ +#define LTQ_PMU_BASE_ADDR (KSEG1 + 0x1F102000) + +#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 */ +#define LTQ_PPE32_BASE_ADDR 0xBE180000 +#define LTQ_PPE32_SIZE 0x40000 + +/*------------ DMA */ +#define LTQ_DMA_BASE_ADDR 0xBE104100 + +/*------------ PCI */ +#define PCI_CR_BASE_ADDR (KSEG1 + 0x1E105400) +#define PCI_CS_BASE_ADDR (KSEG1 + 0x17000000) + +/*------------ WDT */ +#define LTQ_WDT_BASE 0x1F880000 +#define LTQ_WDT_SIZE 0x400 + +/*------------ Serial To Parallel conversion */ +#define LTQ_STP_BASE 0x1E100BB0 +#define LTQ_STP_SIZE 0x40 + +/*------------ GPIO */ +#define LTQ_GPIO0_BASE_ADDR 0x1E100B10 +#define LTQ_GPIO1_BASE_ADDR 0x1E100B40 +#define LTQ_GPIO_SIZE 0x30 + +/*------------ SSC */ +#define LTQ_SSC_BASE_ADDR (KSEG1 + 0x1e100800) + +/*------------ MEI */ +#define LTQ_MEI_BASE_ADDR (KSEG1 + 0x1E116000) + +/*------------ DEU */ +#define LTQ_DEU_BASE (KSEG1 + 0x1E103100) + +/*------------ MPS */ +#define LTQ_MPS_BASE_ADDR (KSEG1 + 0x1F107000) +#define LTQ_MPS_CHIPID ((u32 *)(LTQ_MPS_BASE_ADDR + 0x0344)) + +#endif + +#endif diff --git a/arch/mips/lantiq/Kconfig b/arch/mips/lantiq/Kconfig new file mode 100644 index 0000000..2780461 --- /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 diff --git a/arch/mips/lantiq/Makefile b/arch/mips/lantiq/Makefile index 6a30de6..a268391 100644 --- 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/ diff --git a/arch/mips/lantiq/Platform b/arch/mips/lantiq/Platform index eef587f..f3dff05 100644 --- 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 diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile new file mode 100644 index 0000000..64730d5 --- /dev/null +++ b/arch/mips/lantiq/xway/Makefile @@ -0,0 +1,4 @@ +obj-y := pmu.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 diff --git a/arch/mips/lantiq/xway/clk-ase.c b/arch/mips/lantiq/xway/clk-ase.c new file mode 100644 index 0000000..ecc3b7c --- /dev/null +++ b/arch/mips/lantiq/xway/clk-ase.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. + * + * Copyright (C) 2011 John Crispin <blogic@xxxxxxxxxxx> + */ + +#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> + +#define LTQ_CGU_SYS ((u32 *)(LTQ_CGU_BASE_ADDR + 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_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); + + diff --git a/arch/mips/lantiq/xway/clk-xway.c b/arch/mips/lantiq/xway/clk-xway.c new file mode 100644 index 0000000..8e7e3d6 --- /dev/null +++ b/arch/mips/lantiq/xway/clk-xway.c @@ -0,0 +1,221 @@ +/* + * 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@xxxxxxxxxxx> + */ + +#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_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 CGU_PLL0_PHASE_DIVIDER_ENABLE (ltq_r32(LTQ_CGU_PLL0_CFG) & (1 << 31)) +#define CGU_PLL0_BYPASS (ltq_r32(LTQ_CGU_PLL0_CFG) & (1 << 30)) +#define CGU_PLL0_CFG_DSMSEL (ltq_r32(LTQ_CGU_PLL0_CFG) & (1 << 28)) +#define CGU_PLL0_CFG_FRAC_EN (ltq_r32(LTQ_CGU_PLL0_CFG) & (1 << 27)) +#define CGU_PLL1_SRC (ltq_r32(LTQ_CGU_PLL1_CFG) & (1 << 31)) +#define CGU_PLL2_PHASE_DIVIDER_ENABLE (ltq_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_PLL0_CFG, 26, 17) +#define CGU_PLL0_CFG_PLLN GET_BITS(*LTQ_CGU_PLL0_CFG, 12, 6) +#define CGU_PLL0_CFG_PLLM GET_BITS(*LTQ_CGU_PLL0_CFG, 5, 2) +#define CGU_PLL2_SRC GET_BITS(*LTQ_CGU_PLL2_CFG, 18, 17) +#define CGU_PLL2_CFG_INPUT_DIV GET_BITS(*LTQ_CGU_PLL2_CFG, 16, 13) + +#define LTQ_GPTU_GPT_CLC ((u32 *)(LTQ_GPTU_BASE_ADDR + 0x0000)) +#define LTQ_CGU_PLL0_CFG ((u32 *)(LTQ_CGU_BASE_ADDR + 0x0004)) +#define LTQ_CGU_PLL1_CFG ((u32 *)(LTQ_CGU_BASE_ADDR + 0x0008)) +#define LTQ_CGU_PLL2_CFG ((u32 *)(LTQ_CGU_BASE_ADDR + 0x000C)) +#define LTQ_CGU_SYS ((u32 *)(LTQ_CGU_BASE_ADDR + 0x0010)) +#define LTQ_CGU_UPDATE ((u32 *)(LTQ_CGU_BASE_ADDR + 0x0014)) +#define LTQ_CGU_IF_CLK ((u32 *)(LTQ_CGU_BASE_ADDR + 0x0018)) +#define LTQ_CGU_OSC_CON ((u32 *)(LTQ_CGU_BASE_ADDR + 0x001C)) +#define LTQ_CGU_SMD ((u32 *)(LTQ_CGU_BASE_ADDR + 0x0020)) +#define LTQ_CGU_CT1SR ((u32 *)(LTQ_CGU_BASE_ADDR + 0x0028)) +#define LTQ_CGU_CT2SR ((u32 *)(LTQ_CGU_BASE_ADDR + 0x002C)) +#define LTQ_CGU_PCMCR ((u32 *)(LTQ_CGU_BASE_ADDR + 0x0030)) +#define LTQ_CGU_PCI_CR ((u32 *)(LTQ_CGU_BASE_ADDR + 0x0034)) +#define LTQ_CGU_PD_PC ((u32 *)(LTQ_CGU_BASE_ADDR + 0x0038)) +#define LTQ_CGU_FMR ((u32 *)(LTQ_CGU_BASE_ADDR + 0x003C)) + +static unsigned int ltq_get_pll0_fdiv(void); + +static inline unsigned int +get_input_clock(int pll) +{ + switch (pll) { + case 0: + if (ltq_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_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_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_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_r32(LTQ_CGU_SYS) & 0x40) + return ddr_clock >> 1; + return ddr_clock; +} +EXPORT_SYMBOL(ltq_get_fpi_hz); + + diff --git a/arch/mips/lantiq/xway/gpio.c b/arch/mips/lantiq/xway/gpio.c new file mode 100644 index 0000000..2faa23a --- /dev/null +++ b/arch/mips/lantiq/xway/gpio.c @@ -0,0 +1,205 @@ +/* + * 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@xxxxxxxxxxx> + */ + +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> + +#include <lantiq.h> + +#define LQ_GPIO0_BASE_ADDR 0x1E100B10 +#define LQ_GPIO1_BASE_ADDR 0x1E100B40 +#define LQ_GPIO_SIZE 0x30 + +#define LQ_GPIO_OUT 0x00 +#define LQ_GPIO_IN 0x04 +#define LQ_GPIO_DIR 0x08 +#define LQ_GPIO_ALTSEL0 0x0C +#define LQ_GPIO_ALTSEL1 0x10 +#define LQ_GPIO_OD 0x14 + +#define PINS_PER_PORT 16 + +#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; +}; + +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_setconfig(unsigned int pin, unsigned int reg, unsigned int val) +{ + void __iomem *membase = (void *)KSEG1ADDR(LQ_GPIO0_BASE_ADDR); + if (pin >= (2 * PINS_PER_PORT)) + return -EINVAL; + if (pin >= PINS_PER_PORT) { + pin -= PINS_PER_PORT; + membase += LQ_GPIO_SIZE; + } + if (val) + ltq_w32_mask(0, (1 << pin), membase + reg); + else + ltq_w32_mask((1 << pin), 0, membase + reg); + return 0; +} +EXPORT_SYMBOL(ltq_gpio_setconfig); + +int +ltq_gpio_request(unsigned int pin, unsigned int alt0, + unsigned int alt1, unsigned int dir, const char *name) +{ + void __iomem *membase = (void *)KSEG1ADDR(LQ_GPIO0_BASE_ADDR); + if (pin >= (2 * PINS_PER_PORT)) + return -EINVAL; + if (gpio_request(pin, name)) { + printk(KERN_ERR "failed to register %s gpio\n", name); + return -EBUSY; + } + gpio_direction_output(pin, dir); + if (pin >= PINS_PER_PORT) { + pin -= PINS_PER_PORT; + membase += LQ_GPIO_SIZE; + } + if (alt0) + ltq_gpio_setbit(membase, LQ_GPIO_ALTSEL0, pin); + else + ltq_gpio_clearbit(membase, LQ_GPIO_ALTSEL0, pin); + if (alt1) + ltq_gpio_setbit(membase, LQ_GPIO_ALTSEL1, pin); + else + ltq_gpio_clearbit(membase, LQ_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, LQ_GPIO_OUT, offset); + else + ltq_gpio_clearbit(ltq_gpio->membase, LQ_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, LQ_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, LQ_GPIO_OD, offset); + ltq_gpio_clearbit(ltq_gpio->membase, LQ_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, LQ_GPIO_OD, offset); + ltq_gpio_setbit(ltq_gpio->membase, LQ_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, LQ_GPIO_ALTSEL0, offset); + ltq_gpio_clearbit(ltq_gpio->membase, LQ_GPIO_ALTSEL1, offset); + return 0; +} + +static int +ltq_gpio_probe(struct platform_device *pdev) +{ + struct ltq_gpio *ltq_gpio = + kzalloc(sizeof(struct ltq_gpio), GFP_KERNEL); + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + int ret = 0; + if (!res) { + ret = -ENOENT; + goto err_free; + } + res = request_mem_region(res->start, resource_size(res), + dev_name(&pdev->dev)); + if (!res) { + ret = -EBUSY; + goto err_free; + } + ltq_gpio->membase = ioremap_nocache(res->start, resource_size(res)); + if (!ltq_gpio->membase) { + ret = -ENOMEM; + goto err_release_mem_region; + } + ltq_gpio->chip.label = "ltq_gpio"; + ltq_gpio->chip.direction_input = ltq_gpio_direction_input; + ltq_gpio->chip.direction_output = ltq_gpio_direction_output; + ltq_gpio->chip.get = ltq_gpio_get; + ltq_gpio->chip.set = ltq_gpio_set; + ltq_gpio->chip.request = ltq_gpio_req; + ltq_gpio->chip.base = PINS_PER_PORT * pdev->id; + ltq_gpio->chip.ngpio = PINS_PER_PORT; + platform_set_drvdata(pdev, ltq_gpio); + ret = gpiochip_add(<q_gpio->chip); + if (!ret) + return 0; + + iounmap(ltq_gpio->membase); +err_release_mem_region: + release_mem_region(res->start, resource_size(res)); +err_free: + kfree(ltq_gpio); + return ret; +} + +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) + printk(KERN_INFO "ltq_gpio : Error registering platfom driver!"); + return ret; +} + +arch_initcall(ltq_gpio_init); diff --git a/arch/mips/lantiq/xway/pmu.c b/arch/mips/lantiq/xway/pmu.c new file mode 100644 index 0000000..78f4a4c --- /dev/null +++ b/arch/mips/lantiq/xway/pmu.c @@ -0,0 +1,36 @@ +/* + * 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@xxxxxxxxxxx> + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/version.h> + +#include <lantiq_soc.h> + +#define LTQ_PMU_PWDCR ((u32 *)(LTQ_PMU_BASE_ADDR + 0x001C)) +#define LTQ_PMU_PWDSR ((u32 *)(LTQ_PMU_BASE_ADDR + 0x0020)) + +void +ltq_pmu_enable(unsigned int module) +{ + int err = 1000000; + + ltq_w32(ltq_r32(LTQ_PMU_PWDCR) & ~module, LTQ_PMU_PWDCR); + do {} while (--err && (ltq_r32(LTQ_PMU_PWDSR) & module)); + + if (!err) + panic("activating PMU module failed!"); +} +EXPORT_SYMBOL(ltq_pmu_enable); + +void +ltq_pmu_disable(unsigned int module) +{ + ltq_w32(ltq_r32(LTQ_PMU_PWDCR) | module, LTQ_PMU_PWDCR); +} +EXPORT_SYMBOL(ltq_pmu_disable); diff --git a/arch/mips/lantiq/xway/prom-ase.c b/arch/mips/lantiq/xway/prom-ase.c new file mode 100644 index 0000000..55f5041 --- /dev/null +++ b/arch/mips/lantiq/xway/prom-ase.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@xxxxxxxxxxx> + */ + +#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: + early_printf(KERN_ERR "unknown chiprev : 0x%08X\n", i->partnum); + unreachable(); + break; + } +} diff --git a/arch/mips/lantiq/xway/prom-xway.c b/arch/mips/lantiq/xway/prom-xway.c new file mode 100644 index 0000000..5c4e1a7 --- /dev/null +++ b/arch/mips/lantiq/xway/prom-xway.c @@ -0,0 +1,56 @@ +/* + * 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@xxxxxxxxxxx> + */ + +#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: + early_printf("unknown chiprev : 0x%08X\n", i->partnum); + unreachable(); + break; + } +} diff --git a/arch/mips/lantiq/xway/reset.c b/arch/mips/lantiq/xway/reset.c new file mode 100644 index 0000000..64ecd77 --- /dev/null +++ b/arch/mips/lantiq/xway/reset.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. + * + * Copyright (C) 2010 John Crispin <blogic@xxxxxxxxxxx> + */ + +#include <linux/init.h> +#include <linux/io.h> +#include <linux/pm.h> +#include <asm/reboot.h> + +#include <lantiq_soc.h> + +#define LTQ_RCU_RST ((u32 *)(LTQ_RCU_BASE_ADDR + 0x0010)) +#define LTQ_RCU_RST_ALL 0x40000000 + +static void +ltq_machine_restart(char *command) +{ + printk(KERN_NOTICE "System restart\n"); + local_irq_disable(); + ltq_w32(ltq_r32(LTQ_RCU_RST) | LTQ_RCU_RST_ALL, LTQ_RCU_RST); + unreachable(); +} + +static void +ltq_machine_halt(void) +{ + printk(KERN_NOTICE "System halted.\n"); + local_irq_disable(); + unreachable(); +} + +static void +ltq_machine_power_off(void) +{ + printk(KERN_NOTICE "Please turn off the power now.\n"); + local_irq_disable(); + unreachable(); +} + +static int __init +mips_reboot_setup(void) +{ + _machine_restart = ltq_machine_restart; + _machine_halt = ltq_machine_halt; + pm_power_off = ltq_machine_power_off; + return 0; +} + +arch_initcall(mips_reboot_setup); -- 1.7.2.3