diff options
author | André Fabian Silva Delgado <emulatorman@parabola.nu> | 2015-08-05 17:04:01 -0300 |
---|---|---|
committer | André Fabian Silva Delgado <emulatorman@parabola.nu> | 2015-08-05 17:04:01 -0300 |
commit | 57f0f512b273f60d52568b8c6b77e17f5636edc0 (patch) | |
tree | 5e910f0e82173f4ef4f51111366a3f1299037a7b /arch/mips/ralink |
Initial import
Diffstat (limited to 'arch/mips/ralink')
-rw-r--r-- | arch/mips/ralink/Kconfig | 70 | ||||
-rw-r--r-- | arch/mips/ralink/Makefile | 22 | ||||
-rw-r--r-- | arch/mips/ralink/Platform | 29 | ||||
-rw-r--r-- | arch/mips/ralink/bootrom.c | 48 | ||||
-rw-r--r-- | arch/mips/ralink/cevt-rt3352.c | 145 | ||||
-rw-r--r-- | arch/mips/ralink/clk.c | 79 | ||||
-rw-r--r-- | arch/mips/ralink/common.h | 36 | ||||
-rw-r--r-- | arch/mips/ralink/early_printk.c | 63 | ||||
-rw-r--r-- | arch/mips/ralink/ill_acc.c | 87 | ||||
-rw-r--r-- | arch/mips/ralink/irq.c | 206 | ||||
-rw-r--r-- | arch/mips/ralink/mt7620.c | 548 | ||||
-rw-r--r-- | arch/mips/ralink/of.c | 101 | ||||
-rw-r--r-- | arch/mips/ralink/prom.c | 70 | ||||
-rw-r--r-- | arch/mips/ralink/reset.c | 106 | ||||
-rw-r--r-- | arch/mips/ralink/rt288x.c | 122 | ||||
-rw-r--r-- | arch/mips/ralink/rt305x.c | 283 | ||||
-rw-r--r-- | arch/mips/ralink/rt3883.c | 156 | ||||
-rw-r--r-- | arch/mips/ralink/timer.c | 184 |
18 files changed, 2355 insertions, 0 deletions
diff --git a/arch/mips/ralink/Kconfig b/arch/mips/ralink/Kconfig new file mode 100644 index 000000000..e9bc8c961 --- /dev/null +++ b/arch/mips/ralink/Kconfig @@ -0,0 +1,70 @@ +if RALINK + +config CLKEVT_RT3352 + bool + depends on SOC_RT305X || SOC_MT7620 + default y + select CLKSRC_OF + select CLKSRC_MMIO + +config RALINK_ILL_ACC + bool + depends on SOC_RT305X + default y + +choice + prompt "Ralink SoC selection" + default SOC_RT305X + help + Select Ralink MIPS SoC type. + + config SOC_RT288X + bool "RT288x" + select MIPS_L1_CACHE_SHIFT_4 + select HW_HAS_PCI + + config SOC_RT305X + bool "RT305x" + select USB_ARCH_HAS_HCD + + config SOC_RT3883 + bool "RT3883" + select HW_HAS_PCI + + config SOC_MT7620 + bool "MT7620/8" + +endchoice + +choice + prompt "Devicetree selection" + default DTB_RT_NONE + help + Select the devicetree. + + config DTB_RT_NONE + bool "None" + + config DTB_RT2880_EVAL + bool "RT2880 eval kit" + depends on SOC_RT288X + select BUILTIN_DTB + + config DTB_RT305X_EVAL + bool "RT305x eval kit" + depends on SOC_RT305X + select BUILTIN_DTB + + config DTB_RT3883_EVAL + bool "RT3883 eval kit" + depends on SOC_RT3883 + select BUILTIN_DTB + + config DTB_MT7620A_EVAL + bool "MT7620A eval kit" + depends on SOC_MT7620 + select BUILTIN_DTB + +endchoice + +endif diff --git a/arch/mips/ralink/Makefile b/arch/mips/ralink/Makefile new file mode 100644 index 000000000..a6c9d0061 --- /dev/null +++ b/arch/mips/ralink/Makefile @@ -0,0 +1,22 @@ +# 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.# +# Makefile for the Ralink common stuff +# +# Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org> +# Copyright (C) 2013 John Crispin <blogic@openwrt.org> + +obj-y := prom.o of.o reset.o clk.o irq.o timer.o + +obj-$(CONFIG_CLKEVT_RT3352) += cevt-rt3352.o + +obj-$(CONFIG_RALINK_ILL_ACC) += ill_acc.o + +obj-$(CONFIG_SOC_RT288X) += rt288x.o +obj-$(CONFIG_SOC_RT305X) += rt305x.o +obj-$(CONFIG_SOC_RT3883) += rt3883.o +obj-$(CONFIG_SOC_MT7620) += mt7620.o + +obj-$(CONFIG_EARLY_PRINTK) += early_printk.o + +obj-$(CONFIG_DEBUG_FS) += bootrom.o diff --git a/arch/mips/ralink/Platform b/arch/mips/ralink/Platform new file mode 100644 index 000000000..6d9c8c499 --- /dev/null +++ b/arch/mips/ralink/Platform @@ -0,0 +1,29 @@ +# +# Ralink SoC common stuff +# +core-$(CONFIG_RALINK) += arch/mips/ralink/ +cflags-$(CONFIG_RALINK) += -I$(srctree)/arch/mips/include/asm/mach-ralink + +# +# Ralink RT288x +# +load-$(CONFIG_SOC_RT288X) += 0xffffffff88000000 +cflags-$(CONFIG_SOC_RT288X) += -I$(srctree)/arch/mips/include/asm/mach-ralink/rt288x + +# +# Ralink RT305x +# +load-$(CONFIG_SOC_RT305X) += 0xffffffff80000000 +cflags-$(CONFIG_SOC_RT305X) += -I$(srctree)/arch/mips/include/asm/mach-ralink/rt305x + +# +# Ralink RT3883 +# +load-$(CONFIG_SOC_RT3883) += 0xffffffff80000000 +cflags-$(CONFIG_SOC_RT3883) += -I$(srctree)/arch/mips/include/asm/mach-ralink/rt3883 + +# +# Ralink MT7620 +# +load-$(CONFIG_SOC_MT7620) += 0xffffffff80000000 +cflags-$(CONFIG_SOC_MT7620) += -I$(srctree)/arch/mips/include/asm/mach-ralink/mt7620 diff --git a/arch/mips/ralink/bootrom.c b/arch/mips/ralink/bootrom.c new file mode 100644 index 000000000..540346839 --- /dev/null +++ b/arch/mips/ralink/bootrom.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) 2013 John Crispin <blogic@openwrt.org> + */ + +#include <linux/debugfs.h> +#include <linux/seq_file.h> + +#define BOOTROM_OFFSET 0x10118000 +#define BOOTROM_SIZE 0x8000 + +static void __iomem *membase = (void __iomem *) KSEG1ADDR(BOOTROM_OFFSET); + +static int bootrom_show(struct seq_file *s, void *unused) +{ + seq_write(s, membase, BOOTROM_SIZE); + + return 0; +} + +static int bootrom_open(struct inode *inode, struct file *file) +{ + return single_open(file, bootrom_show, NULL); +} + +static const struct file_operations bootrom_file_ops = { + .open = bootrom_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int bootrom_setup(void) +{ + if (!debugfs_create_file("bootrom", 0444, + NULL, NULL, &bootrom_file_ops)) { + pr_err("Failed to create bootrom debugfs file\n"); + + return -EINVAL; + } + + return 0; +} + +postcore_initcall(bootrom_setup); diff --git a/arch/mips/ralink/cevt-rt3352.c b/arch/mips/ralink/cevt-rt3352.c new file mode 100644 index 000000000..24bf057a3 --- /dev/null +++ b/arch/mips/ralink/cevt-rt3352.c @@ -0,0 +1,145 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2013 by John Crispin <blogic@openwrt.org> + */ + +#include <linux/clockchips.h> +#include <linux/clocksource.h> +#include <linux/interrupt.h> +#include <linux/reset.h> +#include <linux/init.h> +#include <linux/time.h> +#include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/of_address.h> + +#include <asm/mach-ralink/ralink_regs.h> + +#define SYSTICK_FREQ (50 * 1000) + +#define SYSTICK_CONFIG 0x00 +#define SYSTICK_COMPARE 0x04 +#define SYSTICK_COUNT 0x08 + +/* route systick irq to mips irq 7 instead of the r4k-timer */ +#define CFG_EXT_STK_EN 0x2 +/* enable the counter */ +#define CFG_CNT_EN 0x1 + +struct systick_device { + void __iomem *membase; + struct clock_event_device dev; + int irq_requested; + int freq_scale; +}; + +static void systick_set_clock_mode(enum clock_event_mode mode, + struct clock_event_device *evt); + +static int systick_next_event(unsigned long delta, + struct clock_event_device *evt) +{ + struct systick_device *sdev; + u32 count; + + sdev = container_of(evt, struct systick_device, dev); + count = ioread32(sdev->membase + SYSTICK_COUNT); + count = (count + delta) % SYSTICK_FREQ; + iowrite32(count + delta, sdev->membase + SYSTICK_COMPARE); + + return 0; +} + +static void systick_event_handler(struct clock_event_device *dev) +{ + /* noting to do here */ +} + +static irqreturn_t systick_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *dev = (struct clock_event_device *) dev_id; + + dev->event_handler(dev); + + return IRQ_HANDLED; +} + +static struct systick_device systick = { + .dev = { + /* + * cevt-r4k uses 300, make sure systick + * gets used if available + */ + .rating = 310, + .features = CLOCK_EVT_FEAT_ONESHOT, + .set_next_event = systick_next_event, + .set_mode = systick_set_clock_mode, + .event_handler = systick_event_handler, + }, +}; + +static struct irqaction systick_irqaction = { + .handler = systick_interrupt, + .flags = IRQF_PERCPU | IRQF_TIMER, + .dev_id = &systick.dev, +}; + +static void systick_set_clock_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + struct systick_device *sdev; + + sdev = container_of(evt, struct systick_device, dev); + + switch (mode) { + case CLOCK_EVT_MODE_ONESHOT: + if (!sdev->irq_requested) + setup_irq(systick.dev.irq, &systick_irqaction); + sdev->irq_requested = 1; + iowrite32(CFG_EXT_STK_EN | CFG_CNT_EN, + systick.membase + SYSTICK_CONFIG); + break; + + case CLOCK_EVT_MODE_SHUTDOWN: + if (sdev->irq_requested) + free_irq(systick.dev.irq, &systick_irqaction); + sdev->irq_requested = 0; + iowrite32(0, systick.membase + SYSTICK_CONFIG); + break; + + default: + pr_err("%s: Unhandeled mips clock_mode\n", systick.dev.name); + break; + } +} + +static void __init ralink_systick_init(struct device_node *np) +{ + systick.membase = of_iomap(np, 0); + if (!systick.membase) + return; + + systick_irqaction.name = np->name; + systick.dev.name = np->name; + clockevents_calc_mult_shift(&systick.dev, SYSTICK_FREQ, 60); + systick.dev.max_delta_ns = clockevent_delta2ns(0x7fff, &systick.dev); + systick.dev.min_delta_ns = clockevent_delta2ns(0x3, &systick.dev); + systick.dev.irq = irq_of_parse_and_map(np, 0); + if (!systick.dev.irq) { + pr_err("%s: request_irq failed", np->name); + return; + } + + clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name, + SYSTICK_FREQ, 301, 16, clocksource_mmio_readl_up); + + clockevents_register_device(&systick.dev); + + pr_info("%s: running - mult: %d, shift: %d\n", + np->name, systick.dev.mult, systick.dev.shift); +} + +CLOCKSOURCE_OF_DECLARE(systick, "ralink,cevt-systick", ralink_systick_init); diff --git a/arch/mips/ralink/clk.c b/arch/mips/ralink/clk.c new file mode 100644 index 000000000..feb5a9bf9 --- /dev/null +++ b/arch/mips/ralink/clk.c @@ -0,0 +1,79 @@ +/* + * 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 Gabor Juhos <juhosg@openwrt.org> + * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/clkdev.h> +#include <linux/clk.h> + +#include <asm/time.h> + +#include "common.h" + +struct clk { + struct clk_lookup cl; + unsigned long rate; +}; + +void ralink_clk_add(const char *dev, unsigned long rate) +{ + struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL); + + if (!clk) + panic("failed to add clock"); + + clk->cl.dev_id = dev; + clk->cl.clk = clk; + + clk->rate = rate; + + clkdev_add(&clk->cl); +} + +/* + * Linux clock API + */ +int clk_enable(struct clk *clk) +{ + return 0; +} +EXPORT_SYMBOL_GPL(clk_enable); + +void clk_disable(struct clk *clk) +{ +} +EXPORT_SYMBOL_GPL(clk_disable); + +unsigned long clk_get_rate(struct clk *clk) +{ + return clk->rate; +} +EXPORT_SYMBOL_GPL(clk_get_rate); + +int clk_set_rate(struct clk *clk, unsigned long rate) +{ + return -1; +} +EXPORT_SYMBOL_GPL(clk_set_rate); + +void __init plat_time_init(void) +{ + struct clk *clk; + + ralink_of_remap(); + + ralink_clk_init(); + clk = clk_get_sys("cpu", NULL); + if (IS_ERR(clk)) + panic("unable to get CPU clock, err=%ld", PTR_ERR(clk)); + pr_info("CPU Clock: %ldMHz\n", clk_get_rate(clk) / 1000000); + mips_hpt_frequency = clk_get_rate(clk) / 2; + clk_put(clk); + clocksource_of_init(); +} diff --git a/arch/mips/ralink/common.h b/arch/mips/ralink/common.h new file mode 100644 index 000000000..8e7d8e618 --- /dev/null +++ b/arch/mips/ralink/common.h @@ -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) 2013 John Crispin <blogic@openwrt.org> + */ + +#ifndef _RALINK_COMMON_H__ +#define _RALINK_COMMON_H__ + +#define RAMIPS_SYS_TYPE_LEN 32 + +struct ralink_soc_info { + unsigned char sys_type[RAMIPS_SYS_TYPE_LEN]; + unsigned char *compatible; + + unsigned long mem_base; + unsigned long mem_size; + unsigned long mem_size_min; + unsigned long mem_size_max; +}; +extern struct ralink_soc_info soc_info; + +extern void ralink_of_remap(void); + +extern void ralink_clk_init(void); +extern void ralink_clk_add(const char *dev, unsigned long rate); + +extern void ralink_rst_init(void); + +extern void prom_soc_init(struct ralink_soc_info *soc_info); + +__iomem void *plat_of_remap_node(const char *node); + +#endif /* _RALINK_COMMON_H__ */ diff --git a/arch/mips/ralink/early_printk.c b/arch/mips/ralink/early_printk.c new file mode 100644 index 000000000..255d695ec --- /dev/null +++ b/arch/mips/ralink/early_printk.c @@ -0,0 +1,63 @@ +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org> + */ + +#include <linux/io.h> +#include <linux/serial_reg.h> + +#include <asm/addrspace.h> + +#ifdef CONFIG_SOC_RT288X +#define EARLY_UART_BASE 0x300c00 +#define CHIPID_BASE 0x300004 +#elif defined(CONFIG_SOC_MT7621) +#define EARLY_UART_BASE 0x1E000c00 +#define CHIPID_BASE 0x1E000004 +#else +#define EARLY_UART_BASE 0x10000c00 +#define CHIPID_BASE 0x10000004 +#endif + +#define MT7628_CHIP_NAME1 0x20203832 + +#define UART_REG_TX 0x04 +#define UART_REG_LSR 0x14 +#define UART_REG_LSR_RT2880 0x1c + +static __iomem void *uart_membase = (__iomem void *) KSEG1ADDR(EARLY_UART_BASE); +static __iomem void *chipid_membase = (__iomem void *) KSEG1ADDR(CHIPID_BASE); + +static inline void uart_w32(u32 val, unsigned reg) +{ + __raw_writel(val, uart_membase + reg); +} + +static inline u32 uart_r32(unsigned reg) +{ + return __raw_readl(uart_membase + reg); +} + +static inline int soc_is_mt7628(void) +{ + return IS_ENABLED(CONFIG_SOC_MT7620) && + (__raw_readl(chipid_membase) == MT7628_CHIP_NAME1); +} + +void prom_putchar(unsigned char ch) +{ + if (IS_ENABLED(CONFIG_SOC_MT7621) || soc_is_mt7628()) { + uart_w32(ch, UART_TX); + while ((uart_r32(UART_REG_LSR) & UART_LSR_THRE) == 0) + ; + } else { + while ((uart_r32(UART_REG_LSR_RT2880) & UART_LSR_THRE) == 0) + ; + uart_w32(ch, UART_REG_TX); + while ((uart_r32(UART_REG_LSR_RT2880) & UART_LSR_THRE) == 0) + ; + } +} diff --git a/arch/mips/ralink/ill_acc.c b/arch/mips/ralink/ill_acc.c new file mode 100644 index 000000000..e10d10b9e --- /dev/null +++ b/arch/mips/ralink/ill_acc.c @@ -0,0 +1,87 @@ +/* + * 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) 2013 John Crispin <blogic@openwrt.org> + */ + +#include <linux/interrupt.h> +#include <linux/of_platform.h> +#include <linux/of_irq.h> + +#include <asm/mach-ralink/ralink_regs.h> + +#define REG_ILL_ACC_ADDR 0x10 +#define REG_ILL_ACC_TYPE 0x14 + +#define ILL_INT_STATUS BIT(31) +#define ILL_ACC_WRITE BIT(30) +#define ILL_ACC_LEN_M 0xff +#define ILL_ACC_OFF_M 0xf +#define ILL_ACC_OFF_S 16 +#define ILL_ACC_ID_M 0x7 +#define ILL_ACC_ID_S 8 + +#define DRV_NAME "ill_acc" + +static const char * const ill_acc_ids[] = { + "cpu", "dma", "ppe", "pdma rx", "pdma tx", "pci/e", "wmac", "usb", +}; + +static irqreturn_t ill_acc_irq_handler(int irq, void *_priv) +{ + struct device *dev = (struct device *) _priv; + u32 addr = rt_memc_r32(REG_ILL_ACC_ADDR); + u32 type = rt_memc_r32(REG_ILL_ACC_TYPE); + + dev_err(dev, "illegal %s access from %s - addr:0x%08x offset:%d len:%d\n", + (type & ILL_ACC_WRITE) ? ("write") : ("read"), + ill_acc_ids[(type >> ILL_ACC_ID_S) & ILL_ACC_ID_M], + addr, (type >> ILL_ACC_OFF_S) & ILL_ACC_OFF_M, + type & ILL_ACC_LEN_M); + + rt_memc_w32(ILL_INT_STATUS, REG_ILL_ACC_TYPE); + + return IRQ_HANDLED; +} + +static int __init ill_acc_of_setup(void) +{ + struct platform_device *pdev; + struct device_node *np; + int irq; + + /* somehow this driver breaks on RT5350 */ + if (of_machine_is_compatible("ralink,rt5350-soc")) + return -EINVAL; + + np = of_find_compatible_node(NULL, NULL, "ralink,rt3050-memc"); + if (!np) + return -EINVAL; + + pdev = of_find_device_by_node(np); + if (!pdev) { + pr_err("%s: failed to lookup pdev\n", np->name); + return -EINVAL; + } + + irq = irq_of_parse_and_map(np, 0); + if (!irq) { + dev_err(&pdev->dev, "failed to get irq\n"); + return -EINVAL; + } + + if (request_irq(irq, ill_acc_irq_handler, 0, "ill_acc", &pdev->dev)) { + dev_err(&pdev->dev, "failed to request irq\n"); + return -EINVAL; + } + + rt_memc_w32(ILL_INT_STATUS, REG_ILL_ACC_TYPE); + + dev_info(&pdev->dev, "irq registered\n"); + + return 0; +} + +arch_initcall(ill_acc_of_setup); diff --git a/arch/mips/ralink/irq.c b/arch/mips/ralink/irq.c new file mode 100644 index 000000000..7cf91b92e --- /dev/null +++ b/arch/mips/ralink/irq.c @@ -0,0 +1,206 @@ +/* + * 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) 2009 Gabor Juhos <juhosg@openwrt.org> + * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + */ + +#include <linux/io.h> +#include <linux/bitops.h> +#include <linux/of_platform.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/irqdomain.h> +#include <linux/interrupt.h> + +#include <asm/irq_cpu.h> +#include <asm/mipsregs.h> + +#include "common.h" + +#define INTC_INT_GLOBAL BIT(31) + +#define RALINK_CPU_IRQ_INTC (MIPS_CPU_IRQ_BASE + 2) +#define RALINK_CPU_IRQ_PCI (MIPS_CPU_IRQ_BASE + 4) +#define RALINK_CPU_IRQ_FE (MIPS_CPU_IRQ_BASE + 5) +#define RALINK_CPU_IRQ_WIFI (MIPS_CPU_IRQ_BASE + 6) +#define RALINK_CPU_IRQ_COUNTER (MIPS_CPU_IRQ_BASE + 7) + +/* we have a cascade of 8 irqs */ +#define RALINK_INTC_IRQ_BASE 8 + +/* we have 32 SoC irqs */ +#define RALINK_INTC_IRQ_COUNT 32 + +#define RALINK_INTC_IRQ_PERFC (RALINK_INTC_IRQ_BASE + 9) + +enum rt_intc_regs_enum { + INTC_REG_STATUS0 = 0, + INTC_REG_STATUS1, + INTC_REG_TYPE, + INTC_REG_RAW_STATUS, + INTC_REG_ENABLE, + INTC_REG_DISABLE, +}; + +static u32 rt_intc_regs[] = { + [INTC_REG_STATUS0] = 0x00, + [INTC_REG_STATUS1] = 0x04, + [INTC_REG_TYPE] = 0x20, + [INTC_REG_RAW_STATUS] = 0x30, + [INTC_REG_ENABLE] = 0x34, + [INTC_REG_DISABLE] = 0x38, +}; + +static void __iomem *rt_intc_membase; + +static int rt_perfcount_irq; + +static inline void rt_intc_w32(u32 val, unsigned reg) +{ + __raw_writel(val, rt_intc_membase + rt_intc_regs[reg]); +} + +static inline u32 rt_intc_r32(unsigned reg) +{ + return __raw_readl(rt_intc_membase + rt_intc_regs[reg]); +} + +static void ralink_intc_irq_unmask(struct irq_data *d) +{ + rt_intc_w32(BIT(d->hwirq), INTC_REG_ENABLE); +} + +static void ralink_intc_irq_mask(struct irq_data *d) +{ + rt_intc_w32(BIT(d->hwirq), INTC_REG_DISABLE); +} + +static struct irq_chip ralink_intc_irq_chip = { + .name = "INTC", + .irq_unmask = ralink_intc_irq_unmask, + .irq_mask = ralink_intc_irq_mask, + .irq_mask_ack = ralink_intc_irq_mask, +}; + +int get_c0_perfcount_int(void) +{ + return rt_perfcount_irq; +} + +unsigned int get_c0_compare_int(void) +{ + return CP0_LEGACY_COMPARE_IRQ; +} + +static void ralink_intc_irq_handler(unsigned int irq, struct irq_desc *desc) +{ + u32 pending = rt_intc_r32(INTC_REG_STATUS0); + + if (pending) { + struct irq_domain *domain = irq_get_handler_data(irq); + generic_handle_irq(irq_find_mapping(domain, __ffs(pending))); + } 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(RALINK_CPU_IRQ_COUNTER); + + else if (pending & STATUSF_IP5) + do_IRQ(RALINK_CPU_IRQ_FE); + + else if (pending & STATUSF_IP6) + do_IRQ(RALINK_CPU_IRQ_WIFI); + + else if (pending & STATUSF_IP4) + do_IRQ(RALINK_CPU_IRQ_PCI); + + else if (pending & STATUSF_IP2) + do_IRQ(RALINK_CPU_IRQ_INTC); + + else + spurious_interrupt(); +} + +static int intc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) +{ + irq_set_chip_and_handler(irq, &ralink_intc_irq_chip, handle_level_irq); + + return 0; +} + +static const struct irq_domain_ops irq_domain_ops = { + .xlate = irq_domain_xlate_onecell, + .map = intc_map, +}; + +static int __init intc_of_init(struct device_node *node, + struct device_node *parent) +{ + struct resource res; + struct irq_domain *domain; + int irq; + + if (!of_property_read_u32_array(node, "ralink,intc-registers", + rt_intc_regs, 6)) + pr_info("intc: using register map from devicetree\n"); + + irq = irq_of_parse_and_map(node, 0); + if (!irq) + panic("Failed to get INTC IRQ"); + + if (of_address_to_resource(node, 0, &res)) + panic("Failed to get intc memory range"); + + if (request_mem_region(res.start, resource_size(&res), + res.name) < 0) + pr_err("Failed to request intc memory"); + + rt_intc_membase = ioremap_nocache(res.start, + resource_size(&res)); + if (!rt_intc_membase) + panic("Failed to remap intc memory"); + + /* disable all interrupts */ + rt_intc_w32(~0, INTC_REG_DISABLE); + + /* route all INTC interrupts to MIPS HW0 interrupt */ + rt_intc_w32(0, INTC_REG_TYPE); + + domain = irq_domain_add_legacy(node, RALINK_INTC_IRQ_COUNT, + RALINK_INTC_IRQ_BASE, 0, &irq_domain_ops, NULL); + if (!domain) + panic("Failed to add irqdomain"); + + rt_intc_w32(INTC_INT_GLOBAL, INTC_REG_ENABLE); + + irq_set_chained_handler(irq, ralink_intc_irq_handler); + irq_set_handler_data(irq, domain); + + /* tell the kernel which irq is used for performance monitoring */ + rt_perfcount_irq = irq_create_mapping(domain, 9); + + return 0; +} + +static struct of_device_id __initdata of_irq_ids[] = { + { .compatible = "mti,cpu-interrupt-controller", .data = mips_cpu_irq_of_init }, + { .compatible = "ralink,rt2880-intc", .data = intc_of_init }, + {}, +}; + +void __init arch_init_irq(void) +{ + of_irq_init(of_irq_ids); +} + diff --git a/arch/mips/ralink/mt7620.c b/arch/mips/ralink/mt7620.c new file mode 100644 index 000000000..2ea5ff6dc --- /dev/null +++ b/arch/mips/ralink/mt7620.c @@ -0,0 +1,548 @@ +/* + * 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. + * + * Parts of this file are based on Ralink's 2.6.21 BSP + * + * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> + * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> + * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> + +#include <asm/mipsregs.h> +#include <asm/mach-ralink/ralink_regs.h> +#include <asm/mach-ralink/mt7620.h> +#include <asm/mach-ralink/pinmux.h> + +#include "common.h" + +/* analog */ +#define PMU0_CFG 0x88 +#define PMU_SW_SET BIT(28) +#define A_DCDC_EN BIT(24) +#define A_SSC_PERI BIT(19) +#define A_SSC_GEN BIT(18) +#define A_SSC_M 0x3 +#define A_SSC_S 16 +#define A_DLY_M 0x7 +#define A_DLY_S 8 +#define A_VTUNE_M 0xff + +/* digital */ +#define PMU1_CFG 0x8C +#define DIG_SW_SEL BIT(25) + +/* is this a MT7620 or a MT7628 */ +enum mt762x_soc_type mt762x_soc; + +/* does the board have sdram or ddram */ +static int dram_type; + +static struct rt2880_pmx_func i2c_grp[] = { FUNC("i2c", 0, 1, 2) }; +static struct rt2880_pmx_func spi_grp[] = { FUNC("spi", 0, 3, 4) }; +static struct rt2880_pmx_func uartlite_grp[] = { FUNC("uartlite", 0, 15, 2) }; +static struct rt2880_pmx_func mdio_grp[] = { FUNC("mdio", 0, 22, 2) }; +static struct rt2880_pmx_func rgmii1_grp[] = { FUNC("rgmii1", 0, 24, 12) }; +static struct rt2880_pmx_func refclk_grp[] = { FUNC("spi refclk", 0, 37, 3) }; +static struct rt2880_pmx_func ephy_grp[] = { FUNC("ephy", 0, 40, 5) }; +static struct rt2880_pmx_func rgmii2_grp[] = { FUNC("rgmii2", 0, 60, 12) }; +static struct rt2880_pmx_func wled_grp[] = { FUNC("wled", 0, 72, 1) }; +static struct rt2880_pmx_func pa_grp[] = { FUNC("pa", 0, 18, 4) }; +static struct rt2880_pmx_func uartf_grp[] = { + FUNC("uartf", MT7620_GPIO_MODE_UARTF, 7, 8), + FUNC("pcm uartf", MT7620_GPIO_MODE_PCM_UARTF, 7, 8), + FUNC("pcm i2s", MT7620_GPIO_MODE_PCM_I2S, 7, 8), + FUNC("i2s uartf", MT7620_GPIO_MODE_I2S_UARTF, 7, 8), + FUNC("pcm gpio", MT7620_GPIO_MODE_PCM_GPIO, 11, 4), + FUNC("gpio uartf", MT7620_GPIO_MODE_GPIO_UARTF, 7, 4), + FUNC("gpio i2s", MT7620_GPIO_MODE_GPIO_I2S, 7, 4), +}; +static struct rt2880_pmx_func wdt_grp[] = { + FUNC("wdt rst", 0, 17, 1), + FUNC("wdt refclk", 0, 17, 1), + }; +static struct rt2880_pmx_func pcie_rst_grp[] = { + FUNC("pcie rst", MT7620_GPIO_MODE_PCIE_RST, 36, 1), + FUNC("pcie refclk", MT7620_GPIO_MODE_PCIE_REF, 36, 1) +}; +static struct rt2880_pmx_func nd_sd_grp[] = { + FUNC("nand", MT7620_GPIO_MODE_NAND, 45, 15), + FUNC("sd", MT7620_GPIO_MODE_SD, 45, 15) +}; + +static struct rt2880_pmx_group mt7620a_pinmux_data[] = { + GRP("i2c", i2c_grp, 1, MT7620_GPIO_MODE_I2C), + GRP("uartf", uartf_grp, MT7620_GPIO_MODE_UART0_MASK, + MT7620_GPIO_MODE_UART0_SHIFT), + GRP("spi", spi_grp, 1, MT7620_GPIO_MODE_SPI), + GRP("uartlite", uartlite_grp, 1, MT7620_GPIO_MODE_UART1), + GRP_G("wdt", wdt_grp, MT7620_GPIO_MODE_WDT_MASK, + MT7620_GPIO_MODE_WDT_GPIO, MT7620_GPIO_MODE_WDT_SHIFT), + GRP("mdio", mdio_grp, 1, MT7620_GPIO_MODE_MDIO), + GRP("rgmii1", rgmii1_grp, 1, MT7620_GPIO_MODE_RGMII1), + GRP("spi refclk", refclk_grp, 1, MT7620_GPIO_MODE_SPI_REF_CLK), + GRP_G("pcie", pcie_rst_grp, MT7620_GPIO_MODE_PCIE_MASK, + MT7620_GPIO_MODE_PCIE_GPIO, MT7620_GPIO_MODE_PCIE_SHIFT), + GRP_G("nd_sd", nd_sd_grp, MT7620_GPIO_MODE_ND_SD_MASK, + MT7620_GPIO_MODE_ND_SD_GPIO, MT7620_GPIO_MODE_ND_SD_SHIFT), + GRP("rgmii2", rgmii2_grp, 1, MT7620_GPIO_MODE_RGMII2), + GRP("wled", wled_grp, 1, MT7620_GPIO_MODE_WLED), + GRP("ephy", ephy_grp, 1, MT7620_GPIO_MODE_EPHY), + GRP("pa", pa_grp, 1, MT7620_GPIO_MODE_PA), + { 0 } +}; + +static struct rt2880_pmx_func pwm1_grp_mt7628[] = { + FUNC("sdcx", 3, 19, 1), + FUNC("utif", 2, 19, 1), + FUNC("gpio", 1, 19, 1), + FUNC("pwm", 0, 19, 1), +}; + +static struct rt2880_pmx_func pwm0_grp_mt7628[] = { + FUNC("sdcx", 3, 18, 1), + FUNC("utif", 2, 18, 1), + FUNC("gpio", 1, 18, 1), + FUNC("pwm", 0, 18, 1), +}; + +static struct rt2880_pmx_func uart2_grp_mt7628[] = { + FUNC("sdcx", 3, 20, 2), + FUNC("pwm", 2, 20, 2), + FUNC("gpio", 1, 20, 2), + FUNC("uart", 0, 20, 2), +}; + +static struct rt2880_pmx_func uart1_grp_mt7628[] = { + FUNC("sdcx", 3, 45, 2), + FUNC("pwm", 2, 45, 2), + FUNC("gpio", 1, 45, 2), + FUNC("uart", 0, 45, 2), +}; + +static struct rt2880_pmx_func i2c_grp_mt7628[] = { + FUNC("-", 3, 4, 2), + FUNC("debug", 2, 4, 2), + FUNC("gpio", 1, 4, 2), + FUNC("i2c", 0, 4, 2), +}; + +static struct rt2880_pmx_func refclk_grp_mt7628[] = { FUNC("reclk", 0, 36, 1) }; +static struct rt2880_pmx_func perst_grp_mt7628[] = { FUNC("perst", 0, 37, 1) }; +static struct rt2880_pmx_func wdt_grp_mt7628[] = { FUNC("wdt", 0, 15, 38) }; +static struct rt2880_pmx_func spi_grp_mt7628[] = { FUNC("spi", 0, 7, 4) }; + +static struct rt2880_pmx_func sd_mode_grp_mt7628[] = { + FUNC("jtag", 3, 22, 8), + FUNC("utif", 2, 22, 8), + FUNC("gpio", 1, 22, 8), + FUNC("sdcx", 0, 22, 8), +}; + +static struct rt2880_pmx_func uart0_grp_mt7628[] = { + FUNC("-", 3, 12, 2), + FUNC("-", 2, 12, 2), + FUNC("gpio", 1, 12, 2), + FUNC("uart", 0, 12, 2), +}; + +static struct rt2880_pmx_func i2s_grp_mt7628[] = { + FUNC("antenna", 3, 0, 4), + FUNC("pcm", 2, 0, 4), + FUNC("gpio", 1, 0, 4), + FUNC("i2s", 0, 0, 4), +}; + +static struct rt2880_pmx_func spi_cs1_grp_mt7628[] = { + FUNC("-", 3, 6, 1), + FUNC("refclk", 2, 6, 1), + FUNC("gpio", 1, 6, 1), + FUNC("spi", 0, 6, 1), +}; + +static struct rt2880_pmx_func spis_grp_mt7628[] = { + FUNC("pwm", 3, 14, 4), + FUNC("util", 2, 14, 4), + FUNC("gpio", 1, 14, 4), + FUNC("spis", 0, 14, 4), +}; + +static struct rt2880_pmx_func gpio_grp_mt7628[] = { + FUNC("pcie", 3, 11, 1), + FUNC("refclk", 2, 11, 1), + FUNC("gpio", 1, 11, 1), + FUNC("gpio", 0, 11, 1), +}; + +#define MT7628_GPIO_MODE_MASK 0x3 + +#define MT7628_GPIO_MODE_PWM1 30 +#define MT7628_GPIO_MODE_PWM0 28 +#define MT7628_GPIO_MODE_UART2 26 +#define MT7628_GPIO_MODE_UART1 24 +#define MT7628_GPIO_MODE_I2C 20 +#define MT7628_GPIO_MODE_REFCLK 18 +#define MT7628_GPIO_MODE_PERST 16 +#define MT7628_GPIO_MODE_WDT 14 +#define MT7628_GPIO_MODE_SPI 12 +#define MT7628_GPIO_MODE_SDMODE 10 +#define MT7628_GPIO_MODE_UART0 8 +#define MT7628_GPIO_MODE_I2S 6 +#define MT7628_GPIO_MODE_CS1 4 +#define MT7628_GPIO_MODE_SPIS 2 +#define MT7628_GPIO_MODE_GPIO 0 + +static struct rt2880_pmx_group mt7628an_pinmux_data[] = { + GRP_G("pmw1", pwm1_grp_mt7628, MT7628_GPIO_MODE_MASK, + 1, MT7628_GPIO_MODE_PWM1), + GRP_G("pmw1", pwm0_grp_mt7628, MT7628_GPIO_MODE_MASK, + 1, MT7628_GPIO_MODE_PWM0), + GRP_G("uart2", uart2_grp_mt7628, MT7628_GPIO_MODE_MASK, + 1, MT7628_GPIO_MODE_UART2), + GRP_G("uart1", uart1_grp_mt7628, MT7628_GPIO_MODE_MASK, + 1, MT7628_GPIO_MODE_UART1), + GRP_G("i2c", i2c_grp_mt7628, MT7628_GPIO_MODE_MASK, + 1, MT7628_GPIO_MODE_I2C), + GRP("refclk", refclk_grp_mt7628, 1, MT7628_GPIO_MODE_REFCLK), + GRP("perst", perst_grp_mt7628, 1, MT7628_GPIO_MODE_PERST), + GRP("wdt", wdt_grp_mt7628, 1, MT7628_GPIO_MODE_WDT), + GRP("spi", spi_grp_mt7628, 1, MT7628_GPIO_MODE_SPI), + GRP_G("sdmode", sd_mode_grp_mt7628, MT7628_GPIO_MODE_MASK, + 1, MT7628_GPIO_MODE_SDMODE), + GRP_G("uart0", uart0_grp_mt7628, MT7628_GPIO_MODE_MASK, + 1, MT7628_GPIO_MODE_UART0), + GRP_G("i2s", i2s_grp_mt7628, MT7628_GPIO_MODE_MASK, + 1, MT7628_GPIO_MODE_I2S), + GRP_G("spi cs1", spi_cs1_grp_mt7628, MT7628_GPIO_MODE_MASK, + 1, MT7628_GPIO_MODE_CS1), + GRP_G("spis", spis_grp_mt7628, MT7628_GPIO_MODE_MASK, + 1, MT7628_GPIO_MODE_SPIS), + GRP_G("gpio", gpio_grp_mt7628, MT7628_GPIO_MODE_MASK, + 1, MT7628_GPIO_MODE_GPIO), + { 0 } +}; + +static __init u32 +mt7620_calc_rate(u32 ref_rate, u32 mul, u32 div) +{ + u64 t; + + t = ref_rate; + t *= mul; + do_div(t, div); + + return t; +} + +#define MHZ(x) ((x) * 1000 * 1000) + +static __init unsigned long +mt7620_get_xtal_rate(void) +{ + u32 reg; + + reg = rt_sysc_r32(SYSC_REG_SYSTEM_CONFIG0); + if (reg & SYSCFG0_XTAL_FREQ_SEL) + return MHZ(40); + + return MHZ(20); +} + +static __init unsigned long +mt7620_get_periph_rate(unsigned long xtal_rate) +{ + u32 reg; + + reg = rt_sysc_r32(SYSC_REG_CLKCFG0); + if (reg & CLKCFG0_PERI_CLK_SEL) + return xtal_rate; + + return MHZ(40); +} + +static const u32 mt7620_clk_divider[] __initconst = { 2, 3, 4, 8 }; + +static __init unsigned long +mt7620_get_cpu_pll_rate(unsigned long xtal_rate) +{ + u32 reg; + u32 mul; + u32 div; + + reg = rt_sysc_r32(SYSC_REG_CPLL_CONFIG0); + if (reg & CPLL_CFG0_BYPASS_REF_CLK) + return xtal_rate; + + if ((reg & CPLL_CFG0_SW_CFG) == 0) + return MHZ(600); + + mul = (reg >> CPLL_CFG0_PLL_MULT_RATIO_SHIFT) & + CPLL_CFG0_PLL_MULT_RATIO_MASK; + mul += 24; + if (reg & CPLL_CFG0_LC_CURFCK) + mul *= 2; + + div = (reg >> CPLL_CFG0_PLL_DIV_RATIO_SHIFT) & + CPLL_CFG0_PLL_DIV_RATIO_MASK; + + WARN_ON(div >= ARRAY_SIZE(mt7620_clk_divider)); + + return mt7620_calc_rate(xtal_rate, mul, mt7620_clk_divider[div]); +} + +static __init unsigned long +mt7620_get_pll_rate(unsigned long xtal_rate, unsigned long cpu_pll_rate) +{ + u32 reg; + + reg = rt_sysc_r32(SYSC_REG_CPLL_CONFIG1); + if (reg & CPLL_CFG1_CPU_AUX1) + return xtal_rate; + + if (reg & CPLL_CFG1_CPU_AUX0) + return MHZ(480); + + return cpu_pll_rate; +} + +static __init unsigned long +mt7620_get_cpu_rate(unsigned long pll_rate) +{ + u32 reg; + u32 mul; + u32 div; + + reg = rt_sysc_r32(SYSC_REG_CPU_SYS_CLKCFG); + + mul = reg & CPU_SYS_CLKCFG_CPU_FFRAC_MASK; + div = (reg >> CPU_SYS_CLKCFG_CPU_FDIV_SHIFT) & + CPU_SYS_CLKCFG_CPU_FDIV_MASK; + + return mt7620_calc_rate(pll_rate, mul, div); +} + +static const u32 mt7620_ocp_dividers[16] __initconst = { + [CPU_SYS_CLKCFG_OCP_RATIO_2] = 2, + [CPU_SYS_CLKCFG_OCP_RATIO_3] = 3, + [CPU_SYS_CLKCFG_OCP_RATIO_4] = 4, + [CPU_SYS_CLKCFG_OCP_RATIO_5] = 5, + [CPU_SYS_CLKCFG_OCP_RATIO_10] = 10, +}; + +static __init unsigned long +mt7620_get_dram_rate(unsigned long pll_rate) +{ + if (dram_type == SYSCFG0_DRAM_TYPE_SDRAM) + return pll_rate / 4; + + return pll_rate / 3; +} + +static __init unsigned long +mt7620_get_sys_rate(unsigned long cpu_rate) +{ + u32 reg; + u32 ocp_ratio; + u32 div; + + reg = rt_sysc_r32(SYSC_REG_CPU_SYS_CLKCFG); + + ocp_ratio = (reg >> CPU_SYS_CLKCFG_OCP_RATIO_SHIFT) & + CPU_SYS_CLKCFG_OCP_RATIO_MASK; + + if (WARN_ON(ocp_ratio >= ARRAY_SIZE(mt7620_ocp_dividers))) + return cpu_rate; + + div = mt7620_ocp_dividers[ocp_ratio]; + if (WARN(!div, "invalid divider for OCP ratio %u", ocp_ratio)) + return cpu_rate; + + return cpu_rate / div; +} + +void __init ralink_clk_init(void) +{ + unsigned long xtal_rate; + unsigned long cpu_pll_rate; + unsigned long pll_rate; + unsigned long cpu_rate; + unsigned long sys_rate; + unsigned long dram_rate; + unsigned long periph_rate; + + xtal_rate = mt7620_get_xtal_rate(); + +#define RFMT(label) label ":%lu.%03luMHz " +#define RINT(x) ((x) / 1000000) +#define RFRAC(x) (((x) / 1000) % 1000) + + if (mt762x_soc == MT762X_SOC_MT7628AN) { + if (xtal_rate == MHZ(40)) + cpu_rate = MHZ(580); + else + cpu_rate = MHZ(575); + dram_rate = sys_rate = cpu_rate / 3; + periph_rate = MHZ(40); + + ralink_clk_add("10000d00.uartlite", periph_rate); + ralink_clk_add("10000e00.uartlite", periph_rate); + } else { + cpu_pll_rate = mt7620_get_cpu_pll_rate(xtal_rate); + pll_rate = mt7620_get_pll_rate(xtal_rate, cpu_pll_rate); + + cpu_rate = mt7620_get_cpu_rate(pll_rate); + dram_rate = mt7620_get_dram_rate(pll_rate); + sys_rate = mt7620_get_sys_rate(cpu_rate); + periph_rate = mt7620_get_periph_rate(xtal_rate); + + pr_debug(RFMT("XTAL") RFMT("CPU_PLL") RFMT("PLL"), + RINT(xtal_rate), RFRAC(xtal_rate), + RINT(cpu_pll_rate), RFRAC(cpu_pll_rate), + RINT(pll_rate), RFRAC(pll_rate)); + + ralink_clk_add("10000500.uart", periph_rate); + } + + pr_debug(RFMT("CPU") RFMT("DRAM") RFMT("SYS") RFMT("PERIPH"), + RINT(cpu_rate), RFRAC(cpu_rate), + RINT(dram_rate), RFRAC(dram_rate), + RINT(sys_rate), RFRAC(sys_rate), + RINT(periph_rate), RFRAC(periph_rate)); +#undef RFRAC +#undef RINT +#undef RFMT + + ralink_clk_add("cpu", cpu_rate); + ralink_clk_add("10000100.timer", periph_rate); + ralink_clk_add("10000120.watchdog", periph_rate); + ralink_clk_add("10000b00.spi", sys_rate); + ralink_clk_add("10000c00.uartlite", periph_rate); + ralink_clk_add("10180000.wmac", xtal_rate); +} + +void __init ralink_of_remap(void) +{ + rt_sysc_membase = plat_of_remap_node("ralink,mt7620a-sysc"); + rt_memc_membase = plat_of_remap_node("ralink,mt7620a-memc"); + + if (!rt_sysc_membase || !rt_memc_membase) + panic("Failed to remap core resources"); +} + +static __init void +mt7620_dram_init(struct ralink_soc_info *soc_info) +{ + switch (dram_type) { + case SYSCFG0_DRAM_TYPE_SDRAM: + pr_info("Board has SDRAM\n"); + soc_info->mem_size_min = MT7620_SDRAM_SIZE_MIN; + soc_info->mem_size_max = MT7620_SDRAM_SIZE_MAX; + break; + + case SYSCFG0_DRAM_TYPE_DDR1: + pr_info("Board has DDR1\n"); + soc_info->mem_size_min = MT7620_DDR1_SIZE_MIN; + soc_info->mem_size_max = MT7620_DDR1_SIZE_MAX; + break; + + case SYSCFG0_DRAM_TYPE_DDR2: + pr_info("Board has DDR2\n"); + soc_info->mem_size_min = MT7620_DDR2_SIZE_MIN; + soc_info->mem_size_max = MT7620_DDR2_SIZE_MAX; + break; + default: + BUG(); + } +} + +static __init void +mt7628_dram_init(struct ralink_soc_info *soc_info) +{ + switch (dram_type) { + case SYSCFG0_DRAM_TYPE_DDR1_MT7628: + pr_info("Board has DDR1\n"); + soc_info->mem_size_min = MT7620_DDR1_SIZE_MIN; + soc_info->mem_size_max = MT7620_DDR1_SIZE_MAX; + break; + + case SYSCFG0_DRAM_TYPE_DDR2_MT7628: + pr_info("Board has DDR2\n"); + soc_info->mem_size_min = MT7620_DDR2_SIZE_MIN; + soc_info->mem_size_max = MT7620_DDR2_SIZE_MAX; + break; + default: + BUG(); + } +} + +void prom_soc_init(struct ralink_soc_info *soc_info) +{ + void __iomem *sysc = (void __iomem *) KSEG1ADDR(MT7620_SYSC_BASE); + unsigned char *name = NULL; + u32 n0; + u32 n1; + u32 rev; + u32 cfg0; + u32 pmu0; + u32 pmu1; + u32 bga; + + n0 = __raw_readl(sysc + SYSC_REG_CHIP_NAME0); + n1 = __raw_readl(sysc + SYSC_REG_CHIP_NAME1); + rev = __raw_readl(sysc + SYSC_REG_CHIP_REV); + bga = (rev >> CHIP_REV_PKG_SHIFT) & CHIP_REV_PKG_MASK; + + if (n0 == MT7620_CHIP_NAME0 && n1 == MT7620_CHIP_NAME1) { + if (bga) { + mt762x_soc = MT762X_SOC_MT7620A; + name = "MT7620A"; + soc_info->compatible = "ralink,mt7620a-soc"; + } else { + mt762x_soc = MT762X_SOC_MT7620N; + name = "MT7620N"; + soc_info->compatible = "ralink,mt7620n-soc"; +#ifdef CONFIG_PCI + panic("mt7620n is only supported for non pci kernels"); +#endif + } + } else if (n0 == MT7620_CHIP_NAME0 && n1 == MT7628_CHIP_NAME1) { + mt762x_soc = MT762X_SOC_MT7628AN; + name = "MT7628AN"; + soc_info->compatible = "ralink,mt7628an-soc"; + } else { + panic("mt762x: unknown SoC, n0:%08x n1:%08x\n", n0, n1); + } + + snprintf(soc_info->sys_type, RAMIPS_SYS_TYPE_LEN, + "Ralink %s ver:%u eco:%u", + name, + (rev >> CHIP_REV_VER_SHIFT) & CHIP_REV_VER_MASK, + (rev & CHIP_REV_ECO_MASK)); + + cfg0 = __raw_readl(sysc + SYSC_REG_SYSTEM_CONFIG0); + dram_type = (cfg0 >> SYSCFG0_DRAM_TYPE_SHIFT) & SYSCFG0_DRAM_TYPE_MASK; + + soc_info->mem_base = MT7620_DRAM_BASE; + if (mt762x_soc == MT762X_SOC_MT7628AN) + mt7628_dram_init(soc_info); + else + mt7620_dram_init(soc_info); + + pmu0 = __raw_readl(sysc + PMU0_CFG); + pmu1 = __raw_readl(sysc + PMU1_CFG); + + pr_info("Analog PMU set to %s control\n", + (pmu0 & PMU_SW_SET) ? ("sw") : ("hw")); + pr_info("Digital PMU set to %s control\n", + (pmu1 & DIG_SW_SEL) ? ("sw") : ("hw")); + + if (mt762x_soc == MT762X_SOC_MT7628AN) + rt2880_pinmux_data = mt7628an_pinmux_data; + else + rt2880_pinmux_data = mt7620a_pinmux_data; +} diff --git a/arch/mips/ralink/of.c b/arch/mips/ralink/of.c new file mode 100644 index 000000000..0d30dcd63 --- /dev/null +++ b/arch/mips/ralink/of.c @@ -0,0 +1,101 @@ +/* + * 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) 2008 Imre Kaloz <kaloz@openwrt.org> + * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org> + * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + */ + +#include <linux/io.h> +#include <linux/clk.h> +#include <linux/init.h> +#include <linux/sizes.h> +#include <linux/of_fdt.h> +#include <linux/kernel.h> +#include <linux/bootmem.h> +#include <linux/of_platform.h> +#include <linux/of_address.h> + +#include <asm/reboot.h> +#include <asm/bootinfo.h> +#include <asm/addrspace.h> +#include <asm/prom.h> + +#include "common.h" + +__iomem void *rt_sysc_membase; +__iomem void *rt_memc_membase; + +__iomem void *plat_of_remap_node(const char *node) +{ + struct resource res; + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, node); + if (!np) + panic("Failed to find %s node", node); + + if (of_address_to_resource(np, 0, &res)) + panic("Failed to get resource for %s", node); + + if ((request_mem_region(res.start, + resource_size(&res), + res.name) < 0)) + panic("Failed to request resources for %s", node); + + return ioremap_nocache(res.start, resource_size(&res)); +} + +void __init device_tree_init(void) +{ + unflatten_and_copy_device_tree(); +} + +static int memory_dtb; + +static int __init early_init_dt_find_memory(unsigned long node, + const char *uname, int depth, void *data) +{ + if (depth == 1 && !strcmp(uname, "memory@0")) + memory_dtb = 1; + + return 0; +} + +void __init plat_mem_setup(void) +{ + set_io_port_base(KSEG1); + + /* + * Load the builtin devicetree. This causes the chosen node to be + * parsed resulting in our memory appearing + */ + __dt_setup_arch(__dtb_start); + + strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE); + + of_scan_flat_dt(early_init_dt_find_memory, NULL); + if (memory_dtb) + of_scan_flat_dt(early_init_dt_scan_memory, NULL); + else if (soc_info.mem_size) + add_memory_region(soc_info.mem_base, soc_info.mem_size * SZ_1M, + BOOT_MEM_RAM); + else + detect_memory_region(soc_info.mem_base, + soc_info.mem_size_min * SZ_1M, + soc_info.mem_size_max * SZ_1M); +} + +static int __init plat_of_setup(void) +{ + __dt_register_buses(soc_info.compatible, "palmbus"); + + /* make sure that the reset controller is setup early */ + ralink_rst_init(); + + return 0; +} + +arch_initcall(plat_of_setup); diff --git a/arch/mips/ralink/prom.c b/arch/mips/ralink/prom.c new file mode 100644 index 000000000..09419f67d --- /dev/null +++ b/arch/mips/ralink/prom.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) 2009 Gabor Juhos <juhosg@openwrt.org> + * Copyright (C) 2010 Joonas Lahtinen <joonas.lahtinen@gmail.com> + * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + */ + +#include <linux/string.h> +#include <linux/of_fdt.h> +#include <linux/of_platform.h> + +#include <asm/bootinfo.h> +#include <asm/addrspace.h> + +#include "common.h" + +struct ralink_soc_info soc_info; +struct rt2880_pmx_group *rt2880_pinmux_data = NULL; + +const char *get_system_type(void) +{ + return soc_info.sys_type; +} + +static __init void prom_init_cmdline(int argc, char **argv) +{ + int i; + + pr_debug("prom: fw_arg0=%08x fw_arg1=%08x fw_arg2=%08x fw_arg3=%08x\n", + (unsigned int)fw_arg0, (unsigned int)fw_arg1, + (unsigned int)fw_arg2, (unsigned int)fw_arg3); + + argc = fw_arg0; + argv = (char **) KSEG1ADDR(fw_arg1); + + if (!argv) { + pr_debug("argv=%p is invalid, skipping\n", + argv); + return; + } + + for (i = 0; i < argc; i++) { + char *p = (char *) KSEG1ADDR(argv[i]); + + if (CPHYSADDR(p) && *p) { + pr_debug("argv[%d]: %s\n", i, p); + strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline)); + strlcat(arcs_cmdline, p, sizeof(arcs_cmdline)); + } + } +} + +void __init prom_init(void) +{ + int argc; + char **argv; + + prom_soc_init(&soc_info); + + pr_info("SoC Type: %s\n", get_system_type()); + + prom_init_cmdline(argc, argv); +} + +void __init prom_free_prom_memory(void) +{ +} diff --git a/arch/mips/ralink/reset.c b/arch/mips/ralink/reset.c new file mode 100644 index 000000000..55c7ec59d --- /dev/null +++ b/arch/mips/ralink/reset.c @@ -0,0 +1,106 @@ +/* + * 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) 2008-2009 Gabor Juhos <juhosg@openwrt.org> + * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> + * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + */ + +#include <linux/pm.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/reset-controller.h> + +#include <asm/reboot.h> + +#include <asm/mach-ralink/ralink_regs.h> + +/* Reset Control */ +#define SYSC_REG_RESET_CTRL 0x034 +#define RSTCTL_RESET_SYSTEM BIT(0) + +static int ralink_assert_device(struct reset_controller_dev *rcdev, + unsigned long id) +{ + u32 val; + + if (id < 8) + return -1; + + val = rt_sysc_r32(SYSC_REG_RESET_CTRL); + val |= BIT(id); + rt_sysc_w32(val, SYSC_REG_RESET_CTRL); + + return 0; +} + +static int ralink_deassert_device(struct reset_controller_dev *rcdev, + unsigned long id) +{ + u32 val; + + if (id < 8) + return -1; + + val = rt_sysc_r32(SYSC_REG_RESET_CTRL); + val &= ~BIT(id); + rt_sysc_w32(val, SYSC_REG_RESET_CTRL); + + return 0; +} + +static int ralink_reset_device(struct reset_controller_dev *rcdev, + unsigned long id) +{ + ralink_assert_device(rcdev, id); + return ralink_deassert_device(rcdev, id); +} + +static struct reset_control_ops reset_ops = { + .reset = ralink_reset_device, + .assert = ralink_assert_device, + .deassert = ralink_deassert_device, +}; + +static struct reset_controller_dev reset_dev = { + .ops = &reset_ops, + .owner = THIS_MODULE, + .nr_resets = 32, + .of_reset_n_cells = 1, +}; + +void ralink_rst_init(void) +{ + reset_dev.of_node = of_find_compatible_node(NULL, NULL, + "ralink,rt2880-reset"); + if (!reset_dev.of_node) + pr_err("Failed to find reset controller node"); + else + reset_controller_register(&reset_dev); +} + +static void ralink_restart(char *command) +{ + local_irq_disable(); + rt_sysc_w32(RSTCTL_RESET_SYSTEM, SYSC_REG_RESET_CTRL); + unreachable(); +} + +static void ralink_halt(void) +{ + local_irq_disable(); + unreachable(); +} + +static int __init mips_reboot_setup(void) +{ + _machine_restart = ralink_restart; + _machine_halt = ralink_halt; + pm_power_off = ralink_halt; + + return 0; +} + +arch_initcall(mips_reboot_setup); diff --git a/arch/mips/ralink/rt288x.c b/arch/mips/ralink/rt288x.c new file mode 100644 index 000000000..738cec865 --- /dev/null +++ b/arch/mips/ralink/rt288x.c @@ -0,0 +1,122 @@ +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * Parts of this file are based on Ralink's 2.6.21 BSP + * + * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> + * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> + * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> + +#include <asm/mipsregs.h> +#include <asm/mach-ralink/ralink_regs.h> +#include <asm/mach-ralink/rt288x.h> +#include <asm/mach-ralink/pinmux.h> + +#include "common.h" + +static struct rt2880_pmx_func i2c_func[] = { FUNC("i2c", 0, 1, 2) }; +static struct rt2880_pmx_func spi_func[] = { FUNC("spi", 0, 3, 4) }; +static struct rt2880_pmx_func uartlite_func[] = { FUNC("uartlite", 0, 7, 8) }; +static struct rt2880_pmx_func jtag_func[] = { FUNC("jtag", 0, 17, 5) }; +static struct rt2880_pmx_func mdio_func[] = { FUNC("mdio", 0, 22, 2) }; +static struct rt2880_pmx_func sdram_func[] = { FUNC("sdram", 0, 24, 16) }; +static struct rt2880_pmx_func pci_func[] = { FUNC("pci", 0, 40, 32) }; + +static struct rt2880_pmx_group rt2880_pinmux_data_act[] = { + GRP("i2c", i2c_func, 1, RT2880_GPIO_MODE_I2C), + GRP("spi", spi_func, 1, RT2880_GPIO_MODE_SPI), + GRP("uartlite", uartlite_func, 1, RT2880_GPIO_MODE_UART0), + GRP("jtag", jtag_func, 1, RT2880_GPIO_MODE_JTAG), + GRP("mdio", mdio_func, 1, RT2880_GPIO_MODE_MDIO), + GRP("sdram", sdram_func, 1, RT2880_GPIO_MODE_SDRAM), + GRP("pci", pci_func, 1, RT2880_GPIO_MODE_PCI), + { 0 } +}; + +static void rt288x_wdt_reset(void) +{ + u32 t; + + /* enable WDT reset output on pin SRAM_CS_N */ + t = rt_sysc_r32(SYSC_REG_CLKCFG); + t |= CLKCFG_SRAM_CS_N_WDT; + rt_sysc_w32(t, SYSC_REG_CLKCFG); +} + +void __init ralink_clk_init(void) +{ + unsigned long cpu_rate, wmac_rate = 40000000; + u32 t = rt_sysc_r32(SYSC_REG_SYSTEM_CONFIG); + t = ((t >> SYSTEM_CONFIG_CPUCLK_SHIFT) & SYSTEM_CONFIG_CPUCLK_MASK); + + switch (t) { + case SYSTEM_CONFIG_CPUCLK_250: + cpu_rate = 250000000; + break; + case SYSTEM_CONFIG_CPUCLK_266: + cpu_rate = 266666667; + break; + case SYSTEM_CONFIG_CPUCLK_280: + cpu_rate = 280000000; + break; + case SYSTEM_CONFIG_CPUCLK_300: + cpu_rate = 300000000; + break; + } + + ralink_clk_add("cpu", cpu_rate); + ralink_clk_add("300100.timer", cpu_rate / 2); + ralink_clk_add("300120.watchdog", cpu_rate / 2); + ralink_clk_add("300500.uart", cpu_rate / 2); + ralink_clk_add("300c00.uartlite", cpu_rate / 2); + ralink_clk_add("400000.ethernet", cpu_rate / 2); + ralink_clk_add("480000.wmac", wmac_rate); +} + +void __init ralink_of_remap(void) +{ + rt_sysc_membase = plat_of_remap_node("ralink,rt2880-sysc"); + rt_memc_membase = plat_of_remap_node("ralink,rt2880-memc"); + + if (!rt_sysc_membase || !rt_memc_membase) + panic("Failed to remap core resources"); +} + +void prom_soc_init(struct ralink_soc_info *soc_info) +{ + void __iomem *sysc = (void __iomem *) KSEG1ADDR(RT2880_SYSC_BASE); + const char *name; + u32 n0; + u32 n1; + u32 id; + + n0 = __raw_readl(sysc + SYSC_REG_CHIP_NAME0); + n1 = __raw_readl(sysc + SYSC_REG_CHIP_NAME1); + id = __raw_readl(sysc + SYSC_REG_CHIP_ID); + + if (n0 == RT2880_CHIP_NAME0 && n1 == RT2880_CHIP_NAME1) { + soc_info->compatible = "ralink,r2880-soc"; + name = "RT2880"; + } else { + panic("rt288x: unknown SoC, n0:%08x n1:%08x", n0, n1); + } + + snprintf(soc_info->sys_type, RAMIPS_SYS_TYPE_LEN, + "Ralink %s id:%u rev:%u", + name, + (id >> CHIP_ID_ID_SHIFT) & CHIP_ID_ID_MASK, + (id & CHIP_ID_REV_MASK)); + + soc_info->mem_base = RT2880_SDRAM_BASE; + soc_info->mem_size_min = RT2880_MEM_SIZE_MIN; + soc_info->mem_size_max = RT2880_MEM_SIZE_MAX; + + rt2880_pinmux_data = rt2880_pinmux_data_act; +} diff --git a/arch/mips/ralink/rt305x.c b/arch/mips/ralink/rt305x.c new file mode 100644 index 000000000..c40776ab6 --- /dev/null +++ b/arch/mips/ralink/rt305x.c @@ -0,0 +1,283 @@ +/* + * 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. + * + * Parts of this file are based on Ralink's 2.6.21 BSP + * + * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> + * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> + * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> + +#include <asm/mipsregs.h> +#include <asm/mach-ralink/ralink_regs.h> +#include <asm/mach-ralink/rt305x.h> +#include <asm/mach-ralink/pinmux.h> + +#include "common.h" + +enum rt305x_soc_type rt305x_soc; + +static struct rt2880_pmx_func i2c_func[] = { FUNC("i2c", 0, 1, 2) }; +static struct rt2880_pmx_func spi_func[] = { FUNC("spi", 0, 3, 4) }; +static struct rt2880_pmx_func uartf_func[] = { + FUNC("uartf", RT305X_GPIO_MODE_UARTF, 7, 8), + FUNC("pcm uartf", RT305X_GPIO_MODE_PCM_UARTF, 7, 8), + FUNC("pcm i2s", RT305X_GPIO_MODE_PCM_I2S, 7, 8), + FUNC("i2s uartf", RT305X_GPIO_MODE_I2S_UARTF, 7, 8), + FUNC("pcm gpio", RT305X_GPIO_MODE_PCM_GPIO, 11, 4), + FUNC("gpio uartf", RT305X_GPIO_MODE_GPIO_UARTF, 7, 4), + FUNC("gpio i2s", RT305X_GPIO_MODE_GPIO_I2S, 7, 4), +}; +static struct rt2880_pmx_func uartlite_func[] = { FUNC("uartlite", 0, 15, 2) }; +static struct rt2880_pmx_func jtag_func[] = { FUNC("jtag", 0, 17, 5) }; +static struct rt2880_pmx_func mdio_func[] = { FUNC("mdio", 0, 22, 2) }; +static struct rt2880_pmx_func rt5350_led_func[] = { FUNC("led", 0, 22, 5) }; +static struct rt2880_pmx_func rt5350_cs1_func[] = { + FUNC("spi_cs1", 0, 27, 1), + FUNC("wdg_cs1", 1, 27, 1), +}; +static struct rt2880_pmx_func sdram_func[] = { FUNC("sdram", 0, 24, 16) }; +static struct rt2880_pmx_func rt3352_rgmii_func[] = { + FUNC("rgmii", 0, 24, 12) +}; +static struct rt2880_pmx_func rgmii_func[] = { FUNC("rgmii", 0, 40, 12) }; +static struct rt2880_pmx_func rt3352_lna_func[] = { FUNC("lna", 0, 36, 2) }; +static struct rt2880_pmx_func rt3352_pa_func[] = { FUNC("pa", 0, 38, 2) }; +static struct rt2880_pmx_func rt3352_led_func[] = { FUNC("led", 0, 40, 5) }; + +static struct rt2880_pmx_group rt3050_pinmux_data[] = { + GRP("i2c", i2c_func, 1, RT305X_GPIO_MODE_I2C), + GRP("spi", spi_func, 1, RT305X_GPIO_MODE_SPI), + GRP("uartf", uartf_func, RT305X_GPIO_MODE_UART0_MASK, + RT305X_GPIO_MODE_UART0_SHIFT), + GRP("uartlite", uartlite_func, 1, RT305X_GPIO_MODE_UART1), + GRP("jtag", jtag_func, 1, RT305X_GPIO_MODE_JTAG), + GRP("mdio", mdio_func, 1, RT305X_GPIO_MODE_MDIO), + GRP("rgmii", rgmii_func, 1, RT305X_GPIO_MODE_RGMII), + GRP("sdram", sdram_func, 1, RT305X_GPIO_MODE_SDRAM), + { 0 } +}; + +static struct rt2880_pmx_group rt3352_pinmux_data[] = { + GRP("i2c", i2c_func, 1, RT305X_GPIO_MODE_I2C), + GRP("spi", spi_func, 1, RT305X_GPIO_MODE_SPI), + GRP("uartf", uartf_func, RT305X_GPIO_MODE_UART0_MASK, + RT305X_GPIO_MODE_UART0_SHIFT), + GRP("uartlite", uartlite_func, 1, RT305X_GPIO_MODE_UART1), + GRP("jtag", jtag_func, 1, RT305X_GPIO_MODE_JTAG), + GRP("mdio", mdio_func, 1, RT305X_GPIO_MODE_MDIO), + GRP("rgmii", rt3352_rgmii_func, 1, RT305X_GPIO_MODE_RGMII), + GRP("lna", rt3352_lna_func, 1, RT3352_GPIO_MODE_LNA), + GRP("pa", rt3352_pa_func, 1, RT3352_GPIO_MODE_PA), + GRP("led", rt3352_led_func, 1, RT5350_GPIO_MODE_PHY_LED), + { 0 } +}; + +static struct rt2880_pmx_group rt5350_pinmux_data[] = { + GRP("i2c", i2c_func, 1, RT305X_GPIO_MODE_I2C), + GRP("spi", spi_func, 1, RT305X_GPIO_MODE_SPI), + GRP("uartf", uartf_func, RT305X_GPIO_MODE_UART0_MASK, + RT305X_GPIO_MODE_UART0_SHIFT), + GRP("uartlite", uartlite_func, 1, RT305X_GPIO_MODE_UART1), + GRP("jtag", jtag_func, 1, RT305X_GPIO_MODE_JTAG), + GRP("led", rt5350_led_func, 1, RT5350_GPIO_MODE_PHY_LED), + GRP("spi_cs1", rt5350_cs1_func, 2, RT5350_GPIO_MODE_SPI_CS1), + { 0 } +}; + +static void rt305x_wdt_reset(void) +{ + u32 t; + + /* enable WDT reset output on pin SRAM_CS_N */ + t = rt_sysc_r32(SYSC_REG_SYSTEM_CONFIG); + t |= RT305X_SYSCFG_SRAM_CS0_MODE_WDT << + RT305X_SYSCFG_SRAM_CS0_MODE_SHIFT; + rt_sysc_w32(t, SYSC_REG_SYSTEM_CONFIG); +} + +static unsigned long rt5350_get_mem_size(void) +{ + void __iomem *sysc = (void __iomem *) KSEG1ADDR(RT305X_SYSC_BASE); + unsigned long ret; + u32 t; + + t = __raw_readl(sysc + SYSC_REG_SYSTEM_CONFIG); + t = (t >> RT5350_SYSCFG0_DRAM_SIZE_SHIFT) & + RT5350_SYSCFG0_DRAM_SIZE_MASK; + + switch (t) { + case RT5350_SYSCFG0_DRAM_SIZE_2M: + ret = 2; + break; + case RT5350_SYSCFG0_DRAM_SIZE_8M: + ret = 8; + break; + case RT5350_SYSCFG0_DRAM_SIZE_16M: + ret = 16; + break; + case RT5350_SYSCFG0_DRAM_SIZE_32M: + ret = 32; + break; + case RT5350_SYSCFG0_DRAM_SIZE_64M: + ret = 64; + break; + default: + panic("rt5350: invalid DRAM size: %u", t); + break; + } + + return ret; +} + +void __init ralink_clk_init(void) +{ + unsigned long cpu_rate, sys_rate, wdt_rate, uart_rate; + unsigned long wmac_rate = 40000000; + + u32 t = rt_sysc_r32(SYSC_REG_SYSTEM_CONFIG); + + if (soc_is_rt305x() || soc_is_rt3350()) { + t = (t >> RT305X_SYSCFG_CPUCLK_SHIFT) & + RT305X_SYSCFG_CPUCLK_MASK; + switch (t) { + case RT305X_SYSCFG_CPUCLK_LOW: + cpu_rate = 320000000; + break; + case RT305X_SYSCFG_CPUCLK_HIGH: + cpu_rate = 384000000; + break; + } + sys_rate = uart_rate = wdt_rate = cpu_rate / 3; + } else if (soc_is_rt3352()) { + t = (t >> RT3352_SYSCFG0_CPUCLK_SHIFT) & + RT3352_SYSCFG0_CPUCLK_MASK; + switch (t) { + case RT3352_SYSCFG0_CPUCLK_LOW: + cpu_rate = 384000000; + break; + case RT3352_SYSCFG0_CPUCLK_HIGH: + cpu_rate = 400000000; + break; + } + sys_rate = wdt_rate = cpu_rate / 3; + uart_rate = 40000000; + } else if (soc_is_rt5350()) { + t = (t >> RT5350_SYSCFG0_CPUCLK_SHIFT) & + RT5350_SYSCFG0_CPUCLK_MASK; + switch (t) { + case RT5350_SYSCFG0_CPUCLK_360: + cpu_rate = 360000000; + sys_rate = cpu_rate / 3; + break; + case RT5350_SYSCFG0_CPUCLK_320: + cpu_rate = 320000000; + sys_rate = cpu_rate / 4; + break; + case RT5350_SYSCFG0_CPUCLK_300: + cpu_rate = 300000000; + sys_rate = cpu_rate / 3; + break; + default: + BUG(); + } + uart_rate = 40000000; + wdt_rate = sys_rate; + } else { + BUG(); + } + + if (soc_is_rt3352() || soc_is_rt5350()) { + u32 val = rt_sysc_r32(RT3352_SYSC_REG_SYSCFG0); + + if (!(val & RT3352_CLKCFG0_XTAL_SEL)) + wmac_rate = 20000000; + } + + ralink_clk_add("cpu", cpu_rate); + ralink_clk_add("10000b00.spi", sys_rate); + ralink_clk_add("10000100.timer", wdt_rate); + ralink_clk_add("10000120.watchdog", wdt_rate); + ralink_clk_add("10000500.uart", uart_rate); + ralink_clk_add("10000c00.uartlite", uart_rate); + ralink_clk_add("10100000.ethernet", sys_rate); + ralink_clk_add("10180000.wmac", wmac_rate); +} + +void __init ralink_of_remap(void) +{ + rt_sysc_membase = plat_of_remap_node("ralink,rt3050-sysc"); + rt_memc_membase = plat_of_remap_node("ralink,rt3050-memc"); + + if (!rt_sysc_membase || !rt_memc_membase) + panic("Failed to remap core resources"); +} + +void prom_soc_init(struct ralink_soc_info *soc_info) +{ + void __iomem *sysc = (void __iomem *) KSEG1ADDR(RT305X_SYSC_BASE); + unsigned char *name; + u32 n0; + u32 n1; + u32 id; + + n0 = __raw_readl(sysc + SYSC_REG_CHIP_NAME0); + n1 = __raw_readl(sysc + SYSC_REG_CHIP_NAME1); + + if (n0 == RT3052_CHIP_NAME0 && n1 == RT3052_CHIP_NAME1) { + unsigned long icache_sets; + + icache_sets = (read_c0_config1() >> 22) & 7; + if (icache_sets == 1) { + rt305x_soc = RT305X_SOC_RT3050; + name = "RT3050"; + soc_info->compatible = "ralink,rt3050-soc"; + } else { + rt305x_soc = RT305X_SOC_RT3052; + name = "RT3052"; + soc_info->compatible = "ralink,rt3052-soc"; + } + } else if (n0 == RT3350_CHIP_NAME0 && n1 == RT3350_CHIP_NAME1) { + rt305x_soc = RT305X_SOC_RT3350; + name = "RT3350"; + soc_info->compatible = "ralink,rt3350-soc"; + } else if (n0 == RT3352_CHIP_NAME0 && n1 == RT3352_CHIP_NAME1) { + rt305x_soc = RT305X_SOC_RT3352; + name = "RT3352"; + soc_info->compatible = "ralink,rt3352-soc"; + } else if (n0 == RT5350_CHIP_NAME0 && n1 == RT5350_CHIP_NAME1) { + rt305x_soc = RT305X_SOC_RT5350; + name = "RT5350"; + soc_info->compatible = "ralink,rt5350-soc"; + } else { + panic("rt305x: unknown SoC, n0:%08x n1:%08x", n0, n1); + } + + id = __raw_readl(sysc + SYSC_REG_CHIP_ID); + + snprintf(soc_info->sys_type, RAMIPS_SYS_TYPE_LEN, + "Ralink %s id:%u rev:%u", + name, + (id >> CHIP_ID_ID_SHIFT) & CHIP_ID_ID_MASK, + (id & CHIP_ID_REV_MASK)); + + soc_info->mem_base = RT305X_SDRAM_BASE; + if (soc_is_rt5350()) { + soc_info->mem_size = rt5350_get_mem_size(); + rt2880_pinmux_data = rt5350_pinmux_data; + } else if (soc_is_rt305x() || soc_is_rt3350()) { + soc_info->mem_size_min = RT305X_MEM_SIZE_MIN; + soc_info->mem_size_max = RT305X_MEM_SIZE_MAX; + rt2880_pinmux_data = rt3050_pinmux_data; + } else if (soc_is_rt3352()) { + soc_info->mem_size_min = RT3352_MEM_SIZE_MIN; + soc_info->mem_size_max = RT3352_MEM_SIZE_MAX; + rt2880_pinmux_data = rt3352_pinmux_data; + } +} diff --git a/arch/mips/ralink/rt3883.c b/arch/mips/ralink/rt3883.c new file mode 100644 index 000000000..86a535c77 --- /dev/null +++ b/arch/mips/ralink/rt3883.c @@ -0,0 +1,156 @@ +/* + * 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. + * + * Parts of this file are based on Ralink's 2.6.21 BSP + * + * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> + * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> + * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> + +#include <asm/mipsregs.h> +#include <asm/mach-ralink/ralink_regs.h> +#include <asm/mach-ralink/rt3883.h> +#include <asm/mach-ralink/pinmux.h> + +#include "common.h" + +static struct rt2880_pmx_func i2c_func[] = { FUNC("i2c", 0, 1, 2) }; +static struct rt2880_pmx_func spi_func[] = { FUNC("spi", 0, 3, 4) }; +static struct rt2880_pmx_func uartf_func[] = { + FUNC("uartf", RT3883_GPIO_MODE_UARTF, 7, 8), + FUNC("pcm uartf", RT3883_GPIO_MODE_PCM_UARTF, 7, 8), + FUNC("pcm i2s", RT3883_GPIO_MODE_PCM_I2S, 7, 8), + FUNC("i2s uartf", RT3883_GPIO_MODE_I2S_UARTF, 7, 8), + FUNC("pcm gpio", RT3883_GPIO_MODE_PCM_GPIO, 11, 4), + FUNC("gpio uartf", RT3883_GPIO_MODE_GPIO_UARTF, 7, 4), + FUNC("gpio i2s", RT3883_GPIO_MODE_GPIO_I2S, 7, 4), +}; +static struct rt2880_pmx_func uartlite_func[] = { FUNC("uartlite", 0, 15, 2) }; +static struct rt2880_pmx_func jtag_func[] = { FUNC("jtag", 0, 17, 5) }; +static struct rt2880_pmx_func mdio_func[] = { FUNC("mdio", 0, 22, 2) }; +static struct rt2880_pmx_func lna_a_func[] = { FUNC("lna a", 0, 32, 3) }; +static struct rt2880_pmx_func lna_g_func[] = { FUNC("lna a", 0, 35, 3) }; +static struct rt2880_pmx_func pci_func[] = { + FUNC("pci-dev", 0, 40, 32), + FUNC("pci-host2", 1, 40, 32), + FUNC("pci-host1", 2, 40, 32), + FUNC("pci-fnc", 3, 40, 32) +}; +static struct rt2880_pmx_func ge1_func[] = { FUNC("ge1", 0, 72, 12) }; +static struct rt2880_pmx_func ge2_func[] = { FUNC("ge1", 0, 84, 12) }; + +static struct rt2880_pmx_group rt3883_pinmux_data[] = { + GRP("i2c", i2c_func, 1, RT3883_GPIO_MODE_I2C), + GRP("spi", spi_func, 1, RT3883_GPIO_MODE_SPI), + GRP("uartf", uartf_func, RT3883_GPIO_MODE_UART0_MASK, + RT3883_GPIO_MODE_UART0_SHIFT), + GRP("uartlite", uartlite_func, 1, RT3883_GPIO_MODE_UART1), + GRP("jtag", jtag_func, 1, RT3883_GPIO_MODE_JTAG), + GRP("mdio", mdio_func, 1, RT3883_GPIO_MODE_MDIO), + GRP("lna a", lna_a_func, 1, RT3883_GPIO_MODE_LNA_A), + GRP("lna g", lna_g_func, 1, RT3883_GPIO_MODE_LNA_G), + GRP("pci", pci_func, RT3883_GPIO_MODE_PCI_MASK, + RT3883_GPIO_MODE_PCI_SHIFT), + GRP("ge1", ge1_func, 1, RT3883_GPIO_MODE_GE1), + GRP("ge2", ge2_func, 1, RT3883_GPIO_MODE_GE2), + { 0 } +}; + +static void rt3883_wdt_reset(void) +{ + u32 t; + + /* enable WDT reset output on GPIO 2 */ + t = rt_sysc_r32(RT3883_SYSC_REG_SYSCFG1); + t |= RT3883_SYSCFG1_GPIO2_AS_WDT_OUT; + rt_sysc_w32(t, RT3883_SYSC_REG_SYSCFG1); +} + +void __init ralink_clk_init(void) +{ + unsigned long cpu_rate, sys_rate; + u32 syscfg0; + u32 clksel; + u32 ddr2; + + syscfg0 = rt_sysc_r32(RT3883_SYSC_REG_SYSCFG0); + clksel = ((syscfg0 >> RT3883_SYSCFG0_CPUCLK_SHIFT) & + RT3883_SYSCFG0_CPUCLK_MASK); + ddr2 = syscfg0 & RT3883_SYSCFG0_DRAM_TYPE_DDR2; + + switch (clksel) { + case RT3883_SYSCFG0_CPUCLK_250: + cpu_rate = 250000000; + sys_rate = (ddr2) ? 125000000 : 83000000; + break; + case RT3883_SYSCFG0_CPUCLK_384: + cpu_rate = 384000000; + sys_rate = (ddr2) ? 128000000 : 96000000; + break; + case RT3883_SYSCFG0_CPUCLK_480: + cpu_rate = 480000000; + sys_rate = (ddr2) ? 160000000 : 120000000; + break; + case RT3883_SYSCFG0_CPUCLK_500: + cpu_rate = 500000000; + sys_rate = (ddr2) ? 166000000 : 125000000; + break; + } + + ralink_clk_add("cpu", cpu_rate); + ralink_clk_add("10000100.timer", sys_rate); + ralink_clk_add("10000120.watchdog", sys_rate); + ralink_clk_add("10000500.uart", 40000000); + ralink_clk_add("10000b00.spi", sys_rate); + ralink_clk_add("10000c00.uartlite", 40000000); + ralink_clk_add("10100000.ethernet", sys_rate); + ralink_clk_add("10180000.wmac", 40000000); +} + +void __init ralink_of_remap(void) +{ + rt_sysc_membase = plat_of_remap_node("ralink,rt3883-sysc"); + rt_memc_membase = plat_of_remap_node("ralink,rt3883-memc"); + + if (!rt_sysc_membase || !rt_memc_membase) + panic("Failed to remap core resources"); +} + +void prom_soc_init(struct ralink_soc_info *soc_info) +{ + void __iomem *sysc = (void __iomem *) KSEG1ADDR(RT3883_SYSC_BASE); + const char *name; + u32 n0; + u32 n1; + u32 id; + + n0 = __raw_readl(sysc + RT3883_SYSC_REG_CHIPID0_3); + n1 = __raw_readl(sysc + RT3883_SYSC_REG_CHIPID4_7); + id = __raw_readl(sysc + RT3883_SYSC_REG_REVID); + + if (n0 == RT3883_CHIP_NAME0 && n1 == RT3883_CHIP_NAME1) { + soc_info->compatible = "ralink,rt3883-soc"; + name = "RT3883"; + } else { + panic("rt3883: unknown SoC, n0:%08x n1:%08x", n0, n1); + } + + snprintf(soc_info->sys_type, RAMIPS_SYS_TYPE_LEN, + "Ralink %s ver:%u eco:%u", + name, + (id >> RT3883_REVID_VER_ID_SHIFT) & RT3883_REVID_VER_ID_MASK, + (id & RT3883_REVID_ECO_ID_MASK)); + + soc_info->mem_base = RT3883_SDRAM_BASE; + soc_info->mem_size_min = RT3883_MEM_SIZE_MIN; + soc_info->mem_size_max = RT3883_MEM_SIZE_MAX; + + rt2880_pinmux_data = rt3883_pinmux_data; +} diff --git a/arch/mips/ralink/timer.c b/arch/mips/ralink/timer.c new file mode 100644 index 000000000..82c72a15b --- /dev/null +++ b/arch/mips/ralink/timer.c @@ -0,0 +1,184 @@ +/* + * 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) 2013 John Crispin <blogic@openwrt.org> +*/ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/timer.h> +#include <linux/of_gpio.h> +#include <linux/clk.h> + +#include <asm/mach-ralink/ralink_regs.h> + +#define TIMER_REG_TMRSTAT 0x00 +#define TIMER_REG_TMR0LOAD 0x10 +#define TIMER_REG_TMR0CTL 0x18 + +#define TMRSTAT_TMR0INT BIT(0) + +#define TMR0CTL_ENABLE BIT(7) +#define TMR0CTL_MODE_PERIODIC BIT(4) +#define TMR0CTL_PRESCALER 1 +#define TMR0CTL_PRESCALE_VAL (0xf - TMR0CTL_PRESCALER) +#define TMR0CTL_PRESCALE_DIV (65536 / BIT(TMR0CTL_PRESCALER)) + +struct rt_timer { + struct device *dev; + void __iomem *membase; + int irq; + unsigned long timer_freq; + unsigned long timer_div; +}; + +static inline void rt_timer_w32(struct rt_timer *rt, u8 reg, u32 val) +{ + __raw_writel(val, rt->membase + reg); +} + +static inline u32 rt_timer_r32(struct rt_timer *rt, u8 reg) +{ + return __raw_readl(rt->membase + reg); +} + +static irqreturn_t rt_timer_irq(int irq, void *_rt) +{ + struct rt_timer *rt = (struct rt_timer *) _rt; + + rt_timer_w32(rt, TIMER_REG_TMR0LOAD, rt->timer_freq / rt->timer_div); + rt_timer_w32(rt, TIMER_REG_TMRSTAT, TMRSTAT_TMR0INT); + + return IRQ_HANDLED; +} + + +static int rt_timer_request(struct rt_timer *rt) +{ + int err = request_irq(rt->irq, rt_timer_irq, 0, + dev_name(rt->dev), rt); + if (err) { + dev_err(rt->dev, "failed to request irq\n"); + } else { + u32 t = TMR0CTL_MODE_PERIODIC | TMR0CTL_PRESCALE_VAL; + rt_timer_w32(rt, TIMER_REG_TMR0CTL, t); + } + return err; +} + +static void rt_timer_free(struct rt_timer *rt) +{ + free_irq(rt->irq, rt); +} + +static int rt_timer_config(struct rt_timer *rt, unsigned long divisor) +{ + if (rt->timer_freq < divisor) + rt->timer_div = rt->timer_freq; + else + rt->timer_div = divisor; + + rt_timer_w32(rt, TIMER_REG_TMR0LOAD, rt->timer_freq / rt->timer_div); + + return 0; +} + +static int rt_timer_enable(struct rt_timer *rt) +{ + u32 t; + + rt_timer_w32(rt, TIMER_REG_TMR0LOAD, rt->timer_freq / rt->timer_div); + + t = rt_timer_r32(rt, TIMER_REG_TMR0CTL); + t |= TMR0CTL_ENABLE; + rt_timer_w32(rt, TIMER_REG_TMR0CTL, t); + + return 0; +} + +static void rt_timer_disable(struct rt_timer *rt) +{ + u32 t; + + t = rt_timer_r32(rt, TIMER_REG_TMR0CTL); + t &= ~TMR0CTL_ENABLE; + rt_timer_w32(rt, TIMER_REG_TMR0CTL, t); +} + +static int rt_timer_probe(struct platform_device *pdev) +{ + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + struct rt_timer *rt; + struct clk *clk; + + rt = devm_kzalloc(&pdev->dev, sizeof(*rt), GFP_KERNEL); + if (!rt) { + dev_err(&pdev->dev, "failed to allocate memory\n"); + return -ENOMEM; + } + + rt->irq = platform_get_irq(pdev, 0); + if (!rt->irq) { + dev_err(&pdev->dev, "failed to load irq\n"); + return -ENOENT; + } + + rt->membase = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(rt->membase)) + return PTR_ERR(rt->membase); + + clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "failed get clock rate\n"); + return PTR_ERR(clk); + } + + rt->timer_freq = clk_get_rate(clk) / TMR0CTL_PRESCALE_DIV; + if (!rt->timer_freq) + return -EINVAL; + + rt->dev = &pdev->dev; + platform_set_drvdata(pdev, rt); + + rt_timer_request(rt); + rt_timer_config(rt, 2); + rt_timer_enable(rt); + + dev_info(&pdev->dev, "maximum frequency is %luHz\n", rt->timer_freq); + + return 0; +} + +static int rt_timer_remove(struct platform_device *pdev) +{ + struct rt_timer *rt = platform_get_drvdata(pdev); + + rt_timer_disable(rt); + rt_timer_free(rt); + + return 0; +} + +static const struct of_device_id rt_timer_match[] = { + { .compatible = "ralink,rt2880-timer" }, + {}, +}; +MODULE_DEVICE_TABLE(of, rt_timer_match); + +static struct platform_driver rt_timer_driver = { + .probe = rt_timer_probe, + .remove = rt_timer_remove, + .driver = { + .name = "rt-timer", + .of_match_table = rt_timer_match + }, +}; + +module_platform_driver(rt_timer_driver); + +MODULE_DESCRIPTION("Ralink RT2880 timer"); +MODULE_AUTHOR("John Crispin <blogic@openwrt.org"); +MODULE_LICENSE("GPL"); |