diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-06 01:02:30 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-06 01:02:30 +0000 |
commit | 76cb841cb886eef6b3bee341a2266c76578724ad (patch) | |
tree | f5892e5ba6cc11949952a6ce4ecbe6d516d6ce58 /arch/mips/ralink | |
parent | Initial commit. (diff) | |
download | linux-76cb841cb886eef6b3bee341a2266c76578724ad.tar.xz linux-76cb841cb886eef6b3bee341a2266c76578724ad.zip |
Adding upstream version 4.19.249.upstream/4.19.249upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'arch/mips/ralink')
-rw-r--r-- | arch/mips/ralink/Kconfig | 98 | ||||
-rw-r--r-- | arch/mips/ralink/Makefile | 30 | ||||
-rw-r--r-- | arch/mips/ralink/Platform | 34 | ||||
-rw-r--r-- | arch/mips/ralink/bootrom.c | 48 | ||||
-rw-r--r-- | arch/mips/ralink/cevt-rt3352.c | 155 | ||||
-rw-r--r-- | arch/mips/ralink/clk.c | 89 | ||||
-rw-r--r-- | arch/mips/ralink/common.h | 36 | ||||
-rw-r--r-- | arch/mips/ralink/early_printk.c | 90 | ||||
-rw-r--r-- | arch/mips/ralink/ill_acc.c | 87 | ||||
-rw-r--r-- | arch/mips/ralink/irq-gic.c | 25 | ||||
-rw-r--r-- | arch/mips/ralink/irq.c | 206 | ||||
-rw-r--r-- | arch/mips/ralink/mt7620.c | 720 | ||||
-rw-r--r-- | arch/mips/ralink/mt7621.c | 226 | ||||
-rw-r--r-- | arch/mips/ralink/of.c | 109 | ||||
-rw-r--r-- | arch/mips/ralink/prom.c | 74 | ||||
-rw-r--r-- | arch/mips/ralink/reset.c | 106 | ||||
-rw-r--r-- | arch/mips/ralink/rt288x.c | 113 | ||||
-rw-r--r-- | arch/mips/ralink/rt305x.c | 275 | ||||
-rw-r--r-- | arch/mips/ralink/rt3883.c | 150 | ||||
-rw-r--r-- | arch/mips/ralink/timer-gic.c | 24 | ||||
-rw-r--r-- | arch/mips/ralink/timer.c | 156 |
21 files changed, 2851 insertions, 0 deletions
diff --git a/arch/mips/ralink/Kconfig b/arch/mips/ralink/Kconfig new file mode 100644 index 000000000..613d61763 --- /dev/null +++ b/arch/mips/ralink/Kconfig @@ -0,0 +1,98 @@ +# SPDX-License-Identifier: GPL-2.0 +if RALINK + +config CLKEVT_RT3352 + bool + depends on SOC_RT305X || SOC_MT7620 + default y + select TIMER_OF + select CLKSRC_MMIO + +config RALINK_ILL_ACC + bool + depends on SOC_RT305X + default y + +config IRQ_INTC + bool + default y + depends on !SOC_MT7621 + +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" + + config SOC_RT3883 + bool "RT3883" + select HW_HAS_PCI + + config SOC_MT7620 + bool "MT7620/8" + select CPU_MIPSR2_IRQ_VI + select HW_HAS_PCI + + config SOC_MT7621 + bool "MT7621" + select MIPS_CPU_SCACHE + select SYS_SUPPORTS_MULTITHREADING + select SYS_SUPPORTS_SMP + select SYS_SUPPORTS_MIPS_CPS + select SYS_SUPPORTS_HIGHMEM + select MIPS_GIC + select COMMON_CLK + select CLKSRC_MIPS_GIC + select HW_HAS_PCI +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 + + config DTB_OMEGA2P + bool "Onion Omega2+" + depends on SOC_MT7620 + select BUILTIN_DTB + + config DTB_VOCORE2 + bool "VoCore2" + 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..fe3471533 --- /dev/null +++ b/arch/mips/ralink/Makefile @@ -0,0 +1,30 @@ +# 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 <john@phrozen.org> + +obj-y := prom.o of.o reset.o + +ifndef CONFIG_MIPS_GIC + obj-y += clk.o timer.o +endif + +obj-$(CONFIG_CLKEVT_RT3352) += cevt-rt3352.o + +obj-$(CONFIG_RALINK_ILL_ACC) += ill_acc.o + +obj-$(CONFIG_IRQ_INTC) += irq.o +obj-$(CONFIG_MIPS_GIC) += irq-gic.o timer-gic.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_SOC_MT7621) += mt7621.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..6095fcc33 --- /dev/null +++ b/arch/mips/ralink/Platform @@ -0,0 +1,34 @@ +# +# 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 + +# Ralink MT7621 +# +load-$(CONFIG_SOC_MT7621) += 0xffffffff80001000 +cflags-$(CONFIG_SOC_MT7621) += -I$(srctree)/arch/mips/include/asm/mach-ralink/mt7621 diff --git a/arch/mips/ralink/bootrom.c b/arch/mips/ralink/bootrom.c new file mode 100644 index 000000000..e1fa5972a --- /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 <john@phrozen.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..92f284d2b --- /dev/null +++ b/arch/mips/ralink/cevt-rt3352.c @@ -0,0 +1,155 @@ +/* + * 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 <john@phrozen.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 int systick_set_oneshot(struct clock_event_device *evt); +static int systick_shutdown(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, 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_state_shutdown = systick_shutdown, + .set_state_oneshot = systick_set_oneshot, + .event_handler = systick_event_handler, + }, +}; + +static struct irqaction systick_irqaction = { + .handler = systick_interrupt, + .flags = IRQF_PERCPU | IRQF_TIMER, + .dev_id = &systick.dev, +}; + +static int systick_shutdown(struct clock_event_device *evt) +{ + struct systick_device *sdev; + + sdev = container_of(evt, struct systick_device, dev); + + if (sdev->irq_requested) + free_irq(systick.dev.irq, &systick_irqaction); + sdev->irq_requested = 0; + iowrite32(0, systick.membase + SYSTICK_CONFIG); + + return 0; +} + +static int systick_set_oneshot(struct clock_event_device *evt) +{ + struct systick_device *sdev; + + sdev = container_of(evt, struct systick_device, dev); + + 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); + + return 0; +} + +static int __init ralink_systick_init(struct device_node *np) +{ + int ret; + + systick.membase = of_iomap(np, 0); + if (!systick.membase) + return -ENXIO; + + 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.max_delta_ticks = 0x7fff; + systick.dev.min_delta_ns = clockevent_delta2ns(0x3, &systick.dev); + systick.dev.min_delta_ticks = 0x3; + systick.dev.irq = irq_of_parse_and_map(np, 0); + if (!systick.dev.irq) { + pr_err("%s: request_irq failed", np->name); + return -EINVAL; + } + + ret = clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name, + SYSTICK_FREQ, 301, 16, + clocksource_mmio_readl_up); + if (ret) + return ret; + + clockevents_register_device(&systick.dev); + + pr_info("%s: running - mult: %d, shift: %d\n", + np->name, systick.dev.mult, systick.dev.shift); + + return 0; +} + +TIMER_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..1b7df115e --- /dev/null +++ b/arch/mips/ralink/clk.c @@ -0,0 +1,89 @@ +/* + * 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 <john@phrozen.org> + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/export.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) +{ + if (!clk) + return 0; + + 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); + +long clk_round_rate(struct clk *clk, unsigned long rate) +{ + return -1; +} +EXPORT_SYMBOL_GPL(clk_round_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); + timer_probe(); +} diff --git a/arch/mips/ralink/common.h b/arch/mips/ralink/common.h new file mode 100644 index 000000000..b8245d094 --- /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 <john@phrozen.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..ecd30ddfb --- /dev/null +++ b/arch/mips/ralink/early_printk.c @@ -0,0 +1,90 @@ +/* + * 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> +#include <asm/setup.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_LCR 0x0c +#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 int init_complete; + +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); +} + +static void find_uart_base(void) +{ + int i; + + if (!soc_is_mt7628()) + return; + + for (i = 0; i < 3; i++) { + u32 reg = uart_r32(UART_REG_LCR + (0x100 * i)); + + if (!reg) + continue; + + uart_membase = (__iomem void *) KSEG1ADDR(EARLY_UART_BASE + + (0x100 * i)); + break; + } +} + +void prom_putchar(char ch) +{ + if (!init_complete) { + find_uart_base(); + init_complete = 1; + } + + if (IS_ENABLED(CONFIG_SOC_MT7621) || soc_is_mt7628()) { + uart_w32((unsigned char)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((unsigned char)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..765d5ba98 --- /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 <john@phrozen.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-gic.c b/arch/mips/ralink/irq-gic.c new file mode 100644 index 000000000..bda576f2c --- /dev/null +++ b/arch/mips/ralink/irq-gic.c @@ -0,0 +1,25 @@ +/* + * 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) 2015 Nikolay Martynov <mar.kolya@gmail.com> + * Copyright (C) 2015 John Crispin <john@phrozen.org> + */ + +#include <linux/init.h> + +#include <linux/of.h> +#include <linux/irqchip.h> +#include <asm/mips-cps.h> + +int get_c0_perfcount_int(void) +{ + return gic_get_c0_perfcount_int(); +} +EXPORT_SYMBOL_GPL(get_c0_perfcount_int); + +void __init arch_init_irq(void) +{ + irqchip_init(); +} diff --git a/arch/mips/ralink/irq.c b/arch/mips/ralink/irq.c new file mode 100644 index 000000000..9b478c95a --- /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 <john@phrozen.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; +} +EXPORT_SYMBOL_GPL(get_c0_perfcount_int); + +unsigned int get_c0_compare_int(void) +{ + return CP0_LEGACY_COMPARE_IRQ; +} + +static void ralink_intc_irq_handler(struct irq_desc *desc) +{ + u32 pending = rt_intc_r32(INTC_REG_STATUS0); + + if (pending) { + struct irq_domain *domain = irq_desc_get_handler_data(desc); + 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)) + 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_and_data(irq, ralink_intc_irq_handler, 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..c1ce6f436 --- /dev/null +++ b/arch/mips/ralink/mt7620.c @@ -0,0 +1,720 @@ +/* + * 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 <john@phrozen.org> + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/bug.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) + +/* clock scaling */ +#define CLKCFG_FDIV_MASK 0x1f00 +#define CLKCFG_FDIV_USB_VAL 0x0300 +#define CLKCFG_FFRAC_MASK 0x001f +#define CLKCFG_FFRAC_USB_VAL 0x0003 + +/* EFUSE bits */ +#define EFUSE_MT7688 0x100000 + +/* DRAM type bit */ +#define DRAM_TYPE_MT7628_MASK 0x1 + +/* 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", MT7620_GPIO_MODE_MDIO, 22, 2), + FUNC("refclk", MT7620_GPIO_MODE_MDIO_REFCLK, 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, 47, 13) +}; + +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_G("mdio", mdio_grp, MT7620_GPIO_MODE_MDIO_MASK, + MT7620_GPIO_MODE_MDIO_GPIO, MT7620_GPIO_MODE_MDIO_SHIFT), + 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("sdxc d6", 3, 19, 1), + FUNC("utif", 2, 19, 1), + FUNC("gpio", 1, 19, 1), + FUNC("pwm1", 0, 19, 1), +}; + +static struct rt2880_pmx_func pwm0_grp_mt7628[] = { + FUNC("sdxc d7", 3, 18, 1), + FUNC("utif", 2, 18, 1), + FUNC("gpio", 1, 18, 1), + FUNC("pwm0", 0, 18, 1), +}; + +static struct rt2880_pmx_func uart2_grp_mt7628[] = { + FUNC("sdxc d5 d4", 3, 20, 2), + FUNC("pwm", 2, 20, 2), + FUNC("gpio", 1, 20, 2), + FUNC("uart2", 0, 20, 2), +}; + +static struct rt2880_pmx_func uart1_grp_mt7628[] = { + FUNC("sw_r", 3, 45, 2), + FUNC("pwm", 2, 45, 2), + FUNC("gpio", 1, 45, 2), + FUNC("uart1", 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("refclk", 0, 37, 1) }; +static struct rt2880_pmx_func perst_grp_mt7628[] = { FUNC("perst", 0, 36, 1) }; +static struct rt2880_pmx_func wdt_grp_mt7628[] = { FUNC("wdt", 0, 38, 1) }; +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("sdxc", 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("uart0", 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 cs1", 0, 6, 1), +}; + +static struct rt2880_pmx_func spis_grp_mt7628[] = { + FUNC("pwm_uart2", 3, 14, 4), + FUNC("utif", 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), +}; + +static struct rt2880_pmx_func p4led_kn_grp_mt7628[] = { + FUNC("jtag", 3, 30, 1), + FUNC("utif", 2, 30, 1), + FUNC("gpio", 1, 30, 1), + FUNC("p4led_kn", 0, 30, 1), +}; + +static struct rt2880_pmx_func p3led_kn_grp_mt7628[] = { + FUNC("jtag", 3, 31, 1), + FUNC("utif", 2, 31, 1), + FUNC("gpio", 1, 31, 1), + FUNC("p3led_kn", 0, 31, 1), +}; + +static struct rt2880_pmx_func p2led_kn_grp_mt7628[] = { + FUNC("jtag", 3, 32, 1), + FUNC("utif", 2, 32, 1), + FUNC("gpio", 1, 32, 1), + FUNC("p2led_kn", 0, 32, 1), +}; + +static struct rt2880_pmx_func p1led_kn_grp_mt7628[] = { + FUNC("jtag", 3, 33, 1), + FUNC("utif", 2, 33, 1), + FUNC("gpio", 1, 33, 1), + FUNC("p1led_kn", 0, 33, 1), +}; + +static struct rt2880_pmx_func p0led_kn_grp_mt7628[] = { + FUNC("jtag", 3, 34, 1), + FUNC("rsvd", 2, 34, 1), + FUNC("gpio", 1, 34, 1), + FUNC("p0led_kn", 0, 34, 1), +}; + +static struct rt2880_pmx_func wled_kn_grp_mt7628[] = { + FUNC("rsvd", 3, 35, 1), + FUNC("rsvd", 2, 35, 1), + FUNC("gpio", 1, 35, 1), + FUNC("wled_kn", 0, 35, 1), +}; + +static struct rt2880_pmx_func p4led_an_grp_mt7628[] = { + FUNC("jtag", 3, 39, 1), + FUNC("utif", 2, 39, 1), + FUNC("gpio", 1, 39, 1), + FUNC("p4led_an", 0, 39, 1), +}; + +static struct rt2880_pmx_func p3led_an_grp_mt7628[] = { + FUNC("jtag", 3, 40, 1), + FUNC("utif", 2, 40, 1), + FUNC("gpio", 1, 40, 1), + FUNC("p3led_an", 0, 40, 1), +}; + +static struct rt2880_pmx_func p2led_an_grp_mt7628[] = { + FUNC("jtag", 3, 41, 1), + FUNC("utif", 2, 41, 1), + FUNC("gpio", 1, 41, 1), + FUNC("p2led_an", 0, 41, 1), +}; + +static struct rt2880_pmx_func p1led_an_grp_mt7628[] = { + FUNC("jtag", 3, 42, 1), + FUNC("utif", 2, 42, 1), + FUNC("gpio", 1, 42, 1), + FUNC("p1led_an", 0, 42, 1), +}; + +static struct rt2880_pmx_func p0led_an_grp_mt7628[] = { + FUNC("jtag", 3, 43, 1), + FUNC("rsvd", 2, 43, 1), + FUNC("gpio", 1, 43, 1), + FUNC("p0led_an", 0, 43, 1), +}; + +static struct rt2880_pmx_func wled_an_grp_mt7628[] = { + FUNC("rsvd", 3, 44, 1), + FUNC("rsvd", 2, 44, 1), + FUNC("gpio", 1, 44, 1), + FUNC("wled_an", 0, 44, 1), +}; + +#define MT7628_GPIO_MODE_MASK 0x3 + +#define MT7628_GPIO_MODE_P4LED_KN 58 +#define MT7628_GPIO_MODE_P3LED_KN 56 +#define MT7628_GPIO_MODE_P2LED_KN 54 +#define MT7628_GPIO_MODE_P1LED_KN 52 +#define MT7628_GPIO_MODE_P0LED_KN 50 +#define MT7628_GPIO_MODE_WLED_KN 48 +#define MT7628_GPIO_MODE_P4LED_AN 42 +#define MT7628_GPIO_MODE_P3LED_AN 40 +#define MT7628_GPIO_MODE_P2LED_AN 38 +#define MT7628_GPIO_MODE_P1LED_AN 36 +#define MT7628_GPIO_MODE_P0LED_AN 34 +#define MT7628_GPIO_MODE_WLED_AN 32 +#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("pwm1", pwm1_grp_mt7628, MT7628_GPIO_MODE_MASK, + 1, MT7628_GPIO_MODE_PWM1), + GRP_G("pwm0", 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), + GRP_G("wled_an", wled_an_grp_mt7628, MT7628_GPIO_MODE_MASK, + 1, MT7628_GPIO_MODE_WLED_AN), + GRP_G("p0led_an", p0led_an_grp_mt7628, MT7628_GPIO_MODE_MASK, + 1, MT7628_GPIO_MODE_P0LED_AN), + GRP_G("p1led_an", p1led_an_grp_mt7628, MT7628_GPIO_MODE_MASK, + 1, MT7628_GPIO_MODE_P1LED_AN), + GRP_G("p2led_an", p2led_an_grp_mt7628, MT7628_GPIO_MODE_MASK, + 1, MT7628_GPIO_MODE_P2LED_AN), + GRP_G("p3led_an", p3led_an_grp_mt7628, MT7628_GPIO_MODE_MASK, + 1, MT7628_GPIO_MODE_P3LED_AN), + GRP_G("p4led_an", p4led_an_grp_mt7628, MT7628_GPIO_MODE_MASK, + 1, MT7628_GPIO_MODE_P4LED_AN), + GRP_G("wled_kn", wled_kn_grp_mt7628, MT7628_GPIO_MODE_MASK, + 1, MT7628_GPIO_MODE_WLED_KN), + GRP_G("p0led_kn", p0led_kn_grp_mt7628, MT7628_GPIO_MODE_MASK, + 1, MT7628_GPIO_MODE_P0LED_KN), + GRP_G("p1led_kn", p1led_kn_grp_mt7628, MT7628_GPIO_MODE_MASK, + 1, MT7628_GPIO_MODE_P1LED_KN), + GRP_G("p2led_kn", p2led_kn_grp_mt7628, MT7628_GPIO_MODE_MASK, + 1, MT7628_GPIO_MODE_P2LED_KN), + GRP_G("p3led_kn", p3led_kn_grp_mt7628, MT7628_GPIO_MODE_MASK, + 1, MT7628_GPIO_MODE_P3LED_KN), + GRP_G("p4led_kn", p4led_kn_grp_mt7628, MT7628_GPIO_MODE_MASK, + 1, MT7628_GPIO_MODE_P4LED_KN), + { 0 } +}; + +static inline int is_mt76x8(void) +{ + return ralink_soc == MT762X_SOC_MT7628AN || + ralink_soc == MT762X_SOC_MT7688; +} + +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; + unsigned long pcmi2s_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 (is_mt76x8()) { + 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); + pcmi2s_rate = MHZ(480); + + 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); + pcmi2s_rate = periph_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("10000900.i2c", periph_rate); + ralink_clk_add("10000a00.i2s", pcmi2s_rate); + ralink_clk_add("10000b00.spi", sys_rate); + ralink_clk_add("10000b40.spi", sys_rate); + ralink_clk_add("10000c00.uartlite", periph_rate); + ralink_clk_add("10000d00.uart1", periph_rate); + ralink_clk_add("10000e00.uart2", periph_rate); + ralink_clk_add("10180000.wmac", xtal_rate); + + if (IS_ENABLED(CONFIG_USB) && !is_mt76x8()) { + /* + * When the CPU goes into sleep mode, the BUS clock will be + * too low for USB to function properly. Adjust the busses + * fractional divider to fix this + */ + u32 val = rt_sysc_r32(SYSC_REG_CPU_SYS_CLKCFG); + + val &= ~(CLKCFG_FDIV_MASK | CLKCFG_FFRAC_MASK); + val |= CLKCFG_FDIV_USB_VAL | CLKCFG_FFRAC_USB_VAL; + + rt_sysc_w32(val, SYSC_REG_CPU_SYS_CLKCFG); + } +} + +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) { + ralink_soc = MT762X_SOC_MT7620A; + name = "MT7620A"; + soc_info->compatible = "ralink,mt7620a-soc"; + } else { + ralink_soc = MT762X_SOC_MT7620N; + name = "MT7620N"; + soc_info->compatible = "ralink,mt7620n-soc"; + } + } else if (n0 == MT7620_CHIP_NAME0 && n1 == MT7628_CHIP_NAME1) { + u32 efuse = __raw_readl(sysc + SYSC_REG_EFUSE_CFG); + + if (efuse & EFUSE_MT7688) { + ralink_soc = MT762X_SOC_MT7688; + name = "MT7688"; + } else { + ralink_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, + "MediaTek %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); + if (is_mt76x8()) { + dram_type = cfg0 & DRAM_TYPE_MT7628_MASK; + } else { + dram_type = (cfg0 >> SYSCFG0_DRAM_TYPE_SHIFT) & + SYSCFG0_DRAM_TYPE_MASK; + if (dram_type == SYSCFG0_DRAM_TYPE_UNKNOWN) + dram_type = SYSCFG0_DRAM_TYPE_SDRAM; + } + + soc_info->mem_base = MT7620_DRAM_BASE; + if (is_mt76x8()) + 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 (is_mt76x8()) + rt2880_pinmux_data = mt7628an_pinmux_data; + else + rt2880_pinmux_data = mt7620a_pinmux_data; +} diff --git a/arch/mips/ralink/mt7621.c b/arch/mips/ralink/mt7621.c new file mode 100644 index 000000000..d2718de60 --- /dev/null +++ b/arch/mips/ralink/mt7621.c @@ -0,0 +1,226 @@ +/* + * 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) 2015 Nikolay Martynov <mar.kolya@gmail.com> + * Copyright (C) 2015 John Crispin <john@phrozen.org> + */ + +#include <linux/kernel.h> +#include <linux/init.h> + +#include <asm/mipsregs.h> +#include <asm/smp-ops.h> +#include <asm/mips-cps.h> +#include <asm/mach-ralink/ralink_regs.h> +#include <asm/mach-ralink/mt7621.h> + +#include <pinmux.h> + +#include "common.h" + +#define SYSC_REG_SYSCFG 0x10 +#define SYSC_REG_CPLL_CLKCFG0 0x2c +#define SYSC_REG_CUR_CLK_STS 0x44 +#define CPU_CLK_SEL (BIT(30) | BIT(31)) + +#define MT7621_GPIO_MODE_UART1 1 +#define MT7621_GPIO_MODE_I2C 2 +#define MT7621_GPIO_MODE_UART3_MASK 0x3 +#define MT7621_GPIO_MODE_UART3_SHIFT 3 +#define MT7621_GPIO_MODE_UART3_GPIO 1 +#define MT7621_GPIO_MODE_UART2_MASK 0x3 +#define MT7621_GPIO_MODE_UART2_SHIFT 5 +#define MT7621_GPIO_MODE_UART2_GPIO 1 +#define MT7621_GPIO_MODE_JTAG 7 +#define MT7621_GPIO_MODE_WDT_MASK 0x3 +#define MT7621_GPIO_MODE_WDT_SHIFT 8 +#define MT7621_GPIO_MODE_WDT_GPIO 1 +#define MT7621_GPIO_MODE_PCIE_RST 0 +#define MT7621_GPIO_MODE_PCIE_REF 2 +#define MT7621_GPIO_MODE_PCIE_MASK 0x3 +#define MT7621_GPIO_MODE_PCIE_SHIFT 10 +#define MT7621_GPIO_MODE_PCIE_GPIO 1 +#define MT7621_GPIO_MODE_MDIO_MASK 0x3 +#define MT7621_GPIO_MODE_MDIO_SHIFT 12 +#define MT7621_GPIO_MODE_MDIO_GPIO 1 +#define MT7621_GPIO_MODE_RGMII1 14 +#define MT7621_GPIO_MODE_RGMII2 15 +#define MT7621_GPIO_MODE_SPI_MASK 0x3 +#define MT7621_GPIO_MODE_SPI_SHIFT 16 +#define MT7621_GPIO_MODE_SPI_GPIO 1 +#define MT7621_GPIO_MODE_SDHCI_MASK 0x3 +#define MT7621_GPIO_MODE_SDHCI_SHIFT 18 +#define MT7621_GPIO_MODE_SDHCI_GPIO 1 + +static struct rt2880_pmx_func uart1_grp[] = { FUNC("uart1", 0, 1, 2) }; +static struct rt2880_pmx_func i2c_grp[] = { FUNC("i2c", 0, 3, 2) }; +static struct rt2880_pmx_func uart3_grp[] = { + FUNC("uart3", 0, 5, 4), + FUNC("i2s", 2, 5, 4), + FUNC("spdif3", 3, 5, 4), +}; +static struct rt2880_pmx_func uart2_grp[] = { + FUNC("uart2", 0, 9, 4), + FUNC("pcm", 2, 9, 4), + FUNC("spdif2", 3, 9, 4), +}; +static struct rt2880_pmx_func jtag_grp[] = { FUNC("jtag", 0, 13, 5) }; +static struct rt2880_pmx_func wdt_grp[] = { + FUNC("wdt rst", 0, 18, 1), + FUNC("wdt refclk", 2, 18, 1), +}; +static struct rt2880_pmx_func pcie_rst_grp[] = { + FUNC("pcie rst", MT7621_GPIO_MODE_PCIE_RST, 19, 1), + FUNC("pcie refclk", MT7621_GPIO_MODE_PCIE_REF, 19, 1) +}; +static struct rt2880_pmx_func mdio_grp[] = { FUNC("mdio", 0, 20, 2) }; +static struct rt2880_pmx_func rgmii2_grp[] = { FUNC("rgmii2", 0, 22, 12) }; +static struct rt2880_pmx_func spi_grp[] = { + FUNC("spi", 0, 34, 7), + FUNC("nand1", 2, 34, 7), +}; +static struct rt2880_pmx_func sdhci_grp[] = { + FUNC("sdhci", 0, 41, 8), + FUNC("nand2", 2, 41, 8), +}; +static struct rt2880_pmx_func rgmii1_grp[] = { FUNC("rgmii1", 0, 49, 12) }; + +static struct rt2880_pmx_group mt7621_pinmux_data[] = { + GRP("uart1", uart1_grp, 1, MT7621_GPIO_MODE_UART1), + GRP("i2c", i2c_grp, 1, MT7621_GPIO_MODE_I2C), + GRP_G("uart3", uart3_grp, MT7621_GPIO_MODE_UART3_MASK, + MT7621_GPIO_MODE_UART3_GPIO, MT7621_GPIO_MODE_UART3_SHIFT), + GRP_G("uart2", uart2_grp, MT7621_GPIO_MODE_UART2_MASK, + MT7621_GPIO_MODE_UART2_GPIO, MT7621_GPIO_MODE_UART2_SHIFT), + GRP("jtag", jtag_grp, 1, MT7621_GPIO_MODE_JTAG), + GRP_G("wdt", wdt_grp, MT7621_GPIO_MODE_WDT_MASK, + MT7621_GPIO_MODE_WDT_GPIO, MT7621_GPIO_MODE_WDT_SHIFT), + GRP_G("pcie", pcie_rst_grp, MT7621_GPIO_MODE_PCIE_MASK, + MT7621_GPIO_MODE_PCIE_GPIO, MT7621_GPIO_MODE_PCIE_SHIFT), + GRP_G("mdio", mdio_grp, MT7621_GPIO_MODE_MDIO_MASK, + MT7621_GPIO_MODE_MDIO_GPIO, MT7621_GPIO_MODE_MDIO_SHIFT), + GRP("rgmii2", rgmii2_grp, 1, MT7621_GPIO_MODE_RGMII2), + GRP_G("spi", spi_grp, MT7621_GPIO_MODE_SPI_MASK, + MT7621_GPIO_MODE_SPI_GPIO, MT7621_GPIO_MODE_SPI_SHIFT), + GRP_G("sdhci", sdhci_grp, MT7621_GPIO_MODE_SDHCI_MASK, + MT7621_GPIO_MODE_SDHCI_GPIO, MT7621_GPIO_MODE_SDHCI_SHIFT), + GRP("rgmii1", rgmii1_grp, 1, MT7621_GPIO_MODE_RGMII1), + { 0 } +}; + +phys_addr_t mips_cpc_default_phys_base(void) +{ + panic("Cannot detect cpc address"); +} + +void __init ralink_clk_init(void) +{ + int cpu_fdiv = 0; + int cpu_ffrac = 0; + int fbdiv = 0; + u32 clk_sts, syscfg; + u8 clk_sel = 0, xtal_mode; + u32 cpu_clk; + + if ((rt_sysc_r32(SYSC_REG_CPLL_CLKCFG0) & CPU_CLK_SEL) != 0) + clk_sel = 1; + + switch (clk_sel) { + case 0: + clk_sts = rt_sysc_r32(SYSC_REG_CUR_CLK_STS); + cpu_fdiv = ((clk_sts >> 8) & 0x1F); + cpu_ffrac = (clk_sts & 0x1F); + cpu_clk = (500 * cpu_ffrac / cpu_fdiv) * 1000 * 1000; + break; + + case 1: + fbdiv = ((rt_sysc_r32(0x648) >> 4) & 0x7F) + 1; + syscfg = rt_sysc_r32(SYSC_REG_SYSCFG); + xtal_mode = (syscfg >> 6) & 0x7; + if (xtal_mode >= 6) { + /* 25Mhz Xtal */ + cpu_clk = 25 * fbdiv * 1000 * 1000; + } else if (xtal_mode >= 3) { + /* 40Mhz Xtal */ + cpu_clk = 40 * fbdiv * 1000 * 1000; + } else { + /* 20Mhz Xtal */ + cpu_clk = 20 * fbdiv * 1000 * 1000; + } + break; + } +} + +void __init ralink_of_remap(void) +{ + rt_sysc_membase = plat_of_remap_node("mtk,mt7621-sysc"); + rt_memc_membase = plat_of_remap_node("mtk,mt7621-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(MT7621_SYSC_BASE); + unsigned char *name = NULL; + u32 n0; + u32 n1; + u32 rev; + + /* Early detection of CMP support */ + mips_cm_probe(); + mips_cpc_probe(); + + if (mips_cps_numiocu(0)) { + /* + * mips_cm_probe() wipes out bootloader + * config for CM regions and we have to configure them + * again. This SoC cannot talk to pamlbus devices + * witout proper iocu region set up. + * + * FIXME: it would be better to do this with values + * from DT, but we need this very early because + * without this we cannot talk to pretty much anything + * including serial. + */ + write_gcr_reg0_base(MT7621_PALMBUS_BASE); + write_gcr_reg0_mask(~MT7621_PALMBUS_SIZE | + CM_GCR_REGn_MASK_CMTGT_IOCU0); + __sync(); + } + + n0 = __raw_readl(sysc + SYSC_REG_CHIP_NAME0); + n1 = __raw_readl(sysc + SYSC_REG_CHIP_NAME1); + + if (n0 == MT7621_CHIP_NAME0 && n1 == MT7621_CHIP_NAME1) { + name = "MT7621"; + soc_info->compatible = "mtk,mt7621-soc"; + } else { + panic("mt7621: unknown SoC, n0:%08x n1:%08x\n", n0, n1); + } + ralink_soc = MT762X_SOC_MT7621AT; + rev = __raw_readl(sysc + SYSC_REG_CHIP_REV); + + snprintf(soc_info->sys_type, RAMIPS_SYS_TYPE_LEN, + "MediaTek %s ver:%u eco:%u", + name, + (rev >> CHIP_REV_VER_SHIFT) & CHIP_REV_VER_MASK, + (rev & CHIP_REV_ECO_MASK)); + + soc_info->mem_size_min = MT7621_DDR2_SIZE_MIN; + soc_info->mem_size_max = MT7621_DDR2_SIZE_MAX; + soc_info->mem_base = MT7621_DRAM_BASE; + + rt2880_pinmux_data = mt7621_pinmux_data; + + + if (!register_cps_smp_ops()) + return; + if (!register_cmp_smp_ops()) + return; + if (!register_vsmp_smp_ops()) + return; +} diff --git a/arch/mips/ralink/of.c b/arch/mips/ralink/of.c new file mode 100644 index 000000000..1f7c686f7 --- /dev/null +++ b/arch/mips/ralink/of.c @@ -0,0 +1,109 @@ +/* + * 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 <john@phrozen.org> + */ + +#include <linux/io.h> +#include <linux/clk.h> +#include <linux/export.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; +EXPORT_SYMBOL_GPL(rt_sysc_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)) + 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) +{ + void *dtb = NULL; + + set_io_port_base(KSEG1); + + /* + * Load the builtin devicetree. This causes the chosen node to be + * parsed resulting in our memory appearing. fw_passed_dtb is used + * by CONFIG_MIPS_APPENDED_RAW_DTB as well. + */ + if (fw_passed_dtb) + dtb = (void *)fw_passed_dtb; + else if (&__dtb_start != &__dtb_end) + dtb = (void *)__dtb_start; + + __dt_setup_arch(dtb); + + 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..23198c905 --- /dev/null +++ b/arch/mips/ralink/prom.c @@ -0,0 +1,74 @@ +/* + * 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 <john@phrozen.org> + */ + +#include <linux/string.h> +#include <linux/of_fdt.h> +#include <linux/of_platform.h> + +#include <asm/bootinfo.h> +#include <asm/addrspace.h> + +#include <asm/mach-ralink/ralink_regs.h> + +#include "common.h" + +struct ralink_soc_info soc_info; +struct rt2880_pmx_group *rt2880_pinmux_data = NULL; + +enum ralink_soc_type ralink_soc; +EXPORT_SYMBOL_GPL(ralink_soc); + +const char *get_system_type(void) +{ + return soc_info.sys_type; +} + +static __init void prom_init_cmdline(void) +{ + 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) +{ + prom_soc_init(&soc_info); + + pr_info("SoC Type: %s\n", get_system_type()); + + prom_init_cmdline(); +} + +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..e9531fea2 --- /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 <john@phrozen.org> + */ + +#include <linux/pm.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/delay.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_PCI BIT(26) +#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 const 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) +{ + if (IS_ENABLED(CONFIG_PCI)) { + rt_sysc_m32(0, RSTCTL_RESET_PCI, SYSC_REG_RESET_CTRL); + mdelay(50); + } + + local_irq_disable(); + rt_sysc_w32(RSTCTL_RESET_SYSTEM, SYSC_REG_RESET_CTRL); + unreachable(); +} + +static int __init mips_reboot_setup(void) +{ + _machine_restart = ralink_restart; + + 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..60e44cc8d --- /dev/null +++ b/arch/mips/ralink/rt288x.c @@ -0,0 +1,113 @@ +/* + * 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 <john@phrozen.org> + */ + +#include <linux/kernel.h> +#include <linux/init.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 } +}; + +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("300900.i2c", 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; + ralink_soc = RT2880_SOC; +} diff --git a/arch/mips/ralink/rt305x.c b/arch/mips/ralink/rt305x.c new file mode 100644 index 000000000..93d472c60 --- /dev/null +++ b/arch/mips/ralink/rt305x.c @@ -0,0 +1,275 @@ +/* + * 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 <john@phrozen.org> + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/bug.h> + +#include <asm/io.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" + +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 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("sys", sys_rate); + ralink_clk_add("10000900.i2c", uart_rate); + ralink_clk_add("10000a00.i2s", uart_rate); + ralink_clk_add("10000b00.spi", sys_rate); + ralink_clk_add("10000b40.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) { + ralink_soc = RT305X_SOC_RT3050; + name = "RT3050"; + soc_info->compatible = "ralink,rt3050-soc"; + } else { + ralink_soc = RT305X_SOC_RT3052; + name = "RT3052"; + soc_info->compatible = "ralink,rt3052-soc"; + } + } else if (n0 == RT3350_CHIP_NAME0 && n1 == RT3350_CHIP_NAME1) { + ralink_soc = RT305X_SOC_RT3350; + name = "RT3350"; + soc_info->compatible = "ralink,rt3350-soc"; + } else if (n0 == RT3352_CHIP_NAME0 && n1 == RT3352_CHIP_NAME1) { + ralink_soc = RT305X_SOC_RT3352; + name = "RT3352"; + soc_info->compatible = "ralink,rt3352-soc"; + } else if (n0 == RT5350_CHIP_NAME0 && n1 == RT5350_CHIP_NAME1) { + ralink_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..48ce70155 --- /dev/null +++ b/arch/mips/ralink/rt3883.c @@ -0,0 +1,150 @@ +/* + * 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 <john@phrozen.org> + */ + +#include <linux/kernel.h> +#include <linux/init.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 g", 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("ge2", 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 } +}; + +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("10000900.i2c", 40000000); + ralink_clk_add("10000a00.i2s", 40000000); + ralink_clk_add("10000b00.spi", sys_rate); + ralink_clk_add("10000b40.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; + + ralink_soc = RT3883_SOC; +} diff --git a/arch/mips/ralink/timer-gic.c b/arch/mips/ralink/timer-gic.c new file mode 100644 index 000000000..b5f07d21f --- /dev/null +++ b/arch/mips/ralink/timer-gic.c @@ -0,0 +1,24 @@ +/* + * 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) 2015 Nikolay Martynov <mar.kolya@gmail.com> + * Copyright (C) 2015 John Crispin <john@phrozen.org> + */ + +#include <linux/init.h> + +#include <linux/of.h> +#include <linux/clk-provider.h> +#include <linux/clocksource.h> + +#include "common.h" + +void __init plat_time_init(void) +{ + ralink_of_remap(); + + of_clk_init(NULL); + timer_probe(); +} diff --git a/arch/mips/ralink/timer.c b/arch/mips/ralink/timer.c new file mode 100644 index 000000000..4f46a4509 --- /dev/null +++ b/arch/mips/ralink/timer.c @@ -0,0 +1,156 @@ +/* + * Ralink RT2880 timer + * Author: John Crispin + * + * 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 <john@phrozen.org> +*/ + +#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 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 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 < 0) { + dev_err(&pdev->dev, "failed to load irq\n"); + return rt->irq; + } + + 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 const struct of_device_id rt_timer_match[] = { + { .compatible = "ralink,rt2880-timer" }, + {}, +}; + +static struct platform_driver rt_timer_driver = { + .probe = rt_timer_probe, + .driver = { + .name = "rt-timer", + .of_match_table = rt_timer_match, + .suppress_bind_attrs = true, + }, +}; +builtin_platform_driver(rt_timer_driver); |