parent
b4bd264899
commit
76c376d82a
@ -0,0 +1,13 @@ |
||||
|
||||
config ATHEROS_AR5312 |
||||
bool "Atheros 5312/2312+ support" |
||||
depends on ATHEROS |
||||
default y |
||||
|
||||
config ATHEROS_AR5315 |
||||
bool "Atheros 5315/2315+ support" |
||||
depends on ATHEROS |
||||
default y |
||||
|
||||
|
||||
|
@ -0,0 +1,22 @@ |
||||
#
|
||||
# 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>
|
||||
#
|
||||
|
||||
# Makefile for Atheros ar531x boards
|
||||
#
|
||||
# Note! Dependencies are done automagically by 'make dep', which also
|
||||
# removes any old dependencies. DON'T put your own dependencies here
|
||||
# unless it's something special (ie not a .c file).
|
||||
#
|
||||
|
||||
obj-y += board.o prom.o irq.o
|
||||
obj-$(CONFIG_ATHEROS_AR5312) += ar5312.o
|
||||
obj-$(CONFIG_ATHEROS_AR5315) += ar5315.o
|
||||
|
@ -0,0 +1,471 @@ |
||||
/*
|
||||
* 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" |
||||
|
||||
|
||||
#define AR531X_IRQ_WLAN0_INTRS MIPS_CPU_IRQ_BASE+2 /* C0_CAUSE: 0x0400 */ |
||||
#define AR531X_IRQ_ENET0_INTRS MIPS_CPU_IRQ_BASE+3 /* C0_CAUSE: 0x0800 */ |
||||
#define AR531X_IRQ_ENET1_INTRS MIPS_CPU_IRQ_BASE+4 /* C0_CAUSE: 0x1000 */ |
||||
#define AR531X_IRQ_WLAN1_INTRS MIPS_CPU_IRQ_BASE+5 /* C0_CAUSE: 0x2000 */ |
||||
#define AR531X_IRQ_MISC_INTRS MIPS_CPU_IRQ_BASE+6 /* C0_CAUSE: 0x4000 */ |
||||
|
||||
|
||||
static struct platform_device *ar5312_devs[5]; |
||||
|
||||
static struct resource ar5312_eth0_res[] = { |
||||
{ |
||||
.name = "eth_membase", |
||||
.flags = IORESOURCE_MEM, |
||||
.start = KSEG1ADDR(AR531X_ENET0), |
||||
.end = KSEG1ADDR(AR531X_ENET0 + 0x2000), |
||||
}, |
||||
{ |
||||
.name = "eth_irq", |
||||
.flags = IORESOURCE_IRQ, |
||||
.start = AR531X_IRQ_ENET0_INTRS, |
||||
.end = AR531X_IRQ_ENET0_INTRS, |
||||
}, |
||||
}; |
||||
|
||||
|
||||
static struct resource ar5312_eth1_res[] = { |
||||
{ |
||||
.name = "eth_membase", |
||||
.flags = IORESOURCE_MEM, |
||||
.start = KSEG1ADDR(AR531X_ENET1), |
||||
.end = KSEG1ADDR(AR531X_ENET1 + 0x2000), |
||||
}, |
||||
{ |
||||
.name = "eth_irq", |
||||
.flags = IORESOURCE_IRQ, |
||||
.start = AR531X_IRQ_ENET1_INTRS, |
||||
.end = AR531X_IRQ_ENET1_INTRS, |
||||
}, |
||||
}; |
||||
|
||||
|
||||
static struct ar531x_eth ar5312_eth0_data = { |
||||
.phy = 0x1f, |
||||
.mac = 0, |
||||
.reset_base = AR531X_RESET, |
||||
.reset_mac = AR531X_RESET_ENET0, |
||||
.reset_phy = AR531X_RESET_EPHY0, |
||||
}; |
||||
|
||||
static struct ar531x_eth ar5312_eth1_data = { |
||||
.phy = 0, |
||||
.mac = 1, |
||||
.reset_base = AR531X_RESET, |
||||
.reset_mac = AR531X_RESET_ENET1, |
||||
.reset_phy = AR531X_RESET_EPHY1, |
||||
}; |
||||
|
||||
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) |
||||
}, |
||||
}; |
||||
|
||||
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 + 0x400000 - 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, |
||||
}; |
||||
|
||||
|
||||
/*
|
||||
* 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 */ |
||||
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 + 0x400000); |
||||
} |
||||
|
||||
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) |
||||
{ |
||||
char *radio; |
||||
int dev = 0; |
||||
|
||||
if (mips_machtype != MACH_ATHEROS_AR5312)
|
||||
return 0; |
||||
|
||||
ar531x_find_config(ar5312_flash_limit()); |
||||
ar5312_eth0_data.board_config = board_config; |
||||
ar5312_eth1_data.board_config = board_config; |
||||
ar5312_devs[dev++] = &ar5312_physmap_flash; |
||||
ar5312_devs[dev++] = &ar5312_eth[0]; |
||||
ar5312_devs[dev++] = &ar5312_eth[1]; |
||||
|
||||
radio = radio_config + AR531X_RADIO_MASK_OFF; |
||||
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); |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* 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(AR531X_IRQ_WLAN0_INTRS); |
||||
else if (pending & CAUSEF_IP3) |
||||
do_IRQ(AR531X_IRQ_ENET0_INTRS); |
||||
else if (pending & CAUSEF_IP4) |
||||
do_IRQ(AR531X_IRQ_ENET1_INTRS); |
||||
else if (pending & CAUSEF_IP5) |
||||
do_IRQ(AR531X_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); |
||||
} |
||||
else |
||||
do_IRQ(AR531X_IRQ_NONE); |
||||
} |
||||
|
||||
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; |
||||
} |
||||
|
||||
|
||||
/* 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 = SA_INTERRUPT, |
||||
.name = "ar5312_ahb_proc_interrupt", |
||||
}; |
||||
|
||||
|
||||
static struct irqaction cascade = { |
||||
.handler = no_action, |
||||
.flags = SA_INTERRUPT, |
||||
.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(AR531X_IRQ_MISC_INTRS, &cascade); |
||||
} |
||||
|
||||
|
||||
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); |
@ -0,0 +1,223 @@ |
||||
/*
|
||||
* 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 Imre Kaloz <kaloz@openwrt.org> |
||||
* Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> |
||||
*/ |
||||
|
||||
#ifndef AR5312_H |
||||
#define AR5312_H |
||||
|
||||
#include <asm/addrspace.h> |
||||
|
||||
/* Address Map */ |
||||
#define AR531X_WLAN0 0x18000000 |
||||
#define AR531X_WLAN1 0x18500000 |
||||
#define AR531X_ENET0 0x18100000 |
||||
#define AR531X_ENET1 0x18200000 |
||||
#define AR531X_SDRAMCTL 0x18300000 |
||||
#define AR531X_FLASHCTL 0x18400000 |
||||
#define AR531X_APBBASE 0x1c000000 |
||||
#define AR531X_FLASH 0x1e000000 |
||||
#define AR531X_UART0 0xbc000003 /* UART MMR */ |
||||
|
||||
/*
|
||||
* AR531X_NUM_ENET_MAC defines the number of ethernet MACs that |
||||
* should be considered available. The AR5312 supports 2 enet MACS, |
||||
* even though many reference boards only actually use 1 of them |
||||
* (i.e. Only MAC 0 is actually connected to an enet PHY or PHY switch. |
||||
* The AR2312 supports 1 enet MAC. |
||||
*/ |
||||
#define AR531X_NUM_ENET_MAC 2 |
||||
|
||||
/*
|
||||
* Need these defines to determine true number of ethernet MACs |
||||
*/ |
||||
#define AR5212_AR5312_REV2 0x0052 /* AR5312 WMAC (AP31) */ |
||||
#define AR5212_AR5312_REV7 0x0057 /* AR5312 WMAC (AP30-040) */ |
||||
#define AR5212_AR2313_REV8 0x0058 /* AR2313 WMAC (AP43-030) */ |
||||
#define AR531X_RADIO_MASK_OFF 0xc8 |
||||
#define AR531X_RADIO0_MASK 0x0003 |
||||
#define AR531X_RADIO1_MASK 0x000c |
||||
#define AR531X_RADIO1_S 2 |
||||
|
||||
/*
|
||||
* AR531X_NUM_WMAC defines the number of Wireless MACs that\
|
||||
* should be considered available. |
||||
*/ |
||||
#define AR531X_NUM_WMAC 2 |
||||
|
||||
/* Reset/Timer Block Address Map */ |
||||
#define AR531X_RESETTMR (AR531X_APBBASE + 0x3000) |
||||
#define AR531X_TIMER (AR531X_RESETTMR + 0x0000) /* countdown timer */ |
||||
#define AR531X_WD_CTRL (AR531X_RESETTMR + 0x0008) /* watchdog cntrl */ |
||||
#define AR531X_WD_TIMER (AR531X_RESETTMR + 0x000c) /* watchdog timer */ |
||||
#define AR531X_ISR (AR531X_RESETTMR + 0x0010) /* Intr Status Reg */ |
||||
#define AR531X_IMR (AR531X_RESETTMR + 0x0014) /* Intr Mask Reg */ |
||||
#define AR531X_RESET (AR531X_RESETTMR + 0x0020) |
||||
#define AR5312_CLOCKCTL1 (AR531X_RESETTMR + 0x0064) |
||||
#define AR5312_SCRATCH (AR531X_RESETTMR + 0x006c) |
||||
#define AR531X_PROCADDR (AR531X_RESETTMR + 0x0070) |
||||
#define AR531X_PROC1 (AR531X_RESETTMR + 0x0074) |
||||
#define AR531X_DMAADDR (AR531X_RESETTMR + 0x0078) |
||||
#define AR531X_DMA1 (AR531X_RESETTMR + 0x007c) |
||||
#define AR531X_ENABLE (AR531X_RESETTMR + 0x0080) /* interface enb */ |
||||
#define AR531X_REV (AR531X_RESETTMR + 0x0090) /* revision */ |
||||
|
||||
/* AR531X_WD_CTRL register bit field definitions */ |
||||
#define AR531X_WD_CTRL_IGNORE_EXPIRATION 0x0000 |
||||
#define AR531X_WD_CTRL_NMI 0x0001 |
||||
#define AR531X_WD_CTRL_RESET 0x0002 |
||||
|
||||
/* AR531X_ISR register bit field definitions */ |
||||
#define AR531X_ISR_NONE 0x0000 |
||||
#define AR531X_ISR_TIMER 0x0001 |
||||
#define AR531X_ISR_AHBPROC 0x0002 |
||||
#define AR531X_ISR_AHBDMA 0x0004 |
||||
#define AR531X_ISR_GPIO 0x0008 |
||||
#define AR531X_ISR_UART0 0x0010 |
||||
#define AR531X_ISR_UART0DMA 0x0020 |
||||
#define AR531X_ISR_WD 0x0040 |
||||
#define AR531X_ISR_LOCAL 0x0080 |
||||
|
||||
/* AR531X_RESET register bit field definitions */ |
||||
#define AR531X_RESET_SYSTEM 0x00000001 /* cold reset full system */ |
||||
#define AR531X_RESET_PROC 0x00000002 /* cold reset MIPS core */ |
||||
#define AR531X_RESET_WLAN0 0x00000004 /* cold reset WLAN MAC and BB */ |
||||
#define AR531X_RESET_EPHY0 0x00000008 /* cold reset ENET0 phy */ |
||||
#define AR531X_RESET_EPHY1 0x00000010 /* cold reset ENET1 phy */ |
||||
#define AR531X_RESET_ENET0 0x00000020 /* cold reset ENET0 mac */ |
||||
#define AR531X_RESET_ENET1 0x00000040 /* cold reset ENET1 mac */ |
||||
#define AR531X_RESET_UART0 0x00000100 /* cold reset UART0 (high speed) */ |
||||
#define AR531X_RESET_WLAN1 0x00000200 /* cold reset WLAN MAC/BB */ |
||||
#define AR531X_RESET_APB 0x00000400 /* cold reset APB (ar5312) */ |
||||
#define AR531X_RESET_WARM_PROC 0x00001000 /* warm reset MIPS core */ |
||||
#define AR531X_RESET_WARM_WLAN0_MAC 0x00002000 /* warm reset WLAN0 MAC */ |
||||
#define AR531X_RESET_WARM_WLAN0_BB 0x00004000 /* warm reset WLAN0 BaseBand */ |
||||
#define AR531X_RESET_NMI 0x00010000 /* send an NMI to the processor */ |
||||
#define AR531X_RESET_WARM_WLAN1_MAC 0x00020000 /* warm reset WLAN1 mac */ |
||||
#define AR531X_RESET_WARM_WLAN1_BB 0x00040000 /* warm reset WLAN1 baseband */ |
||||
#define AR531X_RESET_LOCAL_BUS 0x00080000 /* reset local bus */ |
||||
#define AR531X_RESET_WDOG 0x00100000 /* last reset was a watchdog */ |
||||
|
||||
#define AR531X_RESET_WMAC0_BITS \ |
||||
AR531X_RESET_WLAN0 |\
|
||||
AR531X_RESET_WARM_WLAN0_MAC |\
|
||||
AR531X_RESET_WARM_WLAN0_BB |
||||
|
||||
#define AR531X_RESERT_WMAC1_BITS \ |
||||
AR531X_RESET_WLAN1 |\
|
||||
AR531X_RESET_WARM_WLAN1_MAC |\
|
||||
AR531X_RESET_WARM_WLAN1_BB |
||||
|
||||
/* AR5312_CLOCKCTL1 register bit field definitions */ |
||||
#define AR5312_CLOCKCTL1_PREDIVIDE_MASK 0x00000030 |
||||
#define AR5312_CLOCKCTL1_PREDIVIDE_SHIFT 4 |
||||
#define AR5312_CLOCKCTL1_MULTIPLIER_MASK 0x00001f00 |
||||
#define AR5312_CLOCKCTL1_MULTIPLIER_SHIFT 8 |
||||
#define AR5312_CLOCKCTL1_DOUBLER_MASK 0x00010000 |
||||
|
||||
/* Valid for AR5312 and AR2312 */ |
||||
#define AR5312_CLOCKCTL1_PREDIVIDE_MASK 0x00000030 |
||||
#define AR5312_CLOCKCTL1_PREDIVIDE_SHIFT 4 |
||||
#define AR5312_CLOCKCTL1_MULTIPLIER_MASK 0x00001f00 |
||||
#define AR5312_CLOCKCTL1_MULTIPLIER_SHIFT 8 |
||||
#define AR5312_CLOCKCTL1_DOUBLER_MASK 0x00010000 |
||||
|
||||
/* Valid for AR2313 */ |
||||
#define AR2313_CLOCKCTL1_PREDIVIDE_MASK 0x00003000 |
||||
#define AR2313_CLOCKCTL1_PREDIVIDE_SHIFT 12 |
||||
#define AR2313_CLOCKCTL1_MULTIPLIER_MASK 0x001f0000 |
||||
#define AR2313_CLOCKCTL1_MULTIPLIER_SHIFT 16 |
||||
#define AR2313_CLOCKCTL1_DOUBLER_MASK 0x00000000 |
||||
|
||||
|
||||
/* AR531X_ENABLE register bit field definitions */ |
||||
#define AR531X_ENABLE_WLAN0 0x0001 |
||||
#define AR531X_ENABLE_ENET0 0x0002 |
||||
#define AR531X_ENABLE_ENET1 0x0004 |
||||
#define AR531X_ENABLE_UART_AND_WLAN1_PIO 0x0008 /* UART, and WLAN1 PIOs */ |
||||
#define AR531X_ENABLE_WLAN1_DMA 0x0010 /* WLAN1 DMAs */ |
||||
#define AR531X_ENABLE_WLAN1 \ |
||||
(AR531X_ENABLE_UART_AND_WLAN1_PIO | AR531X_ENABLE_WLAN1_DMA) |
||||
|
||||
/* AR531X_REV register bit field definitions */ |
||||
#define AR531X_REV_WMAC_MAJ 0xf000 |
||||
#define AR531X_REV_WMAC_MAJ_S 12 |
||||
#define AR531X_REV_WMAC_MIN 0x0f00 |
||||
#define AR531X_REV_WMAC_MIN_S 8 |
||||
#define AR531X_REV_MAJ 0x00f0 |
||||
#define AR531X_REV_MAJ_S 4 |
||||
#define AR531X_REV_MIN 0x000f |
||||
#define AR531X_REV_MIN_S 0 |
||||
#define AR531X_REV_CHIP (REV_MAJ|REV_MIN) |
||||
|
||||
/* Major revision numbers, bits 7..4 of Revision ID register */ |
||||
#define AR531X_REV_MAJ_AR5312 0x4 |
||||
#define AR531X_REV_MAJ_AR2313 0x5 |
||||
|
||||
/* Minor revision numbers, bits 3..0 of Revision ID register */ |
||||
#define AR5312_REV_MIN_DUAL 0x0 /* Dual WLAN version */ |
||||
#define AR5312_REV_MIN_SINGLE 0x1 /* Single WLAN version */ |
||||
|
||||
/* AR531X_FLASHCTL register bit field definitions */ |
||||
#define FLASHCTL_IDCY 0x0000000f /* Idle cycle turn around time */ |
||||
#define FLASHCTL_IDCY_S 0 |
||||
#define FLASHCTL_WST1 0x000003e0 /* Wait state 1 */ |
||||
#define FLASHCTL_WST1_S 5 |
||||
#define FLASHCTL_RBLE 0x00000400 /* Read byte lane enable */ |
||||
#define FLASHCTL_WST2 0x0000f800 /* Wait state 2 */ |
||||
#define FLASHCTL_WST2_S 11 |
||||
#define FLASHCTL_AC 0x00070000 /* Flash address check (added) */ |
||||
#define FLASHCTL_AC_S 16 |
||||
#define FLASHCTL_AC_128K 0x00000000 |
||||
#define FLASHCTL_AC_256K 0x00010000 |
||||
#define FLASHCTL_AC_512K 0x00020000 |
||||
#define FLASHCTL_AC_1M 0x00030000 |
||||
#define FLASHCTL_AC_2M 0x00040000 |
||||
#define FLASHCTL_AC_4M 0x00050000 |
||||
#define FLASHCTL_AC_8M 0x00060000 |
||||
#define FLASHCTL_AC_RES 0x00070000 /* 16MB is not supported */ |
||||
#define FLASHCTL_E 0x00080000 /* Flash bank enable (added) */ |
||||
#define FLASHCTL_BUSERR 0x01000000 /* Bus transfer error status flag */ |
||||
#define FLASHCTL_WPERR 0x02000000 /* Write protect error status flag */ |
||||
#define FLASHCTL_WP 0x04000000 /* Write protect */ |
||||
#define FLASHCTL_BM 0x08000000 /* Burst mode */ |
||||
#define FLASHCTL_MW 0x30000000 /* Memory width */ |
||||
#define FLASHCTL_MWx8 0x00000000 /* Memory width x8 */ |
||||
#define FLASHCTL_MWx16 0x10000000 /* Memory width x16 */ |
||||
#define FLASHCTL_MWx32 0x20000000 /* Memory width x32 (not supported) */ |
||||
#define FLASHCTL_ATNR 0x00000000 /* Access type == no retry */ |
||||
#define FLASHCTL_ATR 0x80000000 /* Access type == retry every */ |
||||
#define FLASHCTL_ATR4 0xc0000000 /* Access type == retry every 4 */ |
||||
|
||||
/* ARM Flash Controller -- 3 flash banks with either x8 or x16 devices. */ |
||||
#define AR531X_FLASHCTL0 (AR531X_FLASHCTL + 0x00) |
||||
#define AR531X_FLASHCTL1 (AR531X_FLASHCTL + 0x04) |
||||
#define AR531X_FLASHCTL2 (AR531X_FLASHCTL + 0x08) |
||||
|
||||
/* ARM SDRAM Controller -- just enough to determine memory size */ |
||||
#define AR531X_MEM_CFG1 (AR531X_SDRAMCTL + 0x04) |
||||
#define MEM_CFG1_AC0 0x00000700 /* bank 0: SDRAM addr check (added) */ |
||||
#define MEM_CFG1_AC0_S 8 |
||||
#define MEM_CFG1_AC1 0x00007000 /* bank 1: SDRAM addr check (added) */ |
||||
#define MEM_CFG1_AC1_S 12 |
||||
|
||||
/* GPIO Address Map */ |
||||
#define AR531X_GPIO (AR531X_APBBASE + 0x2000) |
||||
#define AR531X_GPIO_DO (AR531X_GPIO + 0x00) /* output register */ |
||||
#define AR531X_GPIO_DI (AR531X_GPIO + 0x04) /* intput register */ |
||||
#define AR531X_GPIO_CR (AR531X_GPIO + 0x08) /* control register */ |
||||
|
||||
/* GPIO Control Register bit field definitions */ |
||||
#define AR531X_GPIO_CR_M(x) (1 << (x)) /* mask for i/o */ |
||||
#define AR531X_GPIO_CR_O(x) (0 << (x)) /* mask for output */ |
||||
#define AR531X_GPIO_CR_I(x) (1 << (x)) /* mask for input */ |
||||
#define AR531X_GPIO_CR_INT(x) (1 << ((x)+8)) /* mask for interrupt */ |
||||
#define AR531X_GPIO_CR_UART(x) (1 << ((x)+16)) /* uart multiplex */ |
||||
|
||||
#endif |
||||
|
@ -0,0 +1,529 @@ |
||||
/*
|
||||
* 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 <asm/bootinfo.h> |
||||
#include <asm/reboot.h> |
||||
#include <asm/time.h> |
||||
#include <asm/irq.h> |
||||
#include <asm/io.h> |
||||
#include "ar531x.h" |
||||
|
||||
#define AR531X_IRQ_MISC_INTRS MIPS_CPU_IRQ_BASE+2 /* C0_CAUSE: 0x0400 */ |
||||
#define AR531X_IRQ_WLAN0_INTRS MIPS_CPU_IRQ_BASE+3 /* C0_CAUSE: 0x0800 */ |
||||
#define AR531X_IRQ_ENET0_INTRS MIPS_CPU_IRQ_BASE+4 /* C0_CAUSE: 0x1000 */ |
||||
#define AR531X_IRQ_LCBUS_PCI MIPS_CPU_IRQ_BASE+5 /* C0_CAUSE: 0x2000 */ |
||||
#define AR531X_IRQ_WLAN0_POLL MIPS_CPU_IRQ_BASE+6 /* C0_CAUSE: 0x4000 */ |
||||
|
||||
static struct resource ar5315_eth_res[] = { |
||||
{ |
||||
.name = "eth_membase", |
||||
.flags = IORESOURCE_MEM, |
||||
.start = AR5315_ENET0, |
||||
.end = AR5315_ENET0 + 0x2000, |
||||
}, |
||||
{ |
||||
.name = "eth_irq", |
||||
.flags = IORESOURCE_IRQ, |
||||
.start = AR531X_IRQ_ENET0_INTRS, |
||||
.end = AR531X_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, |
||||
}; |
||||
|
||||
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) |
||||
}; |
||||
|
||||
static __initdata struct platform_device *ar5315_devs[4]; |
||||
|
||||
|
||||
|
||||
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 |
||||
|
||||
|
||||
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; |
||||
} |
||||
|
||||
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; |
||||
int dev = 0; |
||||
|
||||
if (mips_machtype != MACH_ATHEROS_AR5315)
|
||||
return 0; |
||||
|
||||
ar531x_find_config(ar5315_flash_limit()); |
||||
|
||||
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) & REV_CHIP); |
||||
|
||||
ar5315_eth_data.board_config = board_config; |
||||
ar5315_wmac.dev.platform_data = config; |
||||
|
||||
ar5315_devs[dev++] = &ar5315_eth; |
||||
ar5315_devs[dev++] = &ar5315_wmac; |
||||
ar5315_devs[dev++] = &ar5315_spiflash; |
||||
|
||||
return platform_add_devices(ar5315_devs, dev); |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* 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(AR531X_IRQ_WLAN0_INTRS); |
||||
else if (pending & CAUSEF_IP4) |
||||
do_IRQ(AR531X_IRQ_ENET0_INTRS); |
||||
else if (pending & CAUSEF_IP2) { |
||||
unsigned int ar531x_misc_intrs = sysRegRead(AR5315_ISR) & sysRegRead(AR5315_IMR); |
||||
|
||||
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) { |
||||
sysRegWrite(AR5315_ISR, sysRegRead(AR5315_IMR) | ~AR5315_ISR_GPIO); |
||||
} 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); |
||||
else |
||||
do_IRQ(AR531X_IRQ_NONE); |
||||
} |
||||
|
||||
static void ar5315_halt(void) |
||||
{ |
||||
while (1); |
||||
} |
||||
|
||||
static void ar5315_power_off(void) |
||||
{ |
||||
ar5315_halt(); |
||||
} |
||||
|
||||
|
||||
static void ar5315_restart(char *command) |
||||
{ |
||||
unsigned int reg; |
||||
for(;;) { |
||||
|
||||
/* 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. |
||||
*/ |
||||
|
||||
reg = sysRegRead(AR5315_GPIO_DO); |
||||
reg &= ~(1 << AR5315_RESET_GPIO); |
||||
sysRegWrite(AR5315_GPIO_DO, reg); |
||||
(void)sysRegRead(AR5315_GPIO_DO); /* flush write to hardware */ |
||||
} |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* 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; |
||||
} |
||||
|
||||
|
||||
|
||||
/* 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_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 */ |
||||
//printk("enable Interrupt irq 0x%x imr 0x%x \n",irq,imr);
|
||||
|
||||
} |
||||
|
||||
/* 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_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 = SA_INTERRUPT, |
||||
.name = "ar5315_ahb_proc_interrupt", |
||||
}; |
||||
|
||||
|
||||
static struct irqaction cascade = { |
||||
.handler = no_action, |
||||
.flags = SA_INTERRUPT, |
||||
.name = "cascade", |
||||
}; |
||||
|
||||
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(AR531X_IRQ_MISC_INTRS, &cascade); |
||||
} |
||||
|
||||
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); |
@ -0,0 +1,678 @@ |
||||
/*
|
||||
* 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> |
||||
*/ |
||||
|
||||
#ifndef AR5315_H |
||||
#define AR5315_H |
||||
|
||||
/*
|
||||
* Address map |
||||
*/ |
||||
#define AR5315_SDRAM0 0x00000000 /* DRAM */ |
||||
#define AR5315_SPI_READ 0x08000000 /* SPI FLASH */ |
||||
#define AR5315_WLAN0 0xB0000000 /* Wireless MMR */ |
||||
#define AR5315_PCI 0xB0100000 /* PCI MMR */ |
||||
#define AR5315_SDRAMCTL 0xB0300000 /* SDRAM MMR */ |
||||
#define AR5315_LOCAL 0xB0400000 /* LOCAL BUS MMR */ |
||||
#define AR5315_ENET0 0xB0500000 /* ETHERNET MMR */ |
||||
#define AR5315_DSLBASE 0xB1000000 /* RESET CONTROL MMR */ |
||||
#define AR5315_UART0 0xB1100003 /* UART MMR */ |
||||
#define AR5315_SPI 0xB1300000 /* SPI FLASH MMR */ |
||||
#define AR5315_FLASHBT 0xBfc00000 /* ro boot alias to FLASH */ |
||||
#define AR5315_RAM1 0x40000000 /* ram alias */ |
||||
#define AR5315_PCIEXT 0x80000000 /* pci external */ |
||||
#define AR5315_RAM2 0xc0000000 /* ram alias */ |
||||
#define AR5315_RAM3 0xe0000000 /* ram alias */ |
||||
|
||||
/*
|
||||
* Reset Register |
||||
*/ |
||||
#define AR5315_COLD_RESET (AR5315_DSLBASE + 0x0000) |
||||
|
||||
/* Cold Reset */ |
||||
#define RESET_COLD_AHB 0x00000001 |
||||
#define RESET_COLD_APB 0x00000002 |
||||
#define RESET_COLD_CPU 0x00000004 |
||||
#define RESET_COLD_CPUWARM 0x00000008 |
||||
#define RESET_SYSTEM (RESET_COLD_CPU | RESET_COLD_APB | RESET_COLD_AHB) /* full system */ |
||||
|
||||
#define AR5317_RESET_SYSTEM 0x00000010 |
||||
|
||||
/* Warm Reset */ |
||||
|
||||
#define AR5315_RESET (AR5315_DSLBASE + 0x0004) |
||||
|
||||
#define AR5315_RESET_WARM_WLAN0_MAC 0x00000001 /* warm reset WLAN0 MAC */ |
||||
#define AR5315_RESET_WARM_WLAN0_BB 0x00000002 /* warm reset WLAN0 BaseBand */ |
||||
#define AR5315_RESET_MPEGTS_RSVD 0x00000004 /* warm reset MPEG-TS */ |
||||
#define AR5315_RESET_PCIDMA 0x00000008 /* warm reset PCI ahb/dma */ |
||||
#define AR5315_RESET_MEMCTL 0x00000010 /* warm reset memory controller */ |
||||
#define AR5315_RESET_LOCAL 0x00000020 /* warm reset local bus */ |
||||
#define AR5315_RESET_I2C_RSVD 0x00000040 /* warm reset I2C bus */ |
||||
#define AR5315_RESET_SPI 0x00000080 /* warm reset SPI interface */ |
||||
#define AR5315_RESET_UART0 0x00000100 /* warm reset UART0 */ |
||||
#define AR5315_RESET_IR_RSVD 0x00000200 /* warm reset IR interface */ |
||||
#define AR5315_RESET_EPHY0 0x00000400 /* cold reset ENET0 phy */ |
||||
#define AR5315_RESET_ENET0 0x00000800 /* cold reset ENET0 mac */ |
||||
|
||||
/*
|
||||
* AHB master arbitration control |
||||
*/ |
||||
#define AR5315_AHB_ARB_CTL (AR5315_DSLBASE + 0x0008) |
||||
|
||||
#define ARB_CPU 0x00000001 /* CPU, default */ |
||||
#define ARB_WLAN 0x00000002 /* WLAN */ |
||||
#define ARB_MPEGTS_RSVD 0x00000004 /* MPEG-TS */ |
||||
#define ARB_LOCAL 0x00000008 /* LOCAL */ |
||||
#define ARB_PCI 0x00000010 /* PCI */ |
||||
#define ARB_ETHERNET 0x00000020 /* Ethernet */ |
||||
#define ARB_RETRY 0x00000100 /* retry policy, debug only */ |
||||
|
||||
/*
|
||||
* Config Register |
||||
*/ |
||||
#define AR5315_ENDIAN_CTL (AR5315_DSLBASE + 0x000c) |
||||
|
||||
#define CONFIG_AHB 0x00000001 /* EC - AHB bridge endianess */ |
||||
#define CONFIG_WLAN 0x00000002 /* WLAN byteswap */ |
||||
#define CONFIG_MPEGTS_RSVD 0x00000004 /* MPEG-TS byteswap */ |
||||
#define CONFIG_PCI 0x00000008 /* PCI byteswap */ |
||||
#define CONFIG_MEMCTL 0x00000010 /* Memory controller endianess */ |
||||
#define CONFIG_LOCAL 0x00000020 /* Local bus byteswap */ |
||||
#define CONFIG_ETHERNET 0x00000040 /* Ethernet byteswap */ |
||||
|
||||
#define CONFIG_MERGE 0x00000200 /* CPU write buffer merge */ |
||||
#define CONFIG_CPU 0x00000400 /* CPU big endian */ |
||||
#define CONFIG_PCIAHB 0x00000800 |
||||
#define CONFIG_PCIAHB_BRIDGE 0x00001000 |
||||
#define CONFIG_SPI 0x00008000 /* SPI byteswap */ |
||||
#define CONFIG_CPU_DRAM 0x00010000 |
||||
#define CONFIG_CPU_PCI 0x00020000 |
||||
#define CONFIG_CPU_MMR 0x00040000 |
||||
#define CONFIG_BIG 0x00000400 |
||||
|
||||
|
||||
/*
|
||||
* NMI control |
||||
*/ |
||||
#define AR5315_NMI_CTL (AR5315_DSLBASE + 0x0010) |
||||
|
||||
#define NMI_EN 1 |
||||
|
||||
/*
|
||||
* Revision Register - Initial value is 0x3010 (WMAC 3.0, AR531X 1.0). |
||||
*/ |
||||
#define AR5315_SREV (AR5315_DSLBASE + 0x0014) |
||||
|
||||
#define REV_MAJ 0x00f0 |
||||
#define REV_MAJ_S 4 |
||||
#define REV_MIN 0x000f |
||||
#define REV_MIN_S 0 |
||||
#define REV_CHIP (REV_MAJ|REV_MIN) |
||||
|
||||
/*
|
||||
* Interface Enable |
||||
*/ |
||||
#define AR5315_IF_CTL (AR5315_DSLBASE + 0x0018) |
||||
|
||||
#define IF_MASK 0x00000007 |
||||
#define IF_DISABLED 0 |
||||
#define IF_PCI 1 |
||||
#define IF_TS_LOCAL 2 |
||||
#define IF_ALL 3 /* only for emulation with separate pins */ |
||||
#define IF_LOCAL_HOST 0x00000008 |
||||
#define IF_PCI_HOST 0x00000010 |
||||
#define IF_PCI_INTR 0x00000020 |
||||
#define IF_PCI_CLK_MASK 0x00030000 |
||||
#define IF_PCI_CLK_INPUT 0 |
||||
#define IF_PCI_CLK_OUTPUT_LOW 1 |
||||
#define IF_PCI_CLK_OUTPUT_CLK 2 |
||||
#define IF_PCI_CLK_OUTPUT_HIGH 3 |
||||
#define IF_PCI_CLK_SHIFT 16 |
||||
|
||||
|
||||
/* Major revision numbers, bits 7..4 of Revision ID register */ |
||||
#define REV_MAJ_AR5311 0x01 |
||||
#define REV_MAJ_AR5312 0x04 |
||||
#define REV_MAJ_AR5315 0x0B |
||||
|
||||
/*
|
||||
* APB Interrupt control |
||||
*/ |
||||
|
||||
#define AR5315_ISR (AR5315_DSLBASE + 0x0020) |
||||
#define AR5315_IMR (AR5315_DSLBASE + 0x0024) |
||||
#define AR5315_GISR (AR5315_DSLBASE + 0x0028) |
||||
|
||||
#define AR5315_ISR_UART0 0x0001 /* high speed UART */ |
||||
#define AR5315_ISR_I2C_RSVD 0x0002 /* I2C bus */ |
||||
#define AR5315_ISR_SPI 0x0004 /* SPI bus */ |
||||
#define AR5315_ISR_AHB 0x0008 /* AHB error */ |
||||
#define AR5315_ISR_APB 0x0010 /* APB error */ |
||||
#define AR5315_ISR_TIMER 0x0020 /* timer */ |
||||
#define AR5315_ISR_GPIO 0x0040 /* GPIO */ |
||||
#define AR5315_ISR_WD 0x0080 /* watchdog */ |
||||
#define AR5315_ISR_IR_RSVD 0x0100 /* IR */ |
||||
|
||||
#define AR5315_GISR_MISC 0x0001 |
||||
#define AR5315_GISR_WLAN0 0x0002 |
||||
#define AR5315_GISR_MPEGTS_RSVD 0x0004 |
||||
#define AR5315_GISR_LOCALPCI 0x0008 |
||||
#define AR5315_GISR_WMACPOLL 0x0010 |
||||
#define AR5315_GISR_TIMER 0x0020 |
||||
#define AR5315_GISR_ETHERNET 0x0040 |
||||
|
||||
/*
|
||||
* Interrupt routing from IO to the processor IP bits |
||||
* Define our inter mask and level |
||||
*/ |
||||
#define AR5315_INTR_MISCIO SR_IBIT3 |
||||
#define AR5315_INTR_WLAN0 SR_IBIT4 |
||||
#define AR5315_INTR_ENET0 SR_IBIT5 |
||||
#define AR5315_INTR_LOCALPCI SR_IBIT6 |
||||
#define AR5315_INTR_WMACPOLL SR_IBIT7 |
||||
#define AR5315_INTR_COMPARE SR_IBIT8 |
||||
|
||||
/*
|
||||
* Timers |
||||
*/ |
||||
#define AR5315_TIMER (AR5315_DSLBASE + 0x0030) |
||||
#define AR5315_RELOAD (AR5315_DSLBASE + 0x0034) |
||||
#define AR5315_WD (AR5315_DSLBASE + 0x0038) |
||||
#define AR5315_WDC (AR5315_DSLBASE + 0x003c) |
||||
|
||||
#define WDC_RESET 0x00000002 /* reset on watchdog */ |
||||
#define WDC_NMI 0x00000001 /* NMI on watchdog */ |
||||
#define WDC_IGNORE_EXPIRATION 0x00000000 |
||||
|
||||
/*
|
||||
* CPU Performance Counters |
||||
*/ |
||||
#define AR5315_PERFCNT0 (AR5315_DSLBASE + 0x0048) |
||||
#define AR5315_PERFCNT1 (AR5315_DSLBASE + 0x004c) |
||||
|
||||
#define PERF_DATAHIT 0x0001 /* Count Data Cache Hits */ |
||||
#define PERF_DATAMISS 0x0002 /* Count Data Cache Misses */ |
||||
#define PERF_INSTHIT 0x0004 /* Count Instruction Cache Hits */ |
||||
#define PERF_INSTMISS 0x0008 /* Count Instruction Cache Misses */ |
||||
#define PERF_ACTIVE 0x0010 /* Count Active Processor Cycles */ |
||||
#define PERF_WBHIT 0x0020 /* Count CPU Write Buffer Hits */ |
||||
#define PERF_WBMISS 0x0040 /* Count CPU Write Buffer Misses */ |
||||
|
||||
#define PERF_EB_ARDY 0x0001 /* Count EB_ARdy signal */ |
||||
#define PERF_EB_AVALID 0x0002 /* Count EB_AValid signal */ |
||||
#define PERF_EB_WDRDY 0x0004 /* Count EB_WDRdy signal */ |
||||
#define PERF_EB_RDVAL 0x0008 /* Count EB_RdVal signal */ |
||||
#define PERF_VRADDR 0x0010 /* Count valid read address cycles */ |
||||
#define PERF_VWADDR 0x0020 /* Count valid write address cycles */ |
||||
#define PERF_VWDATA 0x0040 /* Count valid write data cycles */ |
||||
|
||||
/*
|
||||
* AHB Error Reporting. |
||||
*/ |
||||
#define AR5315_AHB_ERR0 (AR5315_DSLBASE + 0x0050) /* error */ |
||||
#define AR5315_AHB_ERR1 (AR5315_DSLBASE + 0x0054) /* haddr */ |
||||
#define AR5315_AHB_ERR2 (AR5315_DSLBASE + 0x0058) /* hwdata */ |
||||
#define AR5315_AHB_ERR3 (AR5315_DSLBASE + 0x005c) /* hrdata */ |
||||
#define AR5315_AHB_ERR4 (AR5315_DSLBASE + 0x0060) /* status */ |
||||
|
||||
#define AHB_ERROR_DET 1 /* AHB Error has been detected, */ |
||||
/* write 1 to clear all bits in ERR0 */ |
||||
#define AHB_ERROR_OVR 2 /* AHB Error overflow has been detected */ |
||||
#define AHB_ERROR_WDT 4 /* AHB Error due to wdt instead of hresp */ |
||||
|
||||
#define PROCERR_HMAST 0x0000000f |
||||
#define PROCERR_HMAST_DFLT 0 |
||||
#define PROCERR_HMAST_WMAC 1 |
||||
#define PROCERR_HMAST_ENET 2 |
||||
#define PROCERR_HMAST_PCIENDPT 3 |
||||
#define PROCERR_HMAST_LOCAL 4 |
||||
#define PROCERR_HMAST_CPU 5 |
||||
#define PROCERR_HMAST_PCITGT 6 |
||||
|
||||
#define PROCERR_HMAST_S 0 |
||||
#define PROCERR_HWRITE 0x00000010 |
||||
#define PROCERR_HSIZE 0x00000060 |
||||
#define PROCERR_HSIZE_S 5 |
||||
#define PROCERR_HTRANS 0x00000180 |
||||
#define PROCERR_HTRANS_S 7 |
||||
#define PROCERR_HBURST 0x00000e00 |
||||
#define PROCERR_HBURST_S 9 |
||||
|
||||
|
||||
|
||||
/*
|
||||
* Clock Control |
||||
*/ |
||||
#define AR5315_PLLC_CTL (AR5315_DSLBASE + 0x0064) |
||||
#define AR5315_PLLV_CTL (AR5315_DSLBASE + 0x0068) |
||||
#define AR5315_CPUCLK (AR5315_DSLBASE + 0x006c) |
||||
#define AR5315_AMBACLK (AR5315_DSLBASE + 0x0070) |
||||
#define AR5315_SYNCCLK (AR5315_DSLBASE + 0x0074) |
||||
#define AR5315_DSL_SLEEP_CTL (AR5315_DSLBASE + 0x0080) |
||||
#define AR5315_DSL_SLEEP_DUR (AR5315_DSLBASE + 0x0084) |
||||
|
||||
/* PLLc Control fields */ |
||||
#define PLLC_REF_DIV_M 0x00000003 |
||||
#define PLLC_REF_DIV_S 0 |
||||
#define PLLC_FDBACK_DIV_M 0x0000007C |
||||
#define PLLC_FDBACK_DIV_S 2 |
||||
#define PLLC_ADD_FDBACK_DIV_M 0x00000080 |
||||
#define PLLC_ADD_FDBACK_DIV_S 7 |
||||
#define PLLC_CLKC_DIV_M 0x0001c000 |
||||
#define PLLC_CLKC_DIV_S 14 |
||||
#define PLLC_CLKM_DIV_M 0x00700000 |
||||
#define PLLC_CLKM_DIV_S 20 |
||||
|
||||
/* CPU CLK Control fields */ |
||||
#define CPUCLK_CLK_SEL_M 0x00000003 |
||||
#define CPUCLK_CLK_SEL_S 0 |
||||
#define CPUCLK_CLK_DIV_M 0x0000000c |
||||
#define CPUCLK_CLK_DIV_S 2 |
||||
|
||||
/* AMBA CLK Control fields */ |
||||
#define AMBACLK_CLK_SEL_M 0x00000003 |
||||
#define AMBACLK_CLK_SEL_S 0 |
||||
#define AMBACLK_CLK_DIV_M 0x0000000c |
||||
#define AMBACLK_CLK_DIV_S 2 |
||||
|
||||
#if defined(COBRA_EMUL) |
||||
#define AR5315_AMBA_CLOCK_RATE 20000000 |
||||
#define AR5315_CPU_CLOCK_RATE 40000000 |
||||
#else |
||||
#if defined(DEFAULT_PLL) |
||||
#define AR5315_AMBA_CLOCK_RATE 40000000 |
||||
#define AR5315_CPU_CLOCK_RATE 40000000 |
||||
#else |
||||
#define AR5315_AMBA_CLOCK_RATE 92000000 |
||||
#define AR5315_CPU_CLOCK_RATE 184000000 |
||||
#endif /* ! DEFAULT_PLL */ |
||||
#endif /* ! COBRA_EMUL */ |
||||
|
||||
#define AR5315_UART_CLOCK_RATE AR5315_AMBA_CLOCK_RATE |
||||
#define AR5315_SDRAM_CLOCK_RATE AR5315_AMBA_CLOCK_RATE |
||||
|
||||
/*
|
||||
* The UART computes baud rate as: |
||||
* baud = clock / (16 * divisor) |
||||
* where divisor is specified as a High Byte (DLM) and a Low Byte (DLL). |
||||
*/ |
||||
#define DESIRED_BAUD_RATE 38400 |
||||
|
||||
|
||||
#define CLOCKCTL_UART0 0x0010 /* enable UART0 external clock */ |
||||
|
||||
|
||||
/*
|
||||
* Applicable "PCICFG" bits for WLAN(s). Assoc status and LED mode. |
||||
*/ |
||||
#define ASSOC_STATUS_M 0x00000003 |
||||
#define ASSOC_STATUS_NONE 0 |
||||
#define ASSOC_STATUS_PENDING 1 |
||||
#define ASSOC_STATUS_ASSOCIATED 2 |
||||
#define LED_MODE_M 0x0000001c |
||||
#define LED_BLINK_THRESHOLD_M 0x000000e0 |
||||
#define LED_SLOW_BLINK_MODE 0x00000100 |
||||
|
||||
/*
|
||||
* GPIO |
||||
*/ |
||||
|
||||
#define AR5315_GPIO_DI (AR5315_DSLBASE + 0x0088) |
||||
#define AR5315_GPIO_DO (AR5315_DSLBASE + 0x0090) |
||||
#define AR5315_GPIO_CR (AR5315_DSLBASE + 0x0098) |
||||
#define AR5315_GPIO_INT (AR5315_DSLBASE + 0x00a0) |
||||
|
||||
#define AR5315_GPIO_CR_M(x) (1 << (x)) /* mask for i/o */ |
||||
#define AR5315_GPIO_CR_O(x) (1 << (x)) /* output */ |
||||
#define AR5315_GPIO_CR_I(x) (0 << (x)) /* input */ |
||||
|
||||
#define AR5315_GPIO_INT_S(x,Y) ((x) << (8 * (Y))) /* interrupt enable */ |
||||
#define AR5315_GPIO_INT_M(Y) ((0x3F) << (8 * (Y))) /* mask for int */ |
||||
#define AR5315_GPIO_INT_LVL(x,Y) ((x) << (8 * (Y) + 6)) /* interrupt level */ |
||||
#define AR5315_GPIO_INT_LVL_M(Y) ((0x3) << (8 * (Y) + 6)) /* mask for int level */ |
||||
|
||||
#define AR5315_RESET_GPIO 5 |
||||
#define AR5315_NUM_GPIO 22 |
||||
|
||||
|
||||
/*
|
||||
* PCI Clock Control |
||||
*/
|
||||
|
||||
#define AR5315_PCICLK (AR5315_DSLBASE + 0x00a4) |
||||
|
||||
#define PCICLK_INPUT_M 0x3 |
||||
#define PCICLK_INPUT_S 0 |
||||
|
||||
#define PCICLK_PLLC_CLKM 0 |
||||
#define PCICLK_PLLC_CLKM1 1 |
||||
#define PCICLK_PLLC_CLKC 2 |
||||
#define PCICLK_REF_CLK 3 |
||||
|
||||
#define PCICLK_DIV_M 0xc |
||||
#define PCICLK_DIV_S 2 |
||||
|
||||
#define PCICLK_IN_FREQ 0 |
||||
#define PCICLK_IN_FREQ_DIV_6 1 |
||||
#define PCICLK_IN_FREQ_DIV_8 2 |
||||
#define PCICLK_IN_FREQ_DIV_10 3 |
||||
|
||||
/*
|
||||
* Observation Control Register |
||||
*/ |
||||
#define AR5315_OCR (AR5315_DSLBASE + 0x00b0) |
||||
#define OCR_GPIO0_IRIN 0x0040 |
||||
#define OCR_GPIO1_IROUT 0x0080 |
||||
#define OCR_GPIO3_RXCLR 0x0200 |
||||
|
||||
/*
|
||||
* General Clock Control |
||||
*/
|
||||
|
||||
#define AR5315_MISCCLK (AR5315_DSLBASE + 0x00b4) |
||||
#define MISCCLK_PLLBYPASS_EN 0x00000001 |
||||
#define MISCCLK_PROCREFCLK 0x00000002 |
||||
|
||||
/*
|
||||
* SDRAM Controller |
||||
* - No read or write buffers are included. |
||||
*/ |
||||
#define AR5315_MEM_CFG (AR5315_SDRAMCTL + 0x00) |
||||
#define AR5315_MEM_CTRL (AR5315_SDRAMCTL + 0x0c) |
||||
#define AR5315_MEM_REF (AR5315_SDRAMCTL + 0x10) |
||||
|
||||
#define SDRAM_DATA_WIDTH_M 0x00006000 |
||||
#define SDRAM_DATA_WIDTH_S 13 |
||||
|
||||
#define SDRAM_COL_WIDTH_M 0x00001E00 |
||||
#define SDRAM_COL_WIDTH_S 9 |
||||
|
||||
#define SDRAM_ROW_WIDTH_M 0x000001E0 |
||||
#define SDRAM_ROW_WIDTH_S 5 |
||||
|
||||
#define SDRAM_BANKADDR_BITS_M 0x00000018 |
||||
#define SDRAM_BANKADDR_BITS_S 3 |
||||
|
||||
/*
|
||||
* SPI Flash Interface Registers |
||||
*/ |
||||
|
||||
#define AR5315_SPI_CTL (AR5315_SPI + 0x00) |
||||
#define AR5315_SPI_OPCODE (AR5315_SPI + 0x04) |
||||
#define AR5315_SPI_DATA (AR5315_SPI + 0x08) |
||||
|
||||
#define SPI_CTL_START 0x00000100 |
||||
#define SPI_CTL_BUSY 0x00010000 |
||||
#define SPI_CTL_TXCNT_MASK 0x0000000f |
||||
#define SPI_CTL_RXCNT_MASK 0x000000f0 |
||||
#define SPI_CTL_TX_RX_CNT_MASK 0x000000ff |
||||
#define SPI_CTL_SIZE_MASK 0x00060000 |
||||
|
||||
#define SPI_CTL_CLK_SEL_MASK 0x03000000 |
||||
#define SPI_OPCODE_MASK 0x000000ff |
||||
|
||||
/*
|
||||
* PCI-MAC Configuration registers
|
||||
*/ |
||||
#define PCI_MAC_RC (AR5315_PCI + 0x4000) |
||||
#define PCI_MAC_SCR (AR5315_PCI + 0x4004) |
||||
#define PCI_MAC_INTPEND (AR5315_PCI + 0x4008) |
||||
#define PCI_MAC_SFR (AR5315_PCI + 0x400C) |
||||
#define PCI_MAC_PCICFG (AR5315_PCI + 0x4010) |
||||
#define PCI_MAC_SREV (AR5315_PCI + 0x4020) |
||||
|
||||
#define PCI_MAC_RC_MAC 0x00000001 |
||||
#define PCI_MAC_RC_BB 0x00000002 |
||||
|
||||
#define PCI_MAC_SCR_SLMODE_M 0x00030000 |
||||
#define PCI_MAC_SCR_SLMODE_S 16 |
||||
#define PCI_MAC_SCR_SLM_FWAKE 0 |
||||
#define PCI_MAC_SCR_SLM_FSLEEP 1 |
||||
#define PCI_MAC_SCR_SLM_NORMAL 2 |
||||
|
||||
#define PCI_MAC_SFR_SLEEP 0x00000001 |
||||
|
||||
#define PCI_MAC_PCICFG_SPWR_DN 0x00010000 |
||||
|
||||
|
||||
/*
|
||||
* PCI Bus Interface Registers |
||||
*/ |
||||
#define AR5315_PCI_1MS_REG (AR5315_PCI + 0x0008) |
||||
#define AR5315_PCI_1MS_MASK 0x3FFFF /* # of AHB clk cycles in 1ms */ |
||||
|
||||
#define AR5315_PCI_MISC_CONFIG (AR5315_PCI + 0x000c) |
||||
#define AR5315_PCIMISC_TXD_EN 0x00000001 /* Enable TXD for fragments */ |
||||
#define AR5315_PCIMISC_CFG_SEL 0x00000002 /* mem or config cycles */ |
||||
#define AR5315_PCIMISC_GIG_MASK 0x0000000C /* bits 31-30 for pci req */ |
||||
#define AR5315_PCIMISC_RST_MODE 0x00000030 |
||||
#define AR5315_PCIRST_INPUT 0x00000000 /* 4:5=0 rst is input */ |
||||
#define AR5315_PCIRST_LOW 0x00000010 /* 4:5=1 rst to GND */ |
||||
#define AR5315_PCIRST_HIGH 0x00000020 /* 4:5=2 rst to VDD */ |
||||
#define AR5315_PCIGRANT_EN 0x00000000 /* 6:7=0 early grant en */ |
||||
#define AR5315_PCIGRANT_FRAME 0x00000040 /* 6:7=1 grant waits 4 frame */ |
||||
#define AR5315_PCIGRANT_IDLE 0x00000080 /* 6:7=2 grant waits 4 idle */ |
||||
#define AR5315_PCIGRANT_GAP 0x00000000 /* 6:7=2 grant waits 4 idle */ |
||||
#define AR5315_PCICACHE_DIS 0x00001000 /* PCI external access cache disable */ |
||||
|
||||
#define AR5315_PCI_OUT_TSTAMP (AR5315_PCI + 0x0010) |
||||
|
||||
#define AR5315_PCI_UNCACHE_CFG (AR5315_PCI + 0x0014) |
||||
|
||||
#define AR5315_PCI_IN_EN (AR5315_PCI + 0x0100) |
||||
#define AR5315_PCI_IN_EN0 0x01 /* Enable chain 0 */ |
||||
#define AR5315_PCI_IN_EN1 0x02 /* Enable chain 1 */ |
||||
#define AR5315_PCI_IN_EN2 0x04 /* Enable chain 2 */ |
||||
#define AR5315_PCI_IN_EN3 0x08 /* Enable chain 3 */ |
||||
|
||||
#define AR5315_PCI_IN_DIS (AR5315_PCI + 0x0104) |
||||
#define AR5315_PCI_IN_DIS0 0x01 /* Disable chain 0 */ |
||||
#define AR5315_PCI_IN_DIS1 0x02 /* Disable chain 1 */ |
||||
#define AR5315_PCI_IN_DIS2 0x04 /* Disable chain 2 */ |
||||
#define AR5315_PCI_IN_DIS3 0x08 /* Disable chain 3 */ |
||||
|
||||
#define AR5315_PCI_IN_PTR (AR5315_PCI + 0x0200) |
||||
|
||||
#define AR5315_PCI_OUT_EN (AR5315_PCI + 0x0400) |
||||
#define AR5315_PCI_OUT_EN0 0x01 /* Enable chain 0 */ |
||||
|
||||
#define AR5315_PCI_OUT_DIS (AR5315_PCI + 0x0404) |
||||
#define AR5315_PCI_OUT_DIS0 0x01 /* Disable chain 0 */ |
||||
|
||||
#define AR5315_PCI_OUT_PTR (AR5315_PCI + 0x0408) |
||||
|
||||
#define AR5315_PCI_INT_STATUS (AR5315_PCI + 0x0500) /* write one to clr */ |
||||
#define AR5315_PCI_TXINT 0x00000001 /* Desc In Completed */ |
||||
#define AR5315_PCI_TXOK 0x00000002 /* Desc In OK */ |
||||
#define AR5315_PCI_TXERR 0x00000004 /* Desc In ERR */ |
||||
#define AR5315_PCI_TXEOL 0x00000008 /* Desc In End-of-List */ |
||||
#define AR5315_PCI_RXINT 0x00000010 /* Desc Out Completed */ |
||||
#define AR5315_PCI_RXOK 0x00000020 /* Desc Out OK */ |
||||
#define AR5315_PCI_RXERR 0x00000040 /* Desc Out ERR */ |
||||
#define AR5315_PCI_RXEOL 0x00000080 /* Desc Out EOL */ |
||||
#define AR5315_PCI_TXOOD 0x00000200 /* Desc In Out-of-Desc */ |
||||
#define AR5315_PCI_MASK 0x0000FFFF /* Desc Mask */ |
||||
#define AR5315_PCI_EXT_INT 0x02000000 |
||||
#define AR5315_PCI_ABORT_INT 0x04000000 |
||||
|
||||
#define AR5315_PCI_INT_MASK (AR5315_PCI + 0x0504) /* same as INT_STATUS */ |
||||
|
||||
#define AR5315_PCI_INTEN_REG (AR5315_PCI + 0x0508) |
||||
#define AR5315_PCI_INT_DISABLE 0x00 /* disable pci interrupts */ |
||||
#define AR5315_PCI_INT_ENABLE 0x01 /* enable pci interrupts */ |
||||
|
||||
#define AR5315_PCI_HOST_IN_EN (AR5315_PCI + 0x0800) |
||||
#define AR5315_PCI_HOST_IN_DIS (AR5315_PCI + 0x0804) |
||||
#define AR5315_PCI_HOST_IN_PTR (AR5315_PCI + 0x0810) |
||||
#define AR5315_PCI_HOST_OUT_EN (AR5315_PCI + 0x0900) |
||||
#define AR5315_PCI_HOST_OUT_DIS (AR5315_PCI + 0x0904) |
||||
#define AR5315_PCI_HOST_OUT_PTR (AR5315_PCI + 0x0908) |
||||
|
||||
|
||||
/*
|
||||
* Local Bus Interface Registers |
||||
*/ |
||||
#define AR5315_LB_CONFIG (AR5315_LOCAL + 0x0000) |
||||
#define AR5315_LBCONF_OE 0x00000001 /* =1 OE is low-true */ |
||||
#define AR5315_LBCONF_CS0 0x00000002 /* =1 first CS is low-true */ |
||||
#define AR5315_LBCONF_CS1 0x00000004 /* =1 2nd CS is low-true */ |
||||
#define AR5315_LBCONF_RDY 0x00000008 /* =1 RDY is low-true */ |
||||
#define AR5315_LBCONF_WE 0x00000010 /* =1 Write En is low-true */ |
||||
#define AR5315_LBCONF_WAIT 0x00000020 /* =1 WAIT is low-true */ |
||||
#define AR5315_LBCONF_ADS 0x00000040 /* =1 Adr Strobe is low-true */ |
||||
#define AR5315_LBCONF_MOT 0x00000080 /* =0 Intel, =1 Motorola */ |
||||
#define AR5315_LBCONF_8CS 0x00000100 /* =1 8 bits CS, 0= 16bits */ |
||||
#define AR5315_LBCONF_8DS 0x00000200 /* =1 8 bits Data S, 0=16bits */ |
||||
#define AR5315_LBCONF_ADS_EN 0x00000400 /* =1 Enable ADS */ |
||||
#define AR5315_LBCONF_ADR_OE 0x00000800 /* =1 Adr cap on OE, WE or DS */ |
||||
#define AR5315_LBCONF_ADDT_MUX 0x00001000 /* =1 Adr and Data share bus */ |
||||
#define AR5315_LBCONF_DATA_OE 0x00002000 /* =1 Data cap on OE, WE, DS */ |
||||
#define AR5315_LBCONF_16DATA 0x00004000 /* =1 Data is 16 bits wide */ |
||||
#define AR5315_LBCONF_SWAPDT 0x00008000 /* =1 Byte swap data */ |
||||
#define AR5315_LBCONF_SYNC 0x00010000 /* =1 Bus synchronous to clk */ |
||||
#define AR5315_LBCONF_INT 0x00020000 /* =1 Intr is low true */ |
||||
#define AR5315_LBCONF_INT_CTR0 0x00000000 /* GND high-Z, Vdd is high-Z */ |
||||
#define AR5315_LBCONF_INT_CTR1 0x00040000 /* GND drive, Vdd is high-Z */ |
||||
#define AR5315_LBCONF_INT_CTR2 0x00080000 /* GND high-Z, Vdd drive */ |
||||
#define AR5315_LBCONF_INT_CTR3 0x000C0000 /* GND drive, Vdd drive */ |
||||
#define AR5315_LBCONF_RDY_WAIT 0x00100000 /* =1 RDY is negative of WAIT */ |
||||
#define AR5315_LBCONF_INT_PULSE 0x00200000 /* =1 Interrupt is a pulse */ |
||||
#define AR5315_LBCONF_ENABLE 0x00400000 /* =1 Falcon respond to LB */ |
||||
|
||||
#define AR5315_LB_CLKSEL (AR5315_LOCAL + 0x0004) |
||||
#define AR5315_LBCLK_EXT 0x0001 /* use external clk for lb */ |
||||
|
||||
#define AR5315_LB_1MS (AR5315_LOCAL + 0x0008) |
||||
#define AR5315_LB1MS_MASK 0x3FFFF /* # of AHB clk cycles in 1ms */ |
||||
|
||||
#define AR5315_LB_MISCCFG (AR5315_LOCAL + 0x000C) |
||||
#define AR5315_LBM_TXD_EN 0x00000001 /* Enable TXD for fragments */ |
||||
#define AR5315_LBM_RX_INTEN 0x00000002 /* Enable LB ints on RX ready */ |
||||
#define AR5315_LBM_MBOXWR_INTEN 0x00000004 /* Enable LB ints on mbox wr */ |
||||
#define AR5315_LBM_MBOXRD_INTEN 0x00000008 /* Enable LB ints on mbox rd */ |
||||
#define AR5315_LMB_DESCSWAP_EN 0x00000010 /* Byte swap desc enable */ |
||||
#define AR5315_LBM_TIMEOUT_MASK 0x00FFFF80 |
||||
#define AR5315_LBM_TIMEOUT_SHFT 7 |
||||
#define AR5315_LBM_PORTMUX 0x07000000 |
||||
|
||||
|
||||
#define AR5315_LB_RXTSOFF (AR5315_LOCAL + 0x0010) |
||||
|
||||
#define AR5315_LB_TX_CHAIN_EN (AR5315_LOCAL + 0x0100) |
||||
#define AR5315_LB_TXEN_0 0x01 |
||||
#define AR5315_LB_TXEN_1 0x02 |
||||
#define AR5315_LB_TXEN_2 0x04 |
||||
#define AR5315_LB_TXEN_3 0x08 |
||||
|
||||
#define AR5315_LB_TX_CHAIN_DIS (AR5315_LOCAL + 0x0104) |
||||
#define AR5315_LB_TX_DESC_PTR (AR5315_LOCAL + 0x0200) |
||||
|
||||
#define AR5315_LB_RX_CHAIN_EN (AR5315_LOCAL + 0x0400) |
||||
#define AR5315_LB_RXEN 0x01 |
||||
|
||||
#define AR5315_LB_RX_CHAIN_DIS (AR5315_LOCAL + 0x0404) |
||||
#define AR5315_LB_RX_DESC_PTR (AR5315_LOCAL + 0x0408) |
||||
|
||||
#define AR5315_LB_INT_STATUS (AR5315_LOCAL + 0x0500) |
||||
#define AR5315_INT_TX_DESC 0x0001 |
||||
#define AR5315_INT_TX_OK 0x0002 |
||||
#define AR5315_INT_TX_ERR 0x0004 |
||||
#define AR5315_INT_TX_EOF 0x0008 |
||||
#define AR5315_INT_RX_DESC 0x0010 |
||||
#define AR5315_INT_RX_OK 0x0020 |
||||
#define AR5315_INT_RX_ERR 0x0040 |
||||
#define AR5315_INT_RX_EOF 0x0080 |
||||
#define AR5315_INT_TX_TRUNC 0x0100 |
||||
#define AR5315_INT_TX_STARVE 0x0200 |
||||
#define AR5315_INT_LB_TIMEOUT 0x0400 |
||||
#define AR5315_INT_LB_ERR 0x0800 |
||||
#define AR5315_INT_MBOX_WR 0x1000 |
||||
#define AR5315_INT_MBOX_RD 0x2000 |
||||
|
||||
/* Bit definitions for INT MASK are the same as INT_STATUS */ |
||||
#define AR5315_LB_INT_MASK (AR5315_LOCAL + 0x0504) |
||||
|
||||
#define AR5315_LB_INT_EN (AR5315_LOCAL + 0x0508) |
||||
#define AR5315_LB_MBOX (AR5315_LOCAL + 0x0600) |
||||
|
||||
|
||||
|
||||
/*
|
||||
* IR Interface Registers |
||||
*/ |
||||
#define AR5315_IR_PKTDATA (AR5315_IR + 0x0000) |
||||
|
||||
#define AR5315_IR_PKTLEN (AR5315_IR + 0x07fc) /* 0 - 63 */ |
||||
|
||||
#define AR5315_IR_CONTROL (AR5315_IR + 0x0800) |
||||
#define AR5315_IRCTL_TX 0x00000000 /* use as tranmitter */ |
||||
#define AR5315_IRCTL_RX 0x00000001 /* use as receiver */ |
||||
#define AR5315_IRCTL_SAMPLECLK_MASK 0x00003ffe /* Sample clk divisor mask */ |
||||
#define AR5315_IRCTL_SAMPLECLK_SHFT 1 |
||||
#define AR5315_IRCTL_OUTPUTCLK_MASK 0x03ffc000 /* Output clk divisor mask */ |
||||
#define AR5315_IRCTL_OUTPUTCLK_SHFT 14 |
||||
|
||||
#define AR5315_IR_STATUS (AR5315_IR + 0x0804) |
||||
#define AR5315_IRSTS_RX 0x00000001 /* receive in progress */ |
||||
#define AR5315_IRSTS_TX 0x00000002 /* transmit in progress */ |
||||
|
||||
#define AR5315_IR_CONFIG (AR5315_IR + 0x0808) |
||||
#define AR5315_IRCFG_INVIN 0x00000001 /* invert input polarity */ |
||||
#define AR5315_IRCFG_INVOUT 0x00000002 /* invert output polarity */ |
||||
#define AR5315_IRCFG_SEQ_START_WIN_SEL 0x00000004 /* 1 => 28, 0 => 7 */ |
||||
#define AR5315_IRCFG_SEQ_START_THRESH 0x000000f0 /* */ |
||||
#define AR5315_IRCFG_SEQ_END_UNIT_SEL 0x00000100 /* */ |
||||
#define AR5315_IRCFG_SEQ_END_UNIT_THRESH 0x00007e00 /* */ |
||||
#define AR5315_IRCFG_SEQ_END_WIN_SEL 0x00008000 /* */ |
||||
#define AR5315_IRCFG_SEQ_END_WIN_THRESH 0x001f0000 /* */ |
||||
#define AR5315_IRCFG_NUM_BACKOFF_WORDS 0x01e00000 /* */ |
||||
|
||||
/*
|
||||
* PCI memory constants: Memory area 1 and 2 are the same size - |
||||
* (twice the PCI_TLB_PAGE_SIZE). The definition of |
||||
* CPU_TO_PCI_MEM_SIZE is coupled with the TLB setup routine |
||||
* sysLib.c/sysTlbInit(), in that it assumes that 2 pages of size |
||||
* PCI_TLB_PAGE_SIZE are set up in the TLB for each PCI memory space. |
||||
*/ |
||||
|
||||
#define CPU_TO_PCI_MEM_BASE1 0xE0000000 |
||||
#define CPU_TO_PCI_MEM_SIZE1 (2*PCI_TLB_PAGE_SIZE) |
||||
|
||||
|
||||
/* TLB attributes for PCI transactions */ |
||||
|
||||
#define PCI_MMU_PAGEMASK 0x00003FFF |
||||
#define MMU_PAGE_UNCACHED 0x00000010 |
||||
#define MMU_PAGE_DIRTY 0x00000004 |
||||
#define MMU_PAGE_VALID 0x00000002 |
||||
#define MMU_PAGE_GLOBAL 0x00000001 |
||||
#define PCI_MMU_PAGEATTRIB (MMU_PAGE_UNCACHED|MMU_PAGE_DIRTY|\ |
||||
MMU_PAGE_VALID|MMU_PAGE_GLOBAL) |
||||
#define PCI_MEMORY_SPACE1_VIRT 0xE0000000 /* Used for non-prefet mem */ |
||||
#define PCI_MEMORY_SPACE1_PHYS 0x80000000 |
||||
#define PCI_TLB_PAGE_SIZE 0x01000000 |
||||
#define TLB_HI_MASK 0xFFFFE000 |
||||
#define TLB_LO_MASK 0x3FFFFFFF |
||||
#define PAGEMASK_SHIFT 11 |
||||
#define TLB_LO_SHIFT 6 |
||||
|
||||
#define PCI_MAX_LATENCY 0xFFF /* Max PCI latency */ |
||||
|
||||
#define HOST_PCI_DEV_ID 3 |
||||
#define HOST_PCI_MBAR0 0x10000000 |
||||
#define HOST_PCI_MBAR1 0x20000000 |
||||
#define HOST_PCI_MBAR2 0x30000000 |
||||
|
||||
#define HOST_PCI_SDRAM_BASEADDR HOST_PCI_MBAR1 |
||||
#define PCI_DEVICE_MEM_SPACE 0x800000 |
||||
|
||||
#endif |
||||
|
@ -0,0 +1,106 @@ |
||||
#ifndef __AR531X_H |
||||
#define __AR531X_H |
||||
|
||||
#include <ar531x_platform.h> |
||||
#include "ar5312.h" |
||||
#include "ar5315.h" |
||||
|
||||
#define MIPS_CPU_IRQ_BASE 0x00 |
||||
#define AR531X_HIGH_PRIO 0x10 |
||||
#define AR531X_MISC_IRQ_BASE 0x20 |
||||
#define AR531X_GPIO_IRQ_BASE 0x30 |
||||
|
||||
/* Software's idea of interrupts handled by "CPU Interrupt Controller" */ |
||||
#define AR531X_IRQ_NONE MIPS_CPU_IRQ_BASE+0 |
||||
#define AR531X_IRQ_CPU_CLOCK MIPS_CPU_IRQ_BASE+7 /* C0_CAUSE: 0x8000 */ |
||||
|
||||
/* Miscellaneous interrupts, which share IP6 */ |
||||
#define AR531X_MISC_IRQ_NONE AR531X_MISC_IRQ_BASE+0 |
||||
#define AR531X_MISC_IRQ_TIMER AR531X_MISC_IRQ_BASE+1 |
||||
#define AR531X_MISC_IRQ_AHB_PROC AR531X_MISC_IRQ_BASE+2 |
||||
#define AR531X_MISC_IRQ_AHB_DMA AR531X_MISC_IRQ_BASE+3 |
||||
#define AR531X_MISC_IRQ_GPIO AR531X_MISC_IRQ_BASE+4 |
||||
#define AR531X_MISC_IRQ_UART0 AR531X_MISC_IRQ_BASE+5 |
||||
#define AR531X_MISC_IRQ_UART0_DMA AR531X_MISC_IRQ_BASE+6 |
||||
#define AR531X_MISC_IRQ_WATCHDOG AR531X_MISC_IRQ_BASE+7 |
||||
#define AR531X_MISC_IRQ_LOCAL AR531X_MISC_IRQ_BASE+8 |
||||
#define AR531X_MISC_IRQ_COUNT 9 |
||||
|
||||
/* GPIO Interrupts [0..7], share AR531X_MISC_IRQ_GPIO */ |
||||
#define AR531X_GPIO_IRQ_NONE AR531X_MISC_IRQ_BASE+0 |
||||
#define AR531X_GPIO_IRQ(n) AR531X_MISC_IRQ_BASE+(n)+1 |
||||
#define AR531X_GPIO_IRQ_COUNT 22 |
||||
|
||||
#define sysRegRead(phys) \ |
||||
(*(volatile u32 *)KSEG1ADDR(phys)) |
||||
|
||||
#define sysRegWrite(phys, val) \ |
||||
((*(volatile u32 *)KSEG1ADDR(phys)) = (val)) |
||||
|
||||
/*
|
||||
* This is board-specific data that is stored in a "fixed" location in flash. |
||||
* It is shared across operating systems, so it should not be changed lightly. |
||||
* The main reason we need it is in order to extract the ethernet MAC |
||||
* address(es). |
||||
*/ |
||||
struct ar531x_boarddata { |
||||
u32 magic; /* board data is valid */ |
||||
#define AR531X_BD_MAGIC 0x35333131 /* "5311", for all 531x platforms */ |
||||
u16 cksum; /* checksum (starting with BD_REV 2) */ |
||||
u16 rev; /* revision of this struct */ |
||||
#define BD_REV 4 |
||||
char boardName[64]; /* Name of board */ |
||||
u16 major; /* Board major number */ |
||||
u16 minor; /* Board minor number */ |
||||
u32 config; /* Board configuration */ |
||||
#define BD_ENET0 0x00000001 /* ENET0 is stuffed */ |
||||
#define BD_ENET1 0x00000002 /* ENET1 is stuffed */ |
||||
#define BD_UART1 0x00000004 /* UART1 is stuffed */ |
||||
#define BD_UART0 0x00000008 /* UART0 is stuffed (dma) */ |
||||
#define BD_RSTFACTORY 0x00000010 /* Reset factory defaults stuffed */ |
||||
#define BD_SYSLED 0x00000020 /* System LED stuffed */ |
||||
#define BD_EXTUARTCLK 0x00000040 /* External UART clock */ |
||||
#define BD_CPUFREQ 0x00000080 /* cpu freq is valid in nvram */ |
||||
#define BD_SYSFREQ 0x00000100 /* sys freq is set in nvram */ |
||||
#define BD_WLAN0 0x00000200 /* Enable WLAN0 */ |
||||
#define BD_MEMCAP 0x00000400 /* CAP SDRAM @ memCap for testing */ |
||||
#define BD_DISWATCHDOG 0x00000800 /* disable system watchdog */ |
||||
#define BD_WLAN1 0x00001000 /* Enable WLAN1 (ar5212) */ |
||||
#define BD_ISCASPER 0x00002000 /* FLAG for AR2312 */ |
||||
#define BD_WLAN0_2G_EN 0x00004000 /* FLAG for radio0_2G */ |
||||
#define BD_WLAN0_5G_EN 0x00008000 /* FLAG for radio0_2G */ |
||||
#define BD_WLAN1_2G_EN 0x00020000 /* FLAG for radio0_2G */ |
||||
#define BD_WLAN1_5G_EN 0x00040000 /* FLAG for radio0_2G */ |
||||
u16 resetConfigGpio; /* Reset factory GPIO pin */ |
||||
u16 sysLedGpio; /* System LED GPIO pin */ |
||||
|
||||
u32 cpuFreq; /* CPU core frequency in Hz */ |
||||
u32 sysFreq; /* System frequency in Hz */ |
||||
u32 cntFreq; /* Calculated C0_COUNT frequency */ |
||||
|
||||
u8 wlan0Mac[6]; |
||||
u8 enet0Mac[6]; |
||||
u8 enet1Mac[6]; |
||||
|
||||
u16 pciId; /* Pseudo PCIID for common code */ |
||||
u16 memCap; /* cap bank1 in MB */ |
||||
|
||||
/* version 3 */ |
||||
u8 wlan1Mac[6]; /* (ar5212) */ |
||||
}; |
||||
|
||||
|
||||
extern char *board_config; |
||||
extern char *radio_config; |
||||
extern void serial_setup(unsigned long mapbase, unsigned int uartclk); |
||||
extern int ar531x_find_config(char *flash_limit); |
||||
|
||||
extern void ar5312_misc_intr_init(int irq_base); |
||||
extern void ar5312_irq_dispatch(void); |
||||
extern void ar5312_plat_setup(void); |
||||
|
||||
extern void ar5315_misc_intr_init(int irq_base); |
||||
extern asmlinkage void ar5315_irq_dispatch(void); |
||||
extern void ar5315_plat_setup(void); |
||||
|
||||
#endif |
@ -0,0 +1,190 @@ |
||||
/*
|
||||
* 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 <asm/bootinfo.h> |
||||
#include <asm/io.h> |
||||
#include "ar531x.h" |
||||
|
||||
char *board_config, *radio_config; |
||||
|
||||
static u8 *find_board_config(char *flash_limit) |
||||
{ |
||||
char *addr; |
||||
int found = 0; |
||||
|
||||
for (addr = (char *) (flash_limit - 0x1000); |
||||
addr >= (char *) (flash_limit - 0x30000); |
||||
addr -= 0x1000) { |
||||
|
||||
if ( *(int *)addr == 0x35333131) { |
||||
/* config magic found */ |
||||
found = 1; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (!found) { |
||||
printk("WARNING: No board configuration data found!\n"); |
||||
addr = NULL; |
||||
} |
||||
|
||||
return addr; |
||||
} |
||||
|
||||
static u8 *find_radio_config(char *flash_limit, char *board_config) |
||||
{ |
||||
int dataFound; |
||||
u32 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 = (u32) board_config + 0x1000; |
||||
(radio_config < (u32) flash_limit); |
||||
radio_config += 0x1000) { |
||||
if (*(int *)radio_config != 0xffffffff) { |
||||
dataFound = 1; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
#ifdef CONFIG_ATHEROS_AR5315 |
||||
if (!dataFound) { /* AR2316 relocates radio config to new location */ |
||||
for (radio_config = (u32) board_config + 0xf8; |
||||
(radio_config < (u32) flash_limit - 0x1000 + 0xf8); |
||||
radio_config += 0x1000) { |
||||
if (*(int *)radio_config != 0xffffffff) { |
||||
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) |
||||
{ |
||||
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); |
||||
if (!bcfg) |
||||
return -ENODEV; |
||||
|
||||
board_config = kmalloc(0x1000, GFP_KERNEL); |
||||
memcpy(board_config, bcfg, 0x100); |
||||
|
||||
/* Radio config starts 0x100 bytes after board config, regardless
|
||||
* of what the physical layout on the flash chip looks like */ |
||||
|
||||
rcfg = find_radio_config(flash_limit, bcfg); |
||||
if (!rcfg) |
||||
return -ENODEV; |
||||
|
||||
printk("Radio config found at offset 0x%x\n", rcfg - bcfg); |
||||
radio_config = board_config + 0x100 + ((rcfg - bcfg) & 0xfff); |
||||
rcfg_size = 0x1000 - ((rcfg - bcfg) & 0xfff); |
||||
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) |
||||
{ |
||||
switch(mips_machtype) { |
||||
#ifdef CONFIG_ATHEROS_AR5312 |
||||
case MACH_ATHEROS_AR5312: |
||||
ar5312_plat_setup(); |
||||
break; |
||||
#endif |
||||
#ifdef CONFIG_ATHEROS_AR5315 |
||||
case MACH_ATHEROS_AR5315: |
||||
ar5315_plat_setup(); |
||||
break; |
||||
#endif |
||||
} |
||||
|
||||
/* 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\n"; |
||||
#endif |
||||
#ifdef CONFIG_ATHEROS_AR5315 |
||||
case MACH_ATHEROS_AR5315: |
||||
return "Atheros AR5315\n"; |
||||
#endif |
||||
} |
||||
return "Atheros (unknown)"; |
||||
} |
||||
|
||||
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); |
||||
} |
||||
|
||||
|
@ -0,0 +1,98 @@ |
||||
/*
|
||||
* 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> |
||||
*/ |
||||
|
||||
/*
|
||||
* Interrupt support for AR531X WiSOC. |
||||
*/ |
||||
|
||||
#include <linux/autoconf.h> |
||||
#include <linux/init.h> |
||||
#include <linux/kernel_stat.h> |
||||
#include <linux/signal.h> |
||||
#include <linux/sched.h> |
||||
#include <linux/interrupt.h> |
||||
#include <linux/slab.h> |
||||
#include <linux/random.h> |
||||
#include <linux/pm.h> |
||||
#include <linux/delay.h> |
||||
#include <linux/reboot.h> |
||||
#include <linux/irq.h> |
||||
#include <asm/bootinfo.h> |
||||
#include <asm/mipsregs.h> |
||||
#include <asm/irq_cpu.h> |
||||
#include "ar531x.h" |
||||
|
||||
|
||||
/* ARGSUSED */ |
||||
irqreturn_t |
||||
spurious_irq_handler(int cpl, void *dev_id) |
||||
{ |
||||
/*
|
||||
printk("spurious_irq_handler: %d cause=0x%8.8x status=0x%8.8x\n", |
||||
cpl, cause_intrs, status_intrs);
|
||||
*/ |
||||
return IRQ_NONE; |
||||
} |
||||
|
||||
/* ARGSUSED */ |
||||
irqreturn_t |
||||
spurious_misc_handler(int cpl, void *dev_id) |
||||
{ |
||||
/*
|
||||
printk("spurious_misc_handler: 0x%x isr=0x%8.8x imr=0x%8.8x\n", |
||||
cpl, ar531x_isr, ar531x_imr); |
||||
*/ |
||||
return IRQ_NONE; |
||||
} |
||||
|
||||
static struct irqaction spurious_irq = { |
||||
.handler = spurious_irq_handler, |
||||
.flags = SA_INTERRUPT, |
||||
.name = "spurious_irq", |
||||
}; |
||||
|
||||
static struct irqaction spurious_misc = { |
||||
.handler = spurious_misc_handler, |
||||
.flags = SA_INTERRUPT, |
||||
.name = "spurious_misc", |
||||
}; |
||||
|
||||
asmlinkage void plat_irq_dispatch(void) |
||||
{ |
||||
#ifdef CONFIG_ATHEROS_AR5312 |
||||
if (mips_machtype == MACH_ATHEROS_AR5312) |
||||
ar5312_irq_dispatch(); |
||||
#endif |
||||
#ifdef CONFIG_ATHEROS_AR5315 |
||||
if (mips_machtype == MACH_ATHEROS_AR5315) |
||||
ar5315_irq_dispatch(); |
||||
#endif |
||||
} |
||||
|
||||
void __init arch_init_irq(void) |
||||
{ |
||||
clear_c0_status(ST0_IM); |
||||
mips_cpu_irq_init(0); |
||||
|
||||
/* Initialize interrupt controllers */ |
||||
#ifdef CONFIG_ATHEROS_AR5312 |
||||
if (mips_machtype == MACH_ATHEROS_AR5312) |
||||
ar5312_misc_intr_init(AR531X_MISC_IRQ_BASE); |
||||
#endif |
||||
#ifdef CONFIG_ATHEROS_AR5315 |
||||
if (mips_machtype == MACH_ATHEROS_AR5315) |
||||
ar5315_misc_intr_init(AR531X_MISC_IRQ_BASE); |
||||
#endif |
||||
|
||||
/* Default "spurious interrupt" handlers */ |
||||
setup_irq(AR531X_IRQ_NONE, &spurious_irq); |
||||
setup_irq(AR531X_MISC_IRQ_NONE, &spurious_misc); |
||||
} |
@ -0,0 +1,67 @@ |
||||
/*
|
||||
* 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) |
||||
{ |
||||
u32 memsize, memcfg; |
||||
|
||||
mips_machgroup = MACH_GROUP_ATHEROS; |
||||
mips_machtype = -1; |
||||
|
||||
/*
|
||||
* Atheros CPUs before the AR2315 are using MIPS 4Kc core, later designs are |
||||
* using MIPS 4KEc R2 core. This makes it easy to determine the board at runtime. |
||||
*/ |
||||
|
||||
if (current_cpu_data.cputype == CPU_4KEC) { |
||||
mips_machtype = MACH_ATHEROS_AR5315; |
||||
|
||||
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; |
||||
} else { |
||||
int bank0AC, bank1AC; |
||||
|
||||
mips_machtype = MACH_ATHEROS_AR5312; |
||||
|
||||
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); |
||||
strcpy(arcs_cmdline, "console=ttyS0,9600 rootfstype=squashfs,jffs2"); |
||||
} |
||||
|
||||
void __init prom_free_prom_memory(void) |
||||
{ |
||||
} |
@ -0,0 +1,596 @@ |
||||
|
||||
/*
|
||||
* MTD driver for the SPI Flash Memory support. |
||||
* |
||||
* Copyright (c) 2005-2006 Atheros Communications Inc. |
||||
* Copyright (C) 2006 FON Technology, SL. |
||||
* Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org> |
||||
* Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> |
||||
* |
||||
* This code 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. |
||||
* |
||||
*/ |
||||
|
||||
/*===========================================================================
|
||||
** !!!! VERY IMPORTANT NOTICE !!!! FLASH DATA STORED IN LITTLE ENDIAN FORMAT |
||||
** |
||||
** This module contains the Serial Flash access routines for the Atheros SOC. |
||||
** The Atheros SOC integrates a SPI flash controller that is used to access |
||||
** serial flash parts. The SPI flash controller executes in "Little Endian" |
||||
** mode. THEREFORE, all WRITES and READS from the MIPS CPU must be |
||||
** BYTESWAPPED! The SPI Flash controller hardware by default performs READ |
||||
** ONLY byteswapping when accessed via the SPI Flash Alias memory region |
||||
** (Physical Address 0x0800_0000 - 0x0fff_ffff). The data stored in the |
||||
** flash sectors is stored in "Little Endian" format. |
||||
** |
||||
** The spiflash_write() routine performs byteswapping on all write |
||||
** operations. |
||||
**===========================================================================*/ |
||||
|
||||
#include <linux/kernel.h> |
||||
#include <linux/module.h> |
||||
#include <linux/types.h> |
||||
#include <linux/version.h> |
||||
#include <linux/errno.h> |
||||
#include <linux/slab.h> |
||||
#include <linux/mtd/mtd.h> |
||||
#include <linux/mtd/partitions.h> |
||||
#include <linux/platform_device.h> |
||||
#include <linux/squashfs_fs.h> |
||||
#include <linux/root_dev.h> |
||||
#include <asm/delay.h> |
||||
#include <asm/io.h> |
||||
#include "spiflash.h" |
||||
|
||||
/* debugging */ |
||||
/* #define SPIFLASH_DEBUG */ |
||||
|
||||
#ifndef __BIG_ENDIAN |
||||
#error This driver currently only works with big endian CPU. |
||||
#endif |
||||
|
||||
#define MAX_PARTS 32 |
||||
|
||||
static char module_name[] = "spiflash"; |
||||
|
||||
#define MIN(a,b) ((a) < (b) ? (a) : (b)) |
||||
#define FALSE 0 |
||||
#define TRUE 1 |
||||
|
||||
#define ROOTFS_NAME "rootfs" |
||||
|
||||
static __u32 spiflash_regread32(int reg); |
||||
static void spiflash_regwrite32(int reg, __u32 data); |
||||
static __u32 spiflash_sendcmd (int op); |
||||
|
||||
int __init spiflash_init (void); |
||||
void __exit spiflash_exit (void); |
||||
static int spiflash_probe_chip (void); |
||||
static int spiflash_erase (struct mtd_info *mtd,struct erase_info *instr); |
||||
static int spiflash_read (struct mtd_info *mtd, loff_t from,size_t len,size_t *retlen,u_char *buf); |
||||
static int spiflash_write (struct mtd_info *mtd,loff_t to,size_t len,size_t *retlen,const u_char *buf); |
||||
|
||||
/* Flash configuration table */ |
||||
struct flashconfig { |
||||
__u32 byte_cnt; |
||||
__u32 sector_cnt; |
||||
__u32 sector_size; |
||||
__u32 cs_addrmask; |
||||
} flashconfig_tbl[MAX_FLASH] = |
||||
{ |
||||
{ 0, 0, 0, 0}, |
||||
{ STM_1MB_BYTE_COUNT, STM_1MB_SECTOR_COUNT, STM_1MB_SECTOR_SIZE, 0x0}, |
||||
{ STM_2MB_BYTE_COUNT, STM_2MB_SECTOR_COUNT, STM_2MB_SECTOR_SIZE, 0x0}, |
||||
{ STM_4MB_BYTE_COUNT, STM_4MB_SECTOR_COUNT, STM_4MB_SECTOR_SIZE, 0x0}, |
||||
{ STM_8MB_BYTE_COUNT, STM_8MB_SECTOR_COUNT, STM_8MB_SECTOR_SIZE, 0x0} |
||||
}; |
||||
|
||||
/* Mapping of generic opcodes to STM serial flash opcodes */ |
||||
struct opcodes { |
||||
__u16 code; |
||||
__s8 tx_cnt; |
||||
__s8 rx_cnt; |
||||
} stm_opcodes[] = { |
||||
{STM_OP_WR_ENABLE, 1, 0}, |
||||
{STM_OP_WR_DISABLE, 1, 0}, |
||||
{STM_OP_RD_STATUS, 1, 1}, |
||||
{STM_OP_WR_STATUS, 1, 0}, |
||||
{STM_OP_RD_DATA, 4, 4}, |
||||
{STM_OP_FAST_RD_DATA, 1, 0}, |
||||
{STM_OP_PAGE_PGRM, 8, 0}, |
||||
{STM_OP_SECTOR_ERASE, 4, 0}, |
||||
{STM_OP_BULK_ERASE, 1, 0}, |
||||
{STM_OP_DEEP_PWRDOWN, 1, 0}, |
||||
{STM_OP_RD_SIG, 4, 1} |
||||
}; |
||||
|
||||
/* Driver private data structure */ |
||||
struct spiflash_data { |
||||
struct mtd_info *mtd;
|
||||
struct mtd_partition *parsed_parts; /* parsed partitions */ |
||||
void *spiflash_readaddr; /* memory mapped data for read */ |
||||
void *spiflash_mmraddr; /* memory mapped register space */ |
||||
spinlock_t mutex; |
||||
}; |
||||
|
||||
static struct spiflash_data *spidata; |
||||
|
||||
extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); |
||||
|
||||
/***************************************************************************************************/ |
||||
|
||||
static __u32 |
||||
spiflash_regread32(int reg) |
||||
{ |
||||
volatile __u32 *data = (__u32 *)(spidata->spiflash_mmraddr + reg); |
||||
|
||||
return (*data); |
||||
} |
||||
|
||||
static void
|
||||
spiflash_regwrite32(int reg, __u32 data) |
||||
{ |
||||
volatile __u32 *addr = (__u32 *)(spidata->spiflash_mmraddr + reg); |
||||
|
||||
*addr = data; |
||||
return; |
||||
} |
||||
|
||||
static __u32
|
||||
spiflash_sendcmd (int op) |
||||
{ |
||||
__u32 reg; |
||||
__u32 mask; |
||||
struct opcodes *ptr_opcode; |
||||
|
||||
ptr_opcode = &stm_opcodes[op]; |
||||
|
||||
do { |
||||
reg = spiflash_regread32(SPI_FLASH_CTL); |
||||
} while (reg & SPI_CTL_BUSY); |
||||
|
||||
spiflash_regwrite32(SPI_FLASH_OPCODE, ptr_opcode->code); |
||||
|
||||
reg = (reg & ~SPI_CTL_TX_RX_CNT_MASK) | ptr_opcode->tx_cnt | |
||||
(ptr_opcode->rx_cnt << 4) | SPI_CTL_START; |
||||
|
||||
spiflash_regwrite32(SPI_FLASH_CTL, reg); |
||||
|
||||
if (ptr_opcode->rx_cnt > 0) { |
||||
do { |
||||
reg = spiflash_regread32(SPI_FLASH_CTL); |
||||
} while (reg & SPI_CTL_BUSY); |
||||
|
||||
reg = (__u32) spiflash_regread32(SPI_FLASH_DATA); |
||||
|
||||
switch (ptr_opcode->rx_cnt) { |
||||
case 1: |
||||
mask = 0x000000ff; |
||||
break; |
||||
case 2: |
||||
mask = 0x0000ffff; |
||||
break; |
||||
case 3: |
||||
mask = 0x00ffffff; |
||||
break; |
||||
default: |
||||
mask = 0xffffffff; |
||||
break; |
||||
} |
||||
|
||||
reg &= mask; |
||||
} |
||||
else { |
||||
reg = 0; |
||||
} |
||||
|
||||
return reg; |
||||
} |
||||
|
||||
/* Probe SPI flash device
|
||||
* Function returns 0 for failure. |
||||
* and flashconfig_tbl array index for success. |
||||
*/ |
||||
static int
|
||||
spiflash_probe_chip (void) |
||||
{ |
||||
__u32 sig; |
||||
int flash_size; |
||||
|
||||
/* Read the signature on the flash device */ |
||||
sig = spiflash_sendcmd(SPI_RD_SIG); |
||||
|
||||
switch (sig) { |
||||
case STM_8MBIT_SIGNATURE: |
||||
flash_size = FLASH_1MB; |
||||
break; |
||||
case STM_16MBIT_SIGNATURE: |
||||
flash_size = FLASH_2MB; |
||||
break; |
||||
case STM_32MBIT_SIGNATURE: |
||||
flash_size = FLASH_4MB; |
||||
break; |
||||
case STM_64MBIT_SIGNATURE: |
||||
flash_size = FLASH_8MB; |
||||
break; |
||||
default: |
||||
printk (KERN_WARNING "%s: Read of flash device signature failed!\n", module_name); |
||||
return (0); |
||||
} |
||||
|
||||
return (flash_size); |
||||
} |
||||
|
||||
|
||||
static int
|
||||
spiflash_erase (struct mtd_info *mtd,struct erase_info *instr) |
||||
{ |
||||
struct opcodes *ptr_opcode; |
||||
__u32 temp, reg; |
||||
int finished = FALSE; |
||||
|
||||
#ifdef SPIFLASH_DEBUG |
||||
printk (KERN_DEBUG "%s(addr = 0x%.8x, len = %d)\n",__FUNCTION__,instr->addr,instr->len); |
||||
#endif |
||||
|
||||
/* sanity checks */ |
||||
if (instr->addr + instr->len > mtd->size) return (-EINVAL); |
||||
|
||||
ptr_opcode = &stm_opcodes[SPI_SECTOR_ERASE]; |
||||
|
||||
temp = ((__u32)instr->addr << 8) | (__u32)(ptr_opcode->code); |
||||
spin_lock(&spidata->mutex); |
||||
spiflash_sendcmd(SPI_WRITE_ENABLE); |
||||
do { |
||||
schedule(); |
||||
reg = spiflash_regread32(SPI_FLASH_CTL); |
||||
} while (reg & SPI_CTL_BUSY); |
||||
|
||||
spiflash_regwrite32(SPI_FLASH_OPCODE, temp); |
||||
|
||||
reg = (reg & ~SPI_CTL_TX_RX_CNT_MASK) | ptr_opcode->tx_cnt | SPI_CTL_START; |
||||
spiflash_regwrite32(SPI_FLASH_CTL, reg); |
||||
|
||||
do { |
||||
schedule(); |
||||
reg = spiflash_sendcmd(SPI_RD_STATUS); |
||||
if (!(reg & SPI_STATUS_WIP)) { |
||||
finished = TRUE; |
||||
} |
||||
} while (!finished); |
||||
spin_unlock(&spidata->mutex); |
||||
|
||||
instr->state = MTD_ERASE_DONE; |
||||
if (instr->callback) instr->callback (instr); |
||||
|
||||
#ifdef SPIFLASH_DEBUG |
||||
printk (KERN_DEBUG "%s return\n",__FUNCTION__); |
||||
#endif |
||||
return (0); |
||||
} |
||||
|
||||
static int
|
||||
spiflash_read (struct mtd_info *mtd, loff_t from,size_t len,size_t *retlen,u_char *buf) |
||||
{ |
||||
u_char *read_addr; |
||||
|
||||
#ifdef SPIFLASH_DEBUG |
||||
printk (KERN_DEBUG "%s(from = 0x%.8x, len = %d)\n",__FUNCTION__,(__u32) from,(int)len);
|
||||
#endif |
||||
|
||||
/* sanity checks */ |
||||
if (!len) return (0); |
||||
if (from + len > mtd->size) return (-EINVAL); |
||||
|
||||
|
||||
/* we always read len bytes */ |
||||
*retlen = len; |
||||
|
||||
read_addr = (u_char *)(spidata->spiflash_readaddr + from); |
||||
spin_lock(&spidata->mutex); |
||||
memcpy(buf, read_addr, len); |
||||
spin_unlock(&spidata->mutex); |
||||
|
||||
return (0); |
||||
} |
||||
|
||||
static int
|
||||
spiflash_write (struct mtd_info *mtd,loff_t to,size_t len,size_t *retlen,const u_char *buf) |
||||
{ |
||||
int done = FALSE, page_offset, bytes_left, finished; |
||||
__u32 xact_len, spi_data = 0, opcode, reg; |
||||
|
||||
#ifdef SPIFLASH_DEBUG |
||||
printk (KERN_DEBUG "%s(to = 0x%.8x, len = %d)\n",__FUNCTION__,(__u32) to,len);
|
||||
#endif |
||||
|
||||
*retlen = 0; |
||||
|
||||
/* sanity checks */ |
||||
if (!len) return (0); |
||||
if (to + len > mtd->size) return (-EINVAL); |
||||
|
||||
opcode = stm_opcodes[SPI_PAGE_PROGRAM].code; |
||||
bytes_left = len; |
||||
|
||||
while (done == FALSE) { |
||||
xact_len = MIN(bytes_left, sizeof(__u32)); |
||||
|
||||
/* 32-bit writes cannot span across a page boundary
|
||||
* (256 bytes). This types of writes require two page |
||||
* program operations to handle it correctly. The STM part |
||||
* will write the overflow data to the beginning of the |
||||
* current page as opposed to the subsequent page. |
||||
*/ |
||||
page_offset = (to & (STM_PAGE_SIZE - 1)) + xact_len; |
||||
|
||||
if (page_offset > STM_PAGE_SIZE) { |
||||
xact_len -= (page_offset - STM_PAGE_SIZE); |
||||
} |
||||
|
||||
spin_lock(&spidata->mutex); |
||||
spiflash_sendcmd(SPI_WRITE_ENABLE); |
||||
|
||||
do { |
||||
schedule(); |
||||
reg = spiflash_regread32(SPI_FLASH_CTL); |
||||
} while (reg & SPI_CTL_BUSY); |
||||
|
||||
switch (xact_len) { |
||||
case 1: |
||||
spi_data = (u32) ((u8) *buf); |
||||
break; |
||||
case 2: |
||||
spi_data = (buf[1] << 8) | buf[0]; |
||||
break; |
||||
case 3: |
||||
spi_data = (buf[2] << 16) | (buf[1] << 8) | buf[0]; |
||||
break; |
||||
case 4: |
||||
spi_data = (buf[3] << 24) | (buf[2] << 16) |
|
||||
(buf[1] << 8) | buf[0]; |
||||
break; |
||||
default: |
||||
printk("spiflash_write: default case\n"); |
||||
break; |
||||
} |
||||
|
||||
spiflash_regwrite32(SPI_FLASH_DATA, spi_data); |
||||
opcode = (opcode & SPI_OPCODE_MASK) | ((__u32)to << 8); |
||||
spiflash_regwrite32(SPI_FLASH_OPCODE, opcode); |
||||
|
||||
reg = (reg & ~SPI_CTL_TX_RX_CNT_MASK) | (xact_len + 4) | SPI_CTL_START; |
||||
spiflash_regwrite32(SPI_FLASH_CTL, reg); |
||||
finished = FALSE; |
||||
|
||||
do { |
||||
schedule(); |
||||
reg = spiflash_sendcmd(SPI_RD_STATUS); |
||||
if (!(reg & SPI_STATUS_WIP)) { |
||||
finished = TRUE; |
||||
} |
||||
} while (!finished); |
||||
spin_unlock(&spidata->mutex); |
||||
|
||||
bytes_left -= xact_len; |
||||
to += xact_len; |
||||
buf += xact_len; |
||||
|
||||
*retlen += xact_len; |
||||
|
||||
if (bytes_left == 0) { |
||||
done = TRUE; |
||||
} |
||||
} |
||||
|
||||
return (0); |
||||
} |
||||
|
||||
|
||||
#ifdef CONFIG_MTD_PARTITIONS |
||||
static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL }; |
||||
#endif |
||||
|
||||
|
||||
static int spiflash_probe(struct platform_device *pdev) |
||||
{ |
||||
int result = -1, i, j; |
||||
u32 len; |
||||
int index, num_parts; |
||||
struct mtd_info *mtd; |
||||
struct mtd_partition *mtd_parts; |
||||
char *buf; |
||||
struct mtd_partition *part; |
||||
struct squashfs_super_block *sb; |
||||
u32 config_start; |
||||
|
||||
spidata->spiflash_mmraddr = ioremap_nocache(SPI_FLASH_MMR, SPI_FLASH_MMR_SIZE); |
||||
|
||||
if (!spidata->spiflash_mmraddr) { |
||||
printk (KERN_WARNING "%s: Failed to map flash device\n", module_name); |
||||
kfree(spidata); |
||||
spidata = NULL; |
||||
} |
||||
|
||||
mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL); |
||||
if (!mtd) { |
||||
kfree(spidata); |
||||
return (-ENXIO); |
||||
} |
||||
|
||||
printk ("MTD driver for SPI flash.\n"); |
||||
printk ("%s: Probing for Serial flash ...\n", module_name); |
||||
if (!(index = spiflash_probe_chip())) { |
||||
printk (KERN_WARNING "%s: Found no serial flash device\n", module_name); |
||||
kfree(mtd); |
||||
kfree(spidata); |
||||
return (-ENXIO); |
||||
} |
||||
|
||||
printk ("%s: Found SPI serial Flash.\n", module_name); |
||||
|
||||
spidata->spiflash_readaddr = ioremap_nocache(SPI_FLASH_READ, flashconfig_tbl[index].byte_cnt); |
||||
if (!spidata->spiflash_readaddr) { |
||||
printk (KERN_WARNING "%s: Failed to map flash device\n", module_name); |
||||
kfree(mtd); |
||||
kfree(spidata); |
||||
return (-ENXIO); |
||||
} |
||||
|
||||
mtd->name = module_name; |
||||
mtd->type = MTD_NORFLASH; |
||||
mtd->flags = (MTD_CAP_NORFLASH|MTD_WRITEABLE); |
||||
mtd->size = flashconfig_tbl[index].byte_cnt; |
||||
mtd->erasesize = flashconfig_tbl[index].sector_size; |
||||
mtd->writesize = 1; |
||||
mtd->numeraseregions = 0; |
||||
mtd->eraseregions = NULL; |
||||
mtd->erase = spiflash_erase; |
||||
mtd->read = spiflash_read; |
||||
mtd->write = spiflash_write; |
||||
mtd->owner = THIS_MODULE; |
||||
|
||||
#ifdef SPIFLASH_DEBUG |
||||
printk (KERN_DEBUG |
||||
"mtd->name = %s\n" |
||||
"mtd->size = 0x%.8x (%uM)\n" |
||||
"mtd->erasesize = 0x%.8x (%uK)\n" |
||||
"mtd->numeraseregions = %d\n", |
||||
mtd->name, |
||||
mtd->size, mtd->size / (1024*1024), |
||||
mtd->erasesize, mtd->erasesize / 1024, |
||||
mtd->numeraseregions); |
||||
|
||||
if (mtd->numeraseregions) { |
||||
for (result = 0; result < mtd->numeraseregions; result++) { |
||||
printk (KERN_DEBUG |
||||
"\n\n" |
||||
"mtd->eraseregions[%d].offset = 0x%.8x\n" |
||||
"mtd->eraseregions[%d].erasesize = 0x%.8x (%uK)\n" |
||||
"mtd->eraseregions[%d].numblocks = %d\n", |
||||
result,mtd->eraseregions[result].offset, |
||||
result,mtd->eraseregions[result].erasesize,mtd->eraseregions[result].erasesize / 1024, |
||||
result,mtd->eraseregions[result].numblocks); |
||||
} |
||||
} |
||||
#endif |
||||
|
||||
/* parse redboot partitions */ |
||||
num_parts = parse_mtd_partitions(mtd, part_probe_types, &spidata->parsed_parts, 0); |
||||
|
||||
mtd_parts = kzalloc(sizeof(struct mtd_partition) * MAX_PARTS, GFP_KERNEL); |
||||
buf = kmalloc(mtd->erasesize, GFP_KERNEL); |
||||
sb = (struct squashfs_super_block *) buf; |
||||
for (i = j = 0; i < num_parts; i++, j++) { |
||||
part = &mtd_parts[j]; |
||||
memcpy(part, &spidata->parsed_parts[i], sizeof(struct mtd_partition)); |
||||
|
||||
if (!strcmp(part->name, ROOTFS_NAME)) { |
||||
/* create the root device */ |
||||
ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, i); |
||||
|
||||
part->size -= mtd->erasesize; |
||||
config_start = part->offset + part->size; |
||||
|
||||
while ((mtd->read(mtd, part->offset, mtd->erasesize, &len, buf) == 0) && |
||||
(len == mtd->erasesize) && |
||||
(*((u32 *) buf) == SQUASHFS_MAGIC) && |
||||
(sb->bytes_used > 0)) { |
||||
|
||||
/* this is squashfs, allocate another partition starting from the end of filesystem data */ |
||||
memcpy(&mtd_parts[j + 1], part, sizeof(struct mtd_partition)); |
||||
|
||||
len = (u32) sb->bytes_used; |
||||
len += (part->offset & 0x000fffff); |
||||
len += (mtd->erasesize - 1); |
||||
len &= ~(mtd->erasesize - 1); |
||||
len -= (part->offset & 0x000fffff); |
||||
|
||||
if (len + mtd->erasesize > part->size) |
||||
break; |
||||
|
||||
part = &mtd_parts[++j]; |
||||
|
||||
part->offset += len; |
||||
part->size -= len; |
||||
|
||||
part->name = kmalloc(10, GFP_KERNEL); |
||||
sprintf(part->name, "rootfs%d", j - i); |
||||
} |
||||
} |
||||
if (!strcmp(part->name, "RedBoot config")) { |
||||
/* add anoterh partition for the board config data */ |
||||
memcpy(&mtd_parts[j + 1], part, sizeof(struct mtd_partition)); |
||||
j++; |
||||
part = &mtd_parts[j]; |
||||
part->offset += part->size; |
||||
part->size = mtd->erasesize; |
||||
|
||||
part->name = kmalloc(16, GFP_KERNEL); |
||||
sprintf(part->name, "board_config"); |
||||
} |
||||
} |
||||
num_parts += j - i; |
||||
kfree(buf); |
||||
|
||||
#ifdef SPIFLASH_DEBUG |
||||
printk (KERN_DEBUG "Found %d redboot partitions\n", num_parts); |
||||
#endif |
||||
if (num_parts) { |
||||
result = add_mtd_partitions(mtd, mtd_parts, num_parts); |
||||
} else { |
||||
#ifdef SPIFLASH_DEBUG |
||||
printk (KERN_DEBUG "Did not find any redboot partitions\n"); |
||||
#endif |
||||
kfree(mtd); |
||||
kfree(spidata); |
||||
return (-ENXIO); |
||||
} |
||||
|
||||
spidata->mtd = mtd; |
||||
|
||||
return (result); |
||||
} |
||||
|
||||
static int spiflash_remove (struct platform_device *pdev) |
||||
{ |
||||
del_mtd_partitions (spidata->mtd); |
||||
kfree(spidata->mtd); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
struct platform_driver spiflash_driver = { |
||||
.driver.name = "spiflash", |
||||
.probe = spiflash_probe, |
||||
.remove = spiflash_remove, |
||||
}; |
||||
|
||||
int __init
|
||||
spiflash_init (void) |
||||
{ |
||||
spidata = kmalloc(sizeof(struct spiflash_data), GFP_KERNEL); |
||||
if (!spidata) |
||||
return (-ENXIO); |
||||
|
||||
spin_lock_init(&spidata->mutex); |
||||
platform_driver_register(&spiflash_driver); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
void __exit
|
||||
spiflash_exit (void) |
||||
{ |
||||
kfree(spidata); |
||||
} |
||||
|
||||
module_init (spiflash_init); |
||||
module_exit (spiflash_exit); |
||||
|
||||
MODULE_LICENSE("GPL"); |
||||
MODULE_AUTHOR("Atheros Communications Inc"); |
||||
MODULE_DESCRIPTION("MTD driver for SPI Flash on Atheros SOC"); |
||||
|
@ -0,0 +1,124 @@ |
||||
/*
|
||||
* SPI Flash Memory support header file. |
||||
* |
||||
* $Id: //depot/sw/releases/linuxsrc/src/kernels/mips-linux-2.4.25/drivers/mtd/devices/spiflash.h#3 $
|
||||
* |
||||
* |
||||
* Copyright (c) 2005, Atheros Communications Inc. |
||||
* Copyright (C) 2006 FON Technology, SL. |
||||
* Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org> |
||||
* |
||||
* This code 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. |
||||
* |
||||
*/ |
||||
#define FLASH_1MB 1 |
||||
#define FLASH_2MB 2 |
||||
#define FLASH_4MB 3 |
||||
#define FLASH_8MB 4 |
||||
#define MAX_FLASH 5 |
||||
|
||||
#define STM_PAGE_SIZE 256 |
||||
|
||||
#define SPI_WRITE_ENABLE 0 |
||||
#define SPI_WRITE_DISABLE 1 |
||||
#define SPI_RD_STATUS 2 |
||||
#define SPI_WR_STATUS 3 |
||||
#define SPI_RD_DATA 4 |
||||
#define SPI_FAST_RD_DATA 5 |
||||
#define SPI_PAGE_PROGRAM 6 |
||||
#define SPI_SECTOR_ERASE 7 |
||||
#define SPI_BULK_ERASE 8 |
||||
#define SPI_DEEP_PWRDOWN 9 |
||||
#define SPI_RD_SIG 10 |
||||
#define SPI_MAX_OPCODES 11 |
||||
|
||||
#define SFI_WRITE_BUFFER_SIZE 4 |
||||
#define SFI_FLASH_ADDR_MASK 0x00ffffff |
||||
|
||||
#define STM_8MBIT_SIGNATURE 0x13 |
||||
#define STM_M25P80_BYTE_COUNT 1048576 |
||||
#define STM_M25P80_SECTOR_COUNT 16 |
||||
#define STM_M25P80_SECTOR_SIZE 0x10000 |
||||
|
||||
#define STM_16MBIT_SIGNATURE 0x14 |
||||
#define STM_M25P16_BYTE_COUNT 2097152 |
||||
#define STM_M25P16_SECTOR_COUNT 32 |
||||
#define STM_M25P16_SECTOR_SIZE 0x10000 |
||||
|
||||
#define STM_32MBIT_SIGNATURE 0x15 |
||||
#define STM_M25P32_BYTE_COUNT 4194304 |
||||
#define STM_M25P32_SECTOR_COUNT 64 |
||||
#define STM_M25P32_SECTOR_SIZE 0x10000 |
||||
|
||||
#define STM_64MBIT_SIGNATURE 0x16 |
||||
#define STM_M25P64_BYTE_COUNT 8388608 |
||||
#define STM_M25P64_SECTOR_COUNT 128 |
||||
#define STM_M25P64_SECTOR_SIZE 0x10000 |
||||
|
||||
#define STM_1MB_BYTE_COUNT STM_M25P80_BYTE_COUNT |
||||
#define STM_1MB_SECTOR_COUNT STM_M25P80_SECTOR_COUNT |
||||
#define STM_1MB_SECTOR_SIZE STM_M25P80_SECTOR_SIZE |
||||
#define STM_2MB_BYTE_COUNT STM_M25P16_BYTE_COUNT |
||||
#define STM_2MB_SECTOR_COUNT STM_M25P16_SECTOR_COUNT |
||||
#define STM_2MB_SECTOR_SIZE STM_M25P16_SECTOR_SIZE |
||||
#define STM_4MB_BYTE_COUNT STM_M25P32_BYTE_COUNT |
||||
#define STM_4MB_SECTOR_COUNT STM_M25P32_SECTOR_COUNT |
||||
#define STM_4MB_SECTOR_SIZE STM_M25P32_SECTOR_SIZE |
||||
#define STM_8MB_BYTE_COUNT STM_M25P64_BYTE_COUNT |
||||
#define STM_8MB_SECTOR_COUNT STM_M25P64_SECTOR_COUNT |
||||
#define STM_8MB_SECTOR_SIZE STM_M25P64_SECTOR_SIZE |
||||
|
||||
/*
|
||||
* ST Microelectronics Opcodes for Serial Flash |
||||
*/ |
||||
|
||||
#define STM_OP_WR_ENABLE 0x06 /* Write Enable */ |
||||
#define STM_OP_WR_DISABLE 0x04 /* Write Disable */ |
||||
#define STM_OP_RD_STATUS 0x05 /* Read Status */ |
||||
#define STM_OP_WR_STATUS 0x01 /* Write Status */ |
||||
#define STM_OP_RD_DATA 0x03 /* Read Data */ |
||||
#define STM_OP_FAST_RD_DATA 0x0b /* Fast Read Data */ |
||||
#define STM_OP_PAGE_PGRM 0x02 /* Page Program */ |
||||
#define STM_OP_SECTOR_ERASE 0xd8 /* Sector Erase */ |
||||
#define STM_OP_BULK_ERASE 0xc7 /* Bulk Erase */ |
||||
#define STM_OP_DEEP_PWRDOWN 0xb9 /* Deep Power-Down Mode */ |
||||
#define STM_OP_RD_SIG 0xab /* Read Electronic Signature */ |
||||
|
||||
#define STM_STATUS_WIP 0x01 /* Write-In-Progress */ |
||||
#define STM_STATUS_WEL 0x02 /* Write Enable Latch */ |
||||
#define STM_STATUS_BP0 0x04 /* Block Protect 0 */ |
||||
#define STM_STATUS_BP1 0x08 /* Block Protect 1 */ |
||||
#define STM_STATUS_BP2 0x10 /* Block Protect 2 */ |
||||
#define STM_STATUS_SRWD 0x80 /* Status Register Write Disable */ |
||||
|
||||
/*
|
||||
* SPI Flash Interface Registers |
||||
*/ |
||||
#define AR531XPLUS_SPI_READ 0x08000000 |
||||
#define AR531XPLUS_SPI_MMR 0x11300000 |
||||
#define AR531XPLUS_SPI_MMR_SIZE 12 |
||||
|
||||
#define AR531XPLUS_SPI_CTL 0x00 |
||||
#define AR531XPLUS_SPI_OPCODE 0x04 |
||||
#define AR531XPLUS_SPI_DATA 0x08 |
||||
|
||||
#define SPI_FLASH_READ AR531XPLUS_SPI_READ |
||||
#define SPI_FLASH_MMR AR531XPLUS_SPI_MMR |
||||
#define SPI_FLASH_MMR_SIZE AR531XPLUS_SPI_MMR_SIZE |
||||
#define SPI_FLASH_CTL AR531XPLUS_SPI_CTL |
||||
#define SPI_FLASH_OPCODE AR531XPLUS_SPI_OPCODE |
||||
#define SPI_FLASH_DATA AR531XPLUS_SPI_DATA |
||||
|
||||
#define SPI_CTL_START 0x00000100 |
||||
#define SPI_CTL_BUSY 0x00010000 |
||||
#define SPI_CTL_TXCNT_MASK 0x0000000f |
||||
#define SPI_CTL_RXCNT_MASK 0x000000f0 |
||||
#define SPI_CTL_TX_RX_CNT_MASK 0x000000ff |
||||
#define SPI_CTL_SIZE_MASK 0x00060000 |
||||
|
||||
#define SPI_CTL_CLK_SEL_MASK 0x03000000 |
||||
#define SPI_OPCODE_MASK 0x000000ff |
||||
|
||||
#define SPI_STATUS_WIP STM_STATUS_WIP |
@ -0,0 +1,5 @@ |
||||
#
|
||||
# Makefile for the AR2313 ethernet driver
|
||||
#
|
||||
|
||||
obj-$(CONFIG_AR2313) += ar2313.o
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,191 @@ |
||||
#ifndef _AR2313_H_ |
||||
#define _AR2313_H_ |
||||
|
||||
#include <linux/autoconf.h> |
||||
#include <asm/bootinfo.h> |
||||
#include "platform.h" |
||||
|
||||
extern unsigned long mips_machtype; |
||||
|
||||
#undef ETHERNET_BASE |
||||
#define ETHERNET_BASE ar_eth_base |
||||
#define ETHERNET_SIZE 0x00100000 |
||||
#define ETHERNET_MACS 2 |
||||
|
||||
#undef DMA_BASE |
||||
#define DMA_BASE ar_dma_base |
||||
#define DMA_SIZE 0x00100000 |
||||
|
||||
|
||||
/*
|
||||
* probe link timer - 5 secs |
||||
*/ |
||||
#define LINK_TIMER (5*HZ) |
||||
|
||||
/*
|
||||
* Interrupt register base address |
||||
*/ |
||||
#define INTERRUPT_BASE PHYS_TO_K1(ar_int_base) |
||||
|
||||
/*
|
||||
* Reset Register |
||||
*/ |
||||
#define AR531X_RESET (AR531X_RESETTMR + 0x0020) |
||||
#define RESET_SYSTEM 0x00000001 /* cold reset full system */ |
||||
#define RESET_PROC 0x00000002 /* cold reset MIPS core */ |
||||
#define RESET_WLAN0 0x00000004 /* cold reset WLAN MAC and BB */ |
||||
#define RESET_EPHY0 0x00000008 /* cold reset ENET0 phy */ |
||||
#define RESET_EPHY1 0x00000010 /* cold reset ENET1 phy */ |
||||
#define RESET_ENET0 0x00000020 /* cold reset ENET0 mac */ |
||||
#define RESET_ENET1 0x00000040 /* cold reset ENET1 mac */ |
||||
|
||||
#define IS_DMA_TX_INT(X) (((X) & (DMA_STATUS_TI)) != 0) |
||||
#define IS_DMA_RX_INT(X) (((X) & (DMA_STATUS_RI)) != 0) |
||||
#define IS_DRIVER_OWNED(X) (((X) & (DMA_TX_OWN)) == 0) |
||||
|
||||
#ifndef K1_TO_PHYS |
||||
// hack
|
||||
#define K1_TO_PHYS(x) (((unsigned int)(x)) & 0x1FFFFFFF) /* kseg1 to physical */ |
||||
#endif |
||||
|
||||
#ifndef PHYS_TO_K1 |
||||
// hack
|
||||
#define PHYS_TO_K1(x) (((unsigned int)(x)) | 0xA0000000) /* physical to kseg1 */ |
||||
#endif |
||||
|
||||
#define AR2313_TX_TIMEOUT (HZ/4) |
||||
|
||||
/*
|
||||
* Rings |
||||
*/ |
||||
#define DSC_RING_ENTRIES_SIZE (AR2313_DESCR_ENTRIES * sizeof(struct desc)) |
||||
#define DSC_NEXT(idx) ((idx + 1) & (AR2313_DESCR_ENTRIES - 1)) |
||||
|
||||
static inline int tx_space (u32 csm, u32 prd) |
||||
{ |
||||
return (csm - prd - 1) & (AR2313_DESCR_ENTRIES - 1); |
||||
} |
||||
|
||||
#if MAX_SKB_FRAGS |
||||
#define TX_RESERVED (MAX_SKB_FRAGS+1) /* +1 for message header */ |
||||
#define tx_ring_full(csm, prd) (tx_space(csm, prd) <= TX_RESERVED) |
||||
#else |
||||
#define tx_ring_full 0 |
||||
#endif |
||||
|
||||
#define AR2313_MBGET 2 |
||||
#define AR2313_MBSET 3 |
||||
#define AR2313_PCI_RECONFIG 4 |
||||
#define AR2313_PCI_DUMP 5 |
||||
#define AR2313_TEST_PANIC 6 |
||||
#define AR2313_TEST_NULLPTR 7 |
||||
#define AR2313_READ_DATA 8 |
||||
#define AR2313_WRITE_DATA 9 |
||||
#define AR2313_GET_VERSION 10 |
||||
#define AR2313_TEST_HANG 11 |
||||
#define AR2313_SYNC 12 |
||||
|
||||
|
||||
struct ar2313_cmd { |
||||
u32 cmd; |
||||
u32 address; /* virtual address of image */ |
||||
u32 length; /* size of image to download */ |
||||
u32 mailbox; /* mailbox to get/set */ |
||||
u32 data[2]; /* contents of mailbox to read/write */ |
||||
}; |
||||
|
||||
|
||||
/*
|
||||
* Struct private for the Sibyte. |
||||
* |
||||
* Elements are grouped so variables used by the tx handling goes |
||||
* together, and will go into the same cache lines etc. in order to |
||||
* avoid cache line contention between the rx and tx handling on SMP. |
||||
* |
||||
* Frequently accessed variables are put at the beginning of the |
||||
* struct to help the compiler generate better/shorter code. |
||||
*/ |
||||
struct ar2313_private |
||||
{ |
||||
struct net_device *dev; |
||||
int version; |
||||
u32 mb[2]; |
||||
|
||||
volatile ETHERNET_STRUCT *eth_regs; |
||||
volatile DMA *dma_regs; |
||||
volatile u32 *int_regs; |
||||
|
||||
spinlock_t lock; /* Serialise access to device */ |
||||
|
||||
/*
|
||||
* RX and TX descriptors, must be adjacent |
||||
*/ |
||||
ar2313_descr_t *rx_ring; |
||||
ar2313_descr_t *tx_ring; |
||||
|
||||
|
||||
struct sk_buff **rx_skb; |
||||
struct sk_buff **tx_skb; |
||||
|
||||
/*
|
||||
* RX elements |
||||
*/ |
||||
u32 rx_skbprd; |
||||
u32 cur_rx; |
||||
|
||||
/*
|
||||
* TX elements |
||||
*/ |
||||
u32 tx_prd; |
||||
u32 tx_csm; |
||||
|
||||
/*
|
||||
* Misc elements |
||||
*/ |
||||
int board_idx; |
||||
char name[48]; |
||||
struct net_device_stats stats; |
||||
struct { |
||||
u32 address; |
||||
u32 length; |
||||
char *mapping; |
||||
} desc; |
||||
|
||||
|
||||
struct timer_list link_timer; |
||||
unsigned short phy; /* merlot phy = 1, samsung phy = 0x1f */ |
||||
unsigned short mac; |
||||
unsigned short link; /* 0 - link down, 1 - link up */ |
||||
u16 phyData; |
||||
|
||||
struct tasklet_struct rx_tasklet; |
||||
int unloading; |
||||
}; |
||||
|
||||
|
||||
/*
|
||||
* Prototypes |
||||
*/ |
||||
static int ar2313_init(struct net_device *dev); |
||||
#ifdef TX_TIMEOUT |
||||
static void ar2313_tx_timeout(struct net_device *dev); |
||||
#endif |
||||
#if 0 |
||||
static void ar2313_multicast_list(struct net_device *dev); |
||||
#endif |
||||
static int ar2313_restart(struct net_device *dev); |
||||
#if DEBUG |
||||
static void ar2313_dump_regs(struct net_device *dev); |
||||
#endif |
||||
static void ar2313_load_rx_ring(struct net_device *dev, int bufs); |
||||
static irqreturn_t ar2313_interrupt(int irq, void *dev_id); |
||||
static int ar2313_open(struct net_device *dev); |
||||
static int ar2313_start_xmit(struct sk_buff *skb, struct net_device *dev); |
||||
static int ar2313_close(struct net_device *dev); |
||||
static int ar2313_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); |
||||
static void ar2313_init_cleanup(struct net_device *dev); |
||||
static int ar2313_setup_timer(struct net_device *dev); |
||||
static void ar2313_link_timer_fn(unsigned long data); |
||||
static void ar2313_check_link(struct net_device *dev); |
||||
static struct net_device_stats *ar2313_get_stats(struct net_device *dev); |
||||
#endif /* _AR2313_H_ */ |
@ -0,0 +1,17 @@ |
||||
#ifndef _AR2313_MSG_H_ |
||||
#define _AR2313_MSG_H_ |
||||
|
||||
#define AR2313_MTU 1692 |
||||
#define AR2313_PRIOS 1 |
||||
#define AR2313_QUEUES (2*AR2313_PRIOS) |
||||
|
||||
#define AR2313_DESCR_ENTRIES 64 |
||||
|
||||
typedef struct { |
||||
volatile unsigned int status; // OWN, Device control and status.
|
||||
volatile unsigned int devcs; // pkt Control bits + Length
|
||||
volatile unsigned int addr; // Current Address.
|
||||
volatile unsigned int descr; // Next descriptor in chain.
|
||||
} ar2313_descr_t; |
||||
|
||||
#endif /* _AR2313_MSG_H_ */ |
@ -0,0 +1,135 @@ |
||||
#ifndef __ARUBA_DMA_H__ |
||||
#define __ARUBA_DMA_H__ |
||||
|
||||
/*******************************************************************************
|
||||
* |
||||
* Copyright 2002 Integrated Device Technology, Inc. |
||||
* All rights reserved. |
||||
* |
||||
* DMA register definition. |
||||
* |
||||
* File : $Id: dma.h,v 1.3 2002/06/06 18:34:03 astichte Exp $ |
||||
* |
||||
* Author : ryan.holmQVist@idt.com |
||||
* Date : 20011005 |
||||
* Update : |
||||
* $Log: dma.h,v $ |
||||
* Revision 1.3 2002/06/06 18:34:03 astichte |
||||
* Added XXX_PhysicalAddress and XXX_VirtualAddress |
||||
*
|
||||
* Revision 1.2 2002/06/05 18:30:46 astichte |
||||
* Removed IDTField |
||||
*
|
||||
* Revision 1.1 2002/05/29 17:33:21 sysarch |
||||
* jba File moved from vcode/include/idt/acacia |
||||
*
|
||||
* |
||||
******************************************************************************/ |
||||
|
||||
#define AR_BIT(x) (1 << (x)) |
||||
#define DMA_RX_ERR_CRC AR_BIT(1) |
||||
#define DMA_RX_ERR_DRIB AR_BIT(2) |
||||
#define DMA_RX_ERR_MII AR_BIT(3) |
||||
#define DMA_RX_EV2 AR_BIT(5) |
||||
#define DMA_RX_ERR_COL AR_BIT(6) |
||||
#define DMA_RX_LONG AR_BIT(7) |
||||
#define DMA_RX_LS AR_BIT(8) /* last descriptor */ |
||||
#define DMA_RX_FS AR_BIT(9) /* first descriptor */ |
||||
#define DMA_RX_MF AR_BIT(10) /* multicast frame */ |
||||
#define DMA_RX_ERR_RUNT AR_BIT(11) /* runt frame */ |
||||
#define DMA_RX_ERR_LENGTH AR_BIT(12) /* length error */ |
||||
#define DMA_RX_ERR_DESC AR_BIT(14) /* descriptor error */ |
||||
#define DMA_RX_ERROR AR_BIT(15) /* error summary */ |
||||
#define DMA_RX_LEN_MASK 0x3fff0000 |
||||
#define DMA_RX_LEN_SHIFT 16 |
||||
#define DMA_RX_FILT AR_BIT(30) |
||||
#define DMA_RX_OWN AR_BIT(31) /* desc owned by DMA controller */ |
||||
|
||||
#define DMA_RX1_BSIZE_MASK 0x000007ff |
||||
#define DMA_RX1_BSIZE_SHIFT 0 |
||||
#define DMA_RX1_CHAINED AR_BIT(24) |
||||
#define DMA_RX1_RER AR_BIT(25) |
||||
|
||||
#define DMA_TX_ERR_UNDER AR_BIT(1) /* underflow error */ |
||||
#define DMA_TX_ERR_DEFER AR_BIT(2) /* excessive deferral */ |
||||
#define DMA_TX_COL_MASK 0x78 |
||||
#define DMA_TX_COL_SHIFT 3 |
||||
#define DMA_TX_ERR_HB AR_BIT(7) /* hearbeat failure */ |
||||
#define DMA_TX_ERR_COL AR_BIT(8) /* excessive collisions */ |
||||
#define DMA_TX_ERR_LATE AR_BIT(9) /* late collision */ |
||||
#define DMA_TX_ERR_LINK AR_BIT(10) /* no carrier */ |
||||
#define DMA_TX_ERR_LOSS AR_BIT(11) /* loss of carrier */ |
||||
#define DMA_TX_ERR_JABBER AR_BIT(14) /* transmit jabber timeout */ |
||||
#define DMA_TX_ERROR AR_BIT(15) /* frame aborted */ |
||||
#define DMA_TX_OWN AR_BIT(31) /* descr owned by DMA controller */ |
||||
|
||||
#define DMA_TX1_BSIZE_MASK 0x000007ff |
||||
#define DMA_TX1_BSIZE_SHIFT 0 |
||||
#define DMA_TX1_CHAINED AR_BIT(24) /* chained descriptors */ |
||||
#define DMA_TX1_TER AR_BIT(25) /* transmit end of ring */ |
||||
#define DMA_TX1_FS AR_BIT(29) /* first segment */ |
||||
#define DMA_TX1_LS AR_BIT(30) /* last segment */ |
||||
#define DMA_TX1_IC AR_BIT(31) /* interrupt on completion */ |
||||
|
||||
#define RCVPKT_LENGTH(X) (X >> 16) /* Received pkt Length */ |
||||
|
||||
#define MAC_CONTROL_RE AR_BIT(2) /* receive enable */ |
||||
#define MAC_CONTROL_TE AR_BIT(3) /* transmit enable */ |
||||
#define MAC_CONTROL_DC AR_BIT(5) /* Deferral check*/ |
||||
#define MAC_CONTROL_ASTP AR_BIT(8) /* Auto pad strip */ |
||||
#define MAC_CONTROL_DRTY AR_BIT(10) /* Disable retry */ |
||||
#define MAC_CONTROL_DBF AR_BIT(11) /* Disable bcast frames */ |
||||
#define MAC_CONTROL_LCC AR_BIT(12) /* late collision ctrl */ |
||||
#define MAC_CONTROL_HP AR_BIT(13) /* Hash Perfect filtering */ |
||||
#define MAC_CONTROL_HASH AR_BIT(14) /* Unicast hash filtering */ |
||||
#define MAC_CONTROL_HO AR_BIT(15) /* Hash only filtering */ |
||||
#define MAC_CONTROL_PB AR_BIT(16) /* Pass Bad frames */ |
||||
#define MAC_CONTROL_IF AR_BIT(17) /* Inverse filtering */ |
||||
#define MAC_CONTROL_PR AR_BIT(18) /* promiscuous mode (valid frames only) */ |
||||
#define MAC_CONTROL_PM AR_BIT(19) /* pass multicast */ |
||||
#define MAC_CONTROL_F AR_BIT(20) /* full-duplex */ |
||||
#define MAC_CONTROL_DRO AR_BIT(23) /* Disable Receive Own */ |
||||
#define MAC_CONTROL_HBD AR_BIT(28) /* heart-beat disabled (MUST BE SET) */ |
||||
#define MAC_CONTROL_BLE AR_BIT(30) /* big endian mode */ |
||||
#define MAC_CONTROL_RA AR_BIT(31) /* receive all (valid and invalid frames) */ |
||||
|
||||
#define MII_ADDR_BUSY AR_BIT(0) |
||||
#define MII_ADDR_WRITE AR_BIT(1) |
||||
#define MII_ADDR_REG_SHIFT 6 |
||||
#define MII_ADDR_PHY_SHIFT 11 |
||||
#define MII_DATA_SHIFT 0 |
||||
|
||||
#define FLOW_CONTROL_FCE AR_BIT(1) |
||||
|
||||
#define DMA_BUS_MODE_SWR AR_BIT(0) /* software reset */ |
||||
#define DMA_BUS_MODE_BLE AR_BIT(7) /* big endian mode */ |
||||
#define DMA_BUS_MODE_PBL_SHIFT 8 /* programmable burst length 32 */ |
||||
#define DMA_BUS_MODE_DBO AR_BIT(20) /* big-endian descriptors */ |
||||
|
||||
#define DMA_STATUS_TI AR_BIT(0) /* transmit interrupt */ |
||||
#define DMA_STATUS_TPS AR_BIT(1) /* transmit process stopped */ |
||||
#define DMA_STATUS_TU AR_BIT(2) /* transmit buffer unavailable */ |
||||
#define DMA_STATUS_TJT AR_BIT(3) /* transmit buffer timeout */ |
||||
#define DMA_STATUS_UNF AR_BIT(5) /* transmit underflow */ |
||||
#define DMA_STATUS_RI AR_BIT(6) /* receive interrupt */ |
||||
#define DMA_STATUS_RU AR_BIT(7) /* receive buffer unavailable */ |
||||
#define DMA_STATUS_RPS AR_BIT(8) /* receive process stopped */ |
||||
#define DMA_STATUS_ETI AR_BIT(10) /* early transmit interrupt */ |
||||
#define DMA_STATUS_FBE AR_BIT(13) /* fatal bus interrupt */ |
||||
#define DMA_STATUS_ERI AR_BIT(14) /* early receive interrupt */ |
||||
#define DMA_STATUS_AIS AR_BIT(15) /* abnormal interrupt summary */ |
||||
#define DMA_STATUS_NIS AR_BIT(16) /* normal interrupt summary */ |
||||
#define DMA_STATUS_RS_SHIFT 17 /* receive process state */ |
||||
#define DMA_STATUS_TS_SHIFT 20 /* transmit process state */ |
||||
#define DMA_STATUS_EB_SHIFT 23 /* error bits */ |
||||
|
||||
#define DMA_CONTROL_SR AR_BIT(1) /* start receive */ |
||||
#define DMA_CONTROL_ST AR_BIT(13) /* start transmit */ |
||||
#define DMA_CONTROL_SF AR_BIT(21) /* store and forward */ |
||||
|
||||
#endif // __ARUBA_DMA_H__
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,128 @@ |
||||
/********************************************************************************
|
||||
Title: $Source: platform.h,v $ |
||||
|
||||
Author: Dan Steinberg |
||||
Copyright Integrated Device Technology 2001 |
||||
|
||||
Purpose: AR2313 Register/Bit Definitions |
||||
|
||||
Update: |
||||
$Log: platform.h,v $ |
||||
|
||||
Notes: See Merlot architecture spec for complete details. Note, all |
||||
addresses are virtual addresses in kseg1 (Uncached, Unmapped). |
||||
|
||||
********************************************************************************/ |
||||
|
||||
#ifndef PLATFORM_H |
||||
#define PLATFORM_H |
||||
|
||||
#define BIT(x) (1 << (x)) |
||||
|
||||
#define RESET_BASE 0xBC003020 |
||||
#define RESET_VALUE 0x00000001 |
||||
|
||||
/********************************************************************
|
||||
* Device controller
|
||||
********************************************************************/ |
||||
typedef struct { |
||||
volatile unsigned int flash0; |
||||
} DEVICE; |
||||
|
||||
#define device (*((volatile DEVICE *) DEV_CTL_BASE)) |
||||
|
||||
// DDRC register
|
||||
#define DEV_WP (1<<26) |
||||
|
||||
/********************************************************************
|
||||
* DDR controller
|
||||
********************************************************************/ |
||||
typedef struct { |
||||
volatile unsigned int ddrc0; |
||||
volatile unsigned int ddrc1; |
||||
volatile unsigned int ddrrefresh; |
||||
} DDR; |
||||
|
||||
#define ddr (*((volatile DDR *) DDR_BASE)) |
||||
|
||||
// DDRC register
|
||||
#define DDRC_CS(i) ((i&0x3)<<0) |
||||
#define DDRC_WE (1<<2) |
||||
|
||||
/********************************************************************
|
||||
* Ethernet interfaces |
||||
********************************************************************/ |
||||
#define ETHERNET_BASE 0xB8200000 |
||||
|
||||
//
|
||||
// New Combo structure for Both Eth0 AND eth1
|
||||
//
|
||||
typedef struct { |
||||
volatile unsigned int mac_control; /* 0x00 */ |
||||
volatile unsigned int mac_addr[2]; /* 0x04 - 0x08*/ |
||||
volatile unsigned int mcast_table[2]; /* 0x0c - 0x10 */ |
||||
volatile unsigned int mii_addr; /* 0x14 */ |
||||
volatile unsigned int mii_data; /* 0x18 */ |
||||
volatile unsigned int flow_control; /* 0x1c */ |
||||
volatile unsigned int vlan_tag; /* 0x20 */ |
||||
volatile unsigned int pad[7]; /* 0x24 - 0x3c */ |
||||
volatile unsigned int ucast_table[8]; /* 0x40-0x5c */ |
||||
|
||||
} ETHERNET_STRUCT; |
||||
|
||||
/********************************************************************
|
||||
* Interrupt controller
|
||||
********************************************************************/ |
||||
|
||||
typedef struct { |
||||
volatile unsigned int wdog_control; /* 0x08 */ |
||||
volatile unsigned int wdog_timer; /* 0x0c */ |
||||
volatile unsigned int misc_status; /* 0x10 */ |
||||
volatile unsigned int misc_mask; /* 0x14 */ |
||||
volatile unsigned int global_status; /* 0x18 */ |
||||
volatile unsigned int reserved; /* 0x1c */ |
||||
volatile unsigned int reset_control; /* 0x20 */ |
||||
} INTERRUPT; |
||||
|
||||
#define interrupt (*((volatile INTERRUPT *) INTERRUPT_BASE)) |
||||
|
||||
#define INTERRUPT_MISC_TIMER BIT(0) |
||||
#define INTERRUPT_MISC_AHBPROC BIT(1) |
||||
#define INTERRUPT_MISC_AHBDMA BIT(2) |
||||
#define INTERRUPT_MISC_GPIO BIT(3) |
||||
#define INTERRUPT_MISC_UART BIT(4) |
||||
#define INTERRUPT_MISC_UARTDMA BIT(5) |
||||
#define INTERRUPT_MISC_WATCHDOG BIT(6) |
||||
#define INTERRUPT_MISC_LOCAL BIT(7) |
||||
|
||||
#define INTERRUPT_GLOBAL_ETH BIT(2) |
||||
#define INTERRUPT_GLOBAL_WLAN BIT(3) |
||||
#define INTERRUPT_GLOBAL_MISC BIT(4) |
||||
#define INTERRUPT_GLOBAL_ITIMER BIT(5) |
||||
|
||||
/********************************************************************
|
||||
* DMA controller |
||||
********************************************************************/ |
||||
#define DMA_BASE 0xB8201000 |
||||
|
||||
typedef struct { |
||||
volatile unsigned int bus_mode; /* 0x00 (CSR0) */ |
||||
volatile unsigned int xmt_poll; /* 0x04 (CSR1) */ |
||||
volatile unsigned int rcv_poll; /* 0x08 (CSR2) */ |
||||
volatile unsigned int rcv_base; /* 0x0c (CSR3) */ |
||||
volatile unsigned int xmt_base; /* 0x10 (CSR4) */ |
||||
volatile unsigned int status; /* 0x14 (CSR5) */ |
||||
volatile unsigned int control; /* 0x18 (CSR6) */ |
||||
volatile unsigned int intr_ena; /* 0x1c (CSR7) */ |
||||
volatile unsigned int rcv_missed; /* 0x20 (CSR8) */ |
||||
volatile unsigned int reserved[11]; /* 0x24-0x4c (CSR9-19) */ |
||||
volatile unsigned int cur_tx_buf_addr; /* 0x50 (CSR20) */ |
||||
volatile unsigned int cur_rx_buf_addr; /* 0x50 (CSR21) */ |
||||
} DMA; |
||||
|
||||
#define dma (*((volatile DMA *) DMA_BASE)) |
||||
|
||||
// macro to convert from virtual to physical address
|
||||
#define phys_addr(x) (x & 0x1fffffff) |
||||
|
||||
#endif /* PLATFORM_H */ |
@ -0,0 +1,26 @@ |
||||
#ifndef __AR531X_PLATFORM_H |
||||
#define __AR531X_PLATFORM_H |
||||
|
||||
/*
|
||||
* Board support data. The driver is required to locate |
||||
* and fill-in this information before passing a reference to |
||||
* this structure as the HAL_BUS_TAG parameter supplied to |
||||
* ath_hal_attach. |
||||
*/ |
||||
struct ar531x_config { |
||||
const char *board; /* board config data */ |
||||
const char *radio; /* radio config data */ |
||||
int unit; /* unit number [0, 1] */ |
||||
u32 tag; /* used as devid for now */ |
||||
}; |
||||
|
||||
struct ar531x_eth { |
||||
int phy; |
||||
int mac; |
||||
u32 reset_base; |
||||
u32 reset_mac; |
||||
u32 reset_phy; |
||||
char *board_config; |
||||
}; |
||||
|
||||
#endif /* __AR531X_PLATFORM_H */ |
File diff suppressed because it is too large
Load Diff
@ -1,750 +1,23 @@ |
||||
diff -urN linux.old/drivers/mtd/devices/Kconfig linux.dev/drivers/mtd/devices/Kconfig
|
||||
--- linux.old/drivers/mtd/devices/Kconfig 2006-11-29 22:57:37.000000000 +0100
|
||||
+++ linux.dev/drivers/mtd/devices/Kconfig 2006-12-15 00:03:11.000000000 +0100
|
||||
--- linux.old/drivers/mtd/devices/Kconfig 2007-02-04 04:30:26.145338240 +0100
|
||||
+++ linux.dev/drivers/mtd/devices/Kconfig 2007-02-02 23:48:28.748969000 +0100
|
||||
@@ -68,6 +68,10 @@
|
||||
used for program and data storage. Set up your spi devices
|
||||
with the right board-specific platform data.
|
||||
|
||||
+config MTD_SPIFLASH
|
||||
+ tristate "Atheros AR2315/6/7 SPI Flash support"
|
||||
+ depends on MTD && AR531X_COBRA
|
||||
+ depends on MTD && ATHEROS_AR5315
|
||||
+
|
||||
config MTD_SLRAM
|
||||
tristate "Uncached system RAM"
|
||||
depends on MTD
|
||||
diff -urN linux.old/drivers/mtd/devices/Makefile linux.dev/drivers/mtd/devices/Makefile
|
||||
--- linux.old/drivers/mtd/devices/Makefile 2006-11-29 22:57:37.000000000 +0100
|
||||
+++ linux.dev/drivers/mtd/devices/Makefile 2006-12-15 00:03:11.000000000 +0100
|
||||
--- linux.old/drivers/mtd/devices/Makefile 2007-02-04 04:30:26.146338088 +0100
|
||||
+++ linux.dev/drivers/mtd/devices/Makefile 2007-02-02 23:48:28.749969000 +0100
|
||||
@@ -17,3 +17,4 @@
|
||||
obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o
|
||||
obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o
|
||||
obj-$(CONFIG_MTD_M25P80) += m25p80.o
|
||||
+obj-$(CONFIG_MTD_SPIFLASH) += spiflash.o
|
||||
diff -urN linux.old/drivers/mtd/devices/spiflash.c linux.dev/drivers/mtd/devices/spiflash.c
|
||||
--- linux.old/drivers/mtd/devices/spiflash.c 1970-01-01 01:00:00.000000000 +0100
|
||||
+++ linux.dev/drivers/mtd/devices/spiflash.c 2006-12-15 08:26:11.000000000 +0100
|
||||
@@ -0,0 +1,595 @@
|
||||
+
|
||||
+/*
|
||||
+ * MTD driver for the SPI Flash Memory support.
|
||||
+ *
|
||||
+ * Copyright (c) 2005-2006 Atheros Communications Inc.
|
||||
+ * Copyright (C) 2006 FON Technology, SL.
|
||||
+ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
|
||||
+ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
|
||||
+ *
|
||||
+ * This code 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.
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+/*===========================================================================
|
||||
+** !!!! VERY IMPORTANT NOTICE !!!! FLASH DATA STORED IN LITTLE ENDIAN FORMAT
|
||||
+**
|
||||
+** This module contains the Serial Flash access routines for the Atheros SOC.
|
||||
+** The Atheros SOC integrates a SPI flash controller that is used to access
|
||||
+** serial flash parts. The SPI flash controller executes in "Little Endian"
|
||||
+** mode. THEREFORE, all WRITES and READS from the MIPS CPU must be
|
||||
+** BYTESWAPPED! The SPI Flash controller hardware by default performs READ
|
||||
+** ONLY byteswapping when accessed via the SPI Flash Alias memory region
|
||||
+** (Physical Address 0x0800_0000 - 0x0fff_ffff). The data stored in the
|
||||
+** flash sectors is stored in "Little Endian" format.
|
||||
+**
|
||||
+** The spiflash_write() routine performs byteswapping on all write
|
||||
+** operations.
|
||||
+**===========================================================================*/
|
||||
+
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/types.h>
|
||||
+#include <linux/version.h>
|
||||
+#include <linux/errno.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/mtd/mtd.h>
|
||||
+#include <linux/mtd/partitions.h>
|
||||
+#include <linux/squashfs_fs.h>
|
||||
+#include <linux/root_dev.h>
|
||||
+#include <asm/delay.h>
|
||||
+#include <asm/io.h>
|
||||
+#include "spiflash.h"
|
||||
+
|
||||
+/* debugging */
|
||||
+/* #define SPIFLASH_DEBUG */
|
||||
+
|
||||
+#ifndef __BIG_ENDIAN
|
||||
+#error This driver currently only works with big endian CPU.
|
||||
+#endif
|
||||
+
|
||||
+#define MAX_PARTS 32
|
||||
+
|
||||
+static char module_name[] = "spiflash";
|
||||
+
|
||||
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||
+#define FALSE 0
|
||||
+#define TRUE 1
|
||||
+
|
||||
+#define ROOTFS_NAME "rootfs"
|
||||
+
|
||||
+static __u32 spiflash_regread32(int reg);
|
||||
+static void spiflash_regwrite32(int reg, __u32 data);
|
||||
+static __u32 spiflash_sendcmd (int op);
|
||||
+
|
||||
+static void __init spidata_init(void);
|
||||
+int __init spiflash_init (void);
|
||||
+void __exit spiflash_exit (void);
|
||||
+static int spiflash_probe (void);
|
||||
+static int spiflash_erase (struct mtd_info *mtd,struct erase_info *instr);
|
||||
+static int spiflash_read (struct mtd_info *mtd, loff_t from,size_t len,size_t *retlen,u_char *buf);
|
||||
+static int spiflash_write (struct mtd_info *mtd,loff_t to,size_t len,size_t *retlen,const u_char *buf);
|
||||
+
|
||||
+/* Flash configuration table */
|
||||
+struct flashconfig {
|
||||
+ __u32 byte_cnt;
|
||||
+ __u32 sector_cnt;
|
||||
+ __u32 sector_size;
|
||||
+ __u32 cs_addrmask;
|
||||
+} flashconfig_tbl[MAX_FLASH] =
|
||||
+ {
|
||||
+ { 0, 0, 0, 0},
|
||||
+ { STM_1MB_BYTE_COUNT, STM_1MB_SECTOR_COUNT, STM_1MB_SECTOR_SIZE, 0x0},
|
||||
+ { STM_2MB_BYTE_COUNT, STM_2MB_SECTOR_COUNT, STM_2MB_SECTOR_SIZE, 0x0},
|
||||
+ { STM_4MB_BYTE_COUNT, STM_4MB_SECTOR_COUNT, STM_4MB_SECTOR_SIZE, 0x0},
|
||||
+ { STM_8MB_BYTE_COUNT, STM_8MB_SECTOR_COUNT, STM_8MB_SECTOR_SIZE, 0x0}
|
||||
+ };
|
||||
+
|
||||
+/* Mapping of generic opcodes to STM serial flash opcodes */
|
||||
+struct opcodes {
|
||||
+ __u16 code;
|
||||
+ __s8 tx_cnt;
|
||||
+ __s8 rx_cnt;
|
||||
+} stm_opcodes[] = {
|
||||
+ {STM_OP_WR_ENABLE, 1, 0},
|
||||
+ {STM_OP_WR_DISABLE, 1, 0},
|
||||
+ {STM_OP_RD_STATUS, 1, 1},
|
||||
+ {STM_OP_WR_STATUS, 1, 0},
|
||||
+ {STM_OP_RD_DATA, 4, 4},
|
||||
+ {STM_OP_FAST_RD_DATA, 1, 0},
|
||||
+ {STM_OP_PAGE_PGRM, 8, 0},
|
||||
+ {STM_OP_SECTOR_ERASE, 4, 0},
|
||||
+ {STM_OP_BULK_ERASE, 1, 0},
|
||||
+ {STM_OP_DEEP_PWRDOWN, 1, 0},
|
||||
+ {STM_OP_RD_SIG, 4, 1}
|
||||
+};
|
||||
+
|
||||
+/* Driver private data structure */
|
||||
+struct spiflash_data {
|
||||
+ struct mtd_info *mtd;
|
||||
+ struct mtd_partition *parsed_parts; /* parsed partitions */
|
||||
+ void *spiflash_readaddr; /* memory mapped data for read */
|
||||
+ void *spiflash_mmraddr; /* memory mapped register space */
|
||||
+ spinlock_t mutex;
|
||||
+};
|
||||
+
|
||||
+static struct spiflash_data *spidata;
|
||||
+
|
||||
+extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
|
||||
+
|
||||
+/***************************************************************************************************/
|
||||
+
|
||||
+static __u32
|
||||
+spiflash_regread32(int reg)
|
||||
+{
|
||||
+ volatile __u32 *data = (__u32 *)(spidata->spiflash_mmraddr + reg);
|
||||
+
|
||||
+ return (*data);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+spiflash_regwrite32(int reg, __u32 data)
|
||||
+{
|
||||
+ volatile __u32 *addr = (__u32 *)(spidata->spiflash_mmraddr + reg);
|
||||
+
|
||||
+ *addr = data;
|
||||
+ return;
|
||||
+}
|
||||
+
|
||||
+static __u32
|
||||
+spiflash_sendcmd (int op)
|
||||
+{
|
||||
+ __u32 reg;
|
||||
+ __u32 mask;
|
||||
+ struct opcodes *ptr_opcode;
|
||||
+
|
||||
+ ptr_opcode = &stm_opcodes[op];
|
||||
+
|
||||
+ do {
|
||||
+ reg = spiflash_regread32(SPI_FLASH_CTL);
|
||||
+ } while (reg & SPI_CTL_BUSY);
|
||||
+
|
||||
+ spiflash_regwrite32(SPI_FLASH_OPCODE, ptr_opcode->code);
|
||||
+
|
||||
+ reg = (reg & ~SPI_CTL_TX_RX_CNT_MASK) | ptr_opcode->tx_cnt |
|
||||
+ (ptr_opcode->rx_cnt << 4) | SPI_CTL_START;
|
||||
+
|
||||
+ spiflash_regwrite32(SPI_FLASH_CTL, reg);
|
||||
+
|
||||
+ if (ptr_opcode->rx_cnt > 0) {
|
||||
+ do {
|
||||
+ reg = spiflash_regread32(SPI_FLASH_CTL);
|
||||
+ } while (reg & SPI_CTL_BUSY);
|
||||
+
|
||||
+ reg = (__u32) spiflash_regread32(SPI_FLASH_DATA);
|
||||
+
|
||||
+ switch (ptr_opcode->rx_cnt) {
|
||||
+ case 1:
|
||||
+ mask = 0x000000ff;
|
||||
+ break;
|
||||
+ case 2:
|
||||
+ mask = 0x0000ffff;
|
||||
+ break;
|
||||
+ case 3:
|
||||
+ mask = 0x00ffffff;
|
||||
+ break;
|
||||
+ default:
|
||||
+ mask = 0xffffffff;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ reg &= mask;
|
||||
+ }
|
||||
+ else {
|
||||
+ reg = 0;
|
||||
+ }
|
||||
+
|
||||
+ return reg;
|
||||
+}
|
||||
+
|
||||
+/* Probe SPI flash device
|
||||
+ * Function returns 0 for failure.
|
||||
+ * and flashconfig_tbl array index for success.
|
||||
+ */
|
||||
+static int
|
||||
+spiflash_probe (void)
|
||||
+{
|
||||
+ __u32 sig;
|
||||
+ int flash_size;
|
||||
+
|
||||
+ if (!spidata)
|
||||
+ spidata_init();
|
||||
+
|
||||
+ if (!spidata) /* init failed */
|
||||
+ return 0;
|
||||
+
|
||||
+ /* Read the signature on the flash device */
|
||||
+ sig = spiflash_sendcmd(SPI_RD_SIG);
|
||||
+
|
||||
+ switch (sig) {
|
||||
+ case STM_8MBIT_SIGNATURE:
|
||||
+ flash_size = FLASH_1MB;
|
||||
+ break;
|
||||
+ case STM_16MBIT_SIGNATURE:
|
||||
+ flash_size = FLASH_2MB;
|
||||
+ break;
|
||||
+ case STM_32MBIT_SIGNATURE:
|
||||
+ flash_size = FLASH_4MB;
|
||||
+ break;
|
||||
+ case STM_64MBIT_SIGNATURE:
|
||||
+ flash_size = FLASH_8MB;
|
||||
+ break;
|
||||
+ default:
|
||||
+ printk (KERN_WARNING "%s: Read of flash device signature failed!\n", module_name);
|
||||
+ return (0);
|
||||
+ }
|
||||
+
|
||||
+ return (flash_size);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static int
|
||||
+spiflash_erase (struct mtd_info *mtd,struct erase_info *instr)
|
||||
+{
|
||||
+ struct opcodes *ptr_opcode;
|
||||
+ __u32 temp, reg;
|
||||
+ int finished = FALSE;
|
||||
+
|
||||
+#ifdef SPIFLASH_DEBUG
|
||||
+ printk (KERN_DEBUG "%s(addr = 0x%.8x, len = %d)\n",__FUNCTION__,instr->addr,instr->len);
|
||||
+#endif
|
||||
+
|
||||
+ /* sanity checks */
|
||||
+ if (instr->addr + instr->len > mtd->size) return (-EINVAL);
|
||||
+
|
||||
+ ptr_opcode = &stm_opcodes[SPI_SECTOR_ERASE];
|
||||
+
|
||||
+ temp = ((__u32)instr->addr << 8) | (__u32)(ptr_opcode->code);
|
||||
+ spin_lock(&spidata->mutex);
|
||||
+ spiflash_sendcmd(SPI_WRITE_ENABLE);
|
||||
+ do {
|
||||
+ schedule();
|
||||
+ reg = spiflash_regread32(SPI_FLASH_CTL);
|
||||
+ } while (reg & SPI_CTL_BUSY);
|
||||
+
|
||||
+ spiflash_regwrite32(SPI_FLASH_OPCODE, temp);
|
||||
+
|
||||
+ reg = (reg & ~SPI_CTL_TX_RX_CNT_MASK) | ptr_opcode->tx_cnt | SPI_CTL_START;
|
||||
+ spiflash_regwrite32(SPI_FLASH_CTL, reg);
|
||||
+
|
||||
+ do {
|
||||
+ schedule();
|
||||
+ reg = spiflash_sendcmd(SPI_RD_STATUS);
|
||||
+ if (!(reg & SPI_STATUS_WIP)) {
|
||||
+ finished = TRUE;
|
||||
+ }
|
||||
+ } while (!finished);
|
||||
+ spin_unlock(&spidata->mutex);
|
||||
+
|
||||
+ instr->state = MTD_ERASE_DONE;
|
||||
+ if (instr->callback) instr->callback (instr);
|
||||
+
|
||||
+#ifdef SPIFLASH_DEBUG
|
||||
+ printk (KERN_DEBUG "%s return\n",__FUNCTION__);
|
||||
+#endif
|
||||
+ return (0);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+spiflash_read (struct mtd_info *mtd, loff_t from,size_t len,size_t *retlen,u_char *buf)
|
||||
+{
|
||||
+ u_char *read_addr;
|
||||
+
|
||||
+#ifdef SPIFLASH_DEBUG
|
||||
+ printk (KERN_DEBUG "%s(from = 0x%.8x, len = %d)\n",__FUNCTION__,(__u32) from,(int)len);
|
||||
+#endif
|
||||
+
|
||||
+ /* sanity checks */
|
||||
+ if (!len) return (0);
|
||||
+ if (from + len > mtd->size) return (-EINVAL);
|
||||
+
|
||||
+
|
||||
+ /* we always read len bytes */
|
||||
+ *retlen = len;
|
||||
+
|
||||
+ read_addr = (u_char *)(spidata->spiflash_readaddr + from);
|
||||
+ spin_lock(&spidata->mutex);
|
||||
+ memcpy(buf, read_addr, len);
|
||||
+ spin_unlock(&spidata->mutex);
|
||||
+
|
||||
+ return (0);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+spiflash_write (struct mtd_info *mtd,loff_t to,size_t len,size_t *retlen,const u_char *buf)
|
||||
+{
|
||||
+ int done = FALSE, page_offset, bytes_left, finished;
|
||||
+ __u32 xact_len, spi_data = 0, opcode, reg;
|
||||
+
|
||||
+#ifdef SPIFLASH_DEBUG
|
||||
+ printk (KERN_DEBUG "%s(to = 0x%.8x, len = %d)\n",__FUNCTION__,(__u32) to,len);
|
||||
+#endif
|
||||
+
|
||||
+ *retlen = 0;
|
||||
+
|
||||
+ /* sanity checks */
|
||||
+ if (!len) return (0);
|
||||
+ if (to + len > mtd->size) return (-EINVAL);
|
||||
+
|
||||
+ opcode = stm_opcodes[SPI_PAGE_PROGRAM].code;
|
||||
+ bytes_left = len;
|
||||
+
|
||||
+ while (done == FALSE) {
|
||||
+ xact_len = MIN(bytes_left, sizeof(__u32));
|
||||
+
|
||||
+ /* 32-bit writes cannot span across a page boundary
|
||||
+ * (256 bytes). This types of writes require two page
|
||||
+ * program operations to handle it correctly. The STM part
|
||||
+ * will write the overflow data to the beginning of the
|
||||
+ * current page as opposed to the subsequent page.
|
||||
+ */
|
||||
+ page_offset = (to & (STM_PAGE_SIZE - 1)) + xact_len;
|
||||
+
|
||||
+ if (page_offset > STM_PAGE_SIZE) {
|
||||
+ xact_len -= (page_offset - STM_PAGE_SIZE);
|
||||
+ }
|
||||
+
|
||||
+ spin_lock(&spidata->mutex);
|
||||
+ spiflash_sendcmd(SPI_WRITE_ENABLE);
|
||||
+
|
||||
+ do {
|
||||
+ schedule();
|
||||
+ reg = spiflash_regread32(SPI_FLASH_CTL);
|
||||
+ } while (reg & SPI_CTL_BUSY);
|
||||
+
|
||||
+ switch (xact_len) {
|
||||
+ case 1:
|
||||
+ spi_data = (u32) ((u8) *buf);
|
||||
+ break;
|
||||
+ case 2:
|
||||
+ spi_data = (buf[1] << 8) | buf[0];
|
||||
+ break;
|
||||
+ case 3:
|
||||
+ spi_data = (buf[2] << 16) | (buf[1] << 8) | buf[0];
|
||||
+ break;
|
||||
+ case 4:
|
||||
+ spi_data = (buf[3] << 24) | (buf[2] << 16) |
|
||||
+ (buf[1] << 8) | buf[0];
|
||||
+ break;
|
||||
+ default:
|
||||
+ printk("spiflash_write: default case\n");
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ spiflash_regwrite32(SPI_FLASH_DATA, spi_data);
|
||||
+ opcode = (opcode & SPI_OPCODE_MASK) | ((__u32)to << 8);
|
||||
+ spiflash_regwrite32(SPI_FLASH_OPCODE, opcode);
|
||||
+
|
||||
+ reg = (reg & ~SPI_CTL_TX_RX_CNT_MASK) | (xact_len + 4) | SPI_CTL_START;
|
||||
+ spiflash_regwrite32(SPI_FLASH_CTL, reg);
|
||||
+ finished = FALSE;
|
||||
+
|
||||
+ do {
|
||||
+ schedule();
|
||||
+ reg = spiflash_sendcmd(SPI_RD_STATUS);
|
||||
+ if (!(reg & SPI_STATUS_WIP)) {
|
||||
+ finished = TRUE;
|
||||
+ }
|
||||
+ } while (!finished);
|
||||
+ spin_unlock(&spidata->mutex);
|
||||
+
|
||||
+ bytes_left -= xact_len;
|
||||
+ to += xact_len;
|
||||
+ buf += xact_len;
|
||||
+
|
||||
+ *retlen += xact_len;
|
||||
+
|
||||
+ if (bytes_left == 0) {
|
||||
+ done = TRUE;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return (0);
|
||||
+}
|
||||
+
|
||||
+static void __init spidata_init(void)
|
||||
+{
|
||||
+ if (spidata)
|
||||
+ return;
|
||||
+
|
||||
+ spidata = kmalloc(sizeof(struct spiflash_data), GFP_KERNEL);
|
||||
+ spin_lock_init(&spidata->mutex);
|
||||
+
|
||||
+ if (!spidata)
|
||||
+ return;
|
||||
+
|
||||
+ spidata->spiflash_mmraddr = ioremap_nocache(SPI_FLASH_MMR, SPI_FLASH_MMR_SIZE);
|
||||
+
|
||||
+ if (!spidata->spiflash_mmraddr) {
|
||||
+ printk (KERN_WARNING "%s: Failed to map flash device\n", module_name);
|
||||
+ kfree(spidata);
|
||||
+ spidata = NULL;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+#ifdef CONFIG_MTD_PARTITIONS
|
||||
+static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL };
|
||||
+#endif
|
||||
+
|
||||
+int __init
|
||||
+spiflash_init (void)
|
||||
+{
|
||||
+ int result = -1, i, j;
|
||||
+ u32 len;
|
||||
+ int index, num_parts;
|
||||
+ struct mtd_info *mtd;
|
||||
+ struct mtd_partition *mtd_parts;
|
||||
+ char *buf;
|
||||
+ struct mtd_partition *part;
|
||||
+ struct squashfs_super_block *sb;
|
||||
+ u32 config_start;
|
||||
+
|
||||
+ spidata_init();
|
||||
+
|
||||
+ if (!spidata)
|
||||
+ return (-ENXIO);
|
||||
+
|
||||
+ mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
|
||||
+ if (!mtd) {
|
||||
+ kfree(spidata);
|
||||
+ return (-ENXIO);
|
||||
+ }
|
||||
+
|
||||
+ printk ("MTD driver for SPI flash.\n");
|
||||
+ printk ("%s: Probing for Serial flash ...\n", module_name);
|
||||
+ if (!(index = spiflash_probe ())) {
|
||||
+ printk (KERN_WARNING "%s: Found no serial flash device\n", module_name);
|
||||
+ kfree(mtd);
|
||||
+ kfree(spidata);
|
||||
+ return (-ENXIO);
|
||||
+ }
|
||||
+
|
||||
+ printk ("%s: Found SPI serial Flash.\n", module_name);
|
||||
+
|
||||
+ spidata->spiflash_readaddr = ioremap_nocache(SPI_FLASH_READ, flashconfig_tbl[index].byte_cnt);
|
||||
+ if (!spidata->spiflash_readaddr) {
|
||||
+ printk (KERN_WARNING "%s: Failed to map flash device\n", module_name);
|
||||
+ kfree(mtd);
|
||||
+ kfree(spidata);
|
||||
+ return (-ENXIO);
|
||||
+ }
|
||||
+
|
||||
+ mtd->name = module_name;
|
||||
+ mtd->type = MTD_NORFLASH;
|
||||
+ mtd->flags = (MTD_CAP_NORFLASH|MTD_WRITEABLE);
|
||||
+ mtd->size = flashconfig_tbl[index].byte_cnt;
|
||||
+ mtd->erasesize = flashconfig_tbl[index].sector_size;
|
||||
+ mtd->writesize = 1;
|
||||
+ mtd->numeraseregions = 0;
|
||||
+ mtd->eraseregions = NULL;
|
||||
+ mtd->erase = spiflash_erase;
|
||||
+ mtd->read = spiflash_read;
|
||||
+ mtd->write = spiflash_write;
|
||||
+ mtd->owner = THIS_MODULE;
|
||||
+
|
||||
+#ifdef SPIFLASH_DEBUG
|
||||
+ printk (KERN_DEBUG
|
||||
+ "mtd->name = %s\n"
|
||||
+ "mtd->size = 0x%.8x (%uM)\n"
|
||||
+ "mtd->erasesize = 0x%.8x (%uK)\n"
|
||||
+ "mtd->numeraseregions = %d\n",
|
||||
+ mtd->name,
|
||||
+ mtd->size, mtd->size / (1024*1024),
|
||||
+ mtd->erasesize, mtd->erasesize / 1024,
|
||||
+ mtd->numeraseregions);
|
||||
+
|
||||
+ if (mtd->numeraseregions) {
|
||||
+ for (result = 0; result < mtd->numeraseregions; result++) {
|
||||
+ printk (KERN_DEBUG
|
||||
+ "\n\n"
|
||||
+ "mtd->eraseregions[%d].offset = 0x%.8x\n"
|
||||
+ "mtd->eraseregions[%d].erasesize = 0x%.8x (%uK)\n"
|
||||
+ "mtd->eraseregions[%d].numblocks = %d\n",
|
||||
+ result,mtd->eraseregions[result].offset,
|
||||
+ result,mtd->eraseregions[result].erasesize,mtd->eraseregions[result].erasesize / 1024,
|
||||
+ result,mtd->eraseregions[result].numblocks);
|
||||
+ }
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
+ /* parse redboot partitions */
|
||||
+ num_parts = parse_mtd_partitions(mtd, part_probe_types, &spidata->parsed_parts, 0);
|
||||
+
|
||||
+ mtd_parts = kzalloc(sizeof(struct mtd_partition) * MAX_PARTS, GFP_KERNEL);
|
||||
+ buf = kmalloc(mtd->erasesize, GFP_KERNEL);
|
||||
+ sb = (struct squashfs_super_block *) buf;
|
||||
+ for (i = j = 0; i < num_parts; i++, j++) {
|
||||
+ part = &mtd_parts[j];
|
||||
+ memcpy(part, &spidata->parsed_parts[i], sizeof(struct mtd_partition));
|
||||
+
|
||||
+ if (!strcmp(part->name, ROOTFS_NAME)) {
|
||||
+ /* create the root device */
|
||||
+ ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, i);
|
||||
+
|
||||
+ part->size -= mtd->erasesize;
|
||||
+ config_start = part->offset + part->size;
|
||||
+
|
||||
+ while ((mtd->read(mtd, part->offset, mtd->erasesize, &len, buf) == 0) &&
|
||||
+ (len == mtd->erasesize) &&
|
||||
+ (*((u32 *) buf) == SQUASHFS_MAGIC) &&
|
||||
+ (sb->bytes_used > 0)) {
|
||||
+
|
||||
+ /* this is squashfs, allocate another partition starting from the end of filesystem data */
|
||||
+ memcpy(&mtd_parts[j + 1], part, sizeof(struct mtd_partition));
|
||||
+
|
||||
+ len = (u32) sb->bytes_used;
|
||||
+ len += (part->offset & 0x000fffff);
|
||||
+ len += (mtd->erasesize - 1);
|
||||
+ len &= ~(mtd->erasesize - 1);
|
||||
+ len -= (part->offset & 0x000fffff);
|
||||
+
|
||||
+ if (len + mtd->erasesize > part->size)
|
||||
+ break;
|
||||
+
|
||||
+ part = &mtd_parts[++j];
|
||||
+
|
||||
+ part->offset += len;
|
||||
+ part->size -= len;
|
||||
+
|
||||
+ part->name = kmalloc(10, GFP_KERNEL);
|
||||
+ sprintf(part->name, "rootfs%d", j - i);
|
||||
+ }
|
||||
+ }
|
||||
+ if (!strcmp(part->name, "RedBoot config")) {
|
||||
+ /* add anoterh partition for the board config data */
|
||||
+ memcpy(&mtd_parts[j + 1], part, sizeof(struct mtd_partition));
|
||||
+ j++;
|
||||
+ part = &mtd_parts[j];
|
||||
+ part->offset += part->size;
|
||||
+ part->size = mtd->erasesize;
|
||||
+
|
||||
+ part->name = kmalloc(16, GFP_KERNEL);
|
||||
+ sprintf(part->name, "board_config");
|
||||
+ }
|
||||
+ }
|
||||
+ num_parts += j - i;
|
||||
+ kfree(buf);
|
||||
+
|
||||
+#ifdef SPIFLASH_DEBUG
|
||||
+ printk (KERN_DEBUG "Found %d redboot partitions\n", num_parts);
|
||||
+#endif
|
||||
+ if (num_parts) {
|
||||
+ result = add_mtd_partitions(mtd, mtd_parts, num_parts);
|
||||
+ } else {
|
||||
+#ifdef SPIFLASH_DEBUG
|
||||
+ printk (KERN_DEBUG "Did not find any redboot partitions\n");
|
||||
+#endif
|
||||
+ kfree(mtd);
|
||||
+ kfree(spidata);
|
||||
+ return (-ENXIO);
|
||||
+ }
|
||||
+
|
||||
+ spidata->mtd = mtd;
|
||||
+
|
||||
+ return (result);
|
||||
+}
|
||||
+
|
||||
+void __exit
|
||||
+spiflash_exit (void)
|
||||
+{
|
||||
+ if (spidata && spidata->parsed_parts) {
|
||||
+ del_mtd_partitions (spidata->mtd);
|
||||
+ kfree(spidata->mtd);
|
||||
+ kfree(spidata);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+module_init (spiflash_init);
|
||||
+module_exit (spiflash_exit);
|
||||
+
|
||||
+MODULE_LICENSE("GPL");
|
||||
+MODULE_AUTHOR("Atheros Communications Inc");
|
||||
+MODULE_DESCRIPTION("MTD driver for SPI Flash on Atheros SOC");
|
||||
+
|
||||
diff -urN linux.old/drivers/mtd/devices/spiflash.h linux.dev/drivers/mtd/devices/spiflash.h
|
||||
--- linux.old/drivers/mtd/devices/spiflash.h 1970-01-01 01:00:00.000000000 +0100
|
||||
+++ linux.dev/drivers/mtd/devices/spiflash.h 2006-12-15 06:59:43.000000000 +0100
|
||||
@@ -0,0 +1,124 @@
|
||||
+/*
|
||||
+ * SPI Flash Memory support header file.
|
||||
+ *
|
||||
+ * $Id: //depot/sw/releases/linuxsrc/src/kernels/mips-linux-2.4.25/drivers/mtd/devices/spiflash.h#3 $
|
||||
+ *
|
||||
+ *
|
||||
+ * Copyright (c) 2005, Atheros Communications Inc.
|
||||
+ * Copyright (C) 2006 FON Technology, SL.
|
||||
+ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
|
||||
+ *
|
||||
+ * This code 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.
|
||||
+ *
|
||||
+ */
|
||||
+#define FLASH_1MB 1
|
||||
+#define FLASH_2MB 2
|
||||
+#define FLASH_4MB 3
|
||||
+#define FLASH_8MB 4
|
||||
+#define MAX_FLASH 5
|
||||
+
|
||||
+#define STM_PAGE_SIZE 256
|
||||
+
|
||||
+#define SPI_WRITE_ENABLE 0
|
||||
+#define SPI_WRITE_DISABLE 1
|
||||
+#define SPI_RD_STATUS 2
|
||||
+#define SPI_WR_STATUS 3
|
||||
+#define SPI_RD_DATA 4
|
||||
+#define SPI_FAST_RD_DATA 5
|
||||
+#define SPI_PAGE_PROGRAM 6
|
||||
+#define SPI_SECTOR_ERASE 7
|
||||
+#define SPI_BULK_ERASE 8
|
||||
+#define SPI_DEEP_PWRDOWN 9
|
||||
+#define SPI_RD_SIG 10
|
||||
+#define SPI_MAX_OPCODES 11
|
||||
+
|
||||
+#define SFI_WRITE_BUFFER_SIZE 4
|
||||
+#define SFI_FLASH_ADDR_MASK 0x00ffffff
|
||||
+
|
||||
+#define STM_8MBIT_SIGNATURE 0x13
|
||||
+#define STM_M25P80_BYTE_COUNT 1048576
|
||||
+#define STM_M25P80_SECTOR_COUNT 16
|
||||
+#define STM_M25P80_SECTOR_SIZE 0x10000
|
||||
+
|
||||
+#define STM_16MBIT_SIGNATURE 0x14
|
||||
+#define STM_M25P16_BYTE_COUNT 2097152
|
||||
+#define STM_M25P16_SECTOR_COUNT 32
|
||||
+#define STM_M25P16_SECTOR_SIZE 0x10000
|
||||
+
|
||||
+#define STM_32MBIT_SIGNATURE 0x15
|
||||
+#define STM_M25P32_BYTE_COUNT 4194304
|
||||
+#define STM_M25P32_SECTOR_COUNT 64
|
||||
+#define STM_M25P32_SECTOR_SIZE 0x10000
|
||||
+
|
||||
+#define STM_64MBIT_SIGNATURE 0x16
|
||||
+#define STM_M25P64_BYTE_COUNT 8388608
|
||||
+#define STM_M25P64_SECTOR_COUNT 128
|
||||
+#define STM_M25P64_SECTOR_SIZE 0x10000
|
||||
+
|
||||
+#define STM_1MB_BYTE_COUNT STM_M25P80_BYTE_COUNT
|
||||
+#define STM_1MB_SECTOR_COUNT STM_M25P80_SECTOR_COUNT
|
||||
+#define STM_1MB_SECTOR_SIZE STM_M25P80_SECTOR_SIZE
|
||||
+#define STM_2MB_BYTE_COUNT STM_M25P16_BYTE_COUNT
|
||||
+#define STM_2MB_SECTOR_COUNT STM_M25P16_SECTOR_COUNT
|
||||
+#define STM_2MB_SECTOR_SIZE STM_M25P16_SECTOR_SIZE
|
||||
+#define STM_4MB_BYTE_COUNT STM_M25P32_BYTE_COUNT
|
||||
+#define STM_4MB_SECTOR_COUNT STM_M25P32_SECTOR_COUNT
|
||||
+#define STM_4MB_SECTOR_SIZE STM_M25P32_SECTOR_SIZE
|
||||
+#define STM_8MB_BYTE_COUNT STM_M25P64_BYTE_COUNT
|
||||
+#define STM_8MB_SECTOR_COUNT STM_M25P64_SECTOR_COUNT
|
||||
+#define STM_8MB_SECTOR_SIZE STM_M25P64_SECTOR_SIZE
|
||||
+
|
||||
+/*
|
||||
+ * ST Microelectronics Opcodes for Serial Flash
|
||||
+ */
|
||||
+
|
||||
+#define STM_OP_WR_ENABLE 0x06 /* Write Enable */
|
||||
+#define STM_OP_WR_DISABLE 0x04 /* Write Disable */
|
||||
+#define STM_OP_RD_STATUS 0x05 /* Read Status */
|
||||
+#define STM_OP_WR_STATUS 0x01 /* Write Status */
|
||||
+#define STM_OP_RD_DATA 0x03 /* Read Data */
|
||||
+#define STM_OP_FAST_RD_DATA 0x0b /* Fast Read Data */
|
||||
+#define STM_OP_PAGE_PGRM 0x02 /* Page Program */
|
||||
+#define STM_OP_SECTOR_ERASE 0xd8 /* Sector Erase */
|
||||
+#define STM_OP_BULK_ERASE 0xc7 /* Bulk Erase */
|
||||
+#define STM_OP_DEEP_PWRDOWN 0xb9 /* Deep Power-Down Mode */
|
||||
+#define STM_OP_RD_SIG 0xab /* Read Electronic Signature */
|
||||
+
|
||||
+#define STM_STATUS_WIP 0x01 /* Write-In-Progress */
|
||||
+#define STM_STATUS_WEL 0x02 /* Write Enable Latch */
|
||||
+#define STM_STATUS_BP0 0x04 /* Block Protect 0 */
|
||||
+#define STM_STATUS_BP1 0x08 /* Block Protect 1 */
|
||||
+#define STM_STATUS_BP2 0x10 /* Block Protect 2 */
|
||||
+#define STM_STATUS_SRWD 0x80 /* Status Register Write Disable */
|
||||
+
|
||||
+/*
|
||||
+ * SPI Flash Interface Registers
|
||||
+ */
|
||||
+#define AR531XPLUS_SPI_READ 0x08000000
|
||||
+#define AR531XPLUS_SPI_MMR 0x11300000
|
||||
+#define AR531XPLUS_SPI_MMR_SIZE 12
|
||||
+
|
||||
+#define AR531XPLUS_SPI_CTL 0x00
|
||||
+#define AR531XPLUS_SPI_OPCODE 0x04
|
||||
+#define AR531XPLUS_SPI_DATA 0x08
|
||||
+
|
||||
+#define SPI_FLASH_READ AR531XPLUS_SPI_READ
|
||||
+#define SPI_FLASH_MMR AR531XPLUS_SPI_MMR
|
||||
+#define SPI_FLASH_MMR_SIZE AR531XPLUS_SPI_MMR_SIZE
|
||||
+#define SPI_FLASH_CTL AR531XPLUS_SPI_CTL
|
||||
+#define SPI_FLASH_OPCODE AR531XPLUS_SPI_OPCODE
|
||||
+#define SPI_FLASH_DATA AR531XPLUS_SPI_DATA
|
||||
+
|
||||
+#define SPI_CTL_START 0x00000100
|
||||
+#define SPI_CTL_BUSY 0x00010000
|
||||
+#define SPI_CTL_TXCNT_MASK 0x0000000f
|
||||
+#define SPI_CTL_RXCNT_MASK 0x000000f0
|
||||
+#define SPI_CTL_TX_RX_CNT_MASK 0x000000ff
|
||||
+#define SPI_CTL_SIZE_MASK 0x00060000
|
||||
+
|
||||
+#define SPI_CTL_CLK_SEL_MASK 0x03000000
|
||||
+#define SPI_OPCODE_MASK 0x000000ff
|
||||
+
|
||||
+#define SPI_STATUS_WIP STM_STATUS_WIP
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue