From 716ca530e1c4515d8683c9d5be3d56b301758b66 Mon Sep 17 00:00:00 2001 From: James <> Date: Wed, 4 Nov 2015 11:49:21 +0000 Subject: trunk-47381 --- .../files-3.18/arch/mips/adm5120/common/Makefile | 8 + .../files-3.18/arch/mips/adm5120/common/adm5120.c | 76 +++++ .../files-3.18/arch/mips/adm5120/common/clock.c | 65 ++++ .../arch/mips/adm5120/common/early-printk.c | 31 ++ .../files-3.18/arch/mips/adm5120/common/gpio.c | 328 ++++++++++++++++++ .../files-3.18/arch/mips/adm5120/common/irq.c | 171 ++++++++++ .../files-3.18/arch/mips/adm5120/common/memory.c | 149 ++++++++ .../files-3.18/arch/mips/adm5120/common/platform.c | 375 +++++++++++++++++++++ .../files-3.18/arch/mips/adm5120/common/prom.c | 264 +++++++++++++++ .../files-3.18/arch/mips/adm5120/common/setup.c | 129 +++++++ 10 files changed, 1596 insertions(+) create mode 100644 target/linux/adm5120/files-3.18/arch/mips/adm5120/common/Makefile create mode 100644 target/linux/adm5120/files-3.18/arch/mips/adm5120/common/adm5120.c create mode 100644 target/linux/adm5120/files-3.18/arch/mips/adm5120/common/clock.c create mode 100644 target/linux/adm5120/files-3.18/arch/mips/adm5120/common/early-printk.c create mode 100644 target/linux/adm5120/files-3.18/arch/mips/adm5120/common/gpio.c create mode 100644 target/linux/adm5120/files-3.18/arch/mips/adm5120/common/irq.c create mode 100644 target/linux/adm5120/files-3.18/arch/mips/adm5120/common/memory.c create mode 100644 target/linux/adm5120/files-3.18/arch/mips/adm5120/common/platform.c create mode 100644 target/linux/adm5120/files-3.18/arch/mips/adm5120/common/prom.c create mode 100644 target/linux/adm5120/files-3.18/arch/mips/adm5120/common/setup.c (limited to 'target/linux/adm5120/files-3.18/arch/mips/adm5120/common') diff --git a/target/linux/adm5120/files-3.18/arch/mips/adm5120/common/Makefile b/target/linux/adm5120/files-3.18/arch/mips/adm5120/common/Makefile new file mode 100644 index 0000000..8d302c5 --- /dev/null +++ b/target/linux/adm5120/files-3.18/arch/mips/adm5120/common/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for the Infineon/ADMtek ADM5120 SoC specific parts of the kernel +# + +obj-y := adm5120.o setup.o prom.o irq.o memory.o clock.o \ + gpio.o platform.o + +obj-$(CONFIG_EARLY_PRINTK) += early-printk.o diff --git a/target/linux/adm5120/files-3.18/arch/mips/adm5120/common/adm5120.c b/target/linux/adm5120/files-3.18/arch/mips/adm5120/common/adm5120.c new file mode 100644 index 0000000..2838834 --- /dev/null +++ b/target/linux/adm5120/files-3.18/arch/mips/adm5120/common/adm5120.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2007-2008 Gabor Juhos + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + */ + +#include +#include +#include +#include + +#include + +#include +#include +#include + +unsigned int adm5120_product_code; +unsigned int adm5120_revision; +unsigned int adm5120_package; +unsigned int adm5120_nand_boot; +unsigned long adm5120_speed; + +/* + * CPU settings detection + */ +#define CODE_GET_PC(c) ((c) & CODE_PC_MASK) +#define CODE_GET_REV(c) (((c) >> CODE_REV_SHIFT) & CODE_REV_MASK) +#define CODE_GET_PK(c) (((c) >> CODE_PK_SHIFT) & CODE_PK_MASK) +#define CODE_GET_CLKS(c) (((c) >> CODE_CLKS_SHIFT) & CODE_CLKS_MASK) +#define CODE_GET_NAB(c) (((c) & CODE_NAB) != 0) + +void adm5120_ndelay(u32 ns) +{ + u32 t; + + SW_WRITE_REG(SWITCH_REG_TIMER, TIMER_PERIOD_DEFAULT); + SW_WRITE_REG(SWITCH_REG_TIMER_INT, (TIMER_INT_TOS | TIMER_INT_TOM)); + + t = (ns+640) / 640; + t &= TIMER_PERIOD_MASK; + SW_WRITE_REG(SWITCH_REG_TIMER, t | TIMER_TE); + + /* wait until the timer expires */ + do { + t = SW_READ_REG(SWITCH_REG_TIMER_INT); + } while ((t & TIMER_INT_TOS) == 0); + + /* leave the timer disabled */ + SW_WRITE_REG(SWITCH_REG_TIMER, TIMER_PERIOD_DEFAULT); + SW_WRITE_REG(SWITCH_REG_TIMER_INT, (TIMER_INT_TOS | TIMER_INT_TOM)); +} + +void __init adm5120_soc_init(void) +{ + u32 code; + u32 clks; + + code = SW_READ_REG(SWITCH_REG_CODE); + + adm5120_product_code = CODE_GET_PC(code); + adm5120_revision = CODE_GET_REV(code); + adm5120_package = (CODE_GET_PK(code) == CODE_PK_BGA) ? + ADM5120_PACKAGE_BGA : ADM5120_PACKAGE_PQFP; + adm5120_nand_boot = CODE_GET_NAB(code); + + clks = CODE_GET_CLKS(code); + adm5120_speed = ADM5120_SPEED_175; + if (clks & 1) + adm5120_speed += 25000000; + if (clks & 2) + adm5120_speed += 50000000; +} diff --git a/target/linux/adm5120/files-3.18/arch/mips/adm5120/common/clock.c b/target/linux/adm5120/files-3.18/arch/mips/adm5120/common/clock.c new file mode 100644 index 0000000..52ae64c --- /dev/null +++ b/target/linux/adm5120/files-3.18/arch/mips/adm5120/common/clock.c @@ -0,0 +1,65 @@ +/* + * ADM5120 minimal CLK API implementation + * + * Copyright (C) 2007-2008 Gabor Juhos + * + * This file was based on the CLK API implementation in: + * arch/mips/tx4938/toshiba_rbtx4938/setup.c + * Copyright (C) 2000-2001 Toshiba Corporation + * 2003-2005 (c) MontaVista Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include + +#include + +struct clk { + unsigned long rate; +}; + +static struct clk uart_clk = { + .rate = ADM5120_UART_CLOCK +}; + +struct clk *clk_get(struct device *dev, const char *id) +{ + const char *name = dev_name(dev); + + if (!strcmp(name, "apb:uart0") || !strcmp(name, "apb:uart1")) + return &uart_clk; + + return ERR_PTR(-ENOENT); +} +EXPORT_SYMBOL(clk_get); + +int clk_enable(struct clk *clk) +{ + return 0; +} +EXPORT_SYMBOL(clk_enable); + +void clk_disable(struct clk *clk) +{ +} +EXPORT_SYMBOL(clk_disable); + +unsigned long clk_get_rate(struct clk *clk) +{ + return clk->rate; +} +EXPORT_SYMBOL(clk_get_rate); + +void clk_put(struct clk *clk) +{ +} +EXPORT_SYMBOL(clk_put); diff --git a/target/linux/adm5120/files-3.18/arch/mips/adm5120/common/early-printk.c b/target/linux/adm5120/files-3.18/arch/mips/adm5120/common/early-printk.c new file mode 100644 index 0000000..d900712 --- /dev/null +++ b/target/linux/adm5120/files-3.18/arch/mips/adm5120/common/early-printk.c @@ -0,0 +1,31 @@ +/* + * ADM5120 specific early printk support + * + * Copyright (C) 2007-2008 Gabor Juhos + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + */ + +#include +#include + +#include +#include +#include + +#define UART_READ(r) \ + __raw_readl((void __iomem *)(KSEG1ADDR(ADM5120_UART0_BASE)+(r))) +#define UART_WRITE(r, v) \ + __raw_writel((v), (void __iomem *)(KSEG1ADDR(ADM5120_UART0_BASE)+(r))) + +void __init prom_putchar(char ch) +{ + while ((UART_READ(UART_REG_FLAG) & UART_FLAG_TXFE) == 0) + ; + UART_WRITE(UART_REG_DATA, ch); + while ((UART_READ(UART_REG_FLAG) & UART_FLAG_TXFE) == 0) + ; +} diff --git a/target/linux/adm5120/files-3.18/arch/mips/adm5120/common/gpio.c b/target/linux/adm5120/files-3.18/arch/mips/adm5120/common/gpio.c new file mode 100644 index 0000000..461ea15 --- /dev/null +++ b/target/linux/adm5120/files-3.18/arch/mips/adm5120/common/gpio.c @@ -0,0 +1,328 @@ +/* + * ADM5120 generic GPIO API support via GPIOLIB + * + * Copyright (C) 2007-2008 Gabor Juhos + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#define GPIO_REG(r) (void __iomem *)(KSEG1ADDR(ADM5120_SWITCH_BASE) + r) + +struct gpio1_desc { + void __iomem *reg; /* register address */ + u8 iv_shift; /* shift amount for input bit */ + u8 mode_shift; /* shift amount for mode bits */ +}; + +#define GPIO1_DESC(p, l) { \ + .reg = GPIO_REG(SWITCH_REG_PORT0_LED + ((p) * 4)), \ + .iv_shift = LED0_IV_SHIFT + (l), \ + .mode_shift = (l) * 4 \ + } + +static struct gpio1_desc gpio1_table[15] = { + GPIO1_DESC(0, 0), GPIO1_DESC(0, 1), GPIO1_DESC(0, 2), + GPIO1_DESC(1, 0), GPIO1_DESC(1, 1), GPIO1_DESC(1, 2), + GPIO1_DESC(2, 0), GPIO1_DESC(2, 1), GPIO1_DESC(2, 2), + GPIO1_DESC(3, 0), GPIO1_DESC(3, 1), GPIO1_DESC(3, 2), + GPIO1_DESC(4, 0), GPIO1_DESC(4, 1), GPIO1_DESC(4, 2) +}; + +static u32 gpio_conf2; + +int adm5120_gpio_to_irq(unsigned gpio) +{ + int ret; + + switch (gpio) { + case ADM5120_GPIO_PIN2: + ret = ADM5120_IRQ_GPIO2; + break; + case ADM5120_GPIO_PIN4: + ret = ADM5120_IRQ_GPIO4; + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} +EXPORT_SYMBOL(adm5120_gpio_to_irq); + +int adm5120_irq_to_gpio(unsigned irq) +{ + int ret; + + switch (irq) { + case ADM5120_IRQ_GPIO2: + ret = ADM5120_GPIO_PIN2; + break; + case ADM5120_IRQ_GPIO4: + ret = ADM5120_GPIO_PIN4; + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} +EXPORT_SYMBOL(adm5120_irq_to_gpio); + +/* + * Helpers for GPIO lines in GPIO_CONF0 register + */ +#define PIN_IM(p) ((1 << GPIO_CONF0_IM_SHIFT) << p) +#define PIN_IV(p) ((1 << GPIO_CONF0_IV_SHIFT) << p) +#define PIN_OE(p) ((1 << GPIO_CONF0_OE_SHIFT) << p) +#define PIN_OV(p) ((1 << GPIO_CONF0_OV_SHIFT) << p) + +int __adm5120_gpio0_get_value(unsigned offset) +{ + void __iomem **reg; + u32 t; + + reg = GPIO_REG(SWITCH_REG_GPIO_CONF0); + + t = __raw_readl(reg); + if ((t & PIN_IM(offset)) != 0) + t &= PIN_IV(offset); + else + t &= PIN_OV(offset); + + return (t) ? 1 : 0; +} +EXPORT_SYMBOL(__adm5120_gpio0_get_value); + +void __adm5120_gpio0_set_value(unsigned offset, int value) +{ + void __iomem **reg; + u32 t; + + reg = GPIO_REG(SWITCH_REG_GPIO_CONF0); + + t = __raw_readl(reg); + if (value == 0) + t &= ~(PIN_OV(offset)); + else + t |= PIN_OV(offset); + + __raw_writel(t, reg); +} +EXPORT_SYMBOL(__adm5120_gpio0_set_value); + +static int adm5120_gpio0_get_value(struct gpio_chip *chip, unsigned offset) +{ + return __adm5120_gpio0_get_value(offset); +} + +static void adm5120_gpio0_set_value(struct gpio_chip *chip, + unsigned offset, int value) +{ + __adm5120_gpio0_set_value(offset, value); +} + +static int adm5120_gpio0_direction_input(struct gpio_chip *chip, + unsigned offset) +{ + void __iomem **reg; + u32 t; + + reg = GPIO_REG(SWITCH_REG_GPIO_CONF0); + + t = __raw_readl(reg); + t &= ~(PIN_OE(offset)); + t |= PIN_IM(offset); + __raw_writel(t, reg); + + return 0; +} + +static int adm5120_gpio0_direction_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + void __iomem **reg; + u32 t; + + reg = GPIO_REG(SWITCH_REG_GPIO_CONF0); + + t = __raw_readl(reg); + t &= ~(PIN_IM(offset) | PIN_OV(offset)); + t |= PIN_OE(offset); + + if (value) + t |= PIN_OV(offset); + + __raw_writel(t, reg); + + return 0; +} + +static struct gpio_chip adm5120_gpio0_chip = { + .label = "adm5120 gpio0", + .get = adm5120_gpio0_get_value, + .set = adm5120_gpio0_set_value, + .direction_input = adm5120_gpio0_direction_input, + .direction_output = adm5120_gpio0_direction_output, + .base = ADM5120_GPIO_PIN0, + .ngpio = ADM5120_GPIO_PIN7 - ADM5120_GPIO_PIN0 + 1, +}; + +int __adm5120_gpio1_get_value(unsigned offset) +{ + void __iomem **reg; + u32 t, m; + + reg = gpio1_table[offset].reg; + + t = __raw_readl(reg); + m = (t >> gpio1_table[offset].mode_shift) & LED_MODE_MASK; + if (m == LED_MODE_INPUT) + return (t >> gpio1_table[offset].iv_shift) & 1; + + if (m == LED_MODE_OUT_LOW) + return 0; + + return 1; +} +EXPORT_SYMBOL(__adm5120_gpio1_get_value); + +void __adm5120_gpio1_set_value(unsigned offset, int value) +{ + void __iomem **reg; + u32 t, s; + + reg = gpio1_table[offset].reg; + s = gpio1_table[offset].mode_shift; + + t = __raw_readl(reg); + t &= ~(LED_MODE_MASK << s); + + switch (value) { + case ADM5120_GPIO_LOW: + t |= (LED_MODE_OUT_LOW << s); + break; + case ADM5120_GPIO_FLASH: + case ADM5120_GPIO_LINK: + case ADM5120_GPIO_SPEED: + case ADM5120_GPIO_DUPLEX: + case ADM5120_GPIO_ACT: + case ADM5120_GPIO_COLL: + case ADM5120_GPIO_LINK_ACT: + case ADM5120_GPIO_DUPLEX_COLL: + case ADM5120_GPIO_10M_ACT: + case ADM5120_GPIO_100M_ACT: + t |= ((value & LED_MODE_MASK) << s); + break; + default: + t |= (LED_MODE_OUT_HIGH << s); + break; + } + + __raw_writel(t, reg); +} +EXPORT_SYMBOL(__adm5120_gpio1_set_value); + +static int adm5120_gpio1_get_value(struct gpio_chip *chip, unsigned offset) +{ + return __adm5120_gpio1_get_value(offset); +} + +static void adm5120_gpio1_set_value(struct gpio_chip *chip, + unsigned offset, int value) +{ + __adm5120_gpio1_set_value(offset, value); +} + +static int adm5120_gpio1_direction_input(struct gpio_chip *chip, + unsigned offset) +{ + void __iomem **reg; + u32 t; + + reg = gpio1_table[offset].reg; + t = __raw_readl(reg); + t &= ~(LED_MODE_MASK << gpio1_table[offset].mode_shift); + __raw_writel(t, reg); + + return 0; +} + +static int adm5120_gpio1_direction_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + __adm5120_gpio1_set_value(offset, value); + return 0; +} + +static struct gpio_chip adm5120_gpio1_chip = { + .label = "adm5120 gpio1", + .get = adm5120_gpio1_get_value, + .set = adm5120_gpio1_set_value, + .direction_input = adm5120_gpio1_direction_input, + .direction_output = adm5120_gpio1_direction_output, + .base = ADM5120_GPIO_P0L0, + .ngpio = ADM5120_GPIO_P4L2 - ADM5120_GPIO_P0L0 + 1, +}; + +void __init adm5120_gpio_csx0_enable(void) +{ + gpio_conf2 |= GPIO_CONF2_CSX0; + SW_WRITE_REG(SWITCH_REG_GPIO_CONF2, gpio_conf2); + + gpio_request(ADM5120_GPIO_PIN1, "CSX0"); +} + +void __init adm5120_gpio_csx1_enable(void) +{ + gpio_conf2 |= GPIO_CONF2_CSX1; + SW_WRITE_REG(SWITCH_REG_GPIO_CONF2, gpio_conf2); + + gpio_request(ADM5120_GPIO_PIN3, "CSX1"); +} + +void __init adm5120_gpio_ew_enable(void) +{ + gpio_conf2 |= GPIO_CONF2_EW; + SW_WRITE_REG(SWITCH_REG_GPIO_CONF2, gpio_conf2); + + gpio_request(ADM5120_GPIO_PIN0, "EW"); +} + +void __init adm5120_gpio_init(void) +{ + int err; + + SW_WRITE_REG(SWITCH_REG_GPIO_CONF2, gpio_conf2); + + if (adm5120_package_pqfp()) + adm5120_gpio0_chip.ngpio = 4; + + err = gpiochip_add(&adm5120_gpio0_chip); + if (err) + panic("cannot add ADM5120 GPIO0 chip, error=%d", err); + + err = gpiochip_add(&adm5120_gpio1_chip); + if (err) + panic("cannot add ADM5120 GPIO1 chip, error=%d", err); + +} diff --git a/target/linux/adm5120/files-3.18/arch/mips/adm5120/common/irq.c b/target/linux/adm5120/files-3.18/arch/mips/adm5120/common/irq.c new file mode 100644 index 0000000..a26e651 --- /dev/null +++ b/target/linux/adm5120/files-3.18/arch/mips/adm5120/common/irq.c @@ -0,0 +1,171 @@ +/* + * ADM5120 specific interrupt handlers + * + * Copyright (C) 2007-2008 Gabor Juhos + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +static void adm5120_intc_irq_unmask(struct irq_data *d); +static void adm5120_intc_irq_mask(struct irq_data *d); +static int adm5120_intc_irq_set_type(struct irq_data *d, unsigned int flow_type); + +static inline void intc_write_reg(unsigned int reg, u32 val) +{ + void __iomem *base = (void __iomem *)KSEG1ADDR(ADM5120_INTC_BASE); + + __raw_writel(val, base + reg); +} + +static inline u32 intc_read_reg(unsigned int reg) +{ + void __iomem *base = (void __iomem *)KSEG1ADDR(ADM5120_INTC_BASE); + + return __raw_readl(base + reg); +} + +static struct irq_chip adm5120_intc_irq_chip = { + .name = "INTC", + .irq_unmask = adm5120_intc_irq_unmask, + .irq_mask = adm5120_intc_irq_mask, + .irq_mask_ack = adm5120_intc_irq_mask, + .irq_set_type = adm5120_intc_irq_set_type +}; + +static struct irqaction adm5120_intc_irq_action = { + .handler = no_action, + .name = "cascade [INTC]" +}; + +static void adm5120_intc_irq_unmask(struct irq_data *d) +{ + intc_write_reg(INTC_REG_IRQ_ENABLE, 1 << (d->irq - ADM5120_INTC_IRQ_BASE)); +} + +static void adm5120_intc_irq_mask(struct irq_data *d) +{ + intc_write_reg(INTC_REG_IRQ_DISABLE, 1 << (d->irq - ADM5120_INTC_IRQ_BASE)); +} + +static int adm5120_intc_irq_set_type(struct irq_data *d, unsigned int flow_type) +{ + unsigned int irq = d->irq; + unsigned int sense; + unsigned long mode; + int err = 0; + + sense = flow_type & (IRQ_TYPE_SENSE_MASK); + switch (sense) { + case IRQ_TYPE_NONE: + case IRQ_TYPE_LEVEL_HIGH: + break; + case IRQ_TYPE_LEVEL_LOW: + switch (irq) { + case ADM5120_IRQ_GPIO2: + case ADM5120_IRQ_GPIO4: + break; + default: + err = -EINVAL; + break; + } + break; + default: + err = -EINVAL; + break; + } + + if (err) + return err; + + switch (irq) { + case ADM5120_IRQ_GPIO2: + case ADM5120_IRQ_GPIO4: + mode = intc_read_reg(INTC_REG_INT_MODE); + if (sense == IRQ_TYPE_LEVEL_LOW) + mode |= (1 << (irq - ADM5120_INTC_IRQ_BASE)); + else + mode &= ~(1 << (irq - ADM5120_INTC_IRQ_BASE)); + + intc_write_reg(INTC_REG_INT_MODE, mode); + break; + } + + return 0; +} + +static void adm5120_intc_irq_dispatch(void) +{ + unsigned long status; + int irq; + + status = intc_read_reg(INTC_REG_IRQ_STATUS) & INTC_INT_ALL; + if (status) { + irq = ADM5120_INTC_IRQ_BASE + fls(status) - 1; + do_IRQ(irq); + } else + spurious_interrupt(); +} + +asmlinkage void plat_irq_dispatch(void) +{ + unsigned long pending; + + pending = read_c0_status() & read_c0_cause() & ST0_IM; + + if (pending & STATUSF_IP7) + do_IRQ(ADM5120_IRQ_COUNTER); + else if (pending & STATUSF_IP2) + adm5120_intc_irq_dispatch(); + else + spurious_interrupt(); +} + +#define INTC_IRQ_STATUS (IRQ_LEVEL | IRQ_TYPE_LEVEL_HIGH | IRQ_DISABLED) +static void __init adm5120_intc_irq_init(void) +{ + int i; + + /* disable all interrupts */ + intc_write_reg(INTC_REG_IRQ_DISABLE, INTC_INT_ALL); + + /* setup all interrupts to generate IRQ instead of FIQ */ + intc_write_reg(INTC_REG_INT_MODE, 0); + + /* set active level for all external interrupts to HIGH */ + intc_write_reg(INTC_REG_INT_LEVEL, 0); + + /* disable usage of the TEST_SOURCE register */ + intc_write_reg(INTC_REG_IRQ_SOURCE_SELECT, 0); + + for (i = ADM5120_INTC_IRQ_BASE; + i <= ADM5120_INTC_IRQ_BASE + INTC_IRQ_LAST; + i++) { + irq_set_chip_and_handler(i, &adm5120_intc_irq_chip, + handle_level_irq); + } + + setup_irq(ADM5120_IRQ_INTC, &adm5120_intc_irq_action); +} + +void __init arch_init_irq(void) +{ + mips_cpu_irq_init(); + adm5120_intc_irq_init(); +} diff --git a/target/linux/adm5120/files-3.18/arch/mips/adm5120/common/memory.c b/target/linux/adm5120/files-3.18/arch/mips/adm5120/common/memory.c new file mode 100644 index 0000000..d07266f --- /dev/null +++ b/target/linux/adm5120/files-3.18/arch/mips/adm5120/common/memory.c @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2007-2008 Gabor Juhos + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#ifdef DEBUG +# define mem_dbg(f, a...) printk(KERN_INFO "mem_detect: " f, ## a) +#else +# define mem_dbg(f, a...) +#endif + +unsigned long adm5120_memsize; + +#define MEM_READL(a) __raw_readl((void __iomem *)(a)) +#define MEM_WRITEL(a, v) __raw_writel((v), (void __iomem *)(a)) + +static int __init mem_check_pattern(u8 *addr, unsigned long offs) +{ + u32 *p1 = (u32 *)addr; + u32 *p2 = (u32 *)(addr+offs); + u32 t, u, v; + + /* save original value */ + t = MEM_READL(p1); + + u = MEM_READL(p2); + if (t != u) + return 0; + + v = 0x55555555; + if (u == v) + v = 0xAAAAAAAA; + + mem_dbg("write 0x%08X to 0x%08lX\n", v, (unsigned long)p1); + + MEM_WRITEL(p1, v); + adm5120_ndelay(1000); + u = MEM_READL(p2); + + mem_dbg("pattern at 0x%08lX is 0x%08X\n", (unsigned long)p2, u); + + /* restore original value */ + MEM_WRITEL(p1, t); + + return (v == u); +} + +static void __init adm5120_detect_memsize(void) +{ + u32 memctrl; + u32 size, maxsize; + u8 *p; + + memctrl = SW_READ_REG(SWITCH_REG_MEMCTRL); + switch (memctrl & MEMCTRL_SDRS_MASK) { + case MEMCTRL_SDRS_4M: + maxsize = 4 << 20; + break; + case MEMCTRL_SDRS_8M: + maxsize = 8 << 20; + break; + case MEMCTRL_SDRS_16M: + maxsize = 16 << 20; + break; + default: + maxsize = 64 << 20; + break; + } + + mem_dbg("checking for %uMB chip in 1st bank\n", maxsize >> 20); + + /* detect size of the 1st SDRAM bank */ + p = (u8 *)KSEG1ADDR(0); + for (size = 2<<20; size <= (maxsize >> 1); size <<= 1) { + if (mem_check_pattern(p, size)) { + /* mirrored address */ + mem_dbg("mirrored data found at offset 0x%08X\n", size); + break; + } + } + + mem_dbg("chip size in 1st bank is %uMB\n", size >> 20); + adm5120_memsize = size; + + if (size != maxsize) + /* 2nd bank is not supported */ + goto out; + + if ((memctrl & MEMCTRL_SDR1_ENABLE) == 0) + /* 2nd bank is disabled */ + goto out; + + /* + * some bootloaders enable 2nd bank, even if the 2nd SDRAM chip + * are missing. + */ + mem_dbg("check presence of 2nd bank\n"); + + p = (u8 *)KSEG1ADDR(maxsize+size-4); + if (mem_check_pattern(p, 0)) + adm5120_memsize += size; + + if (maxsize != size) { + /* adjusting MECTRL register */ + memctrl &= ~(MEMCTRL_SDRS_MASK); + switch (size>>20) { + case 4: + memctrl |= MEMCTRL_SDRS_4M; + break; + case 8: + memctrl |= MEMCTRL_SDRS_8M; + break; + case 16: + memctrl |= MEMCTRL_SDRS_16M; + break; + default: + memctrl |= MEMCTRL_SDRS_64M; + break; + } + SW_WRITE_REG(SWITCH_REG_MEMCTRL, memctrl); + } + +out: + mem_dbg("%dx%uMB memory found\n", (adm5120_memsize == size) ? 1 : 2 , + size>>20); +} + +void __init adm5120_mem_init(void) +{ + adm5120_detect_memsize(); + add_memory_region(0, adm5120_memsize, BOOT_MEM_RAM); +} diff --git a/target/linux/adm5120/files-3.18/arch/mips/adm5120/common/platform.c b/target/linux/adm5120/files-3.18/arch/mips/adm5120/common/platform.c new file mode 100644 index 0000000..bdbfbcb --- /dev/null +++ b/target/linux/adm5120/files-3.18/arch/mips/adm5120/common/platform.c @@ -0,0 +1,375 @@ +/* + * ADM5120 generic platform devices + * + * Copyright (C) 2007-2008 Gabor Juhos + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#if 1 +/* + * TODO:remove global adm5120_eth* variables when the switch driver will be + * converted into a real platform driver + */ +unsigned int adm5120_eth_num_ports = 6; +EXPORT_SYMBOL_GPL(adm5120_eth_num_ports); + +unsigned char adm5120_eth_macs[6][6] = { + {'\00', 'A', 'D', 'M', '\x51', '\x20' }, + {'\00', 'A', 'D', 'M', '\x51', '\x21' }, + {'\00', 'A', 'D', 'M', '\x51', '\x22' }, + {'\00', 'A', 'D', 'M', '\x51', '\x23' }, + {'\00', 'A', 'D', 'M', '\x51', '\x24' }, + {'\00', 'A', 'D', 'M', '\x51', '\x25' } +}; +EXPORT_SYMBOL_GPL(adm5120_eth_macs); + +unsigned char adm5120_eth_vlans[6] = { + 0x41, 0x42, 0x44, 0x48, 0x50, 0x60 +}; +EXPORT_SYMBOL_GPL(adm5120_eth_vlans); +#endif + +void __init adm5120_setup_eth_macs(u8 *mac_base) +{ + u32 t; + int i, j; + + t = ((u32) mac_base[3] << 16) | ((u32) mac_base[4] << 8) + | ((u32) mac_base[5]); + + for (i = 0; i < ARRAY_SIZE(adm5120_eth_macs); i++) { + for (j = 0; j < 3; j++) + adm5120_eth_macs[i][j] = mac_base[j]; + + adm5120_eth_macs[i][3] = (t >> 16) & 0xff; + adm5120_eth_macs[i][4] = (t >> 8) & 0xff; + adm5120_eth_macs[i][5] = t & 0xff; + + t++; + } +} + +/* + * Built-in ethernet switch + */ +struct resource adm5120_switch_resources[] = { + [0] = { + .start = ADM5120_SWITCH_BASE, + .end = ADM5120_SWITCH_BASE+ADM5120_SWITCH_SIZE-1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = ADM5120_IRQ_SWITCH, + .end = ADM5120_IRQ_SWITCH, + .flags = IORESOURCE_IRQ, + }, +}; + +struct adm5120_switch_platform_data adm5120_switch_data; +struct platform_device adm5120_switch_device = { + .name = "adm5120-switch", + .id = -1, + .num_resources = ARRAY_SIZE(adm5120_switch_resources), + .resource = adm5120_switch_resources, + .dev.platform_data = &adm5120_switch_data, +}; + +void __init adm5120_add_device_switch(unsigned num_ports, u8 *vlan_map) +{ + if (num_ports > 0) + adm5120_eth_num_ports = num_ports; + + if (vlan_map) + memcpy(adm5120_eth_vlans, vlan_map, sizeof(adm5120_eth_vlans)); + + platform_device_register(&adm5120_switch_device); +} + +/* + * USB Host Controller + */ +struct resource adm5120_hcd_resources[] = { + [0] = { + .start = ADM5120_USBC_BASE, + .end = ADM5120_USBC_BASE+ADM5120_USBC_SIZE-1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = ADM5120_IRQ_USBC, + .end = ADM5120_IRQ_USBC, + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 adm5120_hcd_dma_mask = DMA_BIT_MASK(24); +struct platform_device adm5120_hcd_device = { + .name = "adm5120-hcd", + .id = -1, + .num_resources = ARRAY_SIZE(adm5120_hcd_resources), + .resource = adm5120_hcd_resources, + .dev = { + .dma_mask = &adm5120_hcd_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(24), + } +}; + +void __init adm5120_add_device_usb(void) +{ + platform_device_register(&adm5120_hcd_device); +} + +/* + * NOR flash devices + */ +struct adm5120_flash_platform_data adm5120_flash0_data; +struct platform_device adm5120_flash0_device = { + .name = "adm5120-flash", + .id = 0, + .dev.platform_data = &adm5120_flash0_data, +}; + +struct adm5120_flash_platform_data adm5120_flash1_data; +struct platform_device adm5120_flash1_device = { + .name = "adm5120-flash", + .id = 1, + .dev.platform_data = &adm5120_flash1_data, +}; + +void __init adm5120_add_device_flash(unsigned id) +{ + struct platform_device *pdev; + + switch (id) { + case 0: + pdev = &adm5120_flash0_device; + break; + case 1: + pdev = &adm5120_flash1_device; + break; + default: + pdev = NULL; + break; + } + + if (pdev) + platform_device_register(pdev); +} + +/* + * built-in UARTs + */ +static void adm5120_uart_set_mctrl(struct amba_device *dev, void __iomem *base, + unsigned int mctrl) +{ +} + +struct amba_pl010_data adm5120_uart0_data = { + .set_mctrl = adm5120_uart_set_mctrl +}; + +struct amba_device adm5120_uart0_device = { + .dev = { + .init_name = "apb:uart0", + .platform_data = &adm5120_uart0_data, + }, + .res = { + .start = ADM5120_UART0_BASE, + .end = ADM5120_UART0_BASE + ADM5120_UART_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + .irq = { ADM5120_IRQ_UART0, 0 }, + .periphid = 0x0041010, +}; + +struct amba_pl010_data adm5120_uart1_data = { + .set_mctrl = adm5120_uart_set_mctrl +}; + +struct amba_device adm5120_uart1_device = { + .dev = { + .init_name = "apb:uart1", + .platform_data = &adm5120_uart1_data, + }, + .res = { + .start = ADM5120_UART1_BASE, + .end = ADM5120_UART1_BASE + ADM5120_UART_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + .irq = { ADM5120_IRQ_UART1, 0 }, + .periphid = 0x0041010, +}; + +void __init adm5120_add_device_uart(unsigned id) +{ + struct amba_device *dev; + + switch (id) { + case 0: + dev = &adm5120_uart0_device; + break; + case 1: + dev = &adm5120_uart1_device; + break; + default: + dev = NULL; + break; + } + + if (dev) + amba_device_register(dev, &iomem_resource); +} + +/* + * GPIO buttons + */ +void __init adm5120_register_gpio_buttons(int id, + unsigned poll_interval, + unsigned nbuttons, + struct gpio_keys_button *buttons) +{ + struct platform_device *pdev; + struct gpio_keys_platform_data pdata; + struct gpio_keys_button *p; + int err; + + p = kmemdup(buttons, nbuttons * sizeof(*p), GFP_KERNEL); + if (!p) + return; + + pdev = platform_device_alloc("gpio-keys-polled", id); + if (!pdev) + goto err_free_buttons; + + memset(&pdata, 0, sizeof(pdata)); + pdata.poll_interval = poll_interval; + pdata.nbuttons = nbuttons; + pdata.buttons = p; + + err = platform_device_add_data(pdev, &pdata, sizeof(pdata)); + if (err) + goto err_put_pdev; + + err = platform_device_add(pdev); + if (err) + goto err_put_pdev; + + return; + +err_put_pdev: + platform_device_put(pdev); + +err_free_buttons: + kfree(p); +} + +/* + * GPIO LEDS + */ +struct gpio_led_platform_data adm5120_gpio_leds_data; +struct platform_device adm5120_gpio_leds_device = { + .name = "leds-gpio", + .id = -1, + .dev.platform_data = &adm5120_gpio_leds_data, +}; + +void __init adm5120_add_device_gpio_leds(unsigned num_leds, + struct gpio_led *leds) +{ + struct gpio_led *p; + + p = kmalloc(num_leds * sizeof(*p), GFP_KERNEL); + if (!p) + return; + + memcpy(p, leds, num_leds * sizeof(*p)); + adm5120_gpio_leds_data.num_leds = num_leds; + adm5120_gpio_leds_data.leds = p; + + platform_device_register(&adm5120_gpio_leds_device); +} + +/* + * NAND flash + */ +struct resource adm5120_nand_resources[] = { + [0] = { + .start = ADM5120_NAND_BASE, + .end = ADM5120_NAND_BASE + ADM5120_NAND_SIZE-1, + .flags = IORESOURCE_MEM, + }, +}; + +static int adm5120_nand_ready(struct mtd_info *mtd) +{ + return ((adm5120_nand_get_status() & ADM5120_NAND_STATUS_READY) != 0); +} + +static void adm5120_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, + unsigned int ctrl) +{ + if (ctrl & NAND_CTRL_CHANGE) { + adm5120_nand_set_cle(ctrl & NAND_CLE); + adm5120_nand_set_ale(ctrl & NAND_ALE); + adm5120_nand_set_cen(ctrl & NAND_NCE); + } + + if (cmd != NAND_CMD_NONE) + NAND_WRITE_REG(NAND_REG_DATA, cmd); +} + +void __init adm5120_add_device_nand(struct platform_nand_data *pdata) +{ + struct platform_device *pdev; + int err; + + pdev = platform_device_alloc("gen_nand", -1); + if (!pdev) + goto err_out; + + err = platform_device_add_resources(pdev, adm5120_nand_resources, + ARRAY_SIZE(adm5120_nand_resources)); + if (err) + goto err_put; + + err = platform_device_add_data(pdev, pdata, sizeof(*pdata)); + if (err) + goto err_put; + + pdata = pdev->dev.platform_data; + pdata->ctrl.dev_ready = adm5120_nand_ready; + pdata->ctrl.cmd_ctrl = adm5120_nand_cmd_ctrl; + + err = platform_device_add(pdev); + if (err) + goto err_put; + + return; + +err_put: + platform_device_put(pdev); +err_out: + return; +} diff --git a/target/linux/adm5120/files-3.18/arch/mips/adm5120/common/prom.c b/target/linux/adm5120/files-3.18/arch/mips/adm5120/common/prom.c new file mode 100644 index 0000000..5c52ea2 --- /dev/null +++ b/target/linux/adm5120/files-3.18/arch/mips/adm5120/common/prom.c @@ -0,0 +1,264 @@ +/* + * ADM5120 specific prom routines + * + * Copyright (C) 2007-2008 Gabor Juhos + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + */ + +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include + +unsigned int adm5120_prom_type = ADM5120_PROM_GENERIC; + +struct board_desc { + unsigned long mach_type; + char *name; +}; + +#define DEFBOARD(n, mt) { .mach_type = (mt), .name = (n)} +static struct board_desc common_boards[] __initdata = { + /* Cellvision/SparkLAN boards */ + DEFBOARD("CAS-630", MACH_ADM5120_CAS630), + DEFBOARD("CAS-670", MACH_ADM5120_CAS670), + DEFBOARD("CAS-700", MACH_ADM5120_CAS700), + DEFBOARD("CAS-771", MACH_ADM5120_CAS771), + DEFBOARD("CAS-790", MACH_ADM5120_CAS790), + DEFBOARD("CAS-861", MACH_ADM5120_CAS861), + DEFBOARD("NFS-101U", MACH_ADM5120_NFS101U), + /* Compex boards */ + DEFBOARD("WP54G-WRT", MACH_ADM5120_WP54G_WRT), + /* Edimax boards */ + DEFBOARD("BR-6104K", MACH_ADM5120_BR6104K), + DEFBOARD("BR-6104KP", MACH_ADM5120_BR6104KP), + DEFBOARD("BR-6104WG", MACH_ADM5120_BR61X4WG), + DEFBOARD("BR-6114WG", MACH_ADM5120_BR61X4WG), + /* Infineon boards */ + DEFBOARD("EASY 5120P-ATA", MACH_ADM5120_EASY5120PATA), + DEFBOARD("EASY 5120-RT", MACH_ADM5120_EASY5120RT), + DEFBOARD("EASY 5120-WVoIP", MACH_ADM5120_EASY5120WVOIP), + DEFBOARD("EASY 83000", MACH_ADM5120_EASY83000), + /* Mikrotik RouterBOARDs */ + DEFBOARD("111", MACH_ADM5120_RB_11X), + DEFBOARD("112", MACH_ADM5120_RB_11X), + DEFBOARD("133", MACH_ADM5120_RB_133), + DEFBOARD("133C", MACH_ADM5120_RB_133C), + DEFBOARD("133C3", MACH_ADM5120_RB_133C), + DEFBOARD("150", MACH_ADM5120_RB_153), /* it's intentional */ + DEFBOARD("153", MACH_ADM5120_RB_153), + DEFBOARD("192", MACH_ADM5120_RB_192), + DEFBOARD("miniROUTER", MACH_ADM5120_RB_150), + /* OSBRiDGE boards */ + DEFBOARD("OSBRiDGE 5GXi", MACH_ADM5120_5GXI), + /* Motorola boards */ + DEFBOARD("Powerline MU Gateway", MACH_ADM5120_PMUGW), + /* Generic EB-214A */ + DEFBOARD("ADM5120", MACH_ADM5120_EB_214A), +}; + +static unsigned long __init find_machtype_byname(char *name) +{ + unsigned long ret; + int i; + + ret = MACH_ADM5120_GENERIC; + if (name == NULL) + goto out; + + if (*name == '\0') + goto out; + + for (i = 0; i < ARRAY_SIZE(common_boards); i++) { + if (strcmp(common_boards[i].name, name) == 0) { + ret = common_boards[i].mach_type; + break; + } + } + +out: + return ret; +} + +static unsigned long __init detect_machtype_routerboot(void) +{ + char *name; + + name = routerboot_get_boardname(); + return find_machtype_byname(name); +} + +static unsigned long __init detect_machtype_generic(void) +{ + char *name; + + name = generic_prom_getenv("board_name"); + return find_machtype_byname(name); +} + +unsigned long __init detect_machtype_cfe(void) +{ + char *name; + + name = cfe_getenv("BOARD_NAME"); + return find_machtype_byname(name); +} + +static struct { + unsigned long mach_type; + u16 vendor_id; + u16 board_id; +} zynos_boards[] __initdata = { +#define ZYNOS_BOARD(vi, bi, mt) \ + {.vendor_id = (vi), .board_id = (bi), .mach_type = (mt)} + +#define ZYXEL_BOARD(bi, mt) ZYNOS_BOARD(ZYNOS_VENDOR_ID_ZYXEL, bi, mt) +#define DLINK_BOARD(bi, mt) ZYNOS_BOARD(ZYNOS_VENDOR_ID_DLINK, bi, mt) +#define LUCENT_BOARD(bi, mt) ZYNOS_BOARD(ZYNOS_VENDOR_ID_LUCENT, bi, mt) + ZYXEL_BOARD(ZYNOS_BOARD_HS100, MACH_ADM5120_HS100), + ZYXEL_BOARD(ZYNOS_BOARD_P334U, MACH_ADM5120_P334U), + ZYXEL_BOARD(ZYNOS_BOARD_P334W, MACH_ADM5120_P334W), + ZYXEL_BOARD(ZYNOS_BOARD_P334WH, MACH_ADM5120_P334WH), + ZYXEL_BOARD(ZYNOS_BOARD_P334WHD, MACH_ADM5120_P334WHD), + ZYXEL_BOARD(ZYNOS_BOARD_P334WT, MACH_ADM5120_P334WT), + ZYXEL_BOARD(ZYNOS_BOARD_P334WT_ALT, MACH_ADM5120_P334WT), + ZYXEL_BOARD(ZYNOS_BOARD_P335, MACH_ADM5120_P335), + ZYXEL_BOARD(ZYNOS_BOARD_P335PLUS, MACH_ADM5120_P335PLUS), + ZYXEL_BOARD(ZYNOS_BOARD_P335U, MACH_ADM5120_P335U) +}; + +static unsigned long __init detect_machtype_bootbase(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(zynos_boards); i++) { + if (zynos_boards[i].vendor_id == bootbase_info.vendor_id && + zynos_boards[i].board_id == bootbase_info.board_id) { + return zynos_boards[i].mach_type; + break; + } + } + + printk(KERN_WARNING "Unknown ZyXEL model (%u)\n", + bootbase_info.board_id); + return MACH_ADM5120_GENERIC; +} + +static struct { + unsigned long mach_type; + u16 vid; + u16 did; + u16 svid; + u16 sdid; +} mylo_boards[] __initdata = { +#define MYLO_BOARD(v, d, sv, sd, mt) \ + {.vid = (v), .did = (d), .svid = (sv), .sdid = (sd), .mach_type = (mt)} +#define COMPEX_BOARD(d, mt) \ + MYLO_BOARD(VENID_COMPEX, (d), VENID_COMPEX, (d), (mt)) + + COMPEX_BOARD(DEVID_COMPEX_NP27G, MACH_ADM5120_NP27G), + COMPEX_BOARD(DEVID_COMPEX_NP28G, MACH_ADM5120_NP28G), + COMPEX_BOARD(DEVID_COMPEX_NP28GHS, MACH_ADM5120_NP28GHS), + COMPEX_BOARD(DEVID_COMPEX_WP54G, MACH_ADM5120_WP54), + COMPEX_BOARD(DEVID_COMPEX_WP54Gv1C, MACH_ADM5120_WP54Gv1C), + COMPEX_BOARD(DEVID_COMPEX_WP54AG, MACH_ADM5120_WP54), + COMPEX_BOARD(DEVID_COMPEX_WPP54G, MACH_ADM5120_WP54), + COMPEX_BOARD(DEVID_COMPEX_WPP54AG, MACH_ADM5120_WP54), +}; + +static unsigned long __init detect_machtype_myloader(void) +{ + unsigned long ret; + int i; + + ret = MACH_ADM5120_GENERIC; + for (i = 0; i < ARRAY_SIZE(mylo_boards); i++) { + if (mylo_boards[i].vid == myloader_info.vid && + mylo_boards[i].did == myloader_info.did && + mylo_boards[i].svid == myloader_info.svid && + mylo_boards[i].sdid == myloader_info.sdid) { + ret = mylo_boards[i].mach_type; + break; + } + } + + return ret; +} + +static void __init prom_detect_machtype(void) +{ + if (bootbase_present()) { + adm5120_prom_type = ADM5120_PROM_BOOTBASE; + mips_machtype = detect_machtype_bootbase(); + return; + } + + if (cfe_present()) { + adm5120_prom_type = ADM5120_PROM_CFE; + mips_machtype = detect_machtype_cfe(); + return; + } + + if (myloader_present()) { + adm5120_prom_type = ADM5120_PROM_MYLOADER; + mips_machtype = detect_machtype_myloader(); + return; + } + + if (routerboot_present()) { + adm5120_prom_type = ADM5120_PROM_ROUTERBOOT; + mips_machtype = detect_machtype_routerboot(); + return; + } + + if (generic_prom_present()) { + adm5120_prom_type = ADM5120_PROM_GENERIC; + mips_machtype = detect_machtype_generic(); + return; + } + + mips_machtype = MACH_ADM5120_GENERIC; +} + +#ifdef CONFIG_IMAGE_CMDLINE_HACK +extern char __image_cmdline[]; + +static void __init prom_init_cmdline(void) +{ + char *cmd; + + /* init command line, register a default kernel command line */ + cmd = __image_cmdline; + if (strlen(cmd) > 0) + strlcpy(arcs_cmdline, cmd, sizeof(arcs_cmdline)); + +} +#else +static inline void prom_init_cmdline(void) {} +#endif /* CONFIG_IMAGE_CMDLINE_HACK */ + +void __init prom_init(void) +{ + prom_detect_machtype(); + prom_init_cmdline(); +} + +void __init prom_free_prom_memory(void) +{ + /* We do not have to prom memory to free */ +} diff --git a/target/linux/adm5120/files-3.18/arch/mips/adm5120/common/setup.c b/target/linux/adm5120/files-3.18/arch/mips/adm5120/common/setup.c new file mode 100644 index 0000000..c0410af --- /dev/null +++ b/target/linux/adm5120/files-3.18/arch/mips/adm5120/common/setup.c @@ -0,0 +1,129 @@ +/* + * ADM5120 specific setup + * + * Copyright (C) 2007-2009 Gabor Juhos + * + * This code was based on the ADM5120 specific port of the Linux 2.6.10 kernel + * done by Jeroen Vreeken + * Copyright (C) 2005 Jeroen Vreeken (pe1rxq@amsat.org) + * + * Jeroen's code was based on the Linux 2.4.xx source codes found in various + * tarballs released by Edimax for it's ADM5120 based devices + * Copyright (C) ADMtek Incorporated + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define ADM5120_SYS_TYPE_LEN 64 + +unsigned char adm5120_sys_type[ADM5120_SYS_TYPE_LEN]; +void (*adm5120_board_reset)(void); + +static char *prom_names[ADM5120_PROM_LAST+1] __initdata = { + [ADM5120_PROM_GENERIC] = "Generic", + [ADM5120_PROM_CFE] = "CFE", + [ADM5120_PROM_UBOOT] = "U-Boot", + [ADM5120_PROM_MYLOADER] = "MyLoader", + [ADM5120_PROM_ROUTERBOOT] = "RouterBOOT", + [ADM5120_PROM_BOOTBASE] = "Bootbase" +}; + +static void __init adm5120_report(void) +{ + printk(KERN_INFO "SoC : %s\n", adm5120_sys_type); + printk(KERN_INFO "Bootdev : %s flash\n", + adm5120_nand_boot ? "NAND" : "NOR"); + printk(KERN_INFO "Prom : %s\n", prom_names[adm5120_prom_type]); +} + +const char *get_system_type(void) +{ + return adm5120_sys_type; +} + +static void adm5120_restart(char *command) +{ + /* TODO: stop switch before reset */ + + if (adm5120_board_reset) + adm5120_board_reset(); + + SW_WRITE_REG(SWITCH_REG_SOFT_RESET, 1); +} + +static void adm5120_halt(void) +{ + local_irq_disable(); + + while (1) { + if (cpu_wait) + cpu_wait(); + } +} + +void __init plat_time_init(void) +{ + mips_hpt_frequency = adm5120_speed / 2; +} + +void __init plat_mem_setup(void) +{ + adm5120_soc_init(); + adm5120_mem_init(); + + sprintf(adm5120_sys_type, "ADM%04X%s rev %u, running at %lu.%03lu MHz", + adm5120_product_code, + adm5120_package_bga() ? "" : "P", + adm5120_revision, + (adm5120_speed / 1000000), (adm5120_speed / 1000) % 1000); + + adm5120_report(); + + _machine_restart = adm5120_restart; + _machine_halt = adm5120_halt; + pm_power_off = adm5120_halt; + + set_io_port_base(KSEG1); +} + +static int __init adm5120_board_setup(void) +{ + adm5120_gpio_init(); + + mips_machine_setup(); + + return 0; +} +arch_initcall(adm5120_board_setup); + +static void __init adm5120_generic_board_setup(void) +{ + adm5120_add_device_uart(0); + adm5120_add_device_uart(1); + + adm5120_add_device_flash(0); + adm5120_add_device_switch(6, NULL); +} + +MIPS_MACHINE(MACH_ADM5120_GENERIC, "Generic", "Generic ADM5120 board", + adm5120_generic_board_setup); -- cgit v1.2.3