Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/upstream-linus
* 'upstream' of git://git.linux-mips.org/pub/scm/upstream-linus: (26 commits) MIPS: Malta: enable Cirrus FB console MIPS: add CONFIG_VIRTUALIZATION for virtio support MIPS: Implement __read_mostly MIPS: ath79: add common WMAC device for AR913X based boards MIPS: ath79: Add initial support for the Atheros AP81 reference board MIPS: ath79: add common SPI controller device SPI: Add SPI controller driver for the Atheros AR71XX/AR724X/AR913X SoCs MIPS: ath79: add common GPIO buttons device MIPS: ath79: add common watchdog device MIPS: ath79: add common GPIO LEDs device MIPS: ath79: add initial support for the Atheros PB44 reference board MIPS: ath79: utilize the MIPS multi-machine support MIPS: ath79: add GPIOLIB support MIPS: Add initial support for the Atheros AR71XX/AR724X/AR931X SoCs MIPS: jump label: Add MIPS support. MIPS: Use WARN() in uasm for better diagnostics. MIPS: Optimize TLB handlers for Octeon CPUs MIPS: Add LDX and LWX instructions to uasm. MIPS: Use BBIT instructions in TLB handlers MIPS: Declare uasm bbit0 and bbit1 functions. ...
This commit is contained in:
Коммит
5d7e8af3c5
|
@ -2,6 +2,7 @@
|
|||
|
||||
platforms += alchemy
|
||||
platforms += ar7
|
||||
platforms += ath79
|
||||
platforms += bcm47xx
|
||||
platforms += bcm63xx
|
||||
platforms += cavium-octeon
|
||||
|
|
|
@ -21,6 +21,7 @@ config MIPS
|
|||
select HAVE_DMA_API_DEBUG
|
||||
select HAVE_GENERIC_HARDIRQS
|
||||
select GENERIC_IRQ_PROBE
|
||||
select HAVE_ARCH_JUMP_LABEL
|
||||
|
||||
menu "Machine selection"
|
||||
|
||||
|
@ -65,6 +66,22 @@ config AR7
|
|||
Support for the Texas Instruments AR7 System-on-a-Chip
|
||||
family: TNETD7100, 7200 and 7300.
|
||||
|
||||
config ATH79
|
||||
bool "Atheros AR71XX/AR724X/AR913X based boards"
|
||||
select ARCH_REQUIRE_GPIOLIB
|
||||
select BOOT_RAW
|
||||
select CEVT_R4K
|
||||
select CSRC_R4K
|
||||
select DMA_NONCOHERENT
|
||||
select IRQ_CPU
|
||||
select MIPS_MACHINE
|
||||
select SYS_HAS_CPU_MIPS32_R2
|
||||
select SYS_HAS_EARLY_PRINTK
|
||||
select SYS_SUPPORTS_32BIT_KERNEL
|
||||
select SYS_SUPPORTS_BIG_ENDIAN
|
||||
help
|
||||
Support for the Atheros AR71XX/AR724X/AR913X SoCs.
|
||||
|
||||
config BCM47XX
|
||||
bool "Broadcom BCM47XX based boards"
|
||||
select CEVT_R4K
|
||||
|
@ -717,6 +734,7 @@ config CAVIUM_OCTEON_REFERENCE_BOARD
|
|||
endchoice
|
||||
|
||||
source "arch/mips/alchemy/Kconfig"
|
||||
source "arch/mips/ath79/Kconfig"
|
||||
source "arch/mips/bcm63xx/Kconfig"
|
||||
source "arch/mips/jazz/Kconfig"
|
||||
source "arch/mips/jz4740/Kconfig"
|
||||
|
@ -883,6 +901,9 @@ config MIPS_DISABLE_OBSOLETE_IDE
|
|||
config SYNC_R4K
|
||||
bool
|
||||
|
||||
config MIPS_MACHINE
|
||||
def_bool n
|
||||
|
||||
config NO_IOPORT
|
||||
def_bool n
|
||||
|
||||
|
@ -2400,4 +2421,20 @@ source "security/Kconfig"
|
|||
|
||||
source "crypto/Kconfig"
|
||||
|
||||
menuconfig VIRTUALIZATION
|
||||
bool "Virtualization"
|
||||
default n
|
||||
---help---
|
||||
Say Y here to get to see options for using your Linux host to run other
|
||||
operating systems inside virtual machines (guests).
|
||||
This option alone does not add any kernel code.
|
||||
|
||||
If you say N, all options in this submenu will be skipped and disabled.
|
||||
|
||||
if VIRTUALIZATION
|
||||
|
||||
source drivers/virtio/Kconfig
|
||||
|
||||
endif # VIRTUALIZATION
|
||||
|
||||
source "lib/Kconfig"
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
if ATH79
|
||||
|
||||
menu "Atheros AR71XX/AR724X/AR913X machine selection"
|
||||
|
||||
config ATH79_MACH_AP81
|
||||
bool "Atheros AP81 reference board"
|
||||
select SOC_AR913X
|
||||
select ATH79_DEV_AR913X_WMAC
|
||||
select ATH79_DEV_GPIO_BUTTONS
|
||||
select ATH79_DEV_LEDS_GPIO
|
||||
select ATH79_DEV_SPI
|
||||
help
|
||||
Say 'Y' here if you want your kernel to support the
|
||||
Atheros AP81 reference board.
|
||||
|
||||
config ATH79_MACH_PB44
|
||||
bool "Atheros PB44 reference board"
|
||||
select SOC_AR71XX
|
||||
select ATH79_DEV_GPIO_BUTTONS
|
||||
select ATH79_DEV_LEDS_GPIO
|
||||
select ATH79_DEV_SPI
|
||||
help
|
||||
Say 'Y' here if you want your kernel to support the
|
||||
Atheros PB44 reference board.
|
||||
|
||||
endmenu
|
||||
|
||||
config SOC_AR71XX
|
||||
def_bool n
|
||||
|
||||
config SOC_AR724X
|
||||
def_bool n
|
||||
|
||||
config SOC_AR913X
|
||||
def_bool n
|
||||
|
||||
config ATH79_DEV_AR913X_WMAC
|
||||
depends on SOC_AR913X
|
||||
def_bool n
|
||||
|
||||
config ATH79_DEV_GPIO_BUTTONS
|
||||
def_bool n
|
||||
|
||||
config ATH79_DEV_LEDS_GPIO
|
||||
def_bool n
|
||||
|
||||
config ATH79_DEV_SPI
|
||||
def_bool n
|
||||
|
||||
endif
|
|
@ -0,0 +1,28 @@
|
|||
#
|
||||
# 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 gpio.o
|
||||
|
||||
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
|
||||
|
||||
#
|
||||
# Devices
|
||||
#
|
||||
obj-y += dev-common.o
|
||||
obj-$(CONFIG_ATH79_DEV_AR913X_WMAC) += dev-ar913x-wmac.o
|
||||
obj-$(CONFIG_ATH79_DEV_GPIO_BUTTONS) += dev-gpio-buttons.o
|
||||
obj-$(CONFIG_ATH79_DEV_LEDS_GPIO) += dev-leds-gpio.o
|
||||
obj-$(CONFIG_ATH79_DEV_SPI) += dev-spi.o
|
||||
|
||||
#
|
||||
# Machines
|
||||
#
|
||||
obj-$(CONFIG_ATH79_MACH_AP81) += mach-ap81.o
|
||||
obj-$(CONFIG_ATH79_MACH_PB44) += mach-pb44.o
|
|
@ -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
|
|
@ -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);
|
|
@ -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);
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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);
|
||||
|
||||
void ath79_gpio_function_enable(u32 mask);
|
||||
void ath79_gpio_function_disable(u32 mask);
|
||||
void ath79_gpio_function_setup(u32 set, u32 clear);
|
||||
void ath79_gpio_init(void);
|
||||
|
||||
#endif /* __ATH79_COMMON_H */
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Atheros AR913X SoC built-in WMAC device 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/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/ath9k_platform.h>
|
||||
|
||||
#include <asm/mach-ath79/ath79.h>
|
||||
#include <asm/mach-ath79/ar71xx_regs.h>
|
||||
#include "dev-ar913x-wmac.h"
|
||||
|
||||
static struct ath9k_platform_data ar913x_wmac_data;
|
||||
|
||||
static struct resource ar913x_wmac_resources[] = {
|
||||
{
|
||||
.start = AR913X_WMAC_BASE,
|
||||
.end = AR913X_WMAC_BASE + AR913X_WMAC_SIZE - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
}, {
|
||||
.start = ATH79_CPU_IRQ_IP2,
|
||||
.end = ATH79_CPU_IRQ_IP2,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device ar913x_wmac_device = {
|
||||
.name = "ath9k",
|
||||
.id = -1,
|
||||
.resource = ar913x_wmac_resources,
|
||||
.num_resources = ARRAY_SIZE(ar913x_wmac_resources),
|
||||
.dev = {
|
||||
.platform_data = &ar913x_wmac_data,
|
||||
},
|
||||
};
|
||||
|
||||
void __init ath79_register_ar913x_wmac(u8 *cal_data)
|
||||
{
|
||||
if (cal_data)
|
||||
memcpy(ar913x_wmac_data.eeprom_data, cal_data,
|
||||
sizeof(ar913x_wmac_data.eeprom_data));
|
||||
|
||||
/* reset the WMAC */
|
||||
ath79_device_reset_set(AR913X_RESET_AMBA2WMAC);
|
||||
mdelay(10);
|
||||
|
||||
ath79_device_reset_clear(AR913X_RESET_AMBA2WMAC);
|
||||
mdelay(10);
|
||||
|
||||
platform_device_register(&ar913x_wmac_device);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Atheros AR913X SoC built-in WMAC device 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.
|
||||
*/
|
||||
|
||||
#ifndef _ATH79_DEV_AR913X_WMAC_H
|
||||
#define _ATH79_DEV_AR913X_WMAC_H
|
||||
|
||||
void ath79_register_ar913x_wmac(u8 *cal_data);
|
||||
|
||||
#endif /* _ATH79_DEV_AR913X_WMAC_H */
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
static struct platform_device ath79_wdt_device = {
|
||||
.name = "ath79-wdt",
|
||||
.id = -1,
|
||||
};
|
||||
|
||||
void __init ath79_register_wdt(void)
|
||||
{
|
||||
platform_device_register(&ath79_wdt_device);
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* 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);
|
||||
void ath79_register_wdt(void);
|
||||
|
||||
#endif /* _ATH79_DEV_COMMON_H */
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Atheros AR71XX/AR724X/AR913X GPIO button 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/init.h"
|
||||
#include "linux/slab.h"
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "dev-gpio-buttons.h"
|
||||
|
||||
void __init ath79_register_gpio_keys_polled(int id,
|
||||
unsigned poll_interval,
|
||||
unsigned nbuttons,
|
||||
struct gpio_keys_button *buttons)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
struct gpio_keys_platform_data pdata;
|
||||
struct gpio_keys_button *p;
|
||||
int err;
|
||||
|
||||
p = kmalloc(nbuttons * sizeof(*p), GFP_KERNEL);
|
||||
if (!p)
|
||||
return;
|
||||
|
||||
memcpy(p, buttons, nbuttons * sizeof(*p));
|
||||
|
||||
pdev = platform_device_alloc("gpio-keys-polled", id);
|
||||
if (!pdev)
|
||||
goto err_free_buttons;
|
||||
|
||||
memset(&pdata, 0, sizeof(pdata));
|
||||
pdata.poll_interval = poll_interval;
|
||||
pdata.nbuttons = nbuttons;
|
||||
pdata.buttons = p;
|
||||
|
||||
err = platform_device_add_data(pdev, &pdata, sizeof(pdata));
|
||||
if (err)
|
||||
goto err_put_pdev;
|
||||
|
||||
err = platform_device_add(pdev);
|
||||
if (err)
|
||||
goto err_put_pdev;
|
||||
|
||||
return;
|
||||
|
||||
err_put_pdev:
|
||||
platform_device_put(pdev);
|
||||
|
||||
err_free_buttons:
|
||||
kfree(p);
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Atheros AR71XX/AR724X/AR913X GPIO button 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.
|
||||
*/
|
||||
|
||||
#ifndef _ATH79_DEV_GPIO_BUTTONS_H
|
||||
#define _ATH79_DEV_GPIO_BUTTONS_H
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <linux/gpio_keys.h>
|
||||
|
||||
void ath79_register_gpio_keys_polled(int id,
|
||||
unsigned poll_interval,
|
||||
unsigned nbuttons,
|
||||
struct gpio_keys_button *buttons);
|
||||
|
||||
#endif /* _ATH79_DEV_GPIO_BUTTONS_H */
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Atheros AR71XX/AR724X/AR913X common GPIO LEDs 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/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "dev-leds-gpio.h"
|
||||
|
||||
void __init ath79_register_leds_gpio(int id,
|
||||
unsigned num_leds,
|
||||
struct gpio_led *leds)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
struct gpio_led_platform_data pdata;
|
||||
struct gpio_led *p;
|
||||
int err;
|
||||
|
||||
p = kmalloc(num_leds * sizeof(*p), GFP_KERNEL);
|
||||
if (!p)
|
||||
return;
|
||||
|
||||
memcpy(p, leds, num_leds * sizeof(*p));
|
||||
|
||||
pdev = platform_device_alloc("leds-gpio", id);
|
||||
if (!pdev)
|
||||
goto err_free_leds;
|
||||
|
||||
memset(&pdata, 0, sizeof(pdata));
|
||||
pdata.num_leds = num_leds;
|
||||
pdata.leds = p;
|
||||
|
||||
err = platform_device_add_data(pdev, &pdata, sizeof(pdata));
|
||||
if (err)
|
||||
goto err_put_pdev;
|
||||
|
||||
err = platform_device_add(pdev);
|
||||
if (err)
|
||||
goto err_put_pdev;
|
||||
|
||||
return;
|
||||
|
||||
err_put_pdev:
|
||||
platform_device_put(pdev);
|
||||
|
||||
err_free_leds:
|
||||
kfree(p);
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Atheros AR71XX/AR724X/AR913X common GPIO LEDs 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.
|
||||
*/
|
||||
|
||||
#ifndef _ATH79_DEV_LEDS_GPIO_H
|
||||
#define _ATH79_DEV_LEDS_GPIO_H
|
||||
|
||||
#include <linux/leds.h>
|
||||
|
||||
void ath79_register_leds_gpio(int id,
|
||||
unsigned num_leds,
|
||||
struct gpio_led *leds);
|
||||
|
||||
#endif /* _ATH79_DEV_LEDS_GPIO_H */
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Atheros AR71XX/AR724X/AR913X SPI controller device
|
||||
*
|
||||
* 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/platform_device.h>
|
||||
#include <asm/mach-ath79/ar71xx_regs.h>
|
||||
#include "dev-spi.h"
|
||||
|
||||
static struct resource ath79_spi_resources[] = {
|
||||
{
|
||||
.start = AR71XX_SPI_BASE,
|
||||
.end = AR71XX_SPI_BASE + AR71XX_SPI_SIZE - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device ath79_spi_device = {
|
||||
.name = "ath79-spi",
|
||||
.id = -1,
|
||||
.resource = ath79_spi_resources,
|
||||
.num_resources = ARRAY_SIZE(ath79_spi_resources),
|
||||
};
|
||||
|
||||
void __init ath79_register_spi(struct ath79_spi_platform_data *pdata,
|
||||
struct spi_board_info const *info,
|
||||
unsigned n)
|
||||
{
|
||||
spi_register_board_info(info, n);
|
||||
ath79_spi_device.dev.platform_data = pdata;
|
||||
platform_device_register(&ath79_spi_device);
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Atheros AR71XX/AR724X/AR913X SPI controller device
|
||||
*
|
||||
* 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_SPI_H
|
||||
#define _ATH79_DEV_SPI_H
|
||||
|
||||
#include <linux/spi/spi.h>
|
||||
#include <asm/mach-ath79/ath79_spi_platform.h>
|
||||
|
||||
void ath79_register_spi(struct ath79_spi_platform_data *pdata,
|
||||
struct spi_board_info const *info,
|
||||
unsigned n);
|
||||
|
||||
#endif /* _ATH79_DEV_SPI_H */
|
|
@ -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);
|
||||
}
|
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
* Atheros AR71XX/AR724X/AR913X GPIO API 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/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <asm/mach-ath79/ar71xx_regs.h>
|
||||
#include <asm/mach-ath79/ath79.h>
|
||||
#include "common.h"
|
||||
|
||||
static void __iomem *ath79_gpio_base;
|
||||
static unsigned long ath79_gpio_count;
|
||||
static DEFINE_SPINLOCK(ath79_gpio_lock);
|
||||
|
||||
static void __ath79_gpio_set_value(unsigned gpio, int value)
|
||||
{
|
||||
void __iomem *base = ath79_gpio_base;
|
||||
|
||||
if (value)
|
||||
__raw_writel(1 << gpio, base + AR71XX_GPIO_REG_SET);
|
||||
else
|
||||
__raw_writel(1 << gpio, base + AR71XX_GPIO_REG_CLEAR);
|
||||
}
|
||||
|
||||
static int __ath79_gpio_get_value(unsigned gpio)
|
||||
{
|
||||
return (__raw_readl(ath79_gpio_base + AR71XX_GPIO_REG_IN) >> gpio) & 1;
|
||||
}
|
||||
|
||||
static int ath79_gpio_get_value(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
return __ath79_gpio_get_value(offset);
|
||||
}
|
||||
|
||||
static void ath79_gpio_set_value(struct gpio_chip *chip,
|
||||
unsigned offset, int value)
|
||||
{
|
||||
__ath79_gpio_set_value(offset, value);
|
||||
}
|
||||
|
||||
static int ath79_gpio_direction_input(struct gpio_chip *chip,
|
||||
unsigned offset)
|
||||
{
|
||||
void __iomem *base = ath79_gpio_base;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ath79_gpio_lock, flags);
|
||||
|
||||
__raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) & ~(1 << offset),
|
||||
base + AR71XX_GPIO_REG_OE);
|
||||
|
||||
spin_unlock_irqrestore(&ath79_gpio_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath79_gpio_direction_output(struct gpio_chip *chip,
|
||||
unsigned offset, int value)
|
||||
{
|
||||
void __iomem *base = ath79_gpio_base;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ath79_gpio_lock, flags);
|
||||
|
||||
if (value)
|
||||
__raw_writel(1 << offset, base + AR71XX_GPIO_REG_SET);
|
||||
else
|
||||
__raw_writel(1 << offset, base + AR71XX_GPIO_REG_CLEAR);
|
||||
|
||||
__raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) | (1 << offset),
|
||||
base + AR71XX_GPIO_REG_OE);
|
||||
|
||||
spin_unlock_irqrestore(&ath79_gpio_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct gpio_chip ath79_gpio_chip = {
|
||||
.label = "ath79",
|
||||
.get = ath79_gpio_get_value,
|
||||
.set = ath79_gpio_set_value,
|
||||
.direction_input = ath79_gpio_direction_input,
|
||||
.direction_output = ath79_gpio_direction_output,
|
||||
.base = 0,
|
||||
};
|
||||
|
||||
void ath79_gpio_function_enable(u32 mask)
|
||||
{
|
||||
void __iomem *base = ath79_gpio_base;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ath79_gpio_lock, flags);
|
||||
|
||||
__raw_writel(__raw_readl(base + AR71XX_GPIO_REG_FUNC) | mask,
|
||||
base + AR71XX_GPIO_REG_FUNC);
|
||||
/* flush write */
|
||||
__raw_readl(base + AR71XX_GPIO_REG_FUNC);
|
||||
|
||||
spin_unlock_irqrestore(&ath79_gpio_lock, flags);
|
||||
}
|
||||
|
||||
void ath79_gpio_function_disable(u32 mask)
|
||||
{
|
||||
void __iomem *base = ath79_gpio_base;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ath79_gpio_lock, flags);
|
||||
|
||||
__raw_writel(__raw_readl(base + AR71XX_GPIO_REG_FUNC) & ~mask,
|
||||
base + AR71XX_GPIO_REG_FUNC);
|
||||
/* flush write */
|
||||
__raw_readl(base + AR71XX_GPIO_REG_FUNC);
|
||||
|
||||
spin_unlock_irqrestore(&ath79_gpio_lock, flags);
|
||||
}
|
||||
|
||||
void ath79_gpio_function_setup(u32 set, u32 clear)
|
||||
{
|
||||
void __iomem *base = ath79_gpio_base;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ath79_gpio_lock, flags);
|
||||
|
||||
__raw_writel((__raw_readl(base + AR71XX_GPIO_REG_FUNC) & ~clear) | set,
|
||||
base + AR71XX_GPIO_REG_FUNC);
|
||||
/* flush write */
|
||||
__raw_readl(base + AR71XX_GPIO_REG_FUNC);
|
||||
|
||||
spin_unlock_irqrestore(&ath79_gpio_lock, flags);
|
||||
}
|
||||
|
||||
void __init ath79_gpio_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (soc_is_ar71xx())
|
||||
ath79_gpio_count = AR71XX_GPIO_COUNT;
|
||||
else if (soc_is_ar724x())
|
||||
ath79_gpio_count = AR724X_GPIO_COUNT;
|
||||
else if (soc_is_ar913x())
|
||||
ath79_gpio_count = AR913X_GPIO_COUNT;
|
||||
else
|
||||
BUG();
|
||||
|
||||
ath79_gpio_base = ioremap_nocache(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE);
|
||||
ath79_gpio_chip.ngpio = ath79_gpio_count;
|
||||
|
||||
err = gpiochip_add(&ath79_gpio_chip);
|
||||
if (err)
|
||||
panic("cannot add AR71xx GPIO chip, error=%d", err);
|
||||
}
|
||||
|
||||
int gpio_get_value(unsigned gpio)
|
||||
{
|
||||
if (gpio < ath79_gpio_count)
|
||||
return __ath79_gpio_get_value(gpio);
|
||||
|
||||
return __gpio_get_value(gpio);
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_get_value);
|
||||
|
||||
void gpio_set_value(unsigned gpio, int value)
|
||||
{
|
||||
if (gpio < ath79_gpio_count)
|
||||
__ath79_gpio_set_value(gpio, value);
|
||||
else
|
||||
__gpio_set_value(gpio, value);
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_set_value);
|
||||
|
||||
int gpio_to_irq(unsigned gpio)
|
||||
{
|
||||
/* FIXME */
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_to_irq);
|
||||
|
||||
int irq_to_gpio(unsigned irq)
|
||||
{
|
||||
/* FIXME */
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL(irq_to_gpio);
|
|
@ -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();
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Atheros AP81 board support
|
||||
*
|
||||
* Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
|
||||
* Copyright (C) 2009 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 "machtypes.h"
|
||||
#include "dev-ar913x-wmac.h"
|
||||
#include "dev-gpio-buttons.h"
|
||||
#include "dev-leds-gpio.h"
|
||||
#include "dev-spi.h"
|
||||
|
||||
#define AP81_GPIO_LED_STATUS 1
|
||||
#define AP81_GPIO_LED_AOSS 3
|
||||
#define AP81_GPIO_LED_WLAN 6
|
||||
#define AP81_GPIO_LED_POWER 14
|
||||
|
||||
#define AP81_GPIO_BTN_SW4 12
|
||||
#define AP81_GPIO_BTN_SW1 21
|
||||
|
||||
#define AP81_KEYS_POLL_INTERVAL 20 /* msecs */
|
||||
#define AP81_KEYS_DEBOUNCE_INTERVAL (3 * AP81_KEYS_POLL_INTERVAL)
|
||||
|
||||
#define AP81_CAL_DATA_ADDR 0x1fff1000
|
||||
|
||||
static struct gpio_led ap81_leds_gpio[] __initdata = {
|
||||
{
|
||||
.name = "ap81:green:status",
|
||||
.gpio = AP81_GPIO_LED_STATUS,
|
||||
.active_low = 1,
|
||||
}, {
|
||||
.name = "ap81:amber:aoss",
|
||||
.gpio = AP81_GPIO_LED_AOSS,
|
||||
.active_low = 1,
|
||||
}, {
|
||||
.name = "ap81:green:wlan",
|
||||
.gpio = AP81_GPIO_LED_WLAN,
|
||||
.active_low = 1,
|
||||
}, {
|
||||
.name = "ap81:green:power",
|
||||
.gpio = AP81_GPIO_LED_POWER,
|
||||
.active_low = 1,
|
||||
}
|
||||
};
|
||||
|
||||
static struct gpio_keys_button ap81_gpio_keys[] __initdata = {
|
||||
{
|
||||
.desc = "sw1",
|
||||
.type = EV_KEY,
|
||||
.code = BTN_0,
|
||||
.debounce_interval = AP81_KEYS_DEBOUNCE_INTERVAL,
|
||||
.gpio = AP81_GPIO_BTN_SW1,
|
||||
.active_low = 1,
|
||||
} , {
|
||||
.desc = "sw4",
|
||||
.type = EV_KEY,
|
||||
.code = BTN_1,
|
||||
.debounce_interval = AP81_KEYS_DEBOUNCE_INTERVAL,
|
||||
.gpio = AP81_GPIO_BTN_SW4,
|
||||
.active_low = 1,
|
||||
}
|
||||
};
|
||||
|
||||
static struct spi_board_info ap81_spi_info[] = {
|
||||
{
|
||||
.bus_num = 0,
|
||||
.chip_select = 0,
|
||||
.max_speed_hz = 25000000,
|
||||
.modalias = "m25p64",
|
||||
}
|
||||
};
|
||||
|
||||
static struct ath79_spi_platform_data ap81_spi_data = {
|
||||
.bus_num = 0,
|
||||
.num_chipselect = 1,
|
||||
};
|
||||
|
||||
static void __init ap81_setup(void)
|
||||
{
|
||||
u8 *cal_data = (u8 *) KSEG1ADDR(AP81_CAL_DATA_ADDR);
|
||||
|
||||
ath79_register_leds_gpio(-1, ARRAY_SIZE(ap81_leds_gpio),
|
||||
ap81_leds_gpio);
|
||||
ath79_register_gpio_keys_polled(-1, AP81_KEYS_POLL_INTERVAL,
|
||||
ARRAY_SIZE(ap81_gpio_keys),
|
||||
ap81_gpio_keys);
|
||||
ath79_register_spi(&ap81_spi_data, ap81_spi_info,
|
||||
ARRAY_SIZE(ap81_spi_info));
|
||||
ath79_register_ar913x_wmac(cal_data);
|
||||
}
|
||||
|
||||
MIPS_MACHINE(ATH79_MACH_AP81, "AP81", "Atheros AP81 reference board",
|
||||
ap81_setup);
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Atheros PB44 reference board support
|
||||
*
|
||||
* Copyright (C) 2009-2010 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/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-gpio.h>
|
||||
#include <linux/i2c/pcf857x.h>
|
||||
|
||||
#include "machtypes.h"
|
||||
#include "dev-gpio-buttons.h"
|
||||
#include "dev-leds-gpio.h"
|
||||
#include "dev-spi.h"
|
||||
|
||||
#define PB44_GPIO_I2C_SCL 0
|
||||
#define PB44_GPIO_I2C_SDA 1
|
||||
|
||||
#define PB44_GPIO_EXP_BASE 16
|
||||
#define PB44_GPIO_SW_RESET (PB44_GPIO_EXP_BASE + 6)
|
||||
#define PB44_GPIO_SW_JUMP (PB44_GPIO_EXP_BASE + 8)
|
||||
#define PB44_GPIO_LED_JUMP1 (PB44_GPIO_EXP_BASE + 9)
|
||||
#define PB44_GPIO_LED_JUMP2 (PB44_GPIO_EXP_BASE + 10)
|
||||
|
||||
#define PB44_KEYS_POLL_INTERVAL 20 /* msecs */
|
||||
#define PB44_KEYS_DEBOUNCE_INTERVAL (3 * PB44_KEYS_POLL_INTERVAL)
|
||||
|
||||
static struct i2c_gpio_platform_data pb44_i2c_gpio_data = {
|
||||
.sda_pin = PB44_GPIO_I2C_SDA,
|
||||
.scl_pin = PB44_GPIO_I2C_SCL,
|
||||
};
|
||||
|
||||
static struct platform_device pb44_i2c_gpio_device = {
|
||||
.name = "i2c-gpio",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
.platform_data = &pb44_i2c_gpio_data,
|
||||
}
|
||||
};
|
||||
|
||||
static struct pcf857x_platform_data pb44_pcf857x_data = {
|
||||
.gpio_base = PB44_GPIO_EXP_BASE,
|
||||
};
|
||||
|
||||
static struct i2c_board_info pb44_i2c_board_info[] __initdata = {
|
||||
{
|
||||
I2C_BOARD_INFO("pcf8575", 0x20),
|
||||
.platform_data = &pb44_pcf857x_data,
|
||||
},
|
||||
};
|
||||
|
||||
static struct gpio_led pb44_leds_gpio[] __initdata = {
|
||||
{
|
||||
.name = "pb44:amber:jump1",
|
||||
.gpio = PB44_GPIO_LED_JUMP1,
|
||||
.active_low = 1,
|
||||
}, {
|
||||
.name = "pb44:green:jump2",
|
||||
.gpio = PB44_GPIO_LED_JUMP2,
|
||||
.active_low = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct gpio_keys_button pb44_gpio_keys[] __initdata = {
|
||||
{
|
||||
.desc = "soft_reset",
|
||||
.type = EV_KEY,
|
||||
.code = KEY_RESTART,
|
||||
.debounce_interval = PB44_KEYS_DEBOUNCE_INTERVAL,
|
||||
.gpio = PB44_GPIO_SW_RESET,
|
||||
.active_low = 1,
|
||||
} , {
|
||||
.desc = "jumpstart",
|
||||
.type = EV_KEY,
|
||||
.code = KEY_WPS_BUTTON,
|
||||
.debounce_interval = PB44_KEYS_DEBOUNCE_INTERVAL,
|
||||
.gpio = PB44_GPIO_SW_JUMP,
|
||||
.active_low = 1,
|
||||
}
|
||||
};
|
||||
|
||||
static struct spi_board_info pb44_spi_info[] = {
|
||||
{
|
||||
.bus_num = 0,
|
||||
.chip_select = 0,
|
||||
.max_speed_hz = 25000000,
|
||||
.modalias = "m25p64",
|
||||
},
|
||||
};
|
||||
|
||||
static struct ath79_spi_platform_data pb44_spi_data = {
|
||||
.bus_num = 0,
|
||||
.num_chipselect = 1,
|
||||
};
|
||||
|
||||
static void __init pb44_init(void)
|
||||
{
|
||||
i2c_register_board_info(0, pb44_i2c_board_info,
|
||||
ARRAY_SIZE(pb44_i2c_board_info));
|
||||
platform_device_register(&pb44_i2c_gpio_device);
|
||||
|
||||
ath79_register_leds_gpio(-1, ARRAY_SIZE(pb44_leds_gpio),
|
||||
pb44_leds_gpio);
|
||||
ath79_register_gpio_keys_polled(-1, PB44_KEYS_POLL_INTERVAL,
|
||||
ARRAY_SIZE(pb44_gpio_keys),
|
||||
pb44_gpio_keys);
|
||||
ath79_register_spi(&pb44_spi_data, pb44_spi_info,
|
||||
ARRAY_SIZE(pb44_spi_info));
|
||||
}
|
||||
|
||||
MIPS_MACHINE(ATH79_MACH_PB44, "PB44", "Atheros PB44 reference board",
|
||||
pb44_init);
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Atheros AR71XX/AR724X/AR913X machine type definitions
|
||||
*
|
||||
* 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_MACHTYPE_H
|
||||
#define _ATH79_MACHTYPE_H
|
||||
|
||||
#include <asm/mips_machine.h>
|
||||
|
||||
enum ath79_mach_type {
|
||||
ATH79_MACH_GENERIC = 0,
|
||||
ATH79_MACH_AP81, /* Atheros AP81 reference board */
|
||||
ATH79_MACH_PB44, /* Atheros PB44 reference board */
|
||||
};
|
||||
|
||||
#endif /* _ATH79_MACHTYPE_H */
|
|
@ -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 */
|
||||
}
|
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
* 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/mips_machine.h>
|
||||
|
||||
#include <asm/mach-ath79/ath79.h>
|
||||
#include <asm/mach-ath79/ar71xx_regs.h>
|
||||
#include "common.h"
|
||||
#include "dev-common.h"
|
||||
#include "machtypes.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_gpio_init();
|
||||
ath79_register_uart();
|
||||
ath79_register_wdt();
|
||||
|
||||
mips_machine_setup();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
arch_initcall(ath79_setup);
|
||||
|
||||
static void __init ath79_generic_init(void)
|
||||
{
|
||||
/* Nothing to do */
|
||||
}
|
||||
|
||||
MIPS_MACHINE(ATH79_MACH_GENERIC,
|
||||
"Generic",
|
||||
"Generic AR71XX/AR724X/AR913X based board",
|
||||
ath79_generic_init);
|
|
@ -369,7 +369,10 @@ CONFIG_VT_HW_CONSOLE_BINDING=y
|
|||
CONFIG_SERIAL_8250=y
|
||||
CONFIG_SERIAL_8250_CONSOLE=y
|
||||
# CONFIG_HWMON is not set
|
||||
CONFIG_FB=y
|
||||
CONFIG_FB_CIRRUS=y
|
||||
# CONFIG_VGA_CONSOLE is not set
|
||||
CONFIG_FRAMEBUFFER_CONSOLE=y
|
||||
CONFIG_HID=m
|
||||
CONFIG_LEDS_CLASS=m
|
||||
CONFIG_LEDS_TRIGGER_TIMER=m
|
||||
|
|
|
@ -17,4 +17,6 @@
|
|||
#define SMP_CACHE_SHIFT L1_CACHE_SHIFT
|
||||
#define SMP_CACHE_BYTES L1_CACHE_BYTES
|
||||
|
||||
#define __read_mostly __attribute__((__section__(".data.read_mostly")))
|
||||
|
||||
#endif /* _ASM_CACHE_H */
|
||||
|
|
|
@ -78,6 +78,7 @@ struct cpuinfo_mips {
|
|||
unsigned int watch_reg_use_cnt; /* Usable by ptrace */
|
||||
#define NUM_WATCH_REGS 4
|
||||
u16 watch_reg_masks[NUM_WATCH_REGS];
|
||||
unsigned int kscratch_mask; /* Usable KScratch mask. */
|
||||
} __attribute__((aligned(SMP_CACHE_BYTES)));
|
||||
|
||||
extern struct cpuinfo_mips cpu_data[];
|
||||
|
|
|
@ -72,6 +72,7 @@ enum spec2_op {
|
|||
enum spec3_op {
|
||||
ext_op, dextm_op, dextu_op, dext_op,
|
||||
ins_op, dinsm_op, dinsu_op, dins_op,
|
||||
lx_op = 0x0a,
|
||||
bshfl_op = 0x20,
|
||||
dbshfl_op = 0x24,
|
||||
rdhwr_op = 0x3b
|
||||
|
@ -178,6 +179,19 @@ enum mad_func {
|
|||
nmadd_fp_op = 0x0c, nmsub_fp_op = 0x0e
|
||||
};
|
||||
|
||||
/*
|
||||
* func field for special3 lx opcodes (Cavium Octeon).
|
||||
*/
|
||||
enum lx_func {
|
||||
lwx_op = 0x00,
|
||||
lhx_op = 0x04,
|
||||
lbux_op = 0x06,
|
||||
ldx_op = 0x08,
|
||||
lwux_op = 0x10,
|
||||
lhux_op = 0x14,
|
||||
lbx_op = 0x16,
|
||||
};
|
||||
|
||||
/*
|
||||
* Damn ... bitfields depend from byteorder :-(
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* 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) 2010 Cavium Networks, Inc.
|
||||
*/
|
||||
#ifndef _ASM_MIPS_JUMP_LABEL_H
|
||||
#define _ASM_MIPS_JUMP_LABEL_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#define JUMP_LABEL_NOP_SIZE 4
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
#define WORD_INSN ".dword"
|
||||
#else
|
||||
#define WORD_INSN ".word"
|
||||
#endif
|
||||
|
||||
#define JUMP_LABEL(key, label) \
|
||||
do { \
|
||||
asm goto("1:\tnop\n\t" \
|
||||
"nop\n\t" \
|
||||
".pushsection __jump_table, \"a\"\n\t" \
|
||||
WORD_INSN " 1b, %l[" #label "], %0\n\t" \
|
||||
".popsection\n\t" \
|
||||
: : "i" (key) : : label); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
typedef u64 jump_label_t;
|
||||
#else
|
||||
typedef u32 jump_label_t;
|
||||
#endif
|
||||
|
||||
struct jump_entry {
|
||||
jump_label_t code;
|
||||
jump_label_t target;
|
||||
jump_label_t key;
|
||||
};
|
||||
|
||||
#endif /* _ASM_MIPS_JUMP_LABEL_H */
|
|
@ -0,0 +1,233 @@
|
|||
/*
|
||||
* Atheros AR71XX/AR724X/AR913X SoC register definitions
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __ASM_MACH_AR71XX_REGS_H
|
||||
#define __ASM_MACH_AR71XX_REGS_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#define AR71XX_APB_BASE 0x18000000
|
||||
#define AR71XX_SPI_BASE 0x1f000000
|
||||
#define AR71XX_SPI_SIZE 0x01000000
|
||||
|
||||
#define AR71XX_DDR_CTRL_BASE (AR71XX_APB_BASE + 0x00000000)
|
||||
#define AR71XX_DDR_CTRL_SIZE 0x100
|
||||
#define AR71XX_UART_BASE (AR71XX_APB_BASE + 0x00020000)
|
||||
#define AR71XX_UART_SIZE 0x100
|
||||
#define AR71XX_GPIO_BASE (AR71XX_APB_BASE + 0x00040000)
|
||||
#define AR71XX_GPIO_SIZE 0x100
|
||||
#define AR71XX_PLL_BASE (AR71XX_APB_BASE + 0x00050000)
|
||||
#define AR71XX_PLL_SIZE 0x100
|
||||
#define AR71XX_RESET_BASE (AR71XX_APB_BASE + 0x00060000)
|
||||
#define AR71XX_RESET_SIZE 0x100
|
||||
|
||||
#define AR913X_WMAC_BASE (AR71XX_APB_BASE + 0x000C0000)
|
||||
#define AR913X_WMAC_SIZE 0x30000
|
||||
|
||||
/*
|
||||
* DDR_CTRL block
|
||||
*/
|
||||
#define AR71XX_DDR_REG_PCI_WIN0 0x7c
|
||||
#define AR71XX_DDR_REG_PCI_WIN1 0x80
|
||||
#define AR71XX_DDR_REG_PCI_WIN2 0x84
|
||||
#define AR71XX_DDR_REG_PCI_WIN3 0x88
|
||||
#define AR71XX_DDR_REG_PCI_WIN4 0x8c
|
||||
#define AR71XX_DDR_REG_PCI_WIN5 0x90
|
||||
#define AR71XX_DDR_REG_PCI_WIN6 0x94
|
||||
#define AR71XX_DDR_REG_PCI_WIN7 0x98
|
||||
#define AR71XX_DDR_REG_FLUSH_GE0 0x9c
|
||||
#define AR71XX_DDR_REG_FLUSH_GE1 0xa0
|
||||
#define AR71XX_DDR_REG_FLUSH_USB 0xa4
|
||||
#define AR71XX_DDR_REG_FLUSH_PCI 0xa8
|
||||
|
||||
#define AR724X_DDR_REG_FLUSH_GE0 0x7c
|
||||
#define AR724X_DDR_REG_FLUSH_GE1 0x80
|
||||
#define AR724X_DDR_REG_FLUSH_USB 0x84
|
||||
#define AR724X_DDR_REG_FLUSH_PCIE 0x88
|
||||
|
||||
#define AR913X_DDR_REG_FLUSH_GE0 0x7c
|
||||
#define AR913X_DDR_REG_FLUSH_GE1 0x80
|
||||
#define AR913X_DDR_REG_FLUSH_USB 0x84
|
||||
#define AR913X_DDR_REG_FLUSH_WMAC 0x88
|
||||
|
||||
/*
|
||||
* PLL block
|
||||
*/
|
||||
#define AR71XX_PLL_REG_CPU_CONFIG 0x00
|
||||
#define AR71XX_PLL_REG_SEC_CONFIG 0x04
|
||||
#define AR71XX_PLL_REG_ETH0_INT_CLOCK 0x10
|
||||
#define AR71XX_PLL_REG_ETH1_INT_CLOCK 0x14
|
||||
|
||||
#define AR71XX_PLL_DIV_SHIFT 3
|
||||
#define AR71XX_PLL_DIV_MASK 0x1f
|
||||
#define AR71XX_CPU_DIV_SHIFT 16
|
||||
#define AR71XX_CPU_DIV_MASK 0x3
|
||||
#define AR71XX_DDR_DIV_SHIFT 18
|
||||
#define AR71XX_DDR_DIV_MASK 0x3
|
||||
#define AR71XX_AHB_DIV_SHIFT 20
|
||||
#define AR71XX_AHB_DIV_MASK 0x7
|
||||
|
||||
#define AR724X_PLL_REG_CPU_CONFIG 0x00
|
||||
#define AR724X_PLL_REG_PCIE_CONFIG 0x18
|
||||
|
||||
#define AR724X_PLL_DIV_SHIFT 0
|
||||
#define AR724X_PLL_DIV_MASK 0x3ff
|
||||
#define AR724X_PLL_REF_DIV_SHIFT 10
|
||||
#define AR724X_PLL_REF_DIV_MASK 0xf
|
||||
#define AR724X_AHB_DIV_SHIFT 19
|
||||
#define AR724X_AHB_DIV_MASK 0x1
|
||||
#define AR724X_DDR_DIV_SHIFT 22
|
||||
#define AR724X_DDR_DIV_MASK 0x3
|
||||
|
||||
#define AR913X_PLL_REG_CPU_CONFIG 0x00
|
||||
#define AR913X_PLL_REG_ETH_CONFIG 0x04
|
||||
#define AR913X_PLL_REG_ETH0_INT_CLOCK 0x14
|
||||
#define AR913X_PLL_REG_ETH1_INT_CLOCK 0x18
|
||||
|
||||
#define AR913X_PLL_DIV_SHIFT 0
|
||||
#define AR913X_PLL_DIV_MASK 0x3ff
|
||||
#define AR913X_DDR_DIV_SHIFT 22
|
||||
#define AR913X_DDR_DIV_MASK 0x3
|
||||
#define AR913X_AHB_DIV_SHIFT 19
|
||||
#define AR913X_AHB_DIV_MASK 0x1
|
||||
|
||||
/*
|
||||
* RESET block
|
||||
*/
|
||||
#define AR71XX_RESET_REG_TIMER 0x00
|
||||
#define AR71XX_RESET_REG_TIMER_RELOAD 0x04
|
||||
#define AR71XX_RESET_REG_WDOG_CTRL 0x08
|
||||
#define AR71XX_RESET_REG_WDOG 0x0c
|
||||
#define AR71XX_RESET_REG_MISC_INT_STATUS 0x10
|
||||
#define AR71XX_RESET_REG_MISC_INT_ENABLE 0x14
|
||||
#define AR71XX_RESET_REG_PCI_INT_STATUS 0x18
|
||||
#define AR71XX_RESET_REG_PCI_INT_ENABLE 0x1c
|
||||
#define AR71XX_RESET_REG_GLOBAL_INT_STATUS 0x20
|
||||
#define AR71XX_RESET_REG_RESET_MODULE 0x24
|
||||
#define AR71XX_RESET_REG_PERFC_CTRL 0x2c
|
||||
#define AR71XX_RESET_REG_PERFC0 0x30
|
||||
#define AR71XX_RESET_REG_PERFC1 0x34
|
||||
#define AR71XX_RESET_REG_REV_ID 0x90
|
||||
|
||||
#define AR913X_RESET_REG_GLOBAL_INT_STATUS 0x18
|
||||
#define AR913X_RESET_REG_RESET_MODULE 0x1c
|
||||
#define AR913X_RESET_REG_PERF_CTRL 0x20
|
||||
#define AR913X_RESET_REG_PERFC0 0x24
|
||||
#define AR913X_RESET_REG_PERFC1 0x28
|
||||
|
||||
#define AR724X_RESET_REG_RESET_MODULE 0x1c
|
||||
|
||||
#define MISC_INT_DMA BIT(7)
|
||||
#define MISC_INT_OHCI BIT(6)
|
||||
#define MISC_INT_PERFC BIT(5)
|
||||
#define MISC_INT_WDOG BIT(4)
|
||||
#define MISC_INT_UART BIT(3)
|
||||
#define MISC_INT_GPIO BIT(2)
|
||||
#define MISC_INT_ERROR BIT(1)
|
||||
#define MISC_INT_TIMER BIT(0)
|
||||
|
||||
#define AR71XX_RESET_EXTERNAL BIT(28)
|
||||
#define AR71XX_RESET_FULL_CHIP BIT(24)
|
||||
#define AR71XX_RESET_CPU_NMI BIT(21)
|
||||
#define AR71XX_RESET_CPU_COLD BIT(20)
|
||||
#define AR71XX_RESET_DMA BIT(19)
|
||||
#define AR71XX_RESET_SLIC BIT(18)
|
||||
#define AR71XX_RESET_STEREO BIT(17)
|
||||
#define AR71XX_RESET_DDR BIT(16)
|
||||
#define AR71XX_RESET_GE1_MAC BIT(13)
|
||||
#define AR71XX_RESET_GE1_PHY BIT(12)
|
||||
#define AR71XX_RESET_USBSUS_OVERRIDE BIT(10)
|
||||
#define AR71XX_RESET_GE0_MAC BIT(9)
|
||||
#define AR71XX_RESET_GE0_PHY BIT(8)
|
||||
#define AR71XX_RESET_USB_OHCI_DLL BIT(6)
|
||||
#define AR71XX_RESET_USB_HOST BIT(5)
|
||||
#define AR71XX_RESET_USB_PHY BIT(4)
|
||||
#define AR71XX_RESET_PCI_BUS BIT(1)
|
||||
#define AR71XX_RESET_PCI_CORE BIT(0)
|
||||
|
||||
#define AR724X_RESET_GE1_MDIO BIT(23)
|
||||
#define AR724X_RESET_GE0_MDIO BIT(22)
|
||||
#define AR724X_RESET_PCIE_PHY_SERIAL BIT(10)
|
||||
#define AR724X_RESET_PCIE_PHY BIT(7)
|
||||
#define AR724X_RESET_PCIE BIT(6)
|
||||
#define AR724X_RESET_OHCI_DLL BIT(3)
|
||||
|
||||
#define AR913X_RESET_AMBA2WMAC BIT(22)
|
||||
|
||||
#define REV_ID_MAJOR_MASK 0xfff0
|
||||
#define REV_ID_MAJOR_AR71XX 0x00a0
|
||||
#define REV_ID_MAJOR_AR913X 0x00b0
|
||||
#define REV_ID_MAJOR_AR7240 0x00c0
|
||||
#define REV_ID_MAJOR_AR7241 0x0100
|
||||
#define REV_ID_MAJOR_AR7242 0x1100
|
||||
|
||||
#define AR71XX_REV_ID_MINOR_MASK 0x3
|
||||
#define AR71XX_REV_ID_MINOR_AR7130 0x0
|
||||
#define AR71XX_REV_ID_MINOR_AR7141 0x1
|
||||
#define AR71XX_REV_ID_MINOR_AR7161 0x2
|
||||
#define AR71XX_REV_ID_REVISION_MASK 0x3
|
||||
#define AR71XX_REV_ID_REVISION_SHIFT 2
|
||||
|
||||
#define AR913X_REV_ID_MINOR_MASK 0x3
|
||||
#define AR913X_REV_ID_MINOR_AR9130 0x0
|
||||
#define AR913X_REV_ID_MINOR_AR9132 0x1
|
||||
#define AR913X_REV_ID_REVISION_MASK 0x3
|
||||
#define AR913X_REV_ID_REVISION_SHIFT 2
|
||||
|
||||
#define AR724X_REV_ID_REVISION_MASK 0x3
|
||||
|
||||
/*
|
||||
* SPI block
|
||||
*/
|
||||
#define AR71XX_SPI_REG_FS 0x00 /* Function Select */
|
||||
#define AR71XX_SPI_REG_CTRL 0x04 /* SPI Control */
|
||||
#define AR71XX_SPI_REG_IOC 0x08 /* SPI I/O Control */
|
||||
#define AR71XX_SPI_REG_RDS 0x0c /* Read Data Shift */
|
||||
|
||||
#define AR71XX_SPI_FS_GPIO BIT(0) /* Enable GPIO mode */
|
||||
|
||||
#define AR71XX_SPI_CTRL_RD BIT(6) /* Remap Disable */
|
||||
#define AR71XX_SPI_CTRL_DIV_MASK 0x3f
|
||||
|
||||
#define AR71XX_SPI_IOC_DO BIT(0) /* Data Out pin */
|
||||
#define AR71XX_SPI_IOC_CLK BIT(8) /* CLK pin */
|
||||
#define AR71XX_SPI_IOC_CS(n) BIT(16 + (n))
|
||||
#define AR71XX_SPI_IOC_CS0 AR71XX_SPI_IOC_CS(0)
|
||||
#define AR71XX_SPI_IOC_CS1 AR71XX_SPI_IOC_CS(1)
|
||||
#define AR71XX_SPI_IOC_CS2 AR71XX_SPI_IOC_CS(2)
|
||||
#define AR71XX_SPI_IOC_CS_ALL (AR71XX_SPI_IOC_CS0 | AR71XX_SPI_IOC_CS1 | \
|
||||
AR71XX_SPI_IOC_CS2)
|
||||
|
||||
/*
|
||||
* GPIO block
|
||||
*/
|
||||
#define AR71XX_GPIO_REG_OE 0x00
|
||||
#define AR71XX_GPIO_REG_IN 0x04
|
||||
#define AR71XX_GPIO_REG_OUT 0x08
|
||||
#define AR71XX_GPIO_REG_SET 0x0c
|
||||
#define AR71XX_GPIO_REG_CLEAR 0x10
|
||||
#define AR71XX_GPIO_REG_INT_MODE 0x14
|
||||
#define AR71XX_GPIO_REG_INT_TYPE 0x18
|
||||
#define AR71XX_GPIO_REG_INT_POLARITY 0x1c
|
||||
#define AR71XX_GPIO_REG_INT_PENDING 0x20
|
||||
#define AR71XX_GPIO_REG_INT_ENABLE 0x24
|
||||
#define AR71XX_GPIO_REG_FUNC 0x28
|
||||
|
||||
#define AR71XX_GPIO_COUNT 16
|
||||
#define AR724X_GPIO_COUNT 18
|
||||
#define AR913X_GPIO_COUNT 22
|
||||
|
||||
#endif /* __ASM_MACH_AR71XX_REGS_H */
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* 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 __ASM_MACH_ATH79_H
|
||||
#define __ASM_MACH_ATH79_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
enum ath79_soc_type {
|
||||
ATH79_SOC_UNKNOWN,
|
||||
ATH79_SOC_AR7130,
|
||||
ATH79_SOC_AR7141,
|
||||
ATH79_SOC_AR7161,
|
||||
ATH79_SOC_AR7240,
|
||||
ATH79_SOC_AR7241,
|
||||
ATH79_SOC_AR7242,
|
||||
ATH79_SOC_AR9130,
|
||||
ATH79_SOC_AR9132
|
||||
};
|
||||
|
||||
extern enum ath79_soc_type ath79_soc;
|
||||
|
||||
static inline int soc_is_ar71xx(void)
|
||||
{
|
||||
return (ath79_soc == ATH79_SOC_AR7130 ||
|
||||
ath79_soc == ATH79_SOC_AR7141 ||
|
||||
ath79_soc == ATH79_SOC_AR7161);
|
||||
}
|
||||
|
||||
static inline int soc_is_ar724x(void)
|
||||
{
|
||||
return (ath79_soc == ATH79_SOC_AR7240 ||
|
||||
ath79_soc == ATH79_SOC_AR7241 ||
|
||||
ath79_soc == ATH79_SOC_AR7242);
|
||||
}
|
||||
|
||||
static inline int soc_is_ar7240(void)
|
||||
{
|
||||
return (ath79_soc == ATH79_SOC_AR7240);
|
||||
}
|
||||
|
||||
static inline int soc_is_ar7241(void)
|
||||
{
|
||||
return (ath79_soc == ATH79_SOC_AR7241);
|
||||
}
|
||||
|
||||
static inline int soc_is_ar7242(void)
|
||||
{
|
||||
return (ath79_soc == ATH79_SOC_AR7242);
|
||||
}
|
||||
|
||||
static inline int soc_is_ar913x(void)
|
||||
{
|
||||
return (ath79_soc == ATH79_SOC_AR9130 ||
|
||||
ath79_soc == ATH79_SOC_AR9132);
|
||||
}
|
||||
|
||||
extern void __iomem *ath79_ddr_base;
|
||||
extern void __iomem *ath79_pll_base;
|
||||
extern void __iomem *ath79_reset_base;
|
||||
|
||||
static inline void ath79_pll_wr(unsigned reg, u32 val)
|
||||
{
|
||||
__raw_writel(val, ath79_pll_base + reg);
|
||||
}
|
||||
|
||||
static inline u32 ath79_pll_rr(unsigned reg)
|
||||
{
|
||||
return __raw_readl(ath79_pll_base + reg);
|
||||
}
|
||||
|
||||
static inline void ath79_reset_wr(unsigned reg, u32 val)
|
||||
{
|
||||
__raw_writel(val, ath79_reset_base + reg);
|
||||
}
|
||||
|
||||
static inline u32 ath79_reset_rr(unsigned reg)
|
||||
{
|
||||
return __raw_readl(ath79_reset_base + reg);
|
||||
}
|
||||
|
||||
void ath79_device_reset_set(u32 mask);
|
||||
void ath79_device_reset_clear(u32 mask);
|
||||
|
||||
#endif /* __ASM_MACH_ATH79_H */
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Platform data definition for Atheros AR71XX/AR724X/AR913X SPI controller
|
||||
*
|
||||
* Copyright (C) 2008-2010 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.
|
||||
*/
|
||||
|
||||
#ifndef _ATH79_SPI_PLATFORM_H
|
||||
#define _ATH79_SPI_PLATFORM_H
|
||||
|
||||
struct ath79_spi_platform_data {
|
||||
unsigned bus_num;
|
||||
unsigned num_chipselect;
|
||||
};
|
||||
|
||||
struct ath79_spi_controller_data {
|
||||
unsigned gpio;
|
||||
};
|
||||
|
||||
#endif /* _ATH79_SPI_PLATFORM_H */
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Atheros AR71XX/AR724X/AR913X specific CPU feature overrides
|
||||
*
|
||||
* Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
|
||||
* Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
|
||||
*
|
||||
* This file was derived from: include/asm-mips/cpu-features.h
|
||||
* Copyright (C) 2003, 2004 Ralf Baechle
|
||||
* Copyright (C) 2004 Maciej W. Rozycki
|
||||
*
|
||||
* 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 __ASM_MACH_ATH79_CPU_FEATURE_OVERRIDES_H
|
||||
#define __ASM_MACH_ATH79_CPU_FEATURE_OVERRIDES_H
|
||||
|
||||
#define cpu_has_tlb 1
|
||||
#define cpu_has_4kex 1
|
||||
#define cpu_has_3k_cache 0
|
||||
#define cpu_has_4k_cache 1
|
||||
#define cpu_has_tx39_cache 0
|
||||
#define cpu_has_sb1_cache 0
|
||||
#define cpu_has_fpu 0
|
||||
#define cpu_has_32fpr 0
|
||||
#define cpu_has_counter 1
|
||||
#define cpu_has_watch 1
|
||||
#define cpu_has_divec 1
|
||||
|
||||
#define cpu_has_prefetch 1
|
||||
#define cpu_has_ejtag 1
|
||||
#define cpu_has_llsc 1
|
||||
|
||||
#define cpu_has_mips16 1
|
||||
#define cpu_has_mdmx 0
|
||||
#define cpu_has_mips3d 0
|
||||
#define cpu_has_smartmips 0
|
||||
|
||||
#define cpu_has_mips32r1 1
|
||||
#define cpu_has_mips32r2 1
|
||||
#define cpu_has_mips64r1 0
|
||||
#define cpu_has_mips64r2 0
|
||||
|
||||
#define cpu_has_dsp 0
|
||||
#define cpu_has_mipsmt 0
|
||||
|
||||
#define cpu_has_64bits 0
|
||||
#define cpu_has_64bit_zero_reg 0
|
||||
#define cpu_has_64bit_gp_regs 0
|
||||
#define cpu_has_64bit_addresses 0
|
||||
|
||||
#define cpu_dcache_line_size() 32
|
||||
#define cpu_icache_line_size() 32
|
||||
|
||||
#endif /* __ASM_MACH_ATH79_CPU_FEATURE_OVERRIDES_H */
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Atheros AR71XX/AR724X/AR913X GPIO API definitions
|
||||
*
|
||||
* 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 __ASM_MACH_ATH79_GPIO_H
|
||||
#define __ASM_MACH_ATH79_GPIO_H
|
||||
|
||||
#define ARCH_NR_GPIOS 64
|
||||
#include <asm-generic/gpio.h>
|
||||
|
||||
int gpio_to_irq(unsigned gpio);
|
||||
int irq_to_gpio(unsigned irq);
|
||||
int gpio_get_value(unsigned gpio);
|
||||
void gpio_set_value(unsigned gpio, int value);
|
||||
|
||||
#define gpio_cansleep __gpio_cansleep
|
||||
|
||||
#endif /* __ASM_MACH_ATH79_GPIO_H */
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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 __ASM_MACH_ATH79_IRQ_H
|
||||
#define __ASM_MACH_ATH79_IRQ_H
|
||||
|
||||
#define MIPS_CPU_IRQ_BASE 0
|
||||
#define NR_IRQS 16
|
||||
|
||||
#define ATH79_MISC_IRQ_BASE 8
|
||||
#define ATH79_MISC_IRQ_COUNT 8
|
||||
|
||||
#define ATH79_CPU_IRQ_IP2 (MIPS_CPU_IRQ_BASE + 2)
|
||||
#define ATH79_CPU_IRQ_USB (MIPS_CPU_IRQ_BASE + 3)
|
||||
#define ATH79_CPU_IRQ_GE0 (MIPS_CPU_IRQ_BASE + 4)
|
||||
#define ATH79_CPU_IRQ_GE1 (MIPS_CPU_IRQ_BASE + 5)
|
||||
#define ATH79_CPU_IRQ_MISC (MIPS_CPU_IRQ_BASE + 6)
|
||||
#define ATH79_CPU_IRQ_TIMER (MIPS_CPU_IRQ_BASE + 7)
|
||||
|
||||
#define ATH79_MISC_IRQ_TIMER (ATH79_MISC_IRQ_BASE + 0)
|
||||
#define ATH79_MISC_IRQ_ERROR (ATH79_MISC_IRQ_BASE + 1)
|
||||
#define ATH79_MISC_IRQ_GPIO (ATH79_MISC_IRQ_BASE + 2)
|
||||
#define ATH79_MISC_IRQ_UART (ATH79_MISC_IRQ_BASE + 3)
|
||||
#define ATH79_MISC_IRQ_WDOG (ATH79_MISC_IRQ_BASE + 4)
|
||||
#define ATH79_MISC_IRQ_PERFC (ATH79_MISC_IRQ_BASE + 5)
|
||||
#define ATH79_MISC_IRQ_OHCI (ATH79_MISC_IRQ_BASE + 6)
|
||||
#define ATH79_MISC_IRQ_DMA (ATH79_MISC_IRQ_BASE + 7)
|
||||
|
||||
#include_next <irq.h>
|
||||
|
||||
#endif /* __ASM_MACH_ATH79_IRQ_H */
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Atheros AR71XX/AR724X/AR913X specific kernel entry setup
|
||||
*
|
||||
* Copyright (C) 2009 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.
|
||||
*
|
||||
*/
|
||||
#ifndef __ASM_MACH_ATH79_KERNEL_ENTRY_H
|
||||
#define __ASM_MACH_ATH79_KERNEL_ENTRY_H
|
||||
|
||||
/*
|
||||
* Some bootloaders set the 'Kseg0 coherency algorithm' to
|
||||
* 'Cacheable, noncoherent, write-through, no write allocate'
|
||||
* and this cause performance issues. Let's go and change it to
|
||||
* 'Cacheable, noncoherent, write-back, write allocate'
|
||||
*/
|
||||
.macro kernel_entry_setup
|
||||
mfc0 t0, CP0_CONFIG
|
||||
li t1, ~CONF_CM_CMASK
|
||||
and t0, t1
|
||||
ori t0, CONF_CM_CACHABLE_NONCOHERENT
|
||||
mtc0 t0, CP0_CONFIG
|
||||
nop
|
||||
.endm
|
||||
|
||||
.macro smp_slave_setup
|
||||
.endm
|
||||
|
||||
#endif /* __ASM_MACH_ATH79_KERNEL_ENTRY_H */
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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) 2002, 2004, 2007 by Ralf Baechle <ralf@linux-mips.org>
|
||||
*/
|
||||
#ifndef __ASM_MACH_ATH79_WAR_H
|
||||
#define __ASM_MACH_ATH79_WAR_H
|
||||
|
||||
#define R4600_V1_INDEX_ICACHEOP_WAR 0
|
||||
#define R4600_V1_HIT_CACHEOP_WAR 0
|
||||
#define R4600_V2_HIT_CACHEOP_WAR 0
|
||||
#define R5432_CP0_INTERRUPT_WAR 0
|
||||
#define BCM1250_M3_WAR 0
|
||||
#define SIBYTE_1956_WAR 0
|
||||
#define MIPS4K_ICACHE_REFILL_WAR 0
|
||||
#define MIPS_CACHE_SYNC_WAR 0
|
||||
#define TX49XX_ICACHE_INDEX_INV_WAR 0
|
||||
#define RM9000_CDEX_SMP_WAR 0
|
||||
#define ICACHE_REFILLS_WORKAROUND_WAR 0
|
||||
#define R10000_LLSC_WAR 0
|
||||
#define MIPS34K_MISSED_ITLB_WAR 0
|
||||
|
||||
#endif /* __ASM_MACH_ATH79_WAR_H */
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright (C) 2008-2010 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __ASM_MIPS_MACHINE_H
|
||||
#define __ASM_MIPS_MACHINE_H
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/stddef.h>
|
||||
|
||||
#include <asm/bootinfo.h>
|
||||
|
||||
struct mips_machine {
|
||||
unsigned long mach_type;
|
||||
const char *mach_id;
|
||||
const char *mach_name;
|
||||
void (*mach_setup)(void);
|
||||
};
|
||||
|
||||
#define MIPS_MACHINE(_type, _id, _name, _setup) \
|
||||
static const char machine_name_##_type[] __initconst \
|
||||
__aligned(1) = _name; \
|
||||
static const char machine_id_##_type[] __initconst \
|
||||
__aligned(1) = _id; \
|
||||
static struct mips_machine machine_##_type \
|
||||
__used __section(.mips.machines.init) = \
|
||||
{ \
|
||||
.mach_type = _type, \
|
||||
.mach_id = machine_id_##_type, \
|
||||
.mach_name = machine_name_##_type, \
|
||||
.mach_setup = _setup, \
|
||||
};
|
||||
|
||||
extern long __mips_machines_start;
|
||||
extern long __mips_machines_end;
|
||||
|
||||
#ifdef CONFIG_MIPS_MACHINE
|
||||
int mips_machtype_setup(char *id) __init;
|
||||
void mips_machine_setup(void) __init;
|
||||
void mips_set_machine_name(const char *name) __init;
|
||||
char *mips_get_machine_name(void);
|
||||
#else
|
||||
static inline int mips_machtype_setup(char *id) { return 1; }
|
||||
static inline void mips_machine_setup(void) { }
|
||||
static inline void mips_set_machine_name(const char *name) { }
|
||||
static inline char *mips_get_machine_name(void) { return NULL; }
|
||||
#endif /* CONFIG_MIPS_MACHINE */
|
||||
|
||||
#endif /* __ASM_MIPS_MACHINE_H */
|
|
@ -29,13 +29,7 @@
|
|||
#define TLBMISS_HANDLER_SETUP_PGD(pgd) \
|
||||
tlbmiss_handler_setup_pgd((unsigned long)(pgd))
|
||||
|
||||
static inline void tlbmiss_handler_setup_pgd(unsigned long pgd)
|
||||
{
|
||||
/* Check for swapper_pg_dir and convert to physical address. */
|
||||
if ((pgd & CKSEG3) == CKSEG0)
|
||||
pgd = CPHYSADDR(pgd);
|
||||
write_c0_context(pgd << 11);
|
||||
}
|
||||
extern void tlbmiss_handler_setup_pgd(unsigned long pgd);
|
||||
|
||||
#define TLBMISS_HANDLER_SETUP() \
|
||||
do { \
|
||||
|
|
|
@ -115,7 +115,12 @@ Ip_0(_tlbwr);
|
|||
Ip_u3u1u2(_xor);
|
||||
Ip_u2u1u3(_xori);
|
||||
Ip_u2u1msbu3(_dins);
|
||||
Ip_u2u1msbu3(_dinsm);
|
||||
Ip_u1(_syscall);
|
||||
Ip_u1u2s3(_bbit0);
|
||||
Ip_u1u2s3(_bbit1);
|
||||
Ip_u3u1u2(_lwx);
|
||||
Ip_u3u1u2(_ldx);
|
||||
|
||||
/* Handle labels. */
|
||||
struct uasm_label {
|
||||
|
@ -153,6 +158,7 @@ static inline void __uasminit uasm_l##lb(struct uasm_label **lab, u32 *addr) \
|
|||
# define UASM_i_SUBU(buf, rs, rt, rd) uasm_i_dsubu(buf, rs, rt, rd)
|
||||
# define UASM_i_LL(buf, rs, rt, off) uasm_i_lld(buf, rs, rt, off)
|
||||
# define UASM_i_SC(buf, rs, rt, off) uasm_i_scd(buf, rs, rt, off)
|
||||
# define UASM_i_LWX(buf, rs, rt, rd) uasm_i_ldx(buf, rs, rt, rd)
|
||||
#else
|
||||
# define UASM_i_LW(buf, rs, rt, off) uasm_i_lw(buf, rs, rt, off)
|
||||
# define UASM_i_SW(buf, rs, rt, off) uasm_i_sw(buf, rs, rt, off)
|
||||
|
@ -167,6 +173,7 @@ static inline void __uasminit uasm_l##lb(struct uasm_label **lab, u32 *addr) \
|
|||
# define UASM_i_SUBU(buf, rs, rt, rd) uasm_i_subu(buf, rs, rt, rd)
|
||||
# define UASM_i_LL(buf, rs, rt, off) uasm_i_ll(buf, rs, rt, off)
|
||||
# define UASM_i_SC(buf, rs, rt, off) uasm_i_sc(buf, rs, rt, off)
|
||||
# define UASM_i_LWX(buf, rs, rt, rd) uasm_i_lwx(buf, rs, rt, rd)
|
||||
#endif
|
||||
|
||||
#define uasm_i_b(buf, off) uasm_i_beq(buf, 0, 0, off)
|
||||
|
|
|
@ -95,6 +95,7 @@ obj-$(CONFIG_GPIO_TXX9) += gpio_txx9.o
|
|||
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
|
||||
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
|
||||
obj-$(CONFIG_SPINLOCK_TEST) += spinlock_test.o
|
||||
obj-$(CONFIG_MIPS_MACHINE) += mips_machine.o
|
||||
|
||||
obj-$(CONFIG_OF) += prom.o
|
||||
|
||||
|
@ -106,4 +107,6 @@ obj-$(CONFIG_MIPS_CPUFREQ) += cpufreq/
|
|||
|
||||
obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
|
||||
|
||||
obj-$(CONFIG_JUMP_LABEL) += jump_label.o
|
||||
|
||||
CPPFLAGS_vmlinux.lds := $(KBUILD_CFLAGS)
|
||||
|
|
|
@ -739,6 +739,8 @@ static inline unsigned int decode_config4(struct cpuinfo_mips *c)
|
|||
&& cpu_has_tlb)
|
||||
c->tlbsize += (config4 & MIPS_CONF4_MMUSIZEEXT) * 0x40;
|
||||
|
||||
c->kscratch_mask = (config4 >> 16) & 0xff;
|
||||
|
||||
return config4 & MIPS_CONF_M;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* 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) 2010 Cavium Networks, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/jump_label.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/memory.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/cpu.h>
|
||||
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/inst.h>
|
||||
|
||||
#ifdef HAVE_JUMP_LABEL
|
||||
|
||||
#define J_RANGE_MASK ((1ul << 28) - 1)
|
||||
|
||||
void arch_jump_label_transform(struct jump_entry *e,
|
||||
enum jump_label_type type)
|
||||
{
|
||||
union mips_instruction insn;
|
||||
union mips_instruction *insn_p =
|
||||
(union mips_instruction *)(unsigned long)e->code;
|
||||
|
||||
/* Jump only works within a 256MB aligned region. */
|
||||
BUG_ON((e->target & ~J_RANGE_MASK) != (e->code & ~J_RANGE_MASK));
|
||||
|
||||
/* Target must have 4 byte alignment. */
|
||||
BUG_ON((e->target & 3) != 0);
|
||||
|
||||
if (type == JUMP_LABEL_ENABLE) {
|
||||
insn.j_format.opcode = j_op;
|
||||
insn.j_format.target = (e->target & J_RANGE_MASK) >> 2;
|
||||
} else {
|
||||
insn.word = 0; /* nop */
|
||||
}
|
||||
|
||||
get_online_cpus();
|
||||
mutex_lock(&text_mutex);
|
||||
*insn_p = insn;
|
||||
|
||||
flush_icache_range((unsigned long)insn_p,
|
||||
(unsigned long)insn_p + sizeof(*insn_p));
|
||||
|
||||
mutex_unlock(&text_mutex);
|
||||
put_online_cpus();
|
||||
}
|
||||
|
||||
#endif /* HAVE_JUMP_LABEL */
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Copyright (C) 2008-2010 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/mm.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <asm/mips_machine.h>
|
||||
|
||||
static struct mips_machine *mips_machine __initdata;
|
||||
static char *mips_machine_name = "Unknown";
|
||||
|
||||
#define for_each_machine(mach) \
|
||||
for ((mach) = (struct mips_machine *)&__mips_machines_start; \
|
||||
(mach) && \
|
||||
(unsigned long)(mach) < (unsigned long)&__mips_machines_end; \
|
||||
(mach)++)
|
||||
|
||||
__init void mips_set_machine_name(const char *name)
|
||||
{
|
||||
char *p;
|
||||
|
||||
if (name == NULL)
|
||||
return;
|
||||
|
||||
p = kstrdup(name, GFP_KERNEL);
|
||||
if (!p)
|
||||
pr_err("MIPS: no memory for machine_name\n");
|
||||
|
||||
mips_machine_name = p;
|
||||
}
|
||||
|
||||
char *mips_get_machine_name(void)
|
||||
{
|
||||
return mips_machine_name;
|
||||
}
|
||||
|
||||
__init int mips_machtype_setup(char *id)
|
||||
{
|
||||
struct mips_machine *mach;
|
||||
|
||||
for_each_machine(mach) {
|
||||
if (mach->mach_id == NULL)
|
||||
continue;
|
||||
|
||||
if (strcmp(mach->mach_id, id) == 0) {
|
||||
mips_machtype = mach->mach_type;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
pr_err("MIPS: no machine found for id '%s', supported machines:\n", id);
|
||||
pr_err("%-24s %s\n", "id", "name");
|
||||
for_each_machine(mach)
|
||||
pr_err("%-24s %s\n", mach->mach_id, mach->mach_name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
__setup("machtype=", mips_machtype_setup);
|
||||
|
||||
__init void mips_machine_setup(void)
|
||||
{
|
||||
struct mips_machine *mach;
|
||||
|
||||
for_each_machine(mach) {
|
||||
if (mips_machtype == mach->mach_type) {
|
||||
mips_machine = mach;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mips_machine)
|
||||
return;
|
||||
|
||||
mips_set_machine_name(mips_machine->mach_name);
|
||||
pr_info("MIPS: machine is %s\n", mips_machine_name);
|
||||
|
||||
if (mips_machine->mach_setup)
|
||||
mips_machine->mach_setup();
|
||||
}
|
|
@ -30,6 +30,8 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/jump_label.h>
|
||||
|
||||
#include <asm/pgtable.h> /* MODULE_START */
|
||||
|
||||
struct mips_hi16 {
|
||||
|
@ -382,6 +384,9 @@ int module_finalize(const Elf_Ehdr *hdr,
|
|||
const Elf_Shdr *s;
|
||||
char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
|
||||
|
||||
/* Make jump label nops. */
|
||||
jump_label_apply_nops(me);
|
||||
|
||||
INIT_LIST_HEAD(&me->arch.dbe_list);
|
||||
for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
|
||||
if (strcmp("__dbe_table", secstrings + s->sh_name) != 0)
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <asm/cpu-features.h>
|
||||
#include <asm/mipsregs.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/mips_machine.h>
|
||||
|
||||
unsigned int vced_count, vcei_count;
|
||||
|
||||
|
@ -31,8 +32,12 @@ static int show_cpuinfo(struct seq_file *m, void *v)
|
|||
/*
|
||||
* For the first processor also print the system type
|
||||
*/
|
||||
if (n == 0)
|
||||
if (n == 0) {
|
||||
seq_printf(m, "system type\t\t: %s\n", get_system_type());
|
||||
if (mips_get_machine_name())
|
||||
seq_printf(m, "machine\t\t\t: %s\n",
|
||||
mips_get_machine_name());
|
||||
}
|
||||
|
||||
seq_printf(m, "processor\t\t: %ld\n", n);
|
||||
sprintf(fmt, "cpu model\t\t: %%s V%%d.%%d%s\n",
|
||||
|
@ -69,6 +74,8 @@ static int show_cpuinfo(struct seq_file *m, void *v)
|
|||
);
|
||||
seq_printf(m, "shadow register sets\t: %d\n",
|
||||
cpu_data[n].srsets);
|
||||
seq_printf(m, "kscratch registers\t: %d\n",
|
||||
hweight8(cpu_data[n].kscratch_mask));
|
||||
seq_printf(m, "core\t\t\t: %d\n", cpu_data[n].core);
|
||||
|
||||
sprintf(fmt, "VCE%%c exceptions\t\t: %s\n",
|
||||
|
|
|
@ -70,7 +70,7 @@ static char __initdata builtin_cmdline[COMMAND_LINE_SIZE] = CONFIG_CMDLINE;
|
|||
* mips_io_port_base is the begin of the address space to which x86 style
|
||||
* I/O ports are mapped.
|
||||
*/
|
||||
const unsigned long mips_io_port_base __read_mostly = -1;
|
||||
const unsigned long mips_io_port_base = -1;
|
||||
EXPORT_SYMBOL(mips_io_port_base);
|
||||
|
||||
static struct resource code_resource = { .name = "Kernel code", };
|
||||
|
|
|
@ -1592,7 +1592,6 @@ void __cpuinit per_cpu_trap_init(void)
|
|||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
|
||||
cpu_data[cpu].asid_cache = ASID_FIRST_VERSION;
|
||||
TLBMISS_HANDLER_SETUP();
|
||||
|
||||
atomic_inc(&init_mm.mm_count);
|
||||
current->active_mm = &init_mm;
|
||||
|
@ -1614,6 +1613,7 @@ void __cpuinit per_cpu_trap_init(void)
|
|||
write_c0_wired(0);
|
||||
}
|
||||
#endif /* CONFIG_MIPS_MT_SMTC */
|
||||
TLBMISS_HANDLER_SETUP();
|
||||
}
|
||||
|
||||
/* Install CPU exception handler */
|
||||
|
|
|
@ -98,6 +98,13 @@ SECTIONS
|
|||
INIT_TEXT_SECTION(PAGE_SIZE)
|
||||
INIT_DATA_SECTION(16)
|
||||
|
||||
. = ALIGN(4);
|
||||
.mips.machines.init : AT(ADDR(.mips.machines.init) - LOAD_OFFSET) {
|
||||
__mips_machines_start = .;
|
||||
*(.mips.machines.init)
|
||||
__mips_machines_end = .;
|
||||
}
|
||||
|
||||
/* .exit.text is discarded at runtime, not link time, to deal with
|
||||
* references from .rodata
|
||||
*/
|
||||
|
|
|
@ -26,8 +26,10 @@
|
|||
#include <linux/smp.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/cache.h>
|
||||
|
||||
#include <asm/mmu_context.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/war.h>
|
||||
#include <asm/uasm.h>
|
||||
|
||||
|
@ -63,6 +65,52 @@ static inline int __maybe_unused r10000_llsc_war(void)
|
|||
return R10000_LLSC_WAR;
|
||||
}
|
||||
|
||||
static int use_bbit_insns(void)
|
||||
{
|
||||
switch (current_cpu_type()) {
|
||||
case CPU_CAVIUM_OCTEON:
|
||||
case CPU_CAVIUM_OCTEON_PLUS:
|
||||
case CPU_CAVIUM_OCTEON2:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int use_lwx_insns(void)
|
||||
{
|
||||
switch (current_cpu_type()) {
|
||||
case CPU_CAVIUM_OCTEON2:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#if defined(CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE) && \
|
||||
CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE > 0
|
||||
static bool scratchpad_available(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
static int scratchpad_offset(int i)
|
||||
{
|
||||
/*
|
||||
* CVMSEG starts at address -32768 and extends for
|
||||
* CAVIUM_OCTEON_CVMSEG_SIZE 128 byte cache lines.
|
||||
*/
|
||||
i += 1; /* Kernel use starts at the top and works down. */
|
||||
return CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE * 128 - (8 * i) - 32768;
|
||||
}
|
||||
#else
|
||||
static bool scratchpad_available(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
static int scratchpad_offset(int i)
|
||||
{
|
||||
BUG();
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* Found by experiment: At least some revisions of the 4kc throw under
|
||||
* some circumstances a machine check exception, triggered by invalid
|
||||
|
@ -173,11 +221,41 @@ static struct uasm_reloc relocs[128] __cpuinitdata;
|
|||
static int check_for_high_segbits __cpuinitdata;
|
||||
#endif
|
||||
|
||||
static int check_for_high_segbits __cpuinitdata;
|
||||
|
||||
static unsigned int kscratch_used_mask __cpuinitdata;
|
||||
|
||||
static int __cpuinit allocate_kscratch(void)
|
||||
{
|
||||
int r;
|
||||
unsigned int a = cpu_data[0].kscratch_mask & ~kscratch_used_mask;
|
||||
|
||||
r = ffs(a);
|
||||
|
||||
if (r == 0)
|
||||
return -1;
|
||||
|
||||
r--; /* make it zero based */
|
||||
|
||||
kscratch_used_mask |= (1 << r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int scratch_reg __cpuinitdata;
|
||||
static int pgd_reg __cpuinitdata;
|
||||
enum vmalloc64_mode {not_refill, refill_scratch, refill_noscratch};
|
||||
|
||||
#ifndef CONFIG_MIPS_PGD_C0_CONTEXT
|
||||
|
||||
/*
|
||||
* CONFIG_MIPS_PGD_C0_CONTEXT implies 64 bit and lack of pgd_current,
|
||||
* we cannot do r3000 under these circumstances.
|
||||
*
|
||||
* Declare pgd_current here instead of including mmu_context.h to avoid type
|
||||
* conflicts for tlbmiss_handler_setup_pgd
|
||||
*/
|
||||
extern unsigned long pgd_current[];
|
||||
|
||||
/*
|
||||
* The R3000 TLB handler is simple.
|
||||
|
@ -440,8 +518,29 @@ static __cpuinit __maybe_unused void build_convert_pte_to_entrylo(u32 **p,
|
|||
static __cpuinit void build_restore_pagemask(u32 **p,
|
||||
struct uasm_reloc **r,
|
||||
unsigned int tmp,
|
||||
enum label_id lid)
|
||||
enum label_id lid,
|
||||
int restore_scratch)
|
||||
{
|
||||
if (restore_scratch) {
|
||||
/* Reset default page size */
|
||||
if (PM_DEFAULT_MASK >> 16) {
|
||||
uasm_i_lui(p, tmp, PM_DEFAULT_MASK >> 16);
|
||||
uasm_i_ori(p, tmp, tmp, PM_DEFAULT_MASK & 0xffff);
|
||||
uasm_i_mtc0(p, tmp, C0_PAGEMASK);
|
||||
uasm_il_b(p, r, lid);
|
||||
} else if (PM_DEFAULT_MASK) {
|
||||
uasm_i_ori(p, tmp, 0, PM_DEFAULT_MASK);
|
||||
uasm_i_mtc0(p, tmp, C0_PAGEMASK);
|
||||
uasm_il_b(p, r, lid);
|
||||
} else {
|
||||
uasm_i_mtc0(p, 0, C0_PAGEMASK);
|
||||
uasm_il_b(p, r, lid);
|
||||
}
|
||||
if (scratch_reg > 0)
|
||||
UASM_i_MFC0(p, 1, 31, scratch_reg);
|
||||
else
|
||||
UASM_i_LW(p, 1, scratchpad_offset(0), 0);
|
||||
} else {
|
||||
/* Reset default page size */
|
||||
if (PM_DEFAULT_MASK >> 16) {
|
||||
uasm_i_lui(p, tmp, PM_DEFAULT_MASK >> 16);
|
||||
|
@ -456,13 +555,15 @@ static __cpuinit void build_restore_pagemask(u32 **p,
|
|||
uasm_il_b(p, r, lid);
|
||||
uasm_i_mtc0(p, 0, C0_PAGEMASK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static __cpuinit void build_huge_tlb_write_entry(u32 **p,
|
||||
struct uasm_label **l,
|
||||
struct uasm_reloc **r,
|
||||
unsigned int tmp,
|
||||
enum tlb_write_entry wmode)
|
||||
enum tlb_write_entry wmode,
|
||||
int restore_scratch)
|
||||
{
|
||||
/* Set huge page tlb entry size */
|
||||
uasm_i_lui(p, tmp, PM_HUGE_MASK >> 16);
|
||||
|
@ -471,7 +572,7 @@ static __cpuinit void build_huge_tlb_write_entry(u32 **p,
|
|||
|
||||
build_tlb_write_entry(p, l, r, wmode);
|
||||
|
||||
build_restore_pagemask(p, r, tmp, label_leave);
|
||||
build_restore_pagemask(p, r, tmp, label_leave, restore_scratch);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -482,8 +583,12 @@ build_is_huge_pte(u32 **p, struct uasm_reloc **r, unsigned int tmp,
|
|||
unsigned int pmd, int lid)
|
||||
{
|
||||
UASM_i_LW(p, tmp, 0, pmd);
|
||||
if (use_bbit_insns()) {
|
||||
uasm_il_bbit1(p, r, tmp, ilog2(_PAGE_HUGE), lid);
|
||||
} else {
|
||||
uasm_i_andi(p, tmp, tmp, _PAGE_HUGE);
|
||||
uasm_il_bnez(p, r, tmp, lid);
|
||||
}
|
||||
}
|
||||
|
||||
static __cpuinit void build_huge_update_entries(u32 **p,
|
||||
|
@ -532,7 +637,7 @@ static __cpuinit void build_huge_handler_tail(u32 **p,
|
|||
UASM_i_SW(p, pte, 0, ptr);
|
||||
#endif
|
||||
build_huge_update_entries(p, pte, ptr);
|
||||
build_huge_tlb_write_entry(p, l, r, pte, tlb_indexed);
|
||||
build_huge_tlb_write_entry(p, l, r, pte, tlb_indexed, 0);
|
||||
}
|
||||
#endif /* CONFIG_HUGETLB_PAGE */
|
||||
|
||||
|
@ -573,13 +678,22 @@ build_get_pmde64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
|
|||
/* No uasm_i_nop needed here, since the next insn doesn't touch TMP. */
|
||||
|
||||
#ifdef CONFIG_MIPS_PGD_C0_CONTEXT
|
||||
if (pgd_reg != -1) {
|
||||
/* pgd is in pgd_reg */
|
||||
UASM_i_MFC0(p, ptr, 31, pgd_reg);
|
||||
} else {
|
||||
/*
|
||||
* &pgd << 11 stored in CONTEXT [23..63].
|
||||
*/
|
||||
UASM_i_MFC0(p, ptr, C0_CONTEXT);
|
||||
uasm_i_dins(p, ptr, 0, 0, 23); /* Clear lower 23 bits of context. */
|
||||
uasm_i_ori(p, ptr, ptr, 0x540); /* 1 0 1 0 1 << 6 xkphys cached */
|
||||
|
||||
/* Clear lower 23 bits of context. */
|
||||
uasm_i_dins(p, ptr, 0, 0, 23);
|
||||
|
||||
/* 1 0 1 0 1 << 6 xkphys cached */
|
||||
uasm_i_ori(p, ptr, ptr, 0x540);
|
||||
uasm_i_drotr(p, ptr, ptr, 11);
|
||||
}
|
||||
#elif defined(CONFIG_SMP)
|
||||
# ifdef CONFIG_MIPS_MT_SMTC
|
||||
/*
|
||||
|
@ -620,7 +734,6 @@ build_get_pmde64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
|
|||
#endif
|
||||
}
|
||||
|
||||
enum vmalloc64_mode {not_refill, refill};
|
||||
/*
|
||||
* BVADDR is the faulting address, PTR is scratch.
|
||||
* PTR will hold the pgd for vmalloc.
|
||||
|
@ -638,7 +751,7 @@ build_get_pgd_vmalloc64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
|
|||
|
||||
uasm_l_vmalloc(l, *p);
|
||||
|
||||
if (mode == refill && check_for_high_segbits) {
|
||||
if (mode != not_refill && check_for_high_segbits) {
|
||||
if (single_insn_swpd) {
|
||||
uasm_il_bltz(p, r, bvaddr, label_vmalloc_done);
|
||||
uasm_i_lui(p, ptr, uasm_rel_hi(swpd));
|
||||
|
@ -661,7 +774,7 @@ build_get_pgd_vmalloc64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
|
|||
uasm_i_daddiu(p, ptr, ptr, uasm_rel_lo(swpd));
|
||||
}
|
||||
}
|
||||
if (mode == refill && check_for_high_segbits) {
|
||||
if (mode != not_refill && check_for_high_segbits) {
|
||||
uasm_l_large_segbits_fault(l, *p);
|
||||
/*
|
||||
* We get here if we are an xsseg address, or if we are
|
||||
|
@ -677,8 +790,16 @@ build_get_pgd_vmalloc64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
|
|||
*/
|
||||
UASM_i_LA(p, ptr, (unsigned long)tlb_do_page_fault_0);
|
||||
uasm_i_jr(p, ptr);
|
||||
|
||||
if (mode == refill_scratch) {
|
||||
if (scratch_reg > 0)
|
||||
UASM_i_MFC0(p, 1, 31, scratch_reg);
|
||||
else
|
||||
UASM_i_LW(p, 1, scratchpad_offset(0), 0);
|
||||
} else {
|
||||
uasm_i_nop(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else /* !CONFIG_64BIT */
|
||||
|
@ -834,6 +955,185 @@ static void __cpuinit build_update_entries(u32 **p, unsigned int tmp,
|
|||
#endif
|
||||
}
|
||||
|
||||
struct mips_huge_tlb_info {
|
||||
int huge_pte;
|
||||
int restore_scratch;
|
||||
};
|
||||
|
||||
static struct mips_huge_tlb_info __cpuinit
|
||||
build_fast_tlb_refill_handler (u32 **p, struct uasm_label **l,
|
||||
struct uasm_reloc **r, unsigned int tmp,
|
||||
unsigned int ptr, int c0_scratch)
|
||||
{
|
||||
struct mips_huge_tlb_info rv;
|
||||
unsigned int even, odd;
|
||||
int vmalloc_branch_delay_filled = 0;
|
||||
const int scratch = 1; /* Our extra working register */
|
||||
|
||||
rv.huge_pte = scratch;
|
||||
rv.restore_scratch = 0;
|
||||
|
||||
if (check_for_high_segbits) {
|
||||
UASM_i_MFC0(p, tmp, C0_BADVADDR);
|
||||
|
||||
if (pgd_reg != -1)
|
||||
UASM_i_MFC0(p, ptr, 31, pgd_reg);
|
||||
else
|
||||
UASM_i_MFC0(p, ptr, C0_CONTEXT);
|
||||
|
||||
if (c0_scratch >= 0)
|
||||
UASM_i_MTC0(p, scratch, 31, c0_scratch);
|
||||
else
|
||||
UASM_i_SW(p, scratch, scratchpad_offset(0), 0);
|
||||
|
||||
uasm_i_dsrl_safe(p, scratch, tmp,
|
||||
PGDIR_SHIFT + PGD_ORDER + PAGE_SHIFT - 3);
|
||||
uasm_il_bnez(p, r, scratch, label_vmalloc);
|
||||
|
||||
if (pgd_reg == -1) {
|
||||
vmalloc_branch_delay_filled = 1;
|
||||
/* Clear lower 23 bits of context. */
|
||||
uasm_i_dins(p, ptr, 0, 0, 23);
|
||||
}
|
||||
} else {
|
||||
if (pgd_reg != -1)
|
||||
UASM_i_MFC0(p, ptr, 31, pgd_reg);
|
||||
else
|
||||
UASM_i_MFC0(p, ptr, C0_CONTEXT);
|
||||
|
||||
UASM_i_MFC0(p, tmp, C0_BADVADDR);
|
||||
|
||||
if (c0_scratch >= 0)
|
||||
UASM_i_MTC0(p, scratch, 31, c0_scratch);
|
||||
else
|
||||
UASM_i_SW(p, scratch, scratchpad_offset(0), 0);
|
||||
|
||||
if (pgd_reg == -1)
|
||||
/* Clear lower 23 bits of context. */
|
||||
uasm_i_dins(p, ptr, 0, 0, 23);
|
||||
|
||||
uasm_il_bltz(p, r, tmp, label_vmalloc);
|
||||
}
|
||||
|
||||
if (pgd_reg == -1) {
|
||||
vmalloc_branch_delay_filled = 1;
|
||||
/* 1 0 1 0 1 << 6 xkphys cached */
|
||||
uasm_i_ori(p, ptr, ptr, 0x540);
|
||||
uasm_i_drotr(p, ptr, ptr, 11);
|
||||
}
|
||||
|
||||
#ifdef __PAGETABLE_PMD_FOLDED
|
||||
#define LOC_PTEP scratch
|
||||
#else
|
||||
#define LOC_PTEP ptr
|
||||
#endif
|
||||
|
||||
if (!vmalloc_branch_delay_filled)
|
||||
/* get pgd offset in bytes */
|
||||
uasm_i_dsrl_safe(p, scratch, tmp, PGDIR_SHIFT - 3);
|
||||
|
||||
uasm_l_vmalloc_done(l, *p);
|
||||
|
||||
/*
|
||||
* tmp ptr
|
||||
* fall-through case = badvaddr *pgd_current
|
||||
* vmalloc case = badvaddr swapper_pg_dir
|
||||
*/
|
||||
|
||||
if (vmalloc_branch_delay_filled)
|
||||
/* get pgd offset in bytes */
|
||||
uasm_i_dsrl_safe(p, scratch, tmp, PGDIR_SHIFT - 3);
|
||||
|
||||
#ifdef __PAGETABLE_PMD_FOLDED
|
||||
GET_CONTEXT(p, tmp); /* get context reg */
|
||||
#endif
|
||||
uasm_i_andi(p, scratch, scratch, (PTRS_PER_PGD - 1) << 3);
|
||||
|
||||
if (use_lwx_insns()) {
|
||||
UASM_i_LWX(p, LOC_PTEP, scratch, ptr);
|
||||
} else {
|
||||
uasm_i_daddu(p, ptr, ptr, scratch); /* add in pgd offset */
|
||||
uasm_i_ld(p, LOC_PTEP, 0, ptr); /* get pmd pointer */
|
||||
}
|
||||
|
||||
#ifndef __PAGETABLE_PMD_FOLDED
|
||||
/* get pmd offset in bytes */
|
||||
uasm_i_dsrl_safe(p, scratch, tmp, PMD_SHIFT - 3);
|
||||
uasm_i_andi(p, scratch, scratch, (PTRS_PER_PMD - 1) << 3);
|
||||
GET_CONTEXT(p, tmp); /* get context reg */
|
||||
|
||||
if (use_lwx_insns()) {
|
||||
UASM_i_LWX(p, scratch, scratch, ptr);
|
||||
} else {
|
||||
uasm_i_daddu(p, ptr, ptr, scratch); /* add in pmd offset */
|
||||
UASM_i_LW(p, scratch, 0, ptr);
|
||||
}
|
||||
#endif
|
||||
/* Adjust the context during the load latency. */
|
||||
build_adjust_context(p, tmp);
|
||||
|
||||
#ifdef CONFIG_HUGETLB_PAGE
|
||||
uasm_il_bbit1(p, r, scratch, ilog2(_PAGE_HUGE), label_tlb_huge_update);
|
||||
/*
|
||||
* The in the LWX case we don't want to do the load in the
|
||||
* delay slot. It cannot issue in the same cycle and may be
|
||||
* speculative and unneeded.
|
||||
*/
|
||||
if (use_lwx_insns())
|
||||
uasm_i_nop(p);
|
||||
#endif /* CONFIG_HUGETLB_PAGE */
|
||||
|
||||
|
||||
/* build_update_entries */
|
||||
if (use_lwx_insns()) {
|
||||
even = ptr;
|
||||
odd = tmp;
|
||||
UASM_i_LWX(p, even, scratch, tmp);
|
||||
UASM_i_ADDIU(p, tmp, tmp, sizeof(pte_t));
|
||||
UASM_i_LWX(p, odd, scratch, tmp);
|
||||
} else {
|
||||
UASM_i_ADDU(p, ptr, scratch, tmp); /* add in offset */
|
||||
even = tmp;
|
||||
odd = ptr;
|
||||
UASM_i_LW(p, even, 0, ptr); /* get even pte */
|
||||
UASM_i_LW(p, odd, sizeof(pte_t), ptr); /* get odd pte */
|
||||
}
|
||||
if (kernel_uses_smartmips_rixi) {
|
||||
uasm_i_dsrl_safe(p, even, even, ilog2(_PAGE_NO_EXEC));
|
||||
uasm_i_dsrl_safe(p, odd, odd, ilog2(_PAGE_NO_EXEC));
|
||||
uasm_i_drotr(p, even, even,
|
||||
ilog2(_PAGE_GLOBAL) - ilog2(_PAGE_NO_EXEC));
|
||||
UASM_i_MTC0(p, even, C0_ENTRYLO0); /* load it */
|
||||
uasm_i_drotr(p, odd, odd,
|
||||
ilog2(_PAGE_GLOBAL) - ilog2(_PAGE_NO_EXEC));
|
||||
} else {
|
||||
uasm_i_dsrl_safe(p, even, even, ilog2(_PAGE_GLOBAL));
|
||||
UASM_i_MTC0(p, even, C0_ENTRYLO0); /* load it */
|
||||
uasm_i_dsrl_safe(p, odd, odd, ilog2(_PAGE_GLOBAL));
|
||||
}
|
||||
UASM_i_MTC0(p, odd, C0_ENTRYLO1); /* load it */
|
||||
|
||||
if (c0_scratch >= 0) {
|
||||
UASM_i_MFC0(p, scratch, 31, c0_scratch);
|
||||
build_tlb_write_entry(p, l, r, tlb_random);
|
||||
uasm_l_leave(l, *p);
|
||||
rv.restore_scratch = 1;
|
||||
} else if (PAGE_SHIFT == 14 || PAGE_SHIFT == 13) {
|
||||
build_tlb_write_entry(p, l, r, tlb_random);
|
||||
uasm_l_leave(l, *p);
|
||||
UASM_i_LW(p, scratch, scratchpad_offset(0), 0);
|
||||
} else {
|
||||
UASM_i_LW(p, scratch, scratchpad_offset(0), 0);
|
||||
build_tlb_write_entry(p, l, r, tlb_random);
|
||||
uasm_l_leave(l, *p);
|
||||
rv.restore_scratch = 1;
|
||||
}
|
||||
|
||||
uasm_i_eret(p); /* return from trap */
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* For a 64-bit kernel, we are using the 64-bit XTLB refill exception
|
||||
* because EXL == 0. If we wrap, we can also use the 32 instruction
|
||||
|
@ -849,12 +1149,25 @@ static void __cpuinit build_r4000_tlb_refill_handler(void)
|
|||
struct uasm_reloc *r = relocs;
|
||||
u32 *f;
|
||||
unsigned int final_len;
|
||||
struct mips_huge_tlb_info htlb_info;
|
||||
enum vmalloc64_mode vmalloc_mode;
|
||||
|
||||
memset(tlb_handler, 0, sizeof(tlb_handler));
|
||||
memset(labels, 0, sizeof(labels));
|
||||
memset(relocs, 0, sizeof(relocs));
|
||||
memset(final_handler, 0, sizeof(final_handler));
|
||||
|
||||
if (scratch_reg == 0)
|
||||
scratch_reg = allocate_kscratch();
|
||||
|
||||
if ((scratch_reg > 0 || scratchpad_available()) && use_bbit_insns()) {
|
||||
htlb_info = build_fast_tlb_refill_handler(&p, &l, &r, K0, K1,
|
||||
scratch_reg);
|
||||
vmalloc_mode = refill_scratch;
|
||||
} else {
|
||||
htlb_info.huge_pte = K0;
|
||||
htlb_info.restore_scratch = 0;
|
||||
vmalloc_mode = refill_noscratch;
|
||||
/*
|
||||
* create the plain linear handler
|
||||
*/
|
||||
|
@ -887,16 +1200,16 @@ static void __cpuinit build_r4000_tlb_refill_handler(void)
|
|||
build_tlb_write_entry(&p, &l, &r, tlb_random);
|
||||
uasm_l_leave(&l, p);
|
||||
uasm_i_eret(&p); /* return from trap */
|
||||
|
||||
}
|
||||
#ifdef CONFIG_HUGETLB_PAGE
|
||||
uasm_l_tlb_huge_update(&l, p);
|
||||
UASM_i_LW(&p, K0, 0, K1);
|
||||
build_huge_update_entries(&p, K0, K1);
|
||||
build_huge_tlb_write_entry(&p, &l, &r, K0, tlb_random);
|
||||
build_huge_update_entries(&p, htlb_info.huge_pte, K1);
|
||||
build_huge_tlb_write_entry(&p, &l, &r, K0, tlb_random,
|
||||
htlb_info.restore_scratch);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
build_get_pgd_vmalloc64(&p, &l, &r, K0, K1, refill);
|
||||
build_get_pgd_vmalloc64(&p, &l, &r, K0, K1, vmalloc_mode);
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -1014,6 +1327,55 @@ static void __cpuinit build_r4000_tlb_refill_handler(void)
|
|||
u32 handle_tlbl[FASTPATH_SIZE] __cacheline_aligned;
|
||||
u32 handle_tlbs[FASTPATH_SIZE] __cacheline_aligned;
|
||||
u32 handle_tlbm[FASTPATH_SIZE] __cacheline_aligned;
|
||||
#ifdef CONFIG_MIPS_PGD_C0_CONTEXT
|
||||
u32 tlbmiss_handler_setup_pgd[16] __cacheline_aligned;
|
||||
|
||||
static void __cpuinit build_r4000_setup_pgd(void)
|
||||
{
|
||||
const int a0 = 4;
|
||||
const int a1 = 5;
|
||||
u32 *p = tlbmiss_handler_setup_pgd;
|
||||
struct uasm_label *l = labels;
|
||||
struct uasm_reloc *r = relocs;
|
||||
|
||||
memset(tlbmiss_handler_setup_pgd, 0, sizeof(tlbmiss_handler_setup_pgd));
|
||||
memset(labels, 0, sizeof(labels));
|
||||
memset(relocs, 0, sizeof(relocs));
|
||||
|
||||
pgd_reg = allocate_kscratch();
|
||||
|
||||
if (pgd_reg == -1) {
|
||||
/* PGD << 11 in c0_Context */
|
||||
/*
|
||||
* If it is a ckseg0 address, convert to a physical
|
||||
* address. Shifting right by 29 and adding 4 will
|
||||
* result in zero for these addresses.
|
||||
*
|
||||
*/
|
||||
UASM_i_SRA(&p, a1, a0, 29);
|
||||
UASM_i_ADDIU(&p, a1, a1, 4);
|
||||
uasm_il_bnez(&p, &r, a1, label_tlbl_goaround1);
|
||||
uasm_i_nop(&p);
|
||||
uasm_i_dinsm(&p, a0, 0, 29, 64 - 29);
|
||||
uasm_l_tlbl_goaround1(&l, p);
|
||||
UASM_i_SLL(&p, a0, a0, 11);
|
||||
uasm_i_jr(&p, 31);
|
||||
UASM_i_MTC0(&p, a0, C0_CONTEXT);
|
||||
} else {
|
||||
/* PGD in c0_KScratch */
|
||||
uasm_i_jr(&p, 31);
|
||||
UASM_i_MTC0(&p, a0, 31, pgd_reg);
|
||||
}
|
||||
if (p - tlbmiss_handler_setup_pgd > ARRAY_SIZE(tlbmiss_handler_setup_pgd))
|
||||
panic("tlbmiss_handler_setup_pgd space exceeded");
|
||||
uasm_resolve_relocs(relocs, labels);
|
||||
pr_debug("Wrote tlbmiss_handler_setup_pgd (%u instructions).\n",
|
||||
(unsigned int)(p - tlbmiss_handler_setup_pgd));
|
||||
|
||||
dump_handler(tlbmiss_handler_setup_pgd,
|
||||
ARRAY_SIZE(tlbmiss_handler_setup_pgd));
|
||||
}
|
||||
#endif
|
||||
|
||||
static void __cpuinit
|
||||
iPTE_LW(u32 **p, unsigned int pte, unsigned int ptr)
|
||||
|
@ -1100,14 +1462,20 @@ build_pte_present(u32 **p, struct uasm_reloc **r,
|
|||
unsigned int pte, unsigned int ptr, enum label_id lid)
|
||||
{
|
||||
if (kernel_uses_smartmips_rixi) {
|
||||
if (use_bbit_insns()) {
|
||||
uasm_il_bbit0(p, r, pte, ilog2(_PAGE_PRESENT), lid);
|
||||
uasm_i_nop(p);
|
||||
} else {
|
||||
uasm_i_andi(p, pte, pte, _PAGE_PRESENT);
|
||||
uasm_il_beqz(p, r, pte, lid);
|
||||
iPTE_LW(p, pte, ptr);
|
||||
}
|
||||
} else {
|
||||
uasm_i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_READ);
|
||||
uasm_i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_READ);
|
||||
uasm_il_bnez(p, r, pte, lid);
|
||||
}
|
||||
iPTE_LW(p, pte, ptr);
|
||||
}
|
||||
}
|
||||
|
||||
/* Make PTE valid, store result in PTR. */
|
||||
|
@ -1128,10 +1496,17 @@ static void __cpuinit
|
|||
build_pte_writable(u32 **p, struct uasm_reloc **r,
|
||||
unsigned int pte, unsigned int ptr, enum label_id lid)
|
||||
{
|
||||
if (use_bbit_insns()) {
|
||||
uasm_il_bbit0(p, r, pte, ilog2(_PAGE_PRESENT), lid);
|
||||
uasm_i_nop(p);
|
||||
uasm_il_bbit0(p, r, pte, ilog2(_PAGE_WRITE), lid);
|
||||
uasm_i_nop(p);
|
||||
} else {
|
||||
uasm_i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE);
|
||||
uasm_i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE);
|
||||
uasm_il_bnez(p, r, pte, lid);
|
||||
iPTE_LW(p, pte, ptr);
|
||||
}
|
||||
}
|
||||
|
||||
/* Make PTE writable, update software status bits as well, then store
|
||||
|
@ -1155,12 +1530,19 @@ static void __cpuinit
|
|||
build_pte_modifiable(u32 **p, struct uasm_reloc **r,
|
||||
unsigned int pte, unsigned int ptr, enum label_id lid)
|
||||
{
|
||||
if (use_bbit_insns()) {
|
||||
uasm_il_bbit0(p, r, pte, ilog2(_PAGE_WRITE), lid);
|
||||
uasm_i_nop(p);
|
||||
} else {
|
||||
uasm_i_andi(p, pte, pte, _PAGE_WRITE);
|
||||
uasm_il_beqz(p, r, pte, lid);
|
||||
iPTE_LW(p, pte, ptr);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef CONFIG_MIPS_PGD_C0_CONTEXT
|
||||
|
||||
|
||||
/*
|
||||
* R3000 style TLB load/store/modify handlers.
|
||||
*/
|
||||
|
@ -1402,14 +1784,23 @@ static void __cpuinit build_r4000_tlb_load_handler(void)
|
|||
* If the page is not _PAGE_VALID, RI or XI could not
|
||||
* have triggered it. Skip the expensive test..
|
||||
*/
|
||||
if (use_bbit_insns()) {
|
||||
uasm_il_bbit0(&p, &r, K0, ilog2(_PAGE_VALID),
|
||||
label_tlbl_goaround1);
|
||||
} else {
|
||||
uasm_i_andi(&p, K0, K0, _PAGE_VALID);
|
||||
uasm_il_beqz(&p, &r, K0, label_tlbl_goaround1);
|
||||
}
|
||||
uasm_i_nop(&p);
|
||||
|
||||
uasm_i_tlbr(&p);
|
||||
/* Examine entrylo 0 or 1 based on ptr. */
|
||||
if (use_bbit_insns()) {
|
||||
uasm_i_bbit0(&p, K1, ilog2(sizeof(pte_t)), 8);
|
||||
} else {
|
||||
uasm_i_andi(&p, K0, K1, sizeof(pte_t));
|
||||
uasm_i_beqz(&p, K0, 8);
|
||||
}
|
||||
|
||||
UASM_i_MFC0(&p, K0, C0_ENTRYLO0); /* load it in the delay slot*/
|
||||
UASM_i_MFC0(&p, K0, C0_ENTRYLO1); /* load it if ptr is odd */
|
||||
|
@ -1417,13 +1808,19 @@ static void __cpuinit build_r4000_tlb_load_handler(void)
|
|||
* If the entryLo (now in K0) is valid (bit 1), RI or
|
||||
* XI must have triggered it.
|
||||
*/
|
||||
if (use_bbit_insns()) {
|
||||
uasm_il_bbit1(&p, &r, K0, 1, label_nopage_tlbl);
|
||||
/* Reload the PTE value */
|
||||
iPTE_LW(&p, K0, K1);
|
||||
uasm_l_tlbl_goaround1(&l, p);
|
||||
} else {
|
||||
uasm_i_andi(&p, K0, K0, 2);
|
||||
uasm_il_bnez(&p, &r, K0, label_nopage_tlbl);
|
||||
|
||||
uasm_l_tlbl_goaround1(&l, p);
|
||||
/* Reload the PTE value */
|
||||
iPTE_LW(&p, K0, K1);
|
||||
}
|
||||
}
|
||||
build_make_valid(&p, &r, K0, K1);
|
||||
build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1);
|
||||
|
||||
|
@ -1442,23 +1839,35 @@ static void __cpuinit build_r4000_tlb_load_handler(void)
|
|||
* If the page is not _PAGE_VALID, RI or XI could not
|
||||
* have triggered it. Skip the expensive test..
|
||||
*/
|
||||
if (use_bbit_insns()) {
|
||||
uasm_il_bbit0(&p, &r, K0, ilog2(_PAGE_VALID),
|
||||
label_tlbl_goaround2);
|
||||
} else {
|
||||
uasm_i_andi(&p, K0, K0, _PAGE_VALID);
|
||||
uasm_il_beqz(&p, &r, K0, label_tlbl_goaround2);
|
||||
}
|
||||
uasm_i_nop(&p);
|
||||
|
||||
uasm_i_tlbr(&p);
|
||||
/* Examine entrylo 0 or 1 based on ptr. */
|
||||
if (use_bbit_insns()) {
|
||||
uasm_i_bbit0(&p, K1, ilog2(sizeof(pte_t)), 8);
|
||||
} else {
|
||||
uasm_i_andi(&p, K0, K1, sizeof(pte_t));
|
||||
uasm_i_beqz(&p, K0, 8);
|
||||
|
||||
}
|
||||
UASM_i_MFC0(&p, K0, C0_ENTRYLO0); /* load it in the delay slot*/
|
||||
UASM_i_MFC0(&p, K0, C0_ENTRYLO1); /* load it if ptr is odd */
|
||||
/*
|
||||
* If the entryLo (now in K0) is valid (bit 1), RI or
|
||||
* XI must have triggered it.
|
||||
*/
|
||||
if (use_bbit_insns()) {
|
||||
uasm_il_bbit0(&p, &r, K0, 1, label_tlbl_goaround2);
|
||||
} else {
|
||||
uasm_i_andi(&p, K0, K0, 2);
|
||||
uasm_il_beqz(&p, &r, K0, label_tlbl_goaround2);
|
||||
}
|
||||
/* Reload the PTE value */
|
||||
iPTE_LW(&p, K0, K1);
|
||||
|
||||
|
@ -1466,7 +1875,7 @@ static void __cpuinit build_r4000_tlb_load_handler(void)
|
|||
* We clobbered C0_PAGEMASK, restore it. On the other branch
|
||||
* it is restored in build_huge_tlb_write_entry.
|
||||
*/
|
||||
build_restore_pagemask(&p, &r, K0, label_nopage_tlbl);
|
||||
build_restore_pagemask(&p, &r, K0, label_nopage_tlbl, 0);
|
||||
|
||||
uasm_l_tlbl_goaround2(&l, p);
|
||||
}
|
||||
|
@ -1623,13 +2032,16 @@ void __cpuinit build_tlb_refill_handler(void)
|
|||
break;
|
||||
|
||||
default:
|
||||
build_r4000_tlb_refill_handler();
|
||||
if (!run_once) {
|
||||
#ifdef CONFIG_MIPS_PGD_C0_CONTEXT
|
||||
build_r4000_setup_pgd();
|
||||
#endif
|
||||
build_r4000_tlb_load_handler();
|
||||
build_r4000_tlb_store_handler();
|
||||
build_r4000_tlb_modify_handler();
|
||||
run_once++;
|
||||
}
|
||||
build_r4000_tlb_refill_handler();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1641,4 +2053,8 @@ void __cpuinit flush_tlb_handlers(void)
|
|||
(unsigned long)handle_tlbs + sizeof(handle_tlbs));
|
||||
local_flush_icache_range((unsigned long)handle_tlbm,
|
||||
(unsigned long)handle_tlbm + sizeof(handle_tlbm));
|
||||
#ifdef CONFIG_MIPS_PGD_C0_CONTEXT
|
||||
local_flush_icache_range((unsigned long)tlbmiss_handler_setup_pgd,
|
||||
(unsigned long)tlbmiss_handler_setup_pgd + sizeof(handle_tlbm));
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -68,7 +68,8 @@ enum opcode {
|
|||
insn_pref, insn_rfe, insn_sc, insn_scd, insn_sd, insn_sll,
|
||||
insn_sra, insn_srl, insn_rotr, insn_subu, insn_sw, insn_tlbp,
|
||||
insn_tlbr, insn_tlbwi, insn_tlbwr, insn_xor, insn_xori,
|
||||
insn_dins, insn_syscall, insn_bbit0, insn_bbit1
|
||||
insn_dins, insn_dinsm, insn_syscall, insn_bbit0, insn_bbit1,
|
||||
insn_lwx, insn_ldx
|
||||
};
|
||||
|
||||
struct insn {
|
||||
|
@ -142,9 +143,12 @@ static struct insn insn_table[] __uasminitdata = {
|
|||
{ insn_xor, M(spec_op, 0, 0, 0, 0, xor_op), RS | RT | RD },
|
||||
{ insn_xori, M(xori_op, 0, 0, 0, 0, 0), RS | RT | UIMM },
|
||||
{ insn_dins, M(spec3_op, 0, 0, 0, 0, dins_op), RS | RT | RD | RE },
|
||||
{ insn_dinsm, M(spec3_op, 0, 0, 0, 0, dinsm_op), RS | RT | RD | RE },
|
||||
{ insn_syscall, M(spec_op, 0, 0, 0, 0, syscall_op), SCIMM},
|
||||
{ insn_bbit0, M(lwc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
|
||||
{ insn_bbit1, M(swc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
|
||||
{ insn_lwx, M(spec3_op, 0, 0, 0, lwx_op, lx_op), RS | RT | RD },
|
||||
{ insn_ldx, M(spec3_op, 0, 0, 0, ldx_op, lx_op), RS | RT | RD },
|
||||
{ insn_invalid, 0, 0 }
|
||||
};
|
||||
|
||||
|
@ -152,91 +156,83 @@ static struct insn insn_table[] __uasminitdata = {
|
|||
|
||||
static inline __uasminit u32 build_rs(u32 arg)
|
||||
{
|
||||
if (arg & ~RS_MASK)
|
||||
printk(KERN_WARNING "Micro-assembler field overflow\n");
|
||||
WARN(arg & ~RS_MASK, KERN_WARNING "Micro-assembler field overflow\n");
|
||||
|
||||
return (arg & RS_MASK) << RS_SH;
|
||||
}
|
||||
|
||||
static inline __uasminit u32 build_rt(u32 arg)
|
||||
{
|
||||
if (arg & ~RT_MASK)
|
||||
printk(KERN_WARNING "Micro-assembler field overflow\n");
|
||||
WARN(arg & ~RT_MASK, KERN_WARNING "Micro-assembler field overflow\n");
|
||||
|
||||
return (arg & RT_MASK) << RT_SH;
|
||||
}
|
||||
|
||||
static inline __uasminit u32 build_rd(u32 arg)
|
||||
{
|
||||
if (arg & ~RD_MASK)
|
||||
printk(KERN_WARNING "Micro-assembler field overflow\n");
|
||||
WARN(arg & ~RD_MASK, KERN_WARNING "Micro-assembler field overflow\n");
|
||||
|
||||
return (arg & RD_MASK) << RD_SH;
|
||||
}
|
||||
|
||||
static inline __uasminit u32 build_re(u32 arg)
|
||||
{
|
||||
if (arg & ~RE_MASK)
|
||||
printk(KERN_WARNING "Micro-assembler field overflow\n");
|
||||
WARN(arg & ~RE_MASK, KERN_WARNING "Micro-assembler field overflow\n");
|
||||
|
||||
return (arg & RE_MASK) << RE_SH;
|
||||
}
|
||||
|
||||
static inline __uasminit u32 build_simm(s32 arg)
|
||||
{
|
||||
if (arg > 0x7fff || arg < -0x8000)
|
||||
printk(KERN_WARNING "Micro-assembler field overflow\n");
|
||||
WARN(arg > 0x7fff || arg < -0x8000,
|
||||
KERN_WARNING "Micro-assembler field overflow\n");
|
||||
|
||||
return arg & 0xffff;
|
||||
}
|
||||
|
||||
static inline __uasminit u32 build_uimm(u32 arg)
|
||||
{
|
||||
if (arg & ~IMM_MASK)
|
||||
printk(KERN_WARNING "Micro-assembler field overflow\n");
|
||||
WARN(arg & ~IMM_MASK, KERN_WARNING "Micro-assembler field overflow\n");
|
||||
|
||||
return arg & IMM_MASK;
|
||||
}
|
||||
|
||||
static inline __uasminit u32 build_bimm(s32 arg)
|
||||
{
|
||||
if (arg > 0x1ffff || arg < -0x20000)
|
||||
printk(KERN_WARNING "Micro-assembler field overflow\n");
|
||||
WARN(arg > 0x1ffff || arg < -0x20000,
|
||||
KERN_WARNING "Micro-assembler field overflow\n");
|
||||
|
||||
if (arg & 0x3)
|
||||
printk(KERN_WARNING "Invalid micro-assembler branch target\n");
|
||||
WARN(arg & 0x3, KERN_WARNING "Invalid micro-assembler branch target\n");
|
||||
|
||||
return ((arg < 0) ? (1 << 15) : 0) | ((arg >> 2) & 0x7fff);
|
||||
}
|
||||
|
||||
static inline __uasminit u32 build_jimm(u32 arg)
|
||||
{
|
||||
if (arg & ~((JIMM_MASK) << 2))
|
||||
printk(KERN_WARNING "Micro-assembler field overflow\n");
|
||||
WARN(arg & ~(JIMM_MASK << 2),
|
||||
KERN_WARNING "Micro-assembler field overflow\n");
|
||||
|
||||
return (arg >> 2) & JIMM_MASK;
|
||||
}
|
||||
|
||||
static inline __uasminit u32 build_scimm(u32 arg)
|
||||
{
|
||||
if (arg & ~SCIMM_MASK)
|
||||
printk(KERN_WARNING "Micro-assembler field overflow\n");
|
||||
WARN(arg & ~SCIMM_MASK,
|
||||
KERN_WARNING "Micro-assembler field overflow\n");
|
||||
|
||||
return (arg & SCIMM_MASK) << SCIMM_SH;
|
||||
}
|
||||
|
||||
static inline __uasminit u32 build_func(u32 arg)
|
||||
{
|
||||
if (arg & ~FUNC_MASK)
|
||||
printk(KERN_WARNING "Micro-assembler field overflow\n");
|
||||
WARN(arg & ~FUNC_MASK, KERN_WARNING "Micro-assembler field overflow\n");
|
||||
|
||||
return arg & FUNC_MASK;
|
||||
}
|
||||
|
||||
static inline __uasminit u32 build_set(u32 arg)
|
||||
{
|
||||
if (arg & ~SET_MASK)
|
||||
printk(KERN_WARNING "Micro-assembler field overflow\n");
|
||||
WARN(arg & ~SET_MASK, KERN_WARNING "Micro-assembler field overflow\n");
|
||||
|
||||
return arg & SET_MASK;
|
||||
}
|
||||
|
@ -340,6 +336,13 @@ Ip_u2u1msbu3(op) \
|
|||
} \
|
||||
UASM_EXPORT_SYMBOL(uasm_i##op);
|
||||
|
||||
#define I_u2u1msb32u3(op) \
|
||||
Ip_u2u1msbu3(op) \
|
||||
{ \
|
||||
build_insn(buf, insn##op, b, a, c+d-33, c); \
|
||||
} \
|
||||
UASM_EXPORT_SYMBOL(uasm_i##op);
|
||||
|
||||
#define I_u1u2(op) \
|
||||
Ip_u1u2(op) \
|
||||
{ \
|
||||
|
@ -422,9 +425,12 @@ I_0(_tlbwr)
|
|||
I_u3u1u2(_xor)
|
||||
I_u2u1u3(_xori)
|
||||
I_u2u1msbu3(_dins);
|
||||
I_u2u1msb32u3(_dinsm);
|
||||
I_u1(_syscall);
|
||||
I_u1u2s3(_bbit0);
|
||||
I_u1u2s3(_bbit1);
|
||||
I_u3u1u2(_lwx)
|
||||
I_u3u1u2(_ldx)
|
||||
|
||||
#ifdef CONFIG_CPU_CAVIUM_OCTEON
|
||||
#include <asm/octeon/octeon.h>
|
||||
|
|
|
@ -410,14 +410,13 @@ static int sbprof_tb_open(struct inode *inode, struct file *filp)
|
|||
return -EBUSY;
|
||||
|
||||
memset(&sbp, 0, sizeof(struct sbprof_tb));
|
||||
sbp.sbprof_tbbuf = vmalloc(MAX_TBSAMPLE_BYTES);
|
||||
sbp.sbprof_tbbuf = vzalloc(MAX_TBSAMPLE_BYTES);
|
||||
if (!sbp.sbprof_tbbuf) {
|
||||
sbp.open = SB_CLOSED;
|
||||
wmb();
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memset(sbp.sbprof_tbbuf, 0, MAX_TBSAMPLE_BYTES);
|
||||
init_waitqueue_head(&sbp.tb_sync);
|
||||
init_waitqueue_head(&sbp.tb_read);
|
||||
mutex_init(&sbp.lock);
|
||||
|
|
|
@ -213,11 +213,8 @@ txx9_alloc_pci_controller(struct pci_controller *pcic,
|
|||
|
||||
pcic->mem_offset = 0; /* busaddr == physaddr */
|
||||
|
||||
printk(KERN_INFO "PCI: IO 0x%08llx-0x%08llx MEM 0x%08llx-0x%08llx\n",
|
||||
(unsigned long long)pcic->mem_resource[1].start,
|
||||
(unsigned long long)pcic->mem_resource[1].end,
|
||||
(unsigned long long)pcic->mem_resource[0].start,
|
||||
(unsigned long long)pcic->mem_resource[0].end);
|
||||
printk(KERN_INFO "PCI: IO %pR MEM %pR\n",
|
||||
&pcic->mem_resource[1], &pcic->mem_resource[0]);
|
||||
|
||||
/* register_pci_controller() will request MEM resource */
|
||||
release_resource(&pcic->mem_resource[0]);
|
||||
|
|
|
@ -53,6 +53,14 @@ if SPI_MASTER
|
|||
|
||||
comment "SPI Master Controller Drivers"
|
||||
|
||||
config SPI_ATH79
|
||||
tristate "Atheros AR71XX/AR724X/AR913X SPI controller driver"
|
||||
depends on ATH79 && GENERIC_GPIO
|
||||
select SPI_BITBANG
|
||||
help
|
||||
This enables support for the SPI controller present on the
|
||||
Atheros AR71XX/AR724X/AR913X SoCs.
|
||||
|
||||
config SPI_ATMEL
|
||||
tristate "Atmel SPI Controller"
|
||||
depends on (ARCH_AT91 || AVR32)
|
||||
|
|
|
@ -10,6 +10,7 @@ obj-$(CONFIG_SPI_MASTER) += spi.o
|
|||
|
||||
# SPI master controller drivers (bus)
|
||||
obj-$(CONFIG_SPI_ATMEL) += atmel_spi.o
|
||||
obj-$(CONFIG_SPI_ATH79) += ath79_spi.o
|
||||
obj-$(CONFIG_SPI_BFIN) += spi_bfin5xx.o
|
||||
obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o
|
||||
obj-$(CONFIG_SPI_AU1550) += au1550_spi.o
|
||||
|
|
|
@ -0,0 +1,292 @@
|
|||
/*
|
||||
* SPI controller driver for the Atheros AR71XX/AR724X/AR913X SoCs
|
||||
*
|
||||
* Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
|
||||
*
|
||||
* This driver has been based on the spi-gpio.c:
|
||||
* Copyright (C) 2006,2008 David Brownell
|
||||
*
|
||||
* 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/delay.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/spi_bitbang.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <asm/mach-ath79/ar71xx_regs.h>
|
||||
#include <asm/mach-ath79/ath79_spi_platform.h>
|
||||
|
||||
#define DRV_NAME "ath79-spi"
|
||||
|
||||
struct ath79_spi {
|
||||
struct spi_bitbang bitbang;
|
||||
u32 ioc_base;
|
||||
u32 reg_ctrl;
|
||||
void __iomem *base;
|
||||
};
|
||||
|
||||
static inline u32 ath79_spi_rr(struct ath79_spi *sp, unsigned reg)
|
||||
{
|
||||
return ioread32(sp->base + reg);
|
||||
}
|
||||
|
||||
static inline void ath79_spi_wr(struct ath79_spi *sp, unsigned reg, u32 val)
|
||||
{
|
||||
iowrite32(val, sp->base + reg);
|
||||
}
|
||||
|
||||
static inline struct ath79_spi *ath79_spidev_to_sp(struct spi_device *spi)
|
||||
{
|
||||
return spi_master_get_devdata(spi->master);
|
||||
}
|
||||
|
||||
static void ath79_spi_chipselect(struct spi_device *spi, int is_active)
|
||||
{
|
||||
struct ath79_spi *sp = ath79_spidev_to_sp(spi);
|
||||
int cs_high = (spi->mode & SPI_CS_HIGH) ? is_active : !is_active;
|
||||
|
||||
if (is_active) {
|
||||
/* set initial clock polarity */
|
||||
if (spi->mode & SPI_CPOL)
|
||||
sp->ioc_base |= AR71XX_SPI_IOC_CLK;
|
||||
else
|
||||
sp->ioc_base &= ~AR71XX_SPI_IOC_CLK;
|
||||
|
||||
ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base);
|
||||
}
|
||||
|
||||
if (spi->chip_select) {
|
||||
struct ath79_spi_controller_data *cdata = spi->controller_data;
|
||||
|
||||
/* SPI is normally active-low */
|
||||
gpio_set_value(cdata->gpio, cs_high);
|
||||
} else {
|
||||
if (cs_high)
|
||||
sp->ioc_base |= AR71XX_SPI_IOC_CS0;
|
||||
else
|
||||
sp->ioc_base &= ~AR71XX_SPI_IOC_CS0;
|
||||
|
||||
ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int ath79_spi_setup_cs(struct spi_device *spi)
|
||||
{
|
||||
struct ath79_spi *sp = ath79_spidev_to_sp(spi);
|
||||
struct ath79_spi_controller_data *cdata;
|
||||
|
||||
cdata = spi->controller_data;
|
||||
if (spi->chip_select && !cdata)
|
||||
return -EINVAL;
|
||||
|
||||
/* enable GPIO mode */
|
||||
ath79_spi_wr(sp, AR71XX_SPI_REG_FS, AR71XX_SPI_FS_GPIO);
|
||||
|
||||
/* save CTRL register */
|
||||
sp->reg_ctrl = ath79_spi_rr(sp, AR71XX_SPI_REG_CTRL);
|
||||
sp->ioc_base = ath79_spi_rr(sp, AR71XX_SPI_REG_IOC);
|
||||
|
||||
/* TODO: setup speed? */
|
||||
ath79_spi_wr(sp, AR71XX_SPI_REG_CTRL, 0x43);
|
||||
|
||||
if (spi->chip_select) {
|
||||
int status = 0;
|
||||
|
||||
status = gpio_request(cdata->gpio, dev_name(&spi->dev));
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
status = gpio_direction_output(cdata->gpio,
|
||||
spi->mode & SPI_CS_HIGH);
|
||||
if (status) {
|
||||
gpio_free(cdata->gpio);
|
||||
return status;
|
||||
}
|
||||
} else {
|
||||
if (spi->mode & SPI_CS_HIGH)
|
||||
sp->ioc_base |= AR71XX_SPI_IOC_CS0;
|
||||
else
|
||||
sp->ioc_base &= ~AR71XX_SPI_IOC_CS0;
|
||||
ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath79_spi_cleanup_cs(struct spi_device *spi)
|
||||
{
|
||||
struct ath79_spi *sp = ath79_spidev_to_sp(spi);
|
||||
|
||||
if (spi->chip_select) {
|
||||
struct ath79_spi_controller_data *cdata = spi->controller_data;
|
||||
gpio_free(cdata->gpio);
|
||||
}
|
||||
|
||||
/* restore CTRL register */
|
||||
ath79_spi_wr(sp, AR71XX_SPI_REG_CTRL, sp->reg_ctrl);
|
||||
/* disable GPIO mode */
|
||||
ath79_spi_wr(sp, AR71XX_SPI_REG_FS, 0);
|
||||
}
|
||||
|
||||
static int ath79_spi_setup(struct spi_device *spi)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
if (spi->bits_per_word > 32)
|
||||
return -EINVAL;
|
||||
|
||||
if (!spi->controller_state) {
|
||||
status = ath79_spi_setup_cs(spi);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
||||
status = spi_bitbang_setup(spi);
|
||||
if (status && !spi->controller_state)
|
||||
ath79_spi_cleanup_cs(spi);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void ath79_spi_cleanup(struct spi_device *spi)
|
||||
{
|
||||
ath79_spi_cleanup_cs(spi);
|
||||
spi_bitbang_cleanup(spi);
|
||||
}
|
||||
|
||||
static u32 ath79_spi_txrx_mode0(struct spi_device *spi, unsigned nsecs,
|
||||
u32 word, u8 bits)
|
||||
{
|
||||
struct ath79_spi *sp = ath79_spidev_to_sp(spi);
|
||||
u32 ioc = sp->ioc_base;
|
||||
|
||||
/* clock starts at inactive polarity */
|
||||
for (word <<= (32 - bits); likely(bits); bits--) {
|
||||
u32 out;
|
||||
|
||||
if (word & (1 << 31))
|
||||
out = ioc | AR71XX_SPI_IOC_DO;
|
||||
else
|
||||
out = ioc & ~AR71XX_SPI_IOC_DO;
|
||||
|
||||
/* setup MSB (to slave) on trailing edge */
|
||||
ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, out);
|
||||
ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, out | AR71XX_SPI_IOC_CLK);
|
||||
|
||||
word <<= 1;
|
||||
}
|
||||
|
||||
return ath79_spi_rr(sp, AR71XX_SPI_REG_RDS);
|
||||
}
|
||||
|
||||
static __devinit int ath79_spi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master;
|
||||
struct ath79_spi *sp;
|
||||
struct ath79_spi_platform_data *pdata;
|
||||
struct resource *r;
|
||||
int ret;
|
||||
|
||||
master = spi_alloc_master(&pdev->dev, sizeof(*sp));
|
||||
if (master == NULL) {
|
||||
dev_err(&pdev->dev, "failed to allocate spi master\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
sp = spi_master_get_devdata(master);
|
||||
platform_set_drvdata(pdev, sp);
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
|
||||
master->setup = ath79_spi_setup;
|
||||
master->cleanup = ath79_spi_cleanup;
|
||||
if (pdata) {
|
||||
master->bus_num = pdata->bus_num;
|
||||
master->num_chipselect = pdata->num_chipselect;
|
||||
} else {
|
||||
master->bus_num = -1;
|
||||
master->num_chipselect = 1;
|
||||
}
|
||||
|
||||
sp->bitbang.master = spi_master_get(master);
|
||||
sp->bitbang.chipselect = ath79_spi_chipselect;
|
||||
sp->bitbang.txrx_word[SPI_MODE_0] = ath79_spi_txrx_mode0;
|
||||
sp->bitbang.setup_transfer = spi_bitbang_setup_transfer;
|
||||
sp->bitbang.flags = SPI_CS_HIGH;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (r == NULL) {
|
||||
ret = -ENOENT;
|
||||
goto err_put_master;
|
||||
}
|
||||
|
||||
sp->base = ioremap(r->start, r->end - r->start + 1);
|
||||
if (!sp->base) {
|
||||
ret = -ENXIO;
|
||||
goto err_put_master;
|
||||
}
|
||||
|
||||
ret = spi_bitbang_start(&sp->bitbang);
|
||||
if (ret)
|
||||
goto err_unmap;
|
||||
|
||||
return 0;
|
||||
|
||||
err_unmap:
|
||||
iounmap(sp->base);
|
||||
err_put_master:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
spi_master_put(sp->bitbang.master);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __devexit int ath79_spi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ath79_spi *sp = platform_get_drvdata(pdev);
|
||||
|
||||
spi_bitbang_stop(&sp->bitbang);
|
||||
iounmap(sp->base);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
spi_master_put(sp->bitbang.master);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver ath79_spi_driver = {
|
||||
.probe = ath79_spi_probe,
|
||||
.remove = __devexit_p(ath79_spi_remove),
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static __init int ath79_spi_init(void)
|
||||
{
|
||||
return platform_driver_register(&ath79_spi_driver);
|
||||
}
|
||||
module_init(ath79_spi_init);
|
||||
|
||||
static __exit void ath79_spi_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&ath79_spi_driver);
|
||||
}
|
||||
module_exit(ath79_spi_exit);
|
||||
|
||||
MODULE_DESCRIPTION("SPI controller driver for Atheros AR71XX/AR724X/AR913X");
|
||||
MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:" DRV_NAME);
|
Загрузка…
Ссылка в новой задаче