mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2025-04-21 12:27:27 +03:00
[atheros]: move files for kernel 2.6.26 to a special directory.
In kernel 2.6.28 the directory structure has chanced, so for kernel 2.6.26 a own files directory is needed. git-svn-id: svn://svn.openwrt.org/openwrt/trunk@14583 3c298f89-4303-0410-b956-a3cf2f4a3e73
This commit is contained in:
27
target/linux/atheros/files-2.6.26/arch/mips/atheros/Kconfig
Normal file
27
target/linux/atheros/files-2.6.26/arch/mips/atheros/Kconfig
Normal file
@@ -0,0 +1,27 @@
|
||||
config ATHEROS_AR5312
|
||||
bool "Atheros 5312/2312+ support"
|
||||
depends on ATHEROS
|
||||
default y
|
||||
|
||||
config ATHEROS_AR5315
|
||||
bool "Atheros 5315/2315+ support"
|
||||
depends on ATHEROS
|
||||
select DMA_NONCOHERENT
|
||||
select CEVT_R4K
|
||||
select CSRC_R4K
|
||||
select IRQ_CPU
|
||||
select SYS_HAS_CPU_MIPS32_R1
|
||||
select SYS_SUPPORTS_32BIT_KERNEL
|
||||
select SYS_SUPPORTS_BIG_ENDIAN
|
||||
select GENERIC_GPIO
|
||||
default y
|
||||
|
||||
config ATHEROS_AR5315_PCI
|
||||
bool "PCI support"
|
||||
select HW_HAS_PCI
|
||||
select PCI
|
||||
select USB_ARCH_HAS_HCD
|
||||
select USB_ARCH_HAS_OHCI
|
||||
select USB_ARCH_HAS_EHCI
|
||||
depends on ATHEROS_AR5315
|
||||
default n
|
||||
13
target/linux/atheros/files-2.6.26/arch/mips/atheros/Makefile
Normal file
13
target/linux/atheros/files-2.6.26/arch/mips/atheros/Makefile
Normal file
@@ -0,0 +1,13 @@
|
||||
#
|
||||
# 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) 2006 FON Technology, SL.
|
||||
# Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
|
||||
# Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
|
||||
#
|
||||
|
||||
obj-y += board.o prom.o reset.o
|
||||
obj-$(CONFIG_ATHEROS_AR5312) += ar5312/
|
||||
obj-$(CONFIG_ATHEROS_AR5315) += ar5315/
|
||||
@@ -0,0 +1,11 @@
|
||||
#
|
||||
# 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) 2007 FON Technology, SL.
|
||||
# Copyright (C) 2007 Imre Kaloz <kaloz@openwrt.org>
|
||||
# Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
|
||||
#
|
||||
|
||||
obj-y := board.o irq.o
|
||||
@@ -0,0 +1,473 @@
|
||||
/*
|
||||
* 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) 2003 Atheros Communications, Inc., All Rights Reserved.
|
||||
* Copyright (C) 2006 FON Technology, SL.
|
||||
* Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
|
||||
* Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Platform devices for Atheros SoCs
|
||||
*/
|
||||
|
||||
#include <linux/autoconf.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/mtd/physmap.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/reboot.h>
|
||||
#include <asm/time.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/io.h>
|
||||
#include <ar531x.h>
|
||||
#include <linux/leds.h>
|
||||
|
||||
#define NO_PHY 0x1f
|
||||
|
||||
static int is_5312 = 0;
|
||||
static struct platform_device *ar5312_devs[6];
|
||||
|
||||
static struct resource ar5312_eth0_res[] = {
|
||||
{
|
||||
.name = "eth0_membase",
|
||||
.flags = IORESOURCE_MEM,
|
||||
.start = KSEG1ADDR(AR531X_ENET0),
|
||||
.end = KSEG1ADDR(AR531X_ENET0 + 0x2000),
|
||||
},
|
||||
{
|
||||
.name = "eth0_irq",
|
||||
.flags = IORESOURCE_IRQ,
|
||||
.start = AR5312_IRQ_ENET0_INTRS,
|
||||
.end = AR5312_IRQ_ENET0_INTRS,
|
||||
},
|
||||
};
|
||||
static struct ar531x_eth ar5312_eth0_data = {
|
||||
.phy = NO_PHY,
|
||||
.mac = 0,
|
||||
.reset_base = AR531X_RESET,
|
||||
.reset_mac = AR531X_RESET_ENET0,
|
||||
.reset_phy = AR531X_RESET_EPHY0,
|
||||
.phy_base = KSEG1ADDR(AR531X_ENET0),
|
||||
};
|
||||
|
||||
static struct resource ar5312_eth1_res[] = {
|
||||
{
|
||||
.name = "eth1_membase",
|
||||
.flags = IORESOURCE_MEM,
|
||||
.start = KSEG1ADDR(AR531X_ENET1),
|
||||
.end = KSEG1ADDR(AR531X_ENET1 + 0x2000),
|
||||
},
|
||||
{
|
||||
.name = "eth1_irq",
|
||||
.flags = IORESOURCE_IRQ,
|
||||
.start = AR5312_IRQ_ENET1_INTRS,
|
||||
.end = AR5312_IRQ_ENET1_INTRS,
|
||||
},
|
||||
};
|
||||
static struct ar531x_eth ar5312_eth1_data = {
|
||||
.phy = NO_PHY,
|
||||
.mac = 1,
|
||||
.reset_base = AR531X_RESET,
|
||||
.reset_mac = AR531X_RESET_ENET1,
|
||||
.reset_phy = AR531X_RESET_EPHY1,
|
||||
.phy_base = KSEG1ADDR(AR531X_ENET1),
|
||||
};
|
||||
|
||||
static struct platform_device ar5312_eth[] = {
|
||||
{
|
||||
.id = 0,
|
||||
.name = "ar531x-eth",
|
||||
.dev.platform_data = &ar5312_eth0_data,
|
||||
.resource = ar5312_eth0_res,
|
||||
.num_resources = ARRAY_SIZE(ar5312_eth0_res)
|
||||
},
|
||||
{
|
||||
.id = 1,
|
||||
.name = "ar531x-eth",
|
||||
.dev.platform_data = &ar5312_eth1_data,
|
||||
.resource = ar5312_eth1_res,
|
||||
.num_resources = ARRAY_SIZE(ar5312_eth1_res)
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* AR2312/3 ethernet uses the PHY of ENET0, but the MAC
|
||||
* of ENET1. Atheros calls it 'twisted' for a reason :)
|
||||
*/
|
||||
static struct resource ar231x_eth0_res[] = {
|
||||
{
|
||||
.name = "eth0_membase",
|
||||
.flags = IORESOURCE_MEM,
|
||||
.start = KSEG1ADDR(AR531X_ENET1),
|
||||
.end = KSEG1ADDR(AR531X_ENET1 + 0x2000),
|
||||
},
|
||||
{
|
||||
.name = "eth0_irq",
|
||||
.flags = IORESOURCE_IRQ,
|
||||
.start = AR5312_IRQ_ENET1_INTRS,
|
||||
.end = AR5312_IRQ_ENET1_INTRS,
|
||||
},
|
||||
};
|
||||
static struct ar531x_eth ar231x_eth0_data = {
|
||||
.phy = 1,
|
||||
.mac = 1,
|
||||
.reset_base = AR531X_RESET,
|
||||
.reset_mac = AR531X_RESET_ENET1,
|
||||
.reset_phy = AR531X_RESET_EPHY1,
|
||||
.phy_base = KSEG1ADDR(AR531X_ENET0),
|
||||
};
|
||||
static struct platform_device ar231x_eth0 = {
|
||||
.id = 0,
|
||||
.name = "ar531x-eth",
|
||||
.dev.platform_data = &ar231x_eth0_data,
|
||||
.resource = ar231x_eth0_res,
|
||||
.num_resources = ARRAY_SIZE(ar231x_eth0_res)
|
||||
};
|
||||
|
||||
|
||||
static struct platform_device ar5312_wmac[] = {
|
||||
{
|
||||
.id = 0,
|
||||
.name = "ar531x-wmac",
|
||||
},
|
||||
{
|
||||
.id = 1,
|
||||
.name = "ar531x-wmac",
|
||||
},
|
||||
};
|
||||
|
||||
static struct physmap_flash_data ar5312_flash_data = {
|
||||
.width = 2,
|
||||
};
|
||||
|
||||
static struct resource ar5312_flash_resource = {
|
||||
.start = AR531X_FLASH,
|
||||
.end = AR531X_FLASH + 0x800000 - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
};
|
||||
|
||||
static struct platform_device ar5312_physmap_flash = {
|
||||
.name = "physmap-flash",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
.platform_data = &ar5312_flash_data,
|
||||
},
|
||||
.num_resources = 1,
|
||||
.resource = &ar5312_flash_resource,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_LEDS_GPIO
|
||||
static struct gpio_led ar5312_leds[] = {
|
||||
{ .name = "wlan", .gpio = 0, .active_low = 1, },
|
||||
};
|
||||
|
||||
static const struct gpio_led_platform_data ar5312_led_data = {
|
||||
.num_leds = ARRAY_SIZE(ar5312_leds),
|
||||
.leds = (void *) ar5312_leds,
|
||||
};
|
||||
|
||||
static struct platform_device ar5312_gpio_leds = {
|
||||
.name = "leds-gpio",
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.platform_data = (void *) &ar5312_led_data,
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* NB: This mapping size is larger than the actual flash size,
|
||||
* but this shouldn't be a problem here, because the flash
|
||||
* will simply be mapped multiple times.
|
||||
*/
|
||||
static char __init *ar5312_flash_limit(void)
|
||||
{
|
||||
u32 ctl;
|
||||
/*
|
||||
* Configure flash bank 0.
|
||||
* Assume 8M window size. Flash will be aliased if it's smaller
|
||||
*/
|
||||
ctl = FLASHCTL_E |
|
||||
FLASHCTL_AC_8M |
|
||||
FLASHCTL_RBLE |
|
||||
(0x01 << FLASHCTL_IDCY_S) |
|
||||
(0x07 << FLASHCTL_WST1_S) |
|
||||
(0x07 << FLASHCTL_WST2_S) |
|
||||
(sysRegRead(AR531X_FLASHCTL0) & FLASHCTL_MW);
|
||||
|
||||
sysRegWrite(AR531X_FLASHCTL0, ctl);
|
||||
|
||||
/* Disable other flash banks */
|
||||
sysRegWrite(AR531X_FLASHCTL1,
|
||||
sysRegRead(AR531X_FLASHCTL1) & ~(FLASHCTL_E | FLASHCTL_AC));
|
||||
|
||||
sysRegWrite(AR531X_FLASHCTL2,
|
||||
sysRegRead(AR531X_FLASHCTL2) & ~(FLASHCTL_E | FLASHCTL_AC));
|
||||
|
||||
return (char *) KSEG1ADDR(AR531X_FLASH + 0x800000);
|
||||
}
|
||||
|
||||
static struct ar531x_config __init *init_wmac(int unit)
|
||||
{
|
||||
struct ar531x_config *config;
|
||||
|
||||
config = (struct ar531x_config *) kzalloc(sizeof(struct ar531x_config), GFP_KERNEL);
|
||||
config->board = board_config;
|
||||
config->radio = radio_config;
|
||||
config->unit = unit;
|
||||
config->tag = (u_int16_t) ((sysRegRead(AR531X_REV) >> AR531X_REV_WMAC_MIN_S) & AR531X_REV_CHIP);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
int __init ar5312_init_devices(void)
|
||||
{
|
||||
struct ar531x_boarddata *bcfg;
|
||||
char *radio, *c;
|
||||
int dev = 0;
|
||||
uint32_t fctl = 0;
|
||||
|
||||
if (!is_5312)
|
||||
return 0;
|
||||
|
||||
/* Locate board/radio config data */
|
||||
ar531x_find_config(ar5312_flash_limit());
|
||||
bcfg = (struct ar531x_boarddata *) board_config;
|
||||
|
||||
|
||||
/*
|
||||
* Chip IDs and hardware detection for some Atheros
|
||||
* models are really broken!
|
||||
*
|
||||
* Atheros uses a disabled WMAC0 and Silicon ID of AR5312
|
||||
* as indication for AR2312, which is otherwise
|
||||
* indistinguishable from the real AR5312.
|
||||
*/
|
||||
if (radio_config) {
|
||||
radio = radio_config + AR531X_RADIO_MASK_OFF;
|
||||
if ((*((u32 *) radio) & AR531X_RADIO0_MASK) == 0)
|
||||
bcfg->config |= BD_ISCASPER;
|
||||
} else
|
||||
radio = NULL;
|
||||
|
||||
/* AR2313 has CPU minor rev. 10 */
|
||||
if ((current_cpu_data.processor_id & 0xff) == 0x0a)
|
||||
mips_machtype = MACH_ATHEROS_AR2313;
|
||||
|
||||
/* AR2312 shares the same Silicon ID as AR5312 */
|
||||
else if (bcfg->config & BD_ISCASPER)
|
||||
mips_machtype = MACH_ATHEROS_AR2312;
|
||||
|
||||
/* Everything else is probably AR5312 or compatible */
|
||||
else
|
||||
mips_machtype = MACH_ATHEROS_AR5312;
|
||||
|
||||
ar5312_eth0_data.board_config = board_config;
|
||||
ar5312_eth1_data.board_config = board_config;
|
||||
|
||||
/* fixup flash width */
|
||||
fctl = sysRegRead(AR531X_FLASHCTL) & FLASHCTL_MW;
|
||||
switch (fctl) {
|
||||
case FLASHCTL_MWx16:
|
||||
ar5312_flash_data.width = 2;
|
||||
break;
|
||||
case FLASHCTL_MWx8:
|
||||
default:
|
||||
ar5312_flash_data.width = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
ar5312_devs[dev++] = &ar5312_physmap_flash;
|
||||
|
||||
#ifdef CONFIG_LEDS_GPIO
|
||||
ar5312_leds[0].gpio = bcfg->sysLedGpio;
|
||||
ar5312_devs[dev++] = &ar5312_gpio_leds;
|
||||
#endif
|
||||
|
||||
if (!memcmp(bcfg->enet0Mac, "\xff\xff\xff\xff\xff\xff", 6))
|
||||
memcpy(bcfg->enet0Mac, bcfg->enet1Mac, 6);
|
||||
|
||||
if (memcmp(bcfg->enet0Mac, bcfg->enet1Mac, 6) == 0) {
|
||||
/* ENET0 and ENET1 have the same mac.
|
||||
* Increment the one from ENET1 */
|
||||
c = bcfg->enet1Mac + 5;
|
||||
while ((c >= (char *) bcfg->enet1Mac) && !(++(*c)))
|
||||
c--;
|
||||
}
|
||||
|
||||
switch(mips_machtype) {
|
||||
case MACH_ATHEROS_AR5312:
|
||||
ar5312_eth0_data.macaddr = bcfg->enet0Mac;
|
||||
ar5312_eth1_data.macaddr = bcfg->enet1Mac;
|
||||
ar5312_devs[dev++] = &ar5312_eth[0];
|
||||
ar5312_devs[dev++] = &ar5312_eth[1];
|
||||
break;
|
||||
case MACH_ATHEROS_AR2312:
|
||||
case MACH_ATHEROS_AR2313:
|
||||
ar231x_eth0_data.macaddr = bcfg->enet0Mac;
|
||||
ar5312_devs[dev++] = &ar231x_eth0;
|
||||
ar5312_flash_data.width = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (radio) {
|
||||
if (mips_machtype == MACH_ATHEROS_AR5312) {
|
||||
if (*((u32 *) radio) & AR531X_RADIO0_MASK) {
|
||||
ar5312_wmac[0].dev.platform_data = init_wmac(0);
|
||||
ar5312_devs[dev++] = &ar5312_wmac[0];
|
||||
}
|
||||
}
|
||||
if (*((u32 *) radio) & AR531X_RADIO1_MASK) {
|
||||
ar5312_wmac[1].dev.platform_data = init_wmac(1);
|
||||
ar5312_devs[dev++] = &ar5312_wmac[1];
|
||||
}
|
||||
}
|
||||
|
||||
return platform_add_devices(ar5312_devs, dev);
|
||||
}
|
||||
|
||||
|
||||
static void ar5312_halt(void)
|
||||
{
|
||||
while (1);
|
||||
}
|
||||
|
||||
static void ar5312_power_off(void)
|
||||
{
|
||||
ar5312_halt();
|
||||
}
|
||||
|
||||
|
||||
static void ar5312_restart(char *command)
|
||||
{
|
||||
/* reset the system */
|
||||
for(;;) sysRegWrite(AR531X_RESET, AR531X_RESET_SYSTEM);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This table is indexed by bits 5..4 of the CLOCKCTL1 register
|
||||
* to determine the predevisor value.
|
||||
*/
|
||||
static int __initdata CLOCKCTL1_PREDIVIDE_TABLE[4] = {
|
||||
1,
|
||||
2,
|
||||
4,
|
||||
5
|
||||
};
|
||||
|
||||
|
||||
static unsigned int __init ar5312_cpu_frequency(void)
|
||||
{
|
||||
unsigned int result;
|
||||
unsigned int predivide_mask, predivide_shift;
|
||||
unsigned int multiplier_mask, multiplier_shift;
|
||||
unsigned int clockCtl1, preDivideSelect, preDivisor, multiplier;
|
||||
unsigned int doubler_mask;
|
||||
unsigned int wisoc_revision;
|
||||
|
||||
/* Trust the bootrom's idea of cpu frequency. */
|
||||
if ((result = sysRegRead(AR5312_SCRATCH)))
|
||||
return result;
|
||||
|
||||
wisoc_revision = (sysRegRead(AR531X_REV) & AR531X_REV_MAJ) >> AR531X_REV_MAJ_S;
|
||||
if (wisoc_revision == AR531X_REV_MAJ_AR2313) {
|
||||
predivide_mask = AR2313_CLOCKCTL1_PREDIVIDE_MASK;
|
||||
predivide_shift = AR2313_CLOCKCTL1_PREDIVIDE_SHIFT;
|
||||
multiplier_mask = AR2313_CLOCKCTL1_MULTIPLIER_MASK;
|
||||
multiplier_shift = AR2313_CLOCKCTL1_MULTIPLIER_SHIFT;
|
||||
doubler_mask = AR2313_CLOCKCTL1_DOUBLER_MASK;
|
||||
} else { /* AR5312 and AR2312 */
|
||||
predivide_mask = AR5312_CLOCKCTL1_PREDIVIDE_MASK;
|
||||
predivide_shift = AR5312_CLOCKCTL1_PREDIVIDE_SHIFT;
|
||||
multiplier_mask = AR5312_CLOCKCTL1_MULTIPLIER_MASK;
|
||||
multiplier_shift = AR5312_CLOCKCTL1_MULTIPLIER_SHIFT;
|
||||
doubler_mask = AR5312_CLOCKCTL1_DOUBLER_MASK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clocking is derived from a fixed 40MHz input clock.
|
||||
*
|
||||
* cpuFreq = InputClock * MULT (where MULT is PLL multiplier)
|
||||
* sysFreq = cpuFreq / 4 (used for APB clock, serial,
|
||||
* flash, Timer, Watchdog Timer)
|
||||
*
|
||||
* cntFreq = cpuFreq / 2 (use for CPU count/compare)
|
||||
*
|
||||
* So, for example, with a PLL multiplier of 5, we have
|
||||
*
|
||||
* cpuFreq = 200MHz
|
||||
* sysFreq = 50MHz
|
||||
* cntFreq = 100MHz
|
||||
*
|
||||
* We compute the CPU frequency, based on PLL settings.
|
||||
*/
|
||||
|
||||
clockCtl1 = sysRegRead(AR5312_CLOCKCTL1);
|
||||
preDivideSelect = (clockCtl1 & predivide_mask) >> predivide_shift;
|
||||
preDivisor = CLOCKCTL1_PREDIVIDE_TABLE[preDivideSelect];
|
||||
multiplier = (clockCtl1 & multiplier_mask) >> multiplier_shift;
|
||||
|
||||
if (clockCtl1 & doubler_mask) {
|
||||
multiplier = multiplier << 1;
|
||||
}
|
||||
return (40000000 / preDivisor) * multiplier;
|
||||
}
|
||||
|
||||
static inline int ar5312_sys_frequency(void)
|
||||
{
|
||||
return ar5312_cpu_frequency() / 4;
|
||||
}
|
||||
|
||||
static void __init ar5312_time_init(void)
|
||||
{
|
||||
mips_hpt_frequency = ar5312_cpu_frequency() / 2;
|
||||
}
|
||||
|
||||
|
||||
void __init ar5312_prom_init(void)
|
||||
{
|
||||
u32 memsize, memcfg, bank0AC, bank1AC;
|
||||
|
||||
is_5312 = 1;
|
||||
|
||||
/* Detect memory size */
|
||||
memcfg = sysRegRead(AR531X_MEM_CFG1);
|
||||
bank0AC = (memcfg & MEM_CFG1_AC0) >> MEM_CFG1_AC0_S;
|
||||
bank1AC = (memcfg & MEM_CFG1_AC1) >> MEM_CFG1_AC1_S;
|
||||
memsize = (bank0AC ? (1 << (bank0AC+1)) : 0)
|
||||
+ (bank1AC ? (1 << (bank1AC+1)) : 0);
|
||||
memsize <<= 20;
|
||||
add_memory_region(0, memsize, BOOT_MEM_RAM);
|
||||
|
||||
/* Initialize it to AR5312 for now. Real detection will be done
|
||||
* in ar5312_init_devices() */
|
||||
mips_machtype = MACH_ATHEROS_AR5312;
|
||||
}
|
||||
|
||||
void __init ar5312_plat_setup(void)
|
||||
{
|
||||
/* Clear any lingering AHB errors */
|
||||
sysRegRead(AR531X_PROCADDR);
|
||||
sysRegRead(AR531X_DMAADDR);
|
||||
sysRegWrite(AR531X_WD_CTRL, AR531X_WD_CTRL_IGNORE_EXPIRATION);
|
||||
|
||||
board_time_init = ar5312_time_init;
|
||||
|
||||
_machine_restart = ar5312_restart;
|
||||
_machine_halt = ar5312_halt;
|
||||
pm_power_off = ar5312_power_off;
|
||||
|
||||
serial_setup(KSEG1ADDR(AR531X_UART0), ar5312_sys_frequency());
|
||||
}
|
||||
|
||||
arch_initcall(ar5312_init_devices);
|
||||
174
target/linux/atheros/files-2.6.26/arch/mips/atheros/ar5312/irq.c
Normal file
174
target/linux/atheros/files-2.6.26/arch/mips/atheros/ar5312/irq.c
Normal file
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* 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) 2003 Atheros Communications, Inc., All Rights Reserved.
|
||||
* Copyright (C) 2006 FON Technology, SL.
|
||||
* Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
|
||||
* Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Platform devices for Atheros SoCs
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/time.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include <ar531x.h>
|
||||
#include <gpio.h>
|
||||
|
||||
/*
|
||||
* Called when an interrupt is received, this function
|
||||
* determines exactly which interrupt it was, and it
|
||||
* invokes the appropriate handler.
|
||||
*
|
||||
* Implicitly, we also define interrupt priority by
|
||||
* choosing which to dispatch first.
|
||||
*/
|
||||
asmlinkage void ar5312_irq_dispatch(void)
|
||||
{
|
||||
int pending = read_c0_status() & read_c0_cause();
|
||||
|
||||
if (pending & CAUSEF_IP2)
|
||||
do_IRQ(AR5312_IRQ_WLAN0_INTRS);
|
||||
else if (pending & CAUSEF_IP3)
|
||||
do_IRQ(AR5312_IRQ_ENET0_INTRS);
|
||||
else if (pending & CAUSEF_IP4)
|
||||
do_IRQ(AR5312_IRQ_ENET1_INTRS);
|
||||
else if (pending & CAUSEF_IP5)
|
||||
do_IRQ(AR5312_IRQ_WLAN1_INTRS);
|
||||
else if (pending & CAUSEF_IP6) {
|
||||
unsigned int ar531x_misc_intrs = sysRegRead(AR531X_ISR) & sysRegRead(AR531X_IMR);
|
||||
|
||||
if (ar531x_misc_intrs & AR531X_ISR_TIMER) {
|
||||
do_IRQ(AR531X_MISC_IRQ_TIMER);
|
||||
(void)sysRegRead(AR531X_TIMER);
|
||||
} else if (ar531x_misc_intrs & AR531X_ISR_AHBPROC)
|
||||
do_IRQ(AR531X_MISC_IRQ_AHB_PROC);
|
||||
else if ((ar531x_misc_intrs & AR531X_ISR_UART0))
|
||||
do_IRQ(AR531X_MISC_IRQ_UART0);
|
||||
else if (ar531x_misc_intrs & AR531X_ISR_WD)
|
||||
do_IRQ(AR531X_MISC_IRQ_WATCHDOG);
|
||||
else
|
||||
do_IRQ(AR531X_MISC_IRQ_NONE);
|
||||
} else if (pending & CAUSEF_IP7) {
|
||||
do_IRQ(AR531X_IRQ_CPU_CLOCK);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Enable the specified AR531X_MISC_IRQ interrupt */
|
||||
static void
|
||||
ar5312_misc_intr_enable(unsigned int irq)
|
||||
{
|
||||
unsigned int imr;
|
||||
|
||||
imr = sysRegRead(AR531X_IMR);
|
||||
imr |= (1 << (irq - AR531X_MISC_IRQ_BASE - 1));
|
||||
sysRegWrite(AR531X_IMR, imr);
|
||||
sysRegRead(AR531X_IMR); /* flush write buffer */
|
||||
}
|
||||
|
||||
/* Disable the specified AR531X_MISC_IRQ interrupt */
|
||||
static void
|
||||
ar5312_misc_intr_disable(unsigned int irq)
|
||||
{
|
||||
unsigned int imr;
|
||||
|
||||
imr = sysRegRead(AR531X_IMR);
|
||||
imr &= ~(1 << (irq - AR531X_MISC_IRQ_BASE - 1));
|
||||
sysRegWrite(AR531X_IMR, imr);
|
||||
sysRegRead(AR531X_IMR); /* flush write buffer */
|
||||
}
|
||||
|
||||
/* Turn on the specified AR531X_MISC_IRQ interrupt */
|
||||
static unsigned int
|
||||
ar5312_misc_intr_startup(unsigned int irq)
|
||||
{
|
||||
ar5312_misc_intr_enable(irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Turn off the specified AR531X_MISC_IRQ interrupt */
|
||||
static void
|
||||
ar5312_misc_intr_shutdown(unsigned int irq)
|
||||
{
|
||||
ar5312_misc_intr_disable(irq);
|
||||
}
|
||||
|
||||
static void
|
||||
ar5312_misc_intr_ack(unsigned int irq)
|
||||
{
|
||||
ar5312_misc_intr_disable(irq);
|
||||
}
|
||||
|
||||
static void
|
||||
ar5312_misc_intr_end(unsigned int irq)
|
||||
{
|
||||
if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
|
||||
ar5312_misc_intr_enable(irq);
|
||||
}
|
||||
|
||||
static struct irq_chip ar5312_misc_intr_controller = {
|
||||
.typename = "AR5312 misc",
|
||||
.startup = ar5312_misc_intr_startup,
|
||||
.shutdown = ar5312_misc_intr_shutdown,
|
||||
.enable = ar5312_misc_intr_enable,
|
||||
.disable = ar5312_misc_intr_disable,
|
||||
.ack = ar5312_misc_intr_ack,
|
||||
.end = ar5312_misc_intr_end,
|
||||
};
|
||||
|
||||
static irqreturn_t ar5312_ahb_proc_handler(int cpl, void *dev_id)
|
||||
{
|
||||
u32 proc1 = sysRegRead(AR531X_PROC1);
|
||||
u32 procAddr = sysRegRead(AR531X_PROCADDR); /* clears error state */
|
||||
u32 dma1 = sysRegRead(AR531X_DMA1);
|
||||
u32 dmaAddr = sysRegRead(AR531X_DMAADDR); /* clears error state */
|
||||
|
||||
printk("AHB interrupt: PROCADDR=0x%8.8x PROC1=0x%8.8x DMAADDR=0x%8.8x DMA1=0x%8.8x\n",
|
||||
procAddr, proc1, dmaAddr, dma1);
|
||||
|
||||
machine_restart("AHB error"); /* Catastrophic failure */
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
static struct irqaction ar5312_ahb_proc_interrupt = {
|
||||
.handler = ar5312_ahb_proc_handler,
|
||||
.flags = IRQF_DISABLED,
|
||||
.name = "ar5312_ahb_proc_interrupt",
|
||||
};
|
||||
|
||||
|
||||
static struct irqaction cascade = {
|
||||
.handler = no_action,
|
||||
.flags = IRQF_DISABLED,
|
||||
.name = "cascade",
|
||||
};
|
||||
|
||||
void __init ar5312_misc_intr_init(int irq_base)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = irq_base; i < irq_base + AR531X_MISC_IRQ_COUNT; i++) {
|
||||
irq_desc[i].status = IRQ_DISABLED;
|
||||
irq_desc[i].action = NULL;
|
||||
irq_desc[i].depth = 1;
|
||||
irq_desc[i].chip = &ar5312_misc_intr_controller;
|
||||
}
|
||||
setup_irq(AR531X_MISC_IRQ_AHB_PROC, &ar5312_ahb_proc_interrupt);
|
||||
setup_irq(AR5312_IRQ_MISC_INTRS, &cascade);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#
|
||||
# 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) 2007 FON Technology, SL.
|
||||
# Copyright (C) 2007 Imre Kaloz <kaloz@openwrt.org>
|
||||
# Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
|
||||
#
|
||||
|
||||
obj-y := board.o irq.o
|
||||
obj-$(CONFIG_ATHEROS_AR5315_PCI) += pci.o
|
||||
@@ -0,0 +1,414 @@
|
||||
/*
|
||||
* 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) 2003 Atheros Communications, Inc., All Rights Reserved.
|
||||
* Copyright (C) 2006 FON Technology, SL.
|
||||
* Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
|
||||
* Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Platform devices for Atheros SoCs
|
||||
*/
|
||||
|
||||
#include <linux/autoconf.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/delay.h>
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/reboot.h>
|
||||
#include <asm/time.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/io.h>
|
||||
#include <ar531x.h>
|
||||
#include <linux/leds.h>
|
||||
#include <asm/gpio.h>
|
||||
|
||||
static int is_5315 = 0;
|
||||
|
||||
static struct resource ar5315_eth_res[] = {
|
||||
{
|
||||
.name = "eth0_membase",
|
||||
.flags = IORESOURCE_MEM,
|
||||
.start = AR5315_ENET0,
|
||||
.end = AR5315_ENET0 + 0x2000,
|
||||
},
|
||||
{
|
||||
.name = "eth0_irq",
|
||||
.flags = IORESOURCE_IRQ,
|
||||
.start = AR5315_IRQ_ENET0_INTRS,
|
||||
.end = AR5315_IRQ_ENET0_INTRS,
|
||||
},
|
||||
};
|
||||
|
||||
static struct ar531x_eth ar5315_eth_data = {
|
||||
.phy = 1,
|
||||
.mac = 0,
|
||||
.reset_base = AR5315_RESET,
|
||||
.reset_mac = AR5315_RESET_ENET0,
|
||||
.reset_phy = AR5315_RESET_EPHY0,
|
||||
.phy_base = AR5315_ENET0
|
||||
};
|
||||
|
||||
static struct platform_device ar5315_eth = {
|
||||
.id = 0,
|
||||
.name = "ar531x-eth",
|
||||
.dev.platform_data = &ar5315_eth_data,
|
||||
.resource = ar5315_eth_res,
|
||||
.num_resources = ARRAY_SIZE(ar5315_eth_res)
|
||||
};
|
||||
|
||||
static struct platform_device ar5315_wmac = {
|
||||
.id = 0,
|
||||
.name = "ar531x-wmac",
|
||||
/* FIXME: add resources */
|
||||
};
|
||||
|
||||
static struct resource ar5315_spiflash_res[] = {
|
||||
{
|
||||
.name = "flash_base",
|
||||
.flags = IORESOURCE_MEM,
|
||||
.start = KSEG1ADDR(AR5315_SPI_READ),
|
||||
.end = KSEG1ADDR(AR5315_SPI_READ) + 0x800000,
|
||||
},
|
||||
{
|
||||
.name = "flash_regs",
|
||||
.flags = IORESOURCE_MEM,
|
||||
.start = 0x11300000,
|
||||
.end = 0x11300012,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device ar5315_spiflash = {
|
||||
.id = 0,
|
||||
.name = "spiflash",
|
||||
.resource = ar5315_spiflash_res,
|
||||
.num_resources = ARRAY_SIZE(ar5315_spiflash_res)
|
||||
};
|
||||
|
||||
#ifdef CONFIG_LEDS_GPIO
|
||||
static struct gpio_led ar5315_leds[8];
|
||||
|
||||
static struct gpio_led_platform_data ar5315_led_data = {
|
||||
.num_leds = ARRAY_SIZE(ar5315_leds),
|
||||
.leds = (void *) ar5315_leds,
|
||||
};
|
||||
|
||||
static struct platform_device ar5315_gpio_leds = {
|
||||
.name = "leds-gpio",
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.platform_data = (void *) &ar5315_led_data,
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct platform_device ar5315_wdt =
|
||||
{
|
||||
.id = 0,
|
||||
.name = "ar2315_wdt",
|
||||
};
|
||||
|
||||
static __initdata struct platform_device *ar5315_devs[6];
|
||||
|
||||
static void *flash_regs;
|
||||
|
||||
static inline __u32 spiflash_regread32(int reg)
|
||||
{
|
||||
volatile __u32 *data = (__u32 *)(flash_regs + reg);
|
||||
|
||||
return (*data);
|
||||
}
|
||||
|
||||
static inline void spiflash_regwrite32(int reg, __u32 data)
|
||||
{
|
||||
volatile __u32 *addr = (__u32 *)(flash_regs + reg);
|
||||
|
||||
*addr = data;
|
||||
}
|
||||
|
||||
#define SPI_FLASH_CTL 0x00
|
||||
#define SPI_FLASH_OPCODE 0x04
|
||||
#define SPI_FLASH_DATA 0x08
|
||||
|
||||
static __u8 spiflash_probe(void)
|
||||
{
|
||||
__u32 reg;
|
||||
|
||||
do {
|
||||
reg = spiflash_regread32(SPI_FLASH_CTL);
|
||||
} while (reg & SPI_CTL_BUSY);
|
||||
|
||||
spiflash_regwrite32(SPI_FLASH_OPCODE, 0xab);
|
||||
|
||||
reg = (reg & ~SPI_CTL_TX_RX_CNT_MASK) | 4 |
|
||||
(1 << 4) | SPI_CTL_START;
|
||||
|
||||
spiflash_regwrite32(SPI_FLASH_CTL, reg);
|
||||
|
||||
do {
|
||||
reg = spiflash_regread32(SPI_FLASH_CTL);
|
||||
} while (reg & SPI_CTL_BUSY);
|
||||
|
||||
reg = (__u32) spiflash_regread32(SPI_FLASH_DATA);
|
||||
reg &= 0xff;
|
||||
|
||||
return (u8) reg;
|
||||
}
|
||||
|
||||
|
||||
#define STM_8MBIT_SIGNATURE 0x13
|
||||
#define STM_16MBIT_SIGNATURE 0x14
|
||||
#define STM_32MBIT_SIGNATURE 0x15
|
||||
#define STM_64MBIT_SIGNATURE 0x16
|
||||
#define STM_128MBIT_SIGNATURE 0x17
|
||||
|
||||
|
||||
static char __init *ar5315_flash_limit(void)
|
||||
{
|
||||
u8 sig;
|
||||
u32 flash_size = 0;
|
||||
|
||||
/* probe the flash chip size */
|
||||
flash_regs = ioremap_nocache(ar5315_spiflash_res[1].start, ar5315_spiflash_res[1].end - ar5315_spiflash_res[1].start);
|
||||
sig = spiflash_probe();
|
||||
iounmap(flash_regs);
|
||||
|
||||
switch(sig) {
|
||||
case STM_8MBIT_SIGNATURE:
|
||||
flash_size = 0x00100000;
|
||||
break;
|
||||
case STM_16MBIT_SIGNATURE:
|
||||
flash_size = 0x00200000;
|
||||
break;
|
||||
case STM_32MBIT_SIGNATURE:
|
||||
flash_size = 0x00400000;
|
||||
break;
|
||||
case STM_64MBIT_SIGNATURE:
|
||||
flash_size = 0x00800000;
|
||||
break;
|
||||
case STM_128MBIT_SIGNATURE:
|
||||
flash_size = 0x01000000;
|
||||
break;
|
||||
}
|
||||
|
||||
ar5315_spiflash_res[0].end = ar5315_spiflash_res[0].start + flash_size;
|
||||
return (char *) ar5315_spiflash_res[0].end;
|
||||
}
|
||||
|
||||
int __init ar5315_init_devices(void)
|
||||
{
|
||||
struct ar531x_config *config;
|
||||
struct ar531x_boarddata *bcfg;
|
||||
int dev = 0;
|
||||
#ifdef CONFIG_LEDS_GPIO
|
||||
int i;
|
||||
char *tmp;
|
||||
#endif
|
||||
|
||||
if (!is_5315)
|
||||
return 0;
|
||||
|
||||
/* Find board configuration */
|
||||
ar531x_find_config(ar5315_flash_limit());
|
||||
bcfg = (struct ar531x_boarddata *) board_config;
|
||||
|
||||
config = (struct ar531x_config *) kzalloc(sizeof(struct ar531x_config), GFP_KERNEL);
|
||||
config->board = board_config;
|
||||
config->radio = radio_config;
|
||||
config->unit = 0;
|
||||
config->tag = (u_int16_t) (sysRegRead(AR5315_SREV) & AR5315_REV_CHIP);
|
||||
|
||||
ar5315_eth_data.board_config = board_config;
|
||||
ar5315_eth_data.macaddr = bcfg->enet0Mac;
|
||||
ar5315_wmac.dev.platform_data = config;
|
||||
|
||||
ar5315_devs[dev++] = &ar5315_eth;
|
||||
ar5315_devs[dev++] = &ar5315_wmac;
|
||||
ar5315_devs[dev++] = &ar5315_spiflash;
|
||||
ar5315_devs[dev++] = &ar5315_wdt;
|
||||
|
||||
#ifdef CONFIG_LEDS_GPIO
|
||||
ar5315_led_data.num_leds = 0;
|
||||
for(i = 1; i < 8; i++)
|
||||
{
|
||||
if((i != AR5315_RESET_GPIO) && (i != bcfg->resetConfigGpio))
|
||||
{
|
||||
if(i == bcfg->sysLedGpio)
|
||||
{
|
||||
tmp = kstrdup("wlan", GFP_KERNEL);
|
||||
} else {
|
||||
tmp = kmalloc(6, GFP_KERNEL);
|
||||
if(tmp)
|
||||
sprintf((char*)tmp, "gpio%d", i);
|
||||
}
|
||||
if(tmp)
|
||||
{
|
||||
ar5315_leds[ar5315_led_data.num_leds].name = tmp;
|
||||
ar5315_leds[ar5315_led_data.num_leds].gpio = i;
|
||||
ar5315_leds[ar5315_led_data.num_leds].active_low = 0;
|
||||
ar5315_led_data.num_leds++;
|
||||
} else {
|
||||
printk("failed to alloc led string\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
ar5315_devs[dev++] = &ar5315_gpio_leds;
|
||||
#endif
|
||||
|
||||
return platform_add_devices(ar5315_devs, dev);
|
||||
}
|
||||
|
||||
static void ar5315_halt(void)
|
||||
{
|
||||
while (1);
|
||||
}
|
||||
|
||||
static void ar5315_power_off(void)
|
||||
{
|
||||
ar5315_halt();
|
||||
}
|
||||
|
||||
|
||||
static void ar5315_restart(char *command)
|
||||
{
|
||||
void (*mips_reset_vec)(void) = (void *) 0xbfc00000;
|
||||
|
||||
/* reset the system */
|
||||
sysRegWrite(AR5315_COLD_RESET,AR5317_RESET_SYSTEM);
|
||||
|
||||
/* Cold reset does not work on the AR2315/6, use the GPIO reset bits a workaround.
|
||||
* give it some time to attempt a gpio based hardware reset
|
||||
* (atheros reference design workaround) */
|
||||
gpio_direction_output(AR5315_RESET_GPIO, 0);
|
||||
mdelay(100);
|
||||
|
||||
/* Some boards (e.g. Senao EOC-2610) don't implement the reset logic
|
||||
* workaround. Attempt to jump to the mips reset location -
|
||||
* the boot loader itself might be able to recover the system */
|
||||
mips_reset_vec();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This table is indexed by bits 5..4 of the CLOCKCTL1 register
|
||||
* to determine the predevisor value.
|
||||
*/
|
||||
static int __initdata CLOCKCTL1_PREDIVIDE_TABLE[4] = {
|
||||
1,
|
||||
2,
|
||||
4,
|
||||
5
|
||||
};
|
||||
|
||||
static int __initdata PLLC_DIVIDE_TABLE[5] = {
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
6,
|
||||
3
|
||||
};
|
||||
|
||||
static unsigned int __init
|
||||
ar5315_sys_clk(unsigned int clockCtl)
|
||||
{
|
||||
unsigned int pllcCtrl,cpuDiv;
|
||||
unsigned int pllcOut,refdiv,fdiv,divby2;
|
||||
unsigned int clkDiv;
|
||||
|
||||
pllcCtrl = sysRegRead(AR5315_PLLC_CTL);
|
||||
refdiv = (pllcCtrl & PLLC_REF_DIV_M) >> PLLC_REF_DIV_S;
|
||||
refdiv = CLOCKCTL1_PREDIVIDE_TABLE[refdiv];
|
||||
fdiv = (pllcCtrl & PLLC_FDBACK_DIV_M) >> PLLC_FDBACK_DIV_S;
|
||||
divby2 = (pllcCtrl & PLLC_ADD_FDBACK_DIV_M) >> PLLC_ADD_FDBACK_DIV_S;
|
||||
divby2 += 1;
|
||||
pllcOut = (40000000/refdiv)*(2*divby2)*fdiv;
|
||||
|
||||
|
||||
/* clkm input selected */
|
||||
switch(clockCtl & CPUCLK_CLK_SEL_M) {
|
||||
case 0:
|
||||
case 1:
|
||||
clkDiv = PLLC_DIVIDE_TABLE[(pllcCtrl & PLLC_CLKM_DIV_M) >> PLLC_CLKM_DIV_S];
|
||||
break;
|
||||
case 2:
|
||||
clkDiv = PLLC_DIVIDE_TABLE[(pllcCtrl & PLLC_CLKC_DIV_M) >> PLLC_CLKC_DIV_S];
|
||||
break;
|
||||
default:
|
||||
pllcOut = 40000000;
|
||||
clkDiv = 1;
|
||||
break;
|
||||
}
|
||||
cpuDiv = (clockCtl & CPUCLK_CLK_DIV_M) >> CPUCLK_CLK_DIV_S;
|
||||
cpuDiv = cpuDiv * 2 ?: 1;
|
||||
return (pllcOut/(clkDiv * cpuDiv));
|
||||
}
|
||||
|
||||
static inline unsigned int ar5315_cpu_frequency(void)
|
||||
{
|
||||
return ar5315_sys_clk(sysRegRead(AR5315_CPUCLK));
|
||||
}
|
||||
|
||||
static inline unsigned int ar5315_apb_frequency(void)
|
||||
{
|
||||
return ar5315_sys_clk(sysRegRead(AR5315_AMBACLK));
|
||||
}
|
||||
|
||||
static void __init ar5315_time_init(void)
|
||||
{
|
||||
mips_hpt_frequency = ar5315_cpu_frequency() / 2;
|
||||
}
|
||||
|
||||
void __init ar5315_prom_init(void)
|
||||
{
|
||||
u32 memsize, memcfg, devid;
|
||||
|
||||
is_5315 = 1;
|
||||
memcfg = sysRegRead(AR5315_MEM_CFG);
|
||||
memsize = 1 + ((memcfg & SDRAM_DATA_WIDTH_M) >> SDRAM_DATA_WIDTH_S);
|
||||
memsize <<= 1 + ((memcfg & SDRAM_COL_WIDTH_M) >> SDRAM_COL_WIDTH_S);
|
||||
memsize <<= 1 + ((memcfg & SDRAM_ROW_WIDTH_M) >> SDRAM_ROW_WIDTH_S);
|
||||
memsize <<= 3;
|
||||
add_memory_region(0, memsize, BOOT_MEM_RAM);
|
||||
|
||||
/* Detect the hardware based on the device ID */
|
||||
devid = sysRegRead(AR5315_SREV) & AR5315_REV_CHIP;
|
||||
switch(devid) {
|
||||
case 0x90:
|
||||
case 0x91:
|
||||
mips_machtype = MACH_ATHEROS_AR2317;
|
||||
break;
|
||||
default:
|
||||
mips_machtype = MACH_ATHEROS_AR2315;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void __init ar5315_plat_setup(void)
|
||||
{
|
||||
unsigned int config = read_c0_config();
|
||||
|
||||
/* Clear any lingering AHB errors */
|
||||
write_c0_config(config & ~0x3);
|
||||
sysRegWrite(AR5315_AHB_ERR0,AHB_ERROR_DET);
|
||||
sysRegRead(AR5315_AHB_ERR1);
|
||||
sysRegWrite(AR5315_WDC, WDC_IGNORE_EXPIRATION);
|
||||
|
||||
board_time_init = ar5315_time_init;
|
||||
|
||||
_machine_restart = ar5315_restart;
|
||||
_machine_halt = ar5315_halt;
|
||||
pm_power_off = ar5315_power_off;
|
||||
|
||||
serial_setup(KSEG1ADDR(AR5315_UART0), ar5315_apb_frequency());
|
||||
}
|
||||
|
||||
arch_initcall(ar5315_init_devices);
|
||||
359
target/linux/atheros/files-2.6.26/arch/mips/atheros/ar5315/irq.c
Normal file
359
target/linux/atheros/files-2.6.26/arch/mips/atheros/ar5315/irq.c
Normal file
@@ -0,0 +1,359 @@
|
||||
/*
|
||||
* 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) 2003 Atheros Communications, Inc., All Rights Reserved.
|
||||
* Copyright (C) 2006 FON Technology, SL.
|
||||
* Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
|
||||
* Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Platform devices for Atheros SoCs
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/irq_cpu.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include <ar531x.h>
|
||||
#include <gpio.h>
|
||||
|
||||
static u32 gpiointmask = 0, gpiointval = 0;
|
||||
|
||||
static inline void ar5315_gpio_irq(void)
|
||||
{
|
||||
u32 pend;
|
||||
sysRegWrite(AR5315_ISR, sysRegRead(AR5315_IMR) | ~AR5315_ISR_GPIO);
|
||||
|
||||
/* only do one gpio interrupt at a time */
|
||||
pend = (sysRegRead(AR5315_GPIO_DI) ^ gpiointval) & gpiointmask;
|
||||
if (!pend)
|
||||
return;
|
||||
|
||||
do_IRQ(AR531X_GPIO_IRQ_BASE + fls(pend) - 1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Called when an interrupt is received, this function
|
||||
* determines exactly which interrupt it was, and it
|
||||
* invokes the appropriate handler.
|
||||
*
|
||||
* Implicitly, we also define interrupt priority by
|
||||
* choosing which to dispatch first.
|
||||
*/
|
||||
asmlinkage void ar5315_irq_dispatch(void)
|
||||
{
|
||||
int pending = read_c0_status() & read_c0_cause();
|
||||
|
||||
if (pending & CAUSEF_IP3)
|
||||
do_IRQ(AR5315_IRQ_WLAN0_INTRS);
|
||||
else if (pending & CAUSEF_IP4)
|
||||
do_IRQ(AR5315_IRQ_ENET0_INTRS);
|
||||
#ifdef CONFIG_PCI
|
||||
else if (pending & CAUSEF_IP5)
|
||||
ar5315_pci_irq(AR5315_IRQ_LCBUS_PCI);
|
||||
#endif
|
||||
else if (pending & CAUSEF_IP2) {
|
||||
unsigned int ar531x_misc_intrs = sysRegRead(AR5315_ISR) & sysRegRead(AR5315_IMR);
|
||||
|
||||
if (ar531x_misc_intrs & AR5315_ISR_SPI)
|
||||
do_IRQ(AR531X_MISC_IRQ_SPI);
|
||||
else if (ar531x_misc_intrs & AR5315_ISR_TIMER)
|
||||
do_IRQ(AR531X_MISC_IRQ_TIMER);
|
||||
else if (ar531x_misc_intrs & AR5315_ISR_AHB)
|
||||
do_IRQ(AR531X_MISC_IRQ_AHB_PROC);
|
||||
else if (ar531x_misc_intrs & AR5315_ISR_GPIO)
|
||||
ar5315_gpio_irq();
|
||||
else if (ar531x_misc_intrs & AR5315_ISR_UART0)
|
||||
do_IRQ(AR531X_MISC_IRQ_UART0);
|
||||
else if (ar531x_misc_intrs & AR5315_ISR_WD)
|
||||
do_IRQ(AR531X_MISC_IRQ_WATCHDOG);
|
||||
else
|
||||
do_IRQ(AR531X_MISC_IRQ_NONE);
|
||||
} else if (pending & CAUSEF_IP7)
|
||||
do_IRQ(AR531X_IRQ_CPU_CLOCK);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
static inline void pci_abort_irq(void)
|
||||
{
|
||||
sysRegWrite(AR5315_PCI_INT_STATUS, AR5315_PCI_ABORT_INT);
|
||||
(void)sysRegRead(AR5315_PCI_INT_STATUS); /* flush write to hardware */
|
||||
}
|
||||
|
||||
static inline void pci_ack_irq(void)
|
||||
{
|
||||
sysRegWrite(AR5315_PCI_INT_STATUS, AR5315_PCI_EXT_INT);
|
||||
(void)sysRegRead(AR5315_PCI_INT_STATUS); /* flush write to hardware */
|
||||
}
|
||||
|
||||
void ar5315_pci_irq(int irq)
|
||||
{
|
||||
if (sysRegRead(AR5315_PCI_INT_STATUS) == AR5315_PCI_ABORT_INT)
|
||||
pci_abort_irq();
|
||||
else {
|
||||
do_IRQ(irq);
|
||||
pci_ack_irq();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void ar5315_gpio_intr_enable(unsigned int irq)
|
||||
{
|
||||
u32 gpio, mask;
|
||||
gpio = irq - AR531X_GPIO_IRQ_BASE;
|
||||
mask = 1 << gpio;
|
||||
gpiointmask |= mask;
|
||||
|
||||
/* reconfigure GPIO line as input */
|
||||
sysRegMask(AR5315_GPIO_CR, AR5315_GPIO_CR_M(gpio), AR5315_GPIO_CR_I(gpio));
|
||||
|
||||
/* Enable interrupt with edge detection */
|
||||
sysRegMask(AR5315_GPIO_INT, AR5315_GPIO_INT_M | AR5315_GPIO_INT_LVL_M, gpio | AR5315_GPIO_INT_LVL(3));
|
||||
}
|
||||
|
||||
static void ar5315_gpio_intr_disable(unsigned int irq)
|
||||
{
|
||||
u32 gpio, mask;
|
||||
gpio = irq - AR531X_GPIO_IRQ_BASE;
|
||||
mask = 1 << gpio;
|
||||
|
||||
gpiointmask &= ~mask;
|
||||
|
||||
/* Disable interrupt with edge detection */
|
||||
sysRegMask(AR5315_GPIO_INT, AR5315_GPIO_INT_M | AR5315_GPIO_INT_LVL_M, gpio | AR5315_GPIO_INT_LVL(0));
|
||||
}
|
||||
|
||||
/* Turn on the specified AR531X_MISC_IRQ interrupt */
|
||||
static unsigned int ar5315_gpio_intr_startup(unsigned int irq)
|
||||
{
|
||||
ar5315_gpio_intr_enable(irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Turn off the specified AR531X_MISC_IRQ interrupt */
|
||||
static void
|
||||
ar5315_gpio_intr_shutdown(unsigned int irq)
|
||||
{
|
||||
ar5315_gpio_intr_disable(irq);
|
||||
}
|
||||
|
||||
static void
|
||||
ar5315_gpio_intr_ack(unsigned int irq)
|
||||
{
|
||||
ar5315_gpio_intr_disable(irq);
|
||||
}
|
||||
|
||||
static void
|
||||
ar5315_gpio_intr_end(unsigned int irq)
|
||||
{
|
||||
if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
|
||||
ar5315_gpio_intr_enable(irq);
|
||||
}
|
||||
|
||||
static struct irq_chip ar5315_gpio_intr_controller = {
|
||||
.typename = "AR5315 GPIO",
|
||||
.startup = ar5315_gpio_intr_startup,
|
||||
.shutdown = ar5315_gpio_intr_shutdown,
|
||||
.enable = ar5315_gpio_intr_enable,
|
||||
.disable = ar5315_gpio_intr_disable,
|
||||
.ack = ar5315_gpio_intr_ack,
|
||||
.end = ar5315_gpio_intr_end,
|
||||
};
|
||||
|
||||
|
||||
/* Enable the specified AR531X_MISC_IRQ interrupt */
|
||||
static void
|
||||
ar5315_misc_intr_enable(unsigned int irq)
|
||||
{
|
||||
unsigned int imr;
|
||||
|
||||
imr = sysRegRead(AR5315_IMR);
|
||||
switch(irq)
|
||||
{
|
||||
case AR531X_MISC_IRQ_SPI:
|
||||
imr |= AR5315_ISR_SPI;
|
||||
break;
|
||||
|
||||
case AR531X_MISC_IRQ_TIMER:
|
||||
imr |= AR5315_ISR_TIMER;
|
||||
break;
|
||||
|
||||
case AR531X_MISC_IRQ_AHB_PROC:
|
||||
imr |= AR5315_ISR_AHB;
|
||||
break;
|
||||
|
||||
case AR531X_MISC_IRQ_AHB_DMA:
|
||||
imr |= 0/* ?? */;
|
||||
break;
|
||||
|
||||
case AR531X_MISC_IRQ_GPIO:
|
||||
imr |= AR5315_ISR_GPIO;
|
||||
break;
|
||||
|
||||
case AR531X_MISC_IRQ_UART0:
|
||||
imr |= AR5315_ISR_UART0;
|
||||
break;
|
||||
|
||||
|
||||
case AR531X_MISC_IRQ_WATCHDOG:
|
||||
imr |= AR5315_ISR_WD;
|
||||
break;
|
||||
|
||||
case AR531X_MISC_IRQ_LOCAL:
|
||||
imr |= 0/* ?? */;
|
||||
break;
|
||||
|
||||
}
|
||||
sysRegWrite(AR5315_IMR, imr);
|
||||
imr=sysRegRead(AR5315_IMR); /* flush write buffer */
|
||||
}
|
||||
|
||||
/* Disable the specified AR531X_MISC_IRQ interrupt */
|
||||
static void
|
||||
ar5315_misc_intr_disable(unsigned int irq)
|
||||
{
|
||||
unsigned int imr;
|
||||
|
||||
imr = sysRegRead(AR5315_IMR);
|
||||
switch(irq)
|
||||
{
|
||||
case AR531X_MISC_IRQ_SPI:
|
||||
imr &= ~AR5315_ISR_SPI;
|
||||
break;
|
||||
|
||||
case AR531X_MISC_IRQ_TIMER:
|
||||
imr &= (~AR5315_ISR_TIMER);
|
||||
break;
|
||||
|
||||
case AR531X_MISC_IRQ_AHB_PROC:
|
||||
imr &= (~AR5315_ISR_AHB);
|
||||
break;
|
||||
|
||||
case AR531X_MISC_IRQ_AHB_DMA:
|
||||
imr &= 0/* ?? */;
|
||||
break;
|
||||
|
||||
case AR531X_MISC_IRQ_GPIO:
|
||||
imr &= ~AR5315_ISR_GPIO;
|
||||
break;
|
||||
|
||||
case AR531X_MISC_IRQ_UART0:
|
||||
imr &= (~AR5315_ISR_UART0);
|
||||
break;
|
||||
|
||||
case AR531X_MISC_IRQ_WATCHDOG:
|
||||
imr &= (~AR5315_ISR_WD);
|
||||
break;
|
||||
|
||||
case AR531X_MISC_IRQ_LOCAL:
|
||||
imr &= ~0/* ?? */;
|
||||
break;
|
||||
|
||||
}
|
||||
sysRegWrite(AR5315_IMR, imr);
|
||||
sysRegRead(AR5315_IMR); /* flush write buffer */
|
||||
}
|
||||
|
||||
/* Turn on the specified AR531X_MISC_IRQ interrupt */
|
||||
static unsigned int
|
||||
ar5315_misc_intr_startup(unsigned int irq)
|
||||
{
|
||||
ar5315_misc_intr_enable(irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Turn off the specified AR531X_MISC_IRQ interrupt */
|
||||
static void
|
||||
ar5315_misc_intr_shutdown(unsigned int irq)
|
||||
{
|
||||
ar5315_misc_intr_disable(irq);
|
||||
}
|
||||
|
||||
static void
|
||||
ar5315_misc_intr_ack(unsigned int irq)
|
||||
{
|
||||
ar5315_misc_intr_disable(irq);
|
||||
}
|
||||
|
||||
static void
|
||||
ar5315_misc_intr_end(unsigned int irq)
|
||||
{
|
||||
if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
|
||||
ar5315_misc_intr_enable(irq);
|
||||
}
|
||||
|
||||
static struct irq_chip ar5315_misc_intr_controller = {
|
||||
.typename = "AR5315 misc",
|
||||
.startup = ar5315_misc_intr_startup,
|
||||
.shutdown = ar5315_misc_intr_shutdown,
|
||||
.enable = ar5315_misc_intr_enable,
|
||||
.disable = ar5315_misc_intr_disable,
|
||||
.ack = ar5315_misc_intr_ack,
|
||||
.end = ar5315_misc_intr_end,
|
||||
};
|
||||
|
||||
static irqreturn_t ar5315_ahb_proc_handler(int cpl, void *dev_id)
|
||||
{
|
||||
sysRegWrite(AR5315_AHB_ERR0,AHB_ERROR_DET);
|
||||
sysRegRead(AR5315_AHB_ERR1);
|
||||
|
||||
printk("AHB fatal error\n");
|
||||
machine_restart("AHB error"); /* Catastrophic failure */
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static struct irqaction ar5315_ahb_proc_interrupt = {
|
||||
.handler = ar5315_ahb_proc_handler,
|
||||
.flags = IRQF_DISABLED,
|
||||
.name = "ar5315_ahb_proc_interrupt",
|
||||
};
|
||||
|
||||
|
||||
static struct irqaction cascade = {
|
||||
.handler = no_action,
|
||||
.flags = IRQF_DISABLED,
|
||||
.name = "cascade",
|
||||
};
|
||||
|
||||
static void ar5315_gpio_intr_init(int irq_base)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = irq_base; i < irq_base + AR531X_GPIO_IRQ_COUNT; i++) {
|
||||
irq_desc[i].status = IRQ_DISABLED;
|
||||
irq_desc[i].action = NULL;
|
||||
irq_desc[i].depth = 1;
|
||||
irq_desc[i].chip = &ar5315_gpio_intr_controller;
|
||||
}
|
||||
setup_irq(AR531X_MISC_IRQ_GPIO, &cascade);
|
||||
gpiointval = sysRegRead(AR5315_GPIO_DI);
|
||||
}
|
||||
|
||||
void ar5315_misc_intr_init(int irq_base)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = irq_base; i < irq_base + AR531X_MISC_IRQ_COUNT; i++) {
|
||||
irq_desc[i].status = IRQ_DISABLED;
|
||||
irq_desc[i].action = NULL;
|
||||
irq_desc[i].depth = 1;
|
||||
irq_desc[i].chip = &ar5315_misc_intr_controller;
|
||||
}
|
||||
setup_irq(AR531X_MISC_IRQ_AHB_PROC, &ar5315_ahb_proc_interrupt);
|
||||
setup_irq(AR5315_IRQ_MISC_INTRS, &cascade);
|
||||
ar5315_gpio_intr_init(AR531X_GPIO_IRQ_BASE);
|
||||
}
|
||||
|
||||
265
target/linux/atheros/files-2.6.26/arch/mips/atheros/ar5315/pci.c
Normal file
265
target/linux/atheros/files-2.6.26/arch/mips/atheros/ar5315/pci.c
Normal file
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/irq.h>
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/paccess.h>
|
||||
#include <asm/irq_cpu.h>
|
||||
#include <asm/io.h>
|
||||
#include "ar531x.h"
|
||||
|
||||
#define AR531X_MEM_BASE 0x80800000UL
|
||||
#define AR531X_MEM_SIZE 0x00ffffffUL
|
||||
#define AR531X_IO_SIZE 0x00007fffUL
|
||||
#define IDSEL_SHIFT 13
|
||||
|
||||
static spinlock_t ar531x_pci_lock = SPIN_LOCK_UNLOCKED;
|
||||
static u32 cfgaddr;
|
||||
|
||||
static int config_access(int busno, int dev, int func, int where, int size, u32 ptr, int write)
|
||||
{
|
||||
u32 address; /* Address to read from */
|
||||
u32 reg;
|
||||
unsigned long flags;
|
||||
int ret = -1;
|
||||
if ((busno != 0) || ((dev != 0) && (dev != 3)) || (func > 2))
|
||||
return ret;
|
||||
|
||||
spin_lock_irqsave(&ar531x_pci_lock, flags);
|
||||
|
||||
/* Select Configuration access */
|
||||
reg = sysRegRead(AR5315_PCI_MISC_CONFIG);
|
||||
reg |= AR5315_PCIMISC_CFG_SEL;
|
||||
sysRegWrite(AR5315_PCI_MISC_CONFIG, reg);
|
||||
(void)sysRegRead(AR5315_PCI_MISC_CONFIG);
|
||||
|
||||
address = (u32)cfgaddr + (1 << (IDSEL_SHIFT + dev)) + (func << 8) + where;
|
||||
|
||||
if (size == 1)
|
||||
address ^= 0x3;
|
||||
else if (size == 2)
|
||||
address ^= 0x2;
|
||||
|
||||
if (write) {
|
||||
if (size == 1)
|
||||
ret = put_dbe(ptr, (u8 *) address);
|
||||
else if (size == 2)
|
||||
ret = put_dbe(ptr, (u16 *) address);
|
||||
else if (size == 4)
|
||||
ret = put_dbe(ptr, (u32 *) address);
|
||||
} else {
|
||||
if (size == 1)
|
||||
ret = get_dbe(*((u32 *)ptr), (u8 *) address);
|
||||
else if (size == 2)
|
||||
ret = get_dbe(*((u32 *)ptr), (u16 *) address);
|
||||
else if (size == 4)
|
||||
ret = get_dbe(*((u32 *)ptr), (u32 *) address);
|
||||
}
|
||||
|
||||
/* Select Memory access */
|
||||
reg = sysRegRead(AR5315_PCI_MISC_CONFIG);
|
||||
reg &= ~AR5315_PCIMISC_CFG_SEL;
|
||||
sysRegWrite(AR5315_PCI_MISC_CONFIG, reg);
|
||||
(void)sysRegRead(AR5315_PCI_MISC_CONFIG);
|
||||
|
||||
spin_unlock_irqrestore(&ar531x_pci_lock, flags);
|
||||
|
||||
if (ret) {
|
||||
*((u32 *)ptr) = 0xffffffff;
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
}
|
||||
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
static int ar531x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 * value)
|
||||
{
|
||||
return config_access(bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, (u32) value, 0);
|
||||
}
|
||||
|
||||
static int ar531x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value)
|
||||
{
|
||||
return config_access(bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, value, 1);
|
||||
}
|
||||
|
||||
struct pci_ops ar531x_pci_ops = {
|
||||
.read = ar531x_pci_read,
|
||||
.write = ar531x_pci_write,
|
||||
};
|
||||
|
||||
static struct resource ar531x_mem_resource = {
|
||||
.name = "AR531x PCI MEM",
|
||||
.start = AR531X_MEM_BASE,
|
||||
.end = AR531X_MEM_BASE + AR531X_MEM_SIZE - AR531X_IO_SIZE - 1 + 0x4000000,
|
||||
.flags = IORESOURCE_MEM,
|
||||
};
|
||||
|
||||
static struct resource ar531x_io_resource = {
|
||||
.name = "AR531x PCI I/O",
|
||||
.start = AR531X_MEM_BASE + AR531X_MEM_SIZE - AR531X_IO_SIZE,
|
||||
.end = AR531X_MEM_BASE + AR531X_MEM_SIZE - 1,
|
||||
.flags = IORESOURCE_IO,
|
||||
};
|
||||
|
||||
struct pci_controller ar531x_pci_controller = {
|
||||
.pci_ops = &ar531x_pci_ops,
|
||||
.mem_resource = &ar531x_mem_resource,
|
||||
.io_resource = &ar531x_io_resource,
|
||||
.mem_offset = 0x00000000UL,
|
||||
.io_offset = 0x00000000UL,
|
||||
};
|
||||
|
||||
int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
||||
{
|
||||
return AR5315_IRQ_LCBUS_PCI;
|
||||
}
|
||||
|
||||
int pcibios_plat_dev_init(struct pci_dev *dev)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 5);
|
||||
pci_write_config_word(dev, 0x40, 0);
|
||||
|
||||
/* Clear any pending Abort or external Interrupts
|
||||
* and enable interrupt processing */
|
||||
reg = sysRegRead(AR5315_PCI_INTEN_REG);
|
||||
reg &= ~AR5315_PCI_INT_ENABLE;
|
||||
sysRegWrite(AR5315_PCI_INTEN_REG, reg);
|
||||
|
||||
reg = sysRegRead(AR5315_PCI_INT_STATUS);
|
||||
reg |= (AR5315_PCI_ABORT_INT | AR5315_PCI_EXT_INT);
|
||||
sysRegWrite(AR5315_PCI_INT_STATUS, reg);
|
||||
|
||||
reg = sysRegRead(AR5315_PCI_INT_MASK);
|
||||
reg |= (AR5315_PCI_EXT_INT | AR5315_PCI_ABORT_INT);
|
||||
sysRegWrite(AR5315_PCI_INT_MASK, reg);
|
||||
|
||||
reg = sysRegRead(AR5315_PCI_INTEN_REG);
|
||||
reg |= AR5315_PCI_INT_ENABLE;
|
||||
sysRegWrite(AR5315_PCI_INTEN_REG, reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ar5315_pci_fixup(struct pci_dev *dev)
|
||||
{
|
||||
struct pci_bus *bus = dev->bus;
|
||||
|
||||
if ((PCI_SLOT(dev->devfn) != 3) || (PCI_FUNC(dev->devfn) != 0) || (bus->number != 0))
|
||||
return;
|
||||
|
||||
#define _DEV bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)
|
||||
printk("PCI: fixing up device %d,%d,%d\n", _DEV);
|
||||
/* fix up mbars */
|
||||
config_access(_DEV, PCI_BASE_ADDRESS_0, 4, HOST_PCI_MBAR0, 1);
|
||||
config_access(_DEV, PCI_BASE_ADDRESS_1, 4, HOST_PCI_MBAR1, 1);
|
||||
config_access(_DEV, PCI_BASE_ADDRESS_2, 4, HOST_PCI_MBAR2, 1);
|
||||
config_access(_DEV, PCI_COMMAND, 4,
|
||||
PCI_COMMAND_MEMORY|PCI_COMMAND_MASTER|PCI_COMMAND_SPECIAL|
|
||||
PCI_COMMAND_INVALIDATE|PCI_COMMAND_PARITY|PCI_COMMAND_SERR|
|
||||
PCI_COMMAND_FAST_BACK, 1);
|
||||
#undef _DEV
|
||||
}
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, ar5315_pci_fixup);
|
||||
|
||||
int __init ar5315_pci_init(void)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
if (mips_machtype != MACH_ATHEROS_AR2315)
|
||||
return -ENODEV;
|
||||
|
||||
printk("AR531x PCI init... \n");
|
||||
|
||||
cfgaddr = (u32) ioremap_nocache(0x80000000, 1*1024*1024); /* Remap PCI config space */
|
||||
ar531x_pci_controller.io_map_base =
|
||||
(unsigned long) ioremap_nocache(AR531X_MEM_BASE + AR531X_MEM_SIZE, AR531X_IO_SIZE);
|
||||
set_io_port_base(ar531x_pci_controller.io_map_base); /* PCI I/O space */
|
||||
|
||||
reg = sysRegRead(AR5315_RESET);
|
||||
sysRegWrite(AR5315_RESET, reg | AR5315_RESET_PCIDMA);
|
||||
|
||||
udelay(10*1000);
|
||||
|
||||
sysRegWrite(AR5315_RESET, reg & ~AR5315_RESET_PCIDMA);
|
||||
sysRegRead(AR5315_RESET); /* read after */
|
||||
|
||||
udelay(10*1000);
|
||||
|
||||
reg = sysRegRead(AR5315_ENDIAN_CTL);
|
||||
reg |= AR5315_CONFIG_PCIAHB | AR5315_CONFIG_PCIAHB_BRIDGE;
|
||||
|
||||
sysRegWrite(AR5315_ENDIAN_CTL, reg);
|
||||
|
||||
reg = sysRegRead(AR5315_PCICLK);
|
||||
reg = 4;
|
||||
sysRegWrite(AR5315_PCICLK, reg);
|
||||
|
||||
reg = sysRegRead(AR5315_AHB_ARB_CTL);
|
||||
reg |= (ARB_PCI);
|
||||
sysRegWrite(AR5315_AHB_ARB_CTL, reg);
|
||||
|
||||
reg = sysRegRead(AR5315_IF_CTL);
|
||||
reg &= ~(IF_PCI_CLK_MASK | IF_MASK);
|
||||
reg |= (IF_PCI | IF_PCI_HOST | IF_PCI_INTR | (IF_PCI_CLK_OUTPUT_CLK << IF_PCI_CLK_SHIFT));
|
||||
|
||||
sysRegWrite(AR5315_IF_CTL, reg);
|
||||
|
||||
/* Reset the PCI bus by setting bits 5-4 in PCI_MCFG */
|
||||
reg = sysRegRead(AR5315_PCI_MISC_CONFIG);
|
||||
reg &= ~(AR5315_PCIMISC_RST_MODE);
|
||||
reg |= AR5315_PCIRST_LOW;
|
||||
sysRegWrite(AR5315_PCI_MISC_CONFIG, reg);
|
||||
|
||||
/* wait for 100 ms */
|
||||
udelay(100*1000);
|
||||
|
||||
/* Bring the PCI out of reset */
|
||||
reg = sysRegRead(AR5315_PCI_MISC_CONFIG);
|
||||
reg &= ~(AR5315_PCIMISC_RST_MODE);
|
||||
reg |= (AR5315_PCIRST_HIGH | AR5315_PCICACHE_DIS | 0x8);
|
||||
sysRegWrite(AR5315_PCI_MISC_CONFIG, reg);
|
||||
|
||||
sysRegWrite(AR5315_PCI_UNCACHE_CFG,
|
||||
0x1E | /* 1GB uncached */
|
||||
(1 << 5) | /* Enable uncached */
|
||||
(0x2 << 30) /* Base: 0x80000000 */
|
||||
);
|
||||
(void)sysRegRead(AR5315_PCI_UNCACHE_CFG); /* flush */
|
||||
|
||||
udelay(500*1000);
|
||||
|
||||
/* dirty hack - anyone with a datasheet that knows the memory map ? */
|
||||
ioport_resource.start = 0x10000000;
|
||||
ioport_resource.end = 0xffffffff;
|
||||
iomem_resource.start = 0x10000000;
|
||||
iomem_resource.end = 0xffffffff;
|
||||
|
||||
register_pci_controller(&ar531x_pci_controller);
|
||||
|
||||
printk("done\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
arch_initcall(ar5315_pci_init);
|
||||
299
target/linux/atheros/files-2.6.26/arch/mips/atheros/board.c
Normal file
299
target/linux/atheros/files-2.6.26/arch/mips/atheros/board.c
Normal file
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
* 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) 2003 Atheros Communications, Inc., All Rights Reserved.
|
||||
* Copyright (C) 2006 FON Technology, SL.
|
||||
* Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
|
||||
* Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Platform devices for Atheros SoCs
|
||||
*/
|
||||
|
||||
#include <linux/autoconf.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/random.h>
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/irq_cpu.h>
|
||||
#include <asm/io.h>
|
||||
#include <ar531x.h>
|
||||
|
||||
char *board_config = NULL;
|
||||
char *radio_config = NULL;
|
||||
int broken_boarddata = 0;
|
||||
|
||||
extern int early_serial_setup(struct uart_port *port);
|
||||
|
||||
static inline bool
|
||||
check_radio_magic(unsigned char *addr)
|
||||
{
|
||||
addr += 0x7a; /* offset for flash magic */
|
||||
if ((addr[0] == 0x5a) && (addr[1] == 0xa5)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
check_board_data(unsigned char *flash_limit, unsigned char *addr, bool broken)
|
||||
{
|
||||
/* config magic found */
|
||||
if ( *(int *)addr == 0x35333131)
|
||||
return 1;
|
||||
|
||||
if (!broken)
|
||||
return 0;
|
||||
|
||||
if (check_radio_magic(addr + 0xf8))
|
||||
radio_config = addr + 0xf8;
|
||||
if ((addr < flash_limit + 0x10000) &&
|
||||
check_radio_magic(addr + 0x10000))
|
||||
radio_config = addr + 0x10000;
|
||||
|
||||
if (radio_config) {
|
||||
/* broken board data detected, use radio data to find the offset,
|
||||
* user will fix this */
|
||||
broken_boarddata = 1;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 *find_board_config(char *flash_limit, bool broken)
|
||||
{
|
||||
char *addr;
|
||||
int found = 0;
|
||||
|
||||
for (addr = (char *) (flash_limit - 0x1000);
|
||||
addr >= (char *) (flash_limit - 0x30000);
|
||||
addr -= 0x1000) {
|
||||
|
||||
if (check_board_data(flash_limit, addr, broken)) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
addr = NULL;
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
static u8 *find_radio_config(char *flash_limit, char *board_config)
|
||||
{
|
||||
int dataFound;
|
||||
char *radio_config;
|
||||
|
||||
/*
|
||||
* Now find the start of Radio Configuration data, using heuristics:
|
||||
* Search forward from Board Configuration data by 0x1000 bytes
|
||||
* at a time until we find non-0xffffffff.
|
||||
*/
|
||||
dataFound = 0;
|
||||
for (radio_config = board_config + 0x1000;
|
||||
(radio_config < flash_limit);
|
||||
radio_config += 0x1000) {
|
||||
if ((*(u32 *)radio_config != 0xffffffff) &&
|
||||
check_radio_magic(radio_config)) {
|
||||
dataFound = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ATHEROS_AR5315
|
||||
if (!dataFound) { /* AR2316 relocates radio config to new location */
|
||||
for (radio_config = board_config + 0xf8;
|
||||
(radio_config < flash_limit - 0x1000 + 0xf8);
|
||||
radio_config += 0x1000) {
|
||||
if ((*(u32 *)radio_config != 0xffffffff) &&
|
||||
check_radio_magic(radio_config)) {
|
||||
dataFound = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!dataFound) {
|
||||
printk("Could not find Radio Configuration data\n");
|
||||
radio_config = 0;
|
||||
}
|
||||
|
||||
return (u8 *) radio_config;
|
||||
}
|
||||
|
||||
int __init ar531x_find_config(char *flash_limit)
|
||||
{
|
||||
struct ar531x_boarddata *bd;
|
||||
unsigned int rcfg_size;
|
||||
char *bcfg, *rcfg;
|
||||
|
||||
/* Copy the board and radio data to RAM, because with the new
|
||||
* spiflash driver, accessing the mapped memory directly is no
|
||||
* longer safe */
|
||||
|
||||
bcfg = find_board_config(flash_limit, false);
|
||||
if (!bcfg)
|
||||
bcfg = find_board_config(flash_limit, true);
|
||||
if (!bcfg) {
|
||||
printk("WARNING: No board configuration data found!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
board_config = kzalloc(BOARD_CONFIG_BUFSZ, GFP_KERNEL);
|
||||
memcpy(board_config, bcfg, 0x100);
|
||||
if (broken_boarddata) {
|
||||
printk("WARNING: broken board data detected\n");
|
||||
bd = (struct ar531x_boarddata *)board_config;
|
||||
if (!memcmp(bd->enet0Mac, "\x00\x00\x00\x00\x00\x00", 6)) {
|
||||
printk("Fixing up empty mac addresses\n");
|
||||
bd->enet0Mac[1] = 0x13;
|
||||
bd->enet0Mac[2] = 0x37;
|
||||
get_random_bytes(bd->enet0Mac + 3, 3);
|
||||
bd->wlan0Mac[1] = 0x13;
|
||||
bd->wlan0Mac[2] = 0x37;
|
||||
get_random_bytes(bd->wlan0Mac + 3, 3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Radio config starts 0x100 bytes after board config, regardless
|
||||
* of what the physical layout on the flash chip looks like */
|
||||
|
||||
if (radio_config)
|
||||
rcfg = radio_config;
|
||||
else
|
||||
rcfg = find_radio_config(flash_limit, bcfg);
|
||||
|
||||
if (!rcfg)
|
||||
return -ENODEV;
|
||||
|
||||
radio_config = board_config + 0x100 + ((rcfg - bcfg) & 0xfff);
|
||||
printk("Radio config found at offset 0x%x(0x%x)\n", rcfg - bcfg, radio_config - board_config);
|
||||
rcfg_size = BOARD_CONFIG_BUFSZ - (radio_config - board_config);
|
||||
memcpy(radio_config, rcfg, rcfg_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __init serial_setup(unsigned long mapbase, unsigned int uartclk)
|
||||
{
|
||||
struct uart_port s;
|
||||
|
||||
memset(&s, 0, sizeof(s));
|
||||
|
||||
s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
|
||||
s.iotype = UPIO_MEM;
|
||||
s.irq = AR531X_MISC_IRQ_UART0;
|
||||
s.regshift = 2;
|
||||
s.mapbase = mapbase;
|
||||
s.uartclk = uartclk;
|
||||
s.membase = (void __iomem *)s.mapbase;
|
||||
|
||||
early_serial_setup(&s);
|
||||
}
|
||||
|
||||
void __init plat_mem_setup(void)
|
||||
{
|
||||
DO_AR5312(ar5312_plat_setup();)
|
||||
DO_AR5315(ar5315_plat_setup();)
|
||||
|
||||
/* Disable data watchpoints */
|
||||
write_c0_watchlo0(0);
|
||||
}
|
||||
|
||||
const char *get_system_type(void)
|
||||
{
|
||||
switch (mips_machtype) {
|
||||
#ifdef CONFIG_ATHEROS_AR5312
|
||||
case MACH_ATHEROS_AR5312:
|
||||
return "Atheros AR5312";
|
||||
|
||||
case MACH_ATHEROS_AR2312:
|
||||
return "Atheros AR2312";
|
||||
|
||||
case MACH_ATHEROS_AR2313:
|
||||
return "Atheros AR2313";
|
||||
#endif
|
||||
#ifdef CONFIG_ATHEROS_AR5315
|
||||
case MACH_ATHEROS_AR2315:
|
||||
return "Atheros AR2315";
|
||||
case MACH_ATHEROS_AR2316:
|
||||
return "Atheros AR2316";
|
||||
case MACH_ATHEROS_AR2317:
|
||||
return "Atheros AR2317";
|
||||
case MACH_ATHEROS_AR2318:
|
||||
return "Atheros AR2318";
|
||||
#endif
|
||||
}
|
||||
return "Atheros (unknown)";
|
||||
}
|
||||
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24))
|
||||
void __init plat_timer_setup(struct irqaction *irq)
|
||||
{
|
||||
unsigned int count;
|
||||
|
||||
/* Usually irq is timer_irqaction (timer_interrupt) */
|
||||
setup_irq(AR531X_IRQ_CPU_CLOCK, irq);
|
||||
|
||||
/* to generate the first CPU timer interrupt */
|
||||
count = read_c0_count();
|
||||
write_c0_compare(count + 1000);
|
||||
}
|
||||
#endif
|
||||
|
||||
asmlinkage void plat_irq_dispatch(void)
|
||||
{
|
||||
DO_AR5312(ar5312_irq_dispatch();)
|
||||
DO_AR5315(ar5315_irq_dispatch();)
|
||||
}
|
||||
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24))
|
||||
void (*board_time_init)(void);
|
||||
void __init plat_time_init(void) {
|
||||
board_time_init();
|
||||
}
|
||||
#endif
|
||||
|
||||
void __init arch_init_irq(void)
|
||||
{
|
||||
clear_c0_status(ST0_IM);
|
||||
mips_cpu_irq_init();
|
||||
|
||||
/* Initialize interrupt controllers */
|
||||
DO_AR5312(ar5312_misc_intr_init(AR531X_MISC_IRQ_BASE);)
|
||||
DO_AR5315(ar5315_misc_intr_init(AR531X_MISC_IRQ_BASE);)
|
||||
}
|
||||
|
||||
static int __init ar531x_register_gpiodev(void)
|
||||
{
|
||||
static struct resource res = {
|
||||
.start = 0xFFFFFFFF,
|
||||
};
|
||||
struct platform_device *pdev;
|
||||
|
||||
printk(KERN_INFO "ar531x: Registering GPIODEV device\n");
|
||||
|
||||
pdev = platform_device_register_simple("GPIODEV", 0, &res, 1);
|
||||
|
||||
if (!pdev) {
|
||||
printk(KERN_ERR "ar531x: GPIODEV init failed\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
device_initcall(ar531x_register_gpiodev);
|
||||
45
target/linux/atheros/files-2.6.26/arch/mips/atheros/prom.c
Normal file
45
target/linux/atheros/files-2.6.26/arch/mips/atheros/prom.c
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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 MontaVista Software Inc
|
||||
* Copyright (C) 2003 Atheros Communications, Inc., All Rights Reserved.
|
||||
* Copyright (C) 2006 FON Technology, SL.
|
||||
* Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
|
||||
* Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Prom setup file for ar531x
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/autoconf.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/bootmem.h>
|
||||
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/addrspace.h>
|
||||
#include <ar531x.h>
|
||||
|
||||
void __init prom_init(void)
|
||||
{
|
||||
char **argv;
|
||||
|
||||
mips_machtype = -1;
|
||||
|
||||
DO_AR5312(ar5312_prom_init();)
|
||||
DO_AR5315(ar5315_prom_init();)
|
||||
#if 0
|
||||
argv = (char **)fw_arg1;
|
||||
/* RedBoot desired command line is argv[1] */
|
||||
strcat(arcs_cmdline, argv[1]);
|
||||
#endif
|
||||
}
|
||||
|
||||
void __init prom_free_prom_memory(void)
|
||||
{
|
||||
}
|
||||
162
target/linux/atheros/files-2.6.26/arch/mips/atheros/reset.c
Normal file
162
target/linux/atheros/files-2.6.26/arch/mips/atheros/reset.c
Normal file
@@ -0,0 +1,162 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <net/sock.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <ar531x.h>
|
||||
|
||||
#define AR531X_RESET_GPIO_IRQ (AR531X_GPIO_IRQ(bcfg->resetConfigGpio))
|
||||
|
||||
struct event_t {
|
||||
struct work_struct wq;
|
||||
int set;
|
||||
unsigned long jiffies;
|
||||
};
|
||||
|
||||
static struct ar531x_boarddata *bcfg;
|
||||
static struct timer_list rst_button_timer;
|
||||
|
||||
extern struct sock *uevent_sock;
|
||||
extern u64 uevent_next_seqnum(void);
|
||||
static unsigned long seen;
|
||||
|
||||
static inline void add_msg(struct sk_buff *skb, char *msg)
|
||||
{
|
||||
char *scratch;
|
||||
scratch = skb_put(skb, strlen(msg) + 1);
|
||||
sprintf(scratch, msg);
|
||||
}
|
||||
|
||||
static void hotplug_button(struct work_struct *wq)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct event_t *event;
|
||||
size_t len;
|
||||
char *scratch, *s;
|
||||
char buf[128];
|
||||
|
||||
event = container_of(wq, struct event_t, wq);
|
||||
if (!uevent_sock)
|
||||
goto done;
|
||||
|
||||
/* allocate message with the maximum possible size */
|
||||
s = event->set ? "pressed" : "released";
|
||||
len = strlen(s) + 2;
|
||||
skb = alloc_skb(len + 2048, GFP_KERNEL);
|
||||
if (!skb)
|
||||
goto done;
|
||||
|
||||
/* add header */
|
||||
scratch = skb_put(skb, len);
|
||||
sprintf(scratch, "%s@",s);
|
||||
|
||||
/* copy keys to our continuous event payload buffer */
|
||||
add_msg(skb, "HOME=/");
|
||||
add_msg(skb, "PATH=/sbin:/bin:/usr/sbin:/usr/bin");
|
||||
add_msg(skb, "SUBSYSTEM=button");
|
||||
add_msg(skb, "BUTTON=reset");
|
||||
add_msg(skb, (event->set ? "ACTION=pressed" : "ACTION=released"));
|
||||
sprintf(buf, "SEEN=%ld", (event->jiffies - seen)/HZ);
|
||||
add_msg(skb, buf);
|
||||
snprintf(buf, 128, "SEQNUM=%llu", uevent_next_seqnum());
|
||||
add_msg(skb, buf);
|
||||
|
||||
NETLINK_CB(skb).dst_group = 1;
|
||||
netlink_broadcast(uevent_sock, skb, 0, 1, GFP_KERNEL);
|
||||
|
||||
done:
|
||||
kfree(event);
|
||||
}
|
||||
|
||||
static int no_release_workaround = 1;
|
||||
|
||||
static void
|
||||
reset_button_poll(unsigned long unused)
|
||||
{
|
||||
struct event_t *event;
|
||||
int gpio = ~0;
|
||||
|
||||
if(!no_release_workaround)
|
||||
return;
|
||||
|
||||
DO_AR5315(gpio = sysRegRead(AR5315_GPIO_DI);)
|
||||
gpio &= 1 << (AR531X_RESET_GPIO_IRQ - AR531X_GPIO_IRQ_BASE);
|
||||
if(gpio)
|
||||
{
|
||||
rst_button_timer.expires = jiffies + (HZ / 4);
|
||||
add_timer(&rst_button_timer);
|
||||
} else {
|
||||
event = (struct event_t *) kzalloc(sizeof(struct event_t), GFP_ATOMIC);
|
||||
if (!event)
|
||||
{
|
||||
printk("Could not alloc hotplug event\n");
|
||||
return;
|
||||
}
|
||||
event->set = 0;
|
||||
event->jiffies = jiffies;
|
||||
INIT_WORK(&event->wq, (void *)(void *)hotplug_button);
|
||||
schedule_work(&event->wq);
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t button_handler(int irq, void *dev_id)
|
||||
{
|
||||
static int pressed = 0;
|
||||
struct event_t *event;
|
||||
u32 gpio = ~0;
|
||||
|
||||
event = (struct event_t *) kzalloc(sizeof(struct event_t), GFP_ATOMIC);
|
||||
if (!event)
|
||||
return IRQ_NONE;
|
||||
|
||||
pressed = !pressed;
|
||||
|
||||
DO_AR5315(gpio = sysRegRead(AR5315_GPIO_DI);)
|
||||
gpio &= 1 << (irq - AR531X_GPIO_IRQ_BASE);
|
||||
|
||||
event->set = gpio;
|
||||
if(!event->set)
|
||||
no_release_workaround = 0;
|
||||
|
||||
event->jiffies = jiffies;
|
||||
|
||||
INIT_WORK(&event->wq, (void *)(void *)hotplug_button);
|
||||
schedule_work(&event->wq);
|
||||
|
||||
seen = jiffies;
|
||||
if(event->set && no_release_workaround)
|
||||
mod_timer(&rst_button_timer, jiffies + (HZ / 4));
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
void ar531x_disable_reset_button(void)
|
||||
{
|
||||
disable_irq(AR531X_RESET_GPIO_IRQ);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(ar531x_disable_reset_button);
|
||||
|
||||
int __init ar531x_init_reset(void)
|
||||
{
|
||||
bcfg = (struct ar531x_boarddata *) board_config;
|
||||
|
||||
seen = jiffies;
|
||||
|
||||
init_timer(&rst_button_timer);
|
||||
rst_button_timer.function = reset_button_poll;
|
||||
rst_button_timer.expires = jiffies + HZ / 50;
|
||||
add_timer(&rst_button_timer);
|
||||
|
||||
request_irq(AR531X_RESET_GPIO_IRQ, &button_handler, IRQF_SAMPLE_RANDOM, "ar531x_reset", NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
module_init(ar531x_init_reset);
|
||||
Reference in New Issue
Block a user