MIPS: Add initial support for the Atheros AR71XX/AR724X/AR931X SoCs
This patch adds initial support for various Atheros SoCs based on the MIPS 24Kc core. The following models are supported at the moment: - AR7130 - AR7141 - AR7161 - AR9130 - AR9132 - AR7240 - AR7241 - AR7242 The current patch contains minimal support only, but the resulting kernel can boot into user-space with using of an initramfs image on various boards which are using these SoCs. Support for more built-in devices and individual boards will be implemented in further patches. Signed-off-by: Gabor Juhos <juhosg@openwrt.org> Signed-off-by: Imre Kaloz <kaloz@openwrt.org> Cc: linux-mips@linux-mips.org Cc: Luis R. Rodriguez <lrodriguez@atheros.com> Cc: Cliff Holden <Cliff.Holden@Atheros.com> Cc: Kathy Giori <Kathy.Giori@Atheros.com> Patchwork: https://patchwork.linux-mips.org/patch/1947/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Este commit está contenido en:
12
arch/mips/ath79/Kconfig
Archivo normal
12
arch/mips/ath79/Kconfig
Archivo normal
@@ -0,0 +1,12 @@
|
||||
if ATH79
|
||||
|
||||
config SOC_AR71XX
|
||||
def_bool n
|
||||
|
||||
config SOC_AR724X
|
||||
def_bool n
|
||||
|
||||
config SOC_AR913X
|
||||
def_bool n
|
||||
|
||||
endif
|
18
arch/mips/ath79/Makefile
Archivo normal
18
arch/mips/ath79/Makefile
Archivo normal
@@ -0,0 +1,18 @@
|
||||
#
|
||||
# Makefile for the Atheros AR71XX/AR724X/AR913X specific parts of the kernel
|
||||
#
|
||||
# Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
|
||||
# Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
|
||||
#
|
||||
# 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.
|
||||
|
||||
obj-y := prom.o setup.o irq.o common.o clock.o
|
||||
|
||||
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
|
||||
|
||||
#
|
||||
# Devices
|
||||
#
|
||||
obj-y += dev-common.o
|
7
arch/mips/ath79/Platform
Archivo normal
7
arch/mips/ath79/Platform
Archivo normal
@@ -0,0 +1,7 @@
|
||||
#
|
||||
# Atheros AR71xx/AR724x/AR913x
|
||||
#
|
||||
|
||||
platform-$(CONFIG_ATH79) += ath79/
|
||||
cflags-$(CONFIG_ATH79) += -I$(srctree)/arch/mips/include/asm/mach-ath79
|
||||
load-$(CONFIG_ATH79) = 0xffffffff80060000
|
183
arch/mips/ath79/clock.c
Archivo normal
183
arch/mips/ath79/clock.c
Archivo normal
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Atheros AR71XX/AR724X/AR913X common routines
|
||||
*
|
||||
* Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include <asm/mach-ath79/ath79.h>
|
||||
#include <asm/mach-ath79/ar71xx_regs.h>
|
||||
#include "common.h"
|
||||
|
||||
#define AR71XX_BASE_FREQ 40000000
|
||||
#define AR724X_BASE_FREQ 5000000
|
||||
#define AR913X_BASE_FREQ 5000000
|
||||
|
||||
struct clk {
|
||||
unsigned long rate;
|
||||
};
|
||||
|
||||
static struct clk ath79_ref_clk;
|
||||
static struct clk ath79_cpu_clk;
|
||||
static struct clk ath79_ddr_clk;
|
||||
static struct clk ath79_ahb_clk;
|
||||
static struct clk ath79_wdt_clk;
|
||||
static struct clk ath79_uart_clk;
|
||||
|
||||
static void __init ar71xx_clocks_init(void)
|
||||
{
|
||||
u32 pll;
|
||||
u32 freq;
|
||||
u32 div;
|
||||
|
||||
ath79_ref_clk.rate = AR71XX_BASE_FREQ;
|
||||
|
||||
pll = ath79_pll_rr(AR71XX_PLL_REG_CPU_CONFIG);
|
||||
|
||||
div = ((pll >> AR71XX_PLL_DIV_SHIFT) & AR71XX_PLL_DIV_MASK) + 1;
|
||||
freq = div * ath79_ref_clk.rate;
|
||||
|
||||
div = ((pll >> AR71XX_CPU_DIV_SHIFT) & AR71XX_CPU_DIV_MASK) + 1;
|
||||
ath79_cpu_clk.rate = freq / div;
|
||||
|
||||
div = ((pll >> AR71XX_DDR_DIV_SHIFT) & AR71XX_DDR_DIV_MASK) + 1;
|
||||
ath79_ddr_clk.rate = freq / div;
|
||||
|
||||
div = (((pll >> AR71XX_AHB_DIV_SHIFT) & AR71XX_AHB_DIV_MASK) + 1) * 2;
|
||||
ath79_ahb_clk.rate = ath79_cpu_clk.rate / div;
|
||||
|
||||
ath79_wdt_clk.rate = ath79_ahb_clk.rate;
|
||||
ath79_uart_clk.rate = ath79_ahb_clk.rate;
|
||||
}
|
||||
|
||||
static void __init ar724x_clocks_init(void)
|
||||
{
|
||||
u32 pll;
|
||||
u32 freq;
|
||||
u32 div;
|
||||
|
||||
ath79_ref_clk.rate = AR724X_BASE_FREQ;
|
||||
pll = ath79_pll_rr(AR724X_PLL_REG_CPU_CONFIG);
|
||||
|
||||
div = ((pll >> AR724X_PLL_DIV_SHIFT) & AR724X_PLL_DIV_MASK);
|
||||
freq = div * ath79_ref_clk.rate;
|
||||
|
||||
div = ((pll >> AR724X_PLL_REF_DIV_SHIFT) & AR724X_PLL_REF_DIV_MASK);
|
||||
freq *= div;
|
||||
|
||||
ath79_cpu_clk.rate = freq;
|
||||
|
||||
div = ((pll >> AR724X_DDR_DIV_SHIFT) & AR724X_DDR_DIV_MASK) + 1;
|
||||
ath79_ddr_clk.rate = freq / div;
|
||||
|
||||
div = (((pll >> AR724X_AHB_DIV_SHIFT) & AR724X_AHB_DIV_MASK) + 1) * 2;
|
||||
ath79_ahb_clk.rate = ath79_cpu_clk.rate / div;
|
||||
|
||||
ath79_wdt_clk.rate = ath79_ahb_clk.rate;
|
||||
ath79_uart_clk.rate = ath79_ahb_clk.rate;
|
||||
}
|
||||
|
||||
static void __init ar913x_clocks_init(void)
|
||||
{
|
||||
u32 pll;
|
||||
u32 freq;
|
||||
u32 div;
|
||||
|
||||
ath79_ref_clk.rate = AR913X_BASE_FREQ;
|
||||
pll = ath79_pll_rr(AR913X_PLL_REG_CPU_CONFIG);
|
||||
|
||||
div = ((pll >> AR913X_PLL_DIV_SHIFT) & AR913X_PLL_DIV_MASK);
|
||||
freq = div * ath79_ref_clk.rate;
|
||||
|
||||
ath79_cpu_clk.rate = freq;
|
||||
|
||||
div = ((pll >> AR913X_DDR_DIV_SHIFT) & AR913X_DDR_DIV_MASK) + 1;
|
||||
ath79_ddr_clk.rate = freq / div;
|
||||
|
||||
div = (((pll >> AR913X_AHB_DIV_SHIFT) & AR913X_AHB_DIV_MASK) + 1) * 2;
|
||||
ath79_ahb_clk.rate = ath79_cpu_clk.rate / div;
|
||||
|
||||
ath79_wdt_clk.rate = ath79_ahb_clk.rate;
|
||||
ath79_uart_clk.rate = ath79_ahb_clk.rate;
|
||||
}
|
||||
|
||||
void __init ath79_clocks_init(void)
|
||||
{
|
||||
if (soc_is_ar71xx())
|
||||
ar71xx_clocks_init();
|
||||
else if (soc_is_ar724x())
|
||||
ar724x_clocks_init();
|
||||
else if (soc_is_ar913x())
|
||||
ar913x_clocks_init();
|
||||
else
|
||||
BUG();
|
||||
|
||||
pr_info("Clocks: CPU:%lu.%03luMHz, DDR:%lu.%03luMHz, AHB:%lu.%03luMHz, "
|
||||
"Ref:%lu.%03luMHz",
|
||||
ath79_cpu_clk.rate / 1000000,
|
||||
(ath79_cpu_clk.rate / 1000) % 1000,
|
||||
ath79_ddr_clk.rate / 1000000,
|
||||
(ath79_ddr_clk.rate / 1000) % 1000,
|
||||
ath79_ahb_clk.rate / 1000000,
|
||||
(ath79_ahb_clk.rate / 1000) % 1000,
|
||||
ath79_ref_clk.rate / 1000000,
|
||||
(ath79_ref_clk.rate / 1000) % 1000);
|
||||
}
|
||||
|
||||
/*
|
||||
* Linux clock API
|
||||
*/
|
||||
struct clk *clk_get(struct device *dev, const char *id)
|
||||
{
|
||||
if (!strcmp(id, "ref"))
|
||||
return &ath79_ref_clk;
|
||||
|
||||
if (!strcmp(id, "cpu"))
|
||||
return &ath79_cpu_clk;
|
||||
|
||||
if (!strcmp(id, "ddr"))
|
||||
return &ath79_ddr_clk;
|
||||
|
||||
if (!strcmp(id, "ahb"))
|
||||
return &ath79_ahb_clk;
|
||||
|
||||
if (!strcmp(id, "wdt"))
|
||||
return &ath79_wdt_clk;
|
||||
|
||||
if (!strcmp(id, "uart"))
|
||||
return &ath79_uart_clk;
|
||||
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
EXPORT_SYMBOL(clk_get);
|
||||
|
||||
int clk_enable(struct clk *clk)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(clk_enable);
|
||||
|
||||
void clk_disable(struct clk *clk)
|
||||
{
|
||||
}
|
||||
EXPORT_SYMBOL(clk_disable);
|
||||
|
||||
unsigned long clk_get_rate(struct clk *clk)
|
||||
{
|
||||
return clk->rate;
|
||||
}
|
||||
EXPORT_SYMBOL(clk_get_rate);
|
||||
|
||||
void clk_put(struct clk *clk)
|
||||
{
|
||||
}
|
||||
EXPORT_SYMBOL(clk_put);
|
97
arch/mips/ath79/common.c
Archivo normal
97
arch/mips/ath79/common.c
Archivo normal
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Atheros AR71XX/AR724X/AR913X common routines
|
||||
*
|
||||
* Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
|
||||
* Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include <asm/mach-ath79/ath79.h>
|
||||
#include <asm/mach-ath79/ar71xx_regs.h>
|
||||
#include "common.h"
|
||||
|
||||
static DEFINE_SPINLOCK(ath79_device_reset_lock);
|
||||
|
||||
u32 ath79_cpu_freq;
|
||||
EXPORT_SYMBOL_GPL(ath79_cpu_freq);
|
||||
|
||||
u32 ath79_ahb_freq;
|
||||
EXPORT_SYMBOL_GPL(ath79_ahb_freq);
|
||||
|
||||
u32 ath79_ddr_freq;
|
||||
EXPORT_SYMBOL_GPL(ath79_ddr_freq);
|
||||
|
||||
enum ath79_soc_type ath79_soc;
|
||||
|
||||
void __iomem *ath79_pll_base;
|
||||
void __iomem *ath79_reset_base;
|
||||
EXPORT_SYMBOL_GPL(ath79_reset_base);
|
||||
void __iomem *ath79_ddr_base;
|
||||
|
||||
void ath79_ddr_wb_flush(u32 reg)
|
||||
{
|
||||
void __iomem *flush_reg = ath79_ddr_base + reg;
|
||||
|
||||
/* Flush the DDR write buffer. */
|
||||
__raw_writel(0x1, flush_reg);
|
||||
while (__raw_readl(flush_reg) & 0x1)
|
||||
;
|
||||
|
||||
/* It must be run twice. */
|
||||
__raw_writel(0x1, flush_reg);
|
||||
while (__raw_readl(flush_reg) & 0x1)
|
||||
;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ath79_ddr_wb_flush);
|
||||
|
||||
void ath79_device_reset_set(u32 mask)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 reg;
|
||||
u32 t;
|
||||
|
||||
if (soc_is_ar71xx())
|
||||
reg = AR71XX_RESET_REG_RESET_MODULE;
|
||||
else if (soc_is_ar724x())
|
||||
reg = AR724X_RESET_REG_RESET_MODULE;
|
||||
else if (soc_is_ar913x())
|
||||
reg = AR913X_RESET_REG_RESET_MODULE;
|
||||
else
|
||||
BUG();
|
||||
|
||||
spin_lock_irqsave(&ath79_device_reset_lock, flags);
|
||||
t = ath79_reset_rr(reg);
|
||||
ath79_reset_wr(reg, t | mask);
|
||||
spin_unlock_irqrestore(&ath79_device_reset_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ath79_device_reset_set);
|
||||
|
||||
void ath79_device_reset_clear(u32 mask)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 reg;
|
||||
u32 t;
|
||||
|
||||
if (soc_is_ar71xx())
|
||||
reg = AR71XX_RESET_REG_RESET_MODULE;
|
||||
else if (soc_is_ar724x())
|
||||
reg = AR724X_RESET_REG_RESET_MODULE;
|
||||
else if (soc_is_ar913x())
|
||||
reg = AR913X_RESET_REG_RESET_MODULE;
|
||||
else
|
||||
BUG();
|
||||
|
||||
spin_lock_irqsave(&ath79_device_reset_lock, flags);
|
||||
t = ath79_reset_rr(reg);
|
||||
ath79_reset_wr(reg, t & ~mask);
|
||||
spin_unlock_irqrestore(&ath79_device_reset_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ath79_device_reset_clear);
|
26
arch/mips/ath79/common.h
Archivo normal
26
arch/mips/ath79/common.h
Archivo normal
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Atheros AR71XX/AR724X/AR913X common definitions
|
||||
*
|
||||
* Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
|
||||
* Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
|
||||
*
|
||||
* Parts of this file are based on Atheros' 2.6.15 BSP
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __ATH79_COMMON_H
|
||||
#define __ATH79_COMMON_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#define ATH79_MEM_SIZE_MIN (2 * 1024 * 1024)
|
||||
#define ATH79_MEM_SIZE_MAX (128 * 1024 * 1024)
|
||||
|
||||
void ath79_clocks_init(void);
|
||||
void ath79_ddr_wb_flush(unsigned int reg);
|
||||
|
||||
#endif /* __ATH79_COMMON_H */
|
67
arch/mips/ath79/dev-common.c
Archivo normal
67
arch/mips/ath79/dev-common.c
Archivo normal
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Atheros AR71XX/AR724X/AR913X common devices
|
||||
*
|
||||
* Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
|
||||
* Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
|
||||
*
|
||||
* Parts of this file are based on Atheros' 2.6.15 BSP
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/serial_8250.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include <asm/mach-ath79/ath79.h>
|
||||
#include <asm/mach-ath79/ar71xx_regs.h>
|
||||
#include "common.h"
|
||||
#include "dev-common.h"
|
||||
|
||||
static struct resource ath79_uart_resources[] = {
|
||||
{
|
||||
.start = AR71XX_UART_BASE,
|
||||
.end = AR71XX_UART_BASE + AR71XX_UART_SIZE - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
#define AR71XX_UART_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP)
|
||||
static struct plat_serial8250_port ath79_uart_data[] = {
|
||||
{
|
||||
.mapbase = AR71XX_UART_BASE,
|
||||
.irq = ATH79_MISC_IRQ_UART,
|
||||
.flags = AR71XX_UART_FLAGS,
|
||||
.iotype = UPIO_MEM32,
|
||||
.regshift = 2,
|
||||
}, {
|
||||
/* terminating entry */
|
||||
}
|
||||
};
|
||||
|
||||
static struct platform_device ath79_uart_device = {
|
||||
.name = "serial8250",
|
||||
.id = PLAT8250_DEV_PLATFORM,
|
||||
.resource = ath79_uart_resources,
|
||||
.num_resources = ARRAY_SIZE(ath79_uart_resources),
|
||||
.dev = {
|
||||
.platform_data = ath79_uart_data
|
||||
},
|
||||
};
|
||||
|
||||
void __init ath79_register_uart(void)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
clk = clk_get(NULL, "uart");
|
||||
if (IS_ERR(clk))
|
||||
panic("unable to get UART clock, err=%ld", PTR_ERR(clk));
|
||||
|
||||
ath79_uart_data[0].uartclk = clk_get_rate(clk);
|
||||
platform_device_register(&ath79_uart_device);
|
||||
}
|
17
arch/mips/ath79/dev-common.h
Archivo normal
17
arch/mips/ath79/dev-common.h
Archivo normal
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Atheros AR71XX/AR724X/AR913X common devices
|
||||
*
|
||||
* Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
|
||||
* Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _ATH79_DEV_COMMON_H
|
||||
#define _ATH79_DEV_COMMON_H
|
||||
|
||||
void ath79_register_uart(void);
|
||||
|
||||
#endif /* _ATH79_DEV_COMMON_H */
|
36
arch/mips/ath79/early_printk.c
Archivo normal
36
arch/mips/ath79/early_printk.c
Archivo normal
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Atheros AR71XX/AR724X/AR913X SoC early printk support
|
||||
*
|
||||
* Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
|
||||
* Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/serial_reg.h>
|
||||
#include <asm/addrspace.h>
|
||||
|
||||
#include <asm/mach-ath79/ar71xx_regs.h>
|
||||
|
||||
static inline void prom_wait_thre(void __iomem *base)
|
||||
{
|
||||
u32 lsr;
|
||||
|
||||
do {
|
||||
lsr = __raw_readl(base + UART_LSR * 4);
|
||||
if (lsr & UART_LSR_THRE)
|
||||
break;
|
||||
} while (1);
|
||||
}
|
||||
|
||||
void prom_putchar(unsigned char ch)
|
||||
{
|
||||
void __iomem *base = (void __iomem *)(KSEG1ADDR(AR71XX_UART_BASE));
|
||||
|
||||
prom_wait_thre(base);
|
||||
__raw_writel(ch, base + UART_TX * 4);
|
||||
prom_wait_thre(base);
|
||||
}
|
187
arch/mips/ath79/irq.c
Archivo normal
187
arch/mips/ath79/irq.c
Archivo normal
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Atheros AR71xx/AR724x/AR913x specific interrupt handling
|
||||
*
|
||||
* Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
|
||||
* Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
|
||||
*
|
||||
* Parts of this file are based on Atheros' 2.6.15 BSP
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
|
||||
#include <asm/irq_cpu.h>
|
||||
#include <asm/mipsregs.h>
|
||||
|
||||
#include <asm/mach-ath79/ath79.h>
|
||||
#include <asm/mach-ath79/ar71xx_regs.h>
|
||||
#include "common.h"
|
||||
|
||||
static unsigned int ath79_ip2_flush_reg;
|
||||
static unsigned int ath79_ip3_flush_reg;
|
||||
|
||||
static void ath79_misc_irq_handler(unsigned int irq, struct irq_desc *desc)
|
||||
{
|
||||
void __iomem *base = ath79_reset_base;
|
||||
u32 pending;
|
||||
|
||||
pending = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS) &
|
||||
__raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
|
||||
|
||||
if (pending & MISC_INT_UART)
|
||||
generic_handle_irq(ATH79_MISC_IRQ_UART);
|
||||
|
||||
else if (pending & MISC_INT_DMA)
|
||||
generic_handle_irq(ATH79_MISC_IRQ_DMA);
|
||||
|
||||
else if (pending & MISC_INT_PERFC)
|
||||
generic_handle_irq(ATH79_MISC_IRQ_PERFC);
|
||||
|
||||
else if (pending & MISC_INT_TIMER)
|
||||
generic_handle_irq(ATH79_MISC_IRQ_TIMER);
|
||||
|
||||
else if (pending & MISC_INT_OHCI)
|
||||
generic_handle_irq(ATH79_MISC_IRQ_OHCI);
|
||||
|
||||
else if (pending & MISC_INT_ERROR)
|
||||
generic_handle_irq(ATH79_MISC_IRQ_ERROR);
|
||||
|
||||
else if (pending & MISC_INT_GPIO)
|
||||
generic_handle_irq(ATH79_MISC_IRQ_GPIO);
|
||||
|
||||
else if (pending & MISC_INT_WDOG)
|
||||
generic_handle_irq(ATH79_MISC_IRQ_WDOG);
|
||||
|
||||
else
|
||||
spurious_interrupt();
|
||||
}
|
||||
|
||||
static void ar71xx_misc_irq_unmask(unsigned int irq)
|
||||
{
|
||||
void __iomem *base = ath79_reset_base;
|
||||
u32 t;
|
||||
|
||||
irq -= ATH79_MISC_IRQ_BASE;
|
||||
|
||||
t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
|
||||
__raw_writel(t | (1 << irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE);
|
||||
|
||||
/* flush write */
|
||||
__raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
|
||||
}
|
||||
|
||||
static void ar71xx_misc_irq_mask(unsigned int irq)
|
||||
{
|
||||
void __iomem *base = ath79_reset_base;
|
||||
u32 t;
|
||||
|
||||
irq -= ATH79_MISC_IRQ_BASE;
|
||||
|
||||
t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
|
||||
__raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE);
|
||||
|
||||
/* flush write */
|
||||
__raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
|
||||
}
|
||||
|
||||
static void ar724x_misc_irq_ack(unsigned int irq)
|
||||
{
|
||||
void __iomem *base = ath79_reset_base;
|
||||
u32 t;
|
||||
|
||||
irq -= ATH79_MISC_IRQ_BASE;
|
||||
|
||||
t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS);
|
||||
__raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_MISC_INT_STATUS);
|
||||
|
||||
/* flush write */
|
||||
__raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS);
|
||||
}
|
||||
|
||||
static struct irq_chip ath79_misc_irq_chip = {
|
||||
.name = "MISC",
|
||||
.unmask = ar71xx_misc_irq_unmask,
|
||||
.mask = ar71xx_misc_irq_mask,
|
||||
};
|
||||
|
||||
static void __init ath79_misc_irq_init(void)
|
||||
{
|
||||
void __iomem *base = ath79_reset_base;
|
||||
int i;
|
||||
|
||||
__raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_ENABLE);
|
||||
__raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_STATUS);
|
||||
|
||||
if (soc_is_ar71xx() || soc_is_ar913x())
|
||||
ath79_misc_irq_chip.mask_ack = ar71xx_misc_irq_mask;
|
||||
else if (soc_is_ar724x())
|
||||
ath79_misc_irq_chip.ack = ar724x_misc_irq_ack;
|
||||
else
|
||||
BUG();
|
||||
|
||||
for (i = ATH79_MISC_IRQ_BASE;
|
||||
i < ATH79_MISC_IRQ_BASE + ATH79_MISC_IRQ_COUNT; i++) {
|
||||
irq_desc[i].status = IRQ_DISABLED;
|
||||
set_irq_chip_and_handler(i, &ath79_misc_irq_chip,
|
||||
handle_level_irq);
|
||||
}
|
||||
|
||||
set_irq_chained_handler(ATH79_CPU_IRQ_MISC, ath79_misc_irq_handler);
|
||||
}
|
||||
|
||||
asmlinkage void plat_irq_dispatch(void)
|
||||
{
|
||||
unsigned long pending;
|
||||
|
||||
pending = read_c0_status() & read_c0_cause() & ST0_IM;
|
||||
|
||||
if (pending & STATUSF_IP7)
|
||||
do_IRQ(ATH79_CPU_IRQ_TIMER);
|
||||
|
||||
else if (pending & STATUSF_IP2) {
|
||||
ath79_ddr_wb_flush(ath79_ip2_flush_reg);
|
||||
do_IRQ(ATH79_CPU_IRQ_IP2);
|
||||
}
|
||||
|
||||
else if (pending & STATUSF_IP4)
|
||||
do_IRQ(ATH79_CPU_IRQ_GE0);
|
||||
|
||||
else if (pending & STATUSF_IP5)
|
||||
do_IRQ(ATH79_CPU_IRQ_GE1);
|
||||
|
||||
else if (pending & STATUSF_IP3) {
|
||||
ath79_ddr_wb_flush(ath79_ip3_flush_reg);
|
||||
do_IRQ(ATH79_CPU_IRQ_USB);
|
||||
}
|
||||
|
||||
else if (pending & STATUSF_IP6)
|
||||
do_IRQ(ATH79_CPU_IRQ_MISC);
|
||||
|
||||
else
|
||||
spurious_interrupt();
|
||||
}
|
||||
|
||||
void __init arch_init_irq(void)
|
||||
{
|
||||
if (soc_is_ar71xx()) {
|
||||
ath79_ip2_flush_reg = AR71XX_DDR_REG_FLUSH_PCI;
|
||||
ath79_ip3_flush_reg = AR71XX_DDR_REG_FLUSH_USB;
|
||||
} else if (soc_is_ar724x()) {
|
||||
ath79_ip2_flush_reg = AR724X_DDR_REG_FLUSH_PCIE;
|
||||
ath79_ip3_flush_reg = AR724X_DDR_REG_FLUSH_USB;
|
||||
} else if (soc_is_ar913x()) {
|
||||
ath79_ip2_flush_reg = AR913X_DDR_REG_FLUSH_WMAC;
|
||||
ath79_ip3_flush_reg = AR913X_DDR_REG_FLUSH_USB;
|
||||
} else
|
||||
BUG();
|
||||
|
||||
cp0_perfcount_irq = ATH79_MISC_IRQ_PERFC;
|
||||
mips_cpu_irq_init();
|
||||
ath79_misc_irq_init();
|
||||
}
|
57
arch/mips/ath79/prom.c
Archivo normal
57
arch/mips/ath79/prom.c
Archivo normal
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Atheros AR71XX/AR724X/AR913X specific prom routines
|
||||
*
|
||||
* Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
|
||||
* Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/addrspace.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
static inline int is_valid_ram_addr(void *addr)
|
||||
{
|
||||
if (((u32) addr > KSEG0) &&
|
||||
((u32) addr < (KSEG0 + ATH79_MEM_SIZE_MAX)))
|
||||
return 1;
|
||||
|
||||
if (((u32) addr > KSEG1) &&
|
||||
((u32) addr < (KSEG1 + ATH79_MEM_SIZE_MAX)))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __init void ath79_prom_init_cmdline(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!is_valid_ram_addr(argv))
|
||||
return;
|
||||
|
||||
for (i = 0; i < argc; i++)
|
||||
if (is_valid_ram_addr(argv[i])) {
|
||||
strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline));
|
||||
strlcat(arcs_cmdline, argv[i], sizeof(arcs_cmdline));
|
||||
}
|
||||
}
|
||||
|
||||
void __init prom_init(void)
|
||||
{
|
||||
ath79_prom_init_cmdline(fw_arg0, (char **)fw_arg1);
|
||||
}
|
||||
|
||||
void __init prom_free_prom_memory(void)
|
||||
{
|
||||
/* We do not have to prom memory to free */
|
||||
}
|
190
arch/mips/ath79/setup.c
Archivo normal
190
arch/mips/ath79/setup.c
Archivo normal
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Atheros AR71XX/AR724X/AR913X specific setup
|
||||
*
|
||||
* Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
|
||||
* Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
|
||||
*
|
||||
* Parts of this file are based on Atheros' 2.6.15 BSP
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/bootmem.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/time.h> /* for mips_hpt_frequency */
|
||||
#include <asm/reboot.h> /* for _machine_{restart,halt} */
|
||||
|
||||
#include <asm/mach-ath79/ath79.h>
|
||||
#include <asm/mach-ath79/ar71xx_regs.h>
|
||||
#include "common.h"
|
||||
#include "dev-common.h"
|
||||
|
||||
#define ATH79_SYS_TYPE_LEN 64
|
||||
|
||||
#define AR71XX_BASE_FREQ 40000000
|
||||
#define AR724X_BASE_FREQ 5000000
|
||||
#define AR913X_BASE_FREQ 5000000
|
||||
|
||||
static char ath79_sys_type[ATH79_SYS_TYPE_LEN];
|
||||
|
||||
static void ath79_restart(char *command)
|
||||
{
|
||||
ath79_device_reset_set(AR71XX_RESET_FULL_CHIP);
|
||||
for (;;)
|
||||
if (cpu_wait)
|
||||
cpu_wait();
|
||||
}
|
||||
|
||||
static void ath79_halt(void)
|
||||
{
|
||||
while (1)
|
||||
cpu_wait();
|
||||
}
|
||||
|
||||
static void __init ath79_detect_mem_size(void)
|
||||
{
|
||||
unsigned long size;
|
||||
|
||||
for (size = ATH79_MEM_SIZE_MIN; size < ATH79_MEM_SIZE_MAX;
|
||||
size <<= 1) {
|
||||
if (!memcmp(ath79_detect_mem_size,
|
||||
ath79_detect_mem_size + size, 1024))
|
||||
break;
|
||||
}
|
||||
|
||||
add_memory_region(0, size, BOOT_MEM_RAM);
|
||||
}
|
||||
|
||||
static void __init ath79_detect_sys_type(void)
|
||||
{
|
||||
char *chip = "????";
|
||||
u32 id;
|
||||
u32 major;
|
||||
u32 minor;
|
||||
u32 rev = 0;
|
||||
|
||||
id = ath79_reset_rr(AR71XX_RESET_REG_REV_ID);
|
||||
major = id & REV_ID_MAJOR_MASK;
|
||||
|
||||
switch (major) {
|
||||
case REV_ID_MAJOR_AR71XX:
|
||||
minor = id & AR71XX_REV_ID_MINOR_MASK;
|
||||
rev = id >> AR71XX_REV_ID_REVISION_SHIFT;
|
||||
rev &= AR71XX_REV_ID_REVISION_MASK;
|
||||
switch (minor) {
|
||||
case AR71XX_REV_ID_MINOR_AR7130:
|
||||
ath79_soc = ATH79_SOC_AR7130;
|
||||
chip = "7130";
|
||||
break;
|
||||
|
||||
case AR71XX_REV_ID_MINOR_AR7141:
|
||||
ath79_soc = ATH79_SOC_AR7141;
|
||||
chip = "7141";
|
||||
break;
|
||||
|
||||
case AR71XX_REV_ID_MINOR_AR7161:
|
||||
ath79_soc = ATH79_SOC_AR7161;
|
||||
chip = "7161";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case REV_ID_MAJOR_AR7240:
|
||||
ath79_soc = ATH79_SOC_AR7240;
|
||||
chip = "7240";
|
||||
rev = (id & AR724X_REV_ID_REVISION_MASK);
|
||||
break;
|
||||
|
||||
case REV_ID_MAJOR_AR7241:
|
||||
ath79_soc = ATH79_SOC_AR7241;
|
||||
chip = "7241";
|
||||
rev = (id & AR724X_REV_ID_REVISION_MASK);
|
||||
break;
|
||||
|
||||
case REV_ID_MAJOR_AR7242:
|
||||
ath79_soc = ATH79_SOC_AR7242;
|
||||
chip = "7242";
|
||||
rev = (id & AR724X_REV_ID_REVISION_MASK);
|
||||
break;
|
||||
|
||||
case REV_ID_MAJOR_AR913X:
|
||||
minor = id & AR913X_REV_ID_MINOR_MASK;
|
||||
rev = id >> AR913X_REV_ID_REVISION_SHIFT;
|
||||
rev &= AR913X_REV_ID_REVISION_MASK;
|
||||
switch (minor) {
|
||||
case AR913X_REV_ID_MINOR_AR9130:
|
||||
ath79_soc = ATH79_SOC_AR9130;
|
||||
chip = "9130";
|
||||
break;
|
||||
|
||||
case AR913X_REV_ID_MINOR_AR9132:
|
||||
ath79_soc = ATH79_SOC_AR9132;
|
||||
chip = "9132";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
panic("ath79: unknown SoC, id:0x%08x\n", id);
|
||||
}
|
||||
|
||||
sprintf(ath79_sys_type, "Atheros AR%s rev %u", chip, rev);
|
||||
pr_info("SoC: %s\n", ath79_sys_type);
|
||||
}
|
||||
|
||||
const char *get_system_type(void)
|
||||
{
|
||||
return ath79_sys_type;
|
||||
}
|
||||
|
||||
unsigned int __cpuinit get_c0_compare_int(void)
|
||||
{
|
||||
return CP0_LEGACY_COMPARE_IRQ;
|
||||
}
|
||||
|
||||
void __init plat_mem_setup(void)
|
||||
{
|
||||
set_io_port_base(KSEG1);
|
||||
|
||||
ath79_reset_base = ioremap_nocache(AR71XX_RESET_BASE,
|
||||
AR71XX_RESET_SIZE);
|
||||
ath79_pll_base = ioremap_nocache(AR71XX_PLL_BASE,
|
||||
AR71XX_PLL_SIZE);
|
||||
|
||||
ath79_ddr_base = ioremap_nocache(AR71XX_DDR_CTRL_BASE,
|
||||
AR71XX_DDR_CTRL_SIZE);
|
||||
|
||||
ath79_detect_sys_type();
|
||||
ath79_detect_mem_size();
|
||||
ath79_clocks_init();
|
||||
|
||||
_machine_restart = ath79_restart;
|
||||
_machine_halt = ath79_halt;
|
||||
pm_power_off = ath79_halt;
|
||||
}
|
||||
|
||||
void __init plat_time_init(void)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
clk = clk_get(NULL, "cpu");
|
||||
if (IS_ERR(clk))
|
||||
panic("unable to get CPU clock, err=%ld", PTR_ERR(clk));
|
||||
|
||||
mips_hpt_frequency = clk_get_rate(clk) / 2;
|
||||
}
|
||||
|
||||
static int __init ath79_setup(void)
|
||||
{
|
||||
ath79_register_uart();
|
||||
return 0;
|
||||
}
|
||||
|
||||
arch_initcall(ath79_setup);
|
Referencia en una nueva incidencia
Block a user