You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
257 lines
6.1 KiB
257 lines
6.1 KiB
13 years ago
|
/*
|
||
|
* carl9170 firmware - used by the ar9170 wireless device
|
||
|
*
|
||
|
* initialization and main() loop
|
||
|
*
|
||
|
* Copyright (c) 2000-2005 ZyDAS Technology Corporation
|
||
|
* Copyright (c) 2007-2009 Atheros Communications, Inc.
|
||
|
* Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
|
||
|
* Copyright 2009-2011 Christian Lamparter <chunkeey@googlemail.com>
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation; either version 2 of the License, or
|
||
|
* (at your option) any later version.
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License along
|
||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||
|
*/
|
||
|
|
||
|
#include "carl9170.h"
|
||
|
#include "timer.h"
|
||
|
#include "hostif.h"
|
||
|
#include "printf.h"
|
||
|
#include "gpio.h"
|
||
|
#include "wl.h"
|
||
|
#include "rf.h"
|
||
|
#include "usb.h"
|
||
|
|
||
|
#define AR9170_WATCH_DOG_TIMER 0x100
|
||
|
|
||
|
static void timer_init(const unsigned int timer, const unsigned int interval)
|
||
|
{
|
||
|
/* Set timer to periodic mode */
|
||
|
orl(AR9170_TIMER_REG_CONTROL, BIT(timer));
|
||
|
|
||
|
/* Set time interval */
|
||
|
set(AR9170_TIMER_REG_TIMER0 + (timer << 2), interval - 1);
|
||
|
|
||
|
/* Clear timer interrupt flag */
|
||
|
orl(AR9170_TIMER_REG_INTERRUPT, BIT(timer));
|
||
|
}
|
||
|
|
||
|
void clock_set(enum cpu_clock_t clock_, bool on)
|
||
|
{
|
||
|
/*
|
||
|
* Word of Warning!
|
||
|
* This setting does more than just mess with the CPU Clock.
|
||
|
* So watch out, if you need _stable_ timer interrupts.
|
||
|
*/
|
||
|
#ifdef CONFIG_CARL9170FW_RADIO_FUNCTIONS
|
||
|
if (fw.phy.frequency < 3000000)
|
||
|
set(AR9170_PWR_REG_PLL_ADDAC, 0x5163);
|
||
|
else
|
||
|
set(AR9170_PWR_REG_PLL_ADDAC, 0x5143);
|
||
|
#else
|
||
|
set(AR9170_PWR_REG_PLL_ADDAC, 0x5163);
|
||
|
#endif /* CONFIG_CARL9170FW_RADIO_FUNCTIONS */
|
||
|
|
||
|
fw.ticks_per_usec = GET_VAL(AR9170_PWR_PLL_ADDAC_DIV,
|
||
|
get(AR9170_PWR_REG_PLL_ADDAC));
|
||
|
|
||
|
set(AR9170_PWR_REG_CLOCK_SEL, (uint32_t) ((on ? 0x70 : 0x600) | clock_));
|
||
|
|
||
|
switch (clock_) {
|
||
|
case AHB_20_22MHZ:
|
||
|
fw.ticks_per_usec >>= 1;
|
||
|
case AHB_40MHZ_OSC:
|
||
|
case AHB_40_44MHZ:
|
||
|
fw.ticks_per_usec >>= 1;
|
||
|
case AHB_80_88MHZ:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void init(void)
|
||
|
{
|
||
|
led_init();
|
||
|
|
||
|
#ifdef CONFIG_CARL9170FW_DEBUG_UART
|
||
|
uart_init();
|
||
|
#endif /* CONFIG_CARL9170FW_DEBUG_UART */
|
||
|
|
||
|
/* 25/50/100ms timer (depends on cpu clock) */
|
||
|
timer_init(0, 50000);
|
||
|
|
||
|
/* USB init */
|
||
|
usb_init();
|
||
|
|
||
|
/* initialize DMA memory */
|
||
|
memset(&dma_mem, 0, sizeof(dma_mem));
|
||
|
|
||
|
/* fill DMA rings */
|
||
|
dma_init_descriptors();
|
||
|
|
||
|
/* clear all interrupt */
|
||
|
set(AR9170_MAC_REG_INT_CTRL, 0xffff);
|
||
|
|
||
|
orl(AR9170_MAC_REG_AFTER_PNP, 1);
|
||
|
|
||
|
/* Init watch dog control flag */
|
||
|
fw.watchdog_enable = 1;
|
||
|
|
||
|
set(AR9170_TIMER_REG_WATCH_DOG, AR9170_WATCH_DOG_TIMER);
|
||
|
|
||
|
#ifdef CONFIG_CARL9170FW_GPIO_INTERRUPT
|
||
|
fw.cached_gpio_state.gpio = get(AR9170_GPIO_REG_PORT_DATA) &
|
||
|
CARL9170_GPIO_MASK;
|
||
|
#endif /* CONFIG_CARL9170FW_GPIO_INTERRUPT */
|
||
|
|
||
|
/* this will get the downqueue moving. */
|
||
|
down_trigger();
|
||
|
}
|
||
|
|
||
|
static void handle_fw(void)
|
||
|
{
|
||
|
if (fw.watchdog_enable == 1)
|
||
|
set(AR9170_TIMER_REG_WATCH_DOG, AR9170_WATCH_DOG_TIMER);
|
||
|
|
||
|
if (fw.reboot)
|
||
|
reboot();
|
||
|
}
|
||
|
|
||
|
static void timer0_isr(void)
|
||
|
{
|
||
|
wlan_timer();
|
||
|
|
||
|
#ifdef CONFIG_CARL9170FW_GPIO_INTERRUPT
|
||
|
gpio_timer();
|
||
|
#endif /* CONFIG_CARL9170FW_GPIO_INTERRUPT */
|
||
|
|
||
|
#ifdef CONFIG_CARL9170FW_DEBUG_LED_HEARTBEAT
|
||
|
set(AR9170_GPIO_REG_PORT_DATA, get(AR9170_GPIO_REG_PORT_DATA) ^ 1);
|
||
|
#endif /* CONFIG_CARL9170FW_DEBUG_LED_HEARTBEAT */
|
||
|
}
|
||
|
|
||
|
static void handle_timer(void)
|
||
|
{
|
||
|
uint32_t intr;
|
||
|
|
||
|
intr = get(AR9170_TIMER_REG_INTERRUPT);
|
||
|
|
||
|
/* ACK timer interrupt */
|
||
|
set(AR9170_TIMER_REG_INTERRUPT, intr);
|
||
|
|
||
|
#define HANDLER(intr, flag, func) \
|
||
|
do { \
|
||
|
if ((intr & flag) != 0) { \
|
||
|
intr &= ~flag; \
|
||
|
func(); \
|
||
|
} \
|
||
|
} while (0)
|
||
|
|
||
|
HANDLER(intr, BIT(0), timer0_isr);
|
||
|
|
||
|
if (intr)
|
||
|
DBG("Unhandled Timer Event %x", (unsigned int) intr);
|
||
|
|
||
|
#undef HANDLER
|
||
|
}
|
||
|
|
||
|
static void tally_update(void)
|
||
|
{
|
||
|
unsigned int boff, time, delta;
|
||
|
|
||
|
time = get_clock_counter();
|
||
|
if (fw.phy.state == CARL9170_PHY_ON) {
|
||
|
delta = (time - fw.tally_clock);
|
||
|
|
||
|
fw.tally.active += delta;
|
||
|
|
||
|
boff = get(AR9170_MAC_REG_BACKOFF_STATUS);
|
||
|
if (boff & AR9170_MAC_BACKOFF_TX_PE)
|
||
|
fw.tally.tx_time += delta;
|
||
|
if (boff & AR9170_MAC_BACKOFF_CCA)
|
||
|
fw.tally.cca += delta;
|
||
|
}
|
||
|
|
||
|
fw.tally_clock = time;
|
||
|
fw.counter++;
|
||
|
}
|
||
|
|
||
|
static void __noreturn main_loop(void)
|
||
|
{
|
||
|
/* main loop */
|
||
|
while (1) {
|
||
|
handle_fw();
|
||
|
|
||
|
/*
|
||
|
* Due to frame order persevation, the wlan subroutines
|
||
|
* must be executed before handle_host_interface.
|
||
|
*/
|
||
|
handle_wlan();
|
||
|
|
||
|
handle_host_interface();
|
||
|
|
||
|
handle_usb();
|
||
|
|
||
|
handle_timer();
|
||
|
|
||
|
tally_update();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* The bootcode will work with the device driver to load the firmware
|
||
|
* onto the device's Program SRAM. The Program SRAM has a size of 16 KB
|
||
|
* and also contains the stack, which grows down from 0x204000.
|
||
|
*
|
||
|
* The Program SRAM starts at address 0x200000 on the device.
|
||
|
* The firmware entry point (0x200004) is located in boot.S.
|
||
|
* we put _start() there with the linker script carl9170.lds.
|
||
|
*/
|
||
|
|
||
|
void __section(boot) start(void)
|
||
|
{
|
||
|
clock_set(AHB_40MHZ_OSC, true);
|
||
|
|
||
|
/* watchdog magic pattern check */
|
||
|
if ((get(AR9170_PWR_REG_WATCH_DOG_MAGIC) & 0xffff0000) == 0x12340000) {
|
||
|
/* watch dog warm start */
|
||
|
incl(AR9170_PWR_REG_WATCH_DOG_MAGIC);
|
||
|
usb_trigger_out();
|
||
|
} else if ((get(AR9170_PWR_REG_WATCH_DOG_MAGIC) & 0xffff0000) == 0x98760000) {
|
||
|
/* suspend/resume */
|
||
|
}
|
||
|
|
||
|
/* write the magic pattern for watch dog */
|
||
|
andl(AR9170_PWR_REG_WATCH_DOG_MAGIC, 0xFFFF);
|
||
|
orl(AR9170_PWR_REG_WATCH_DOG_MAGIC, 0x12340000);
|
||
|
|
||
|
init();
|
||
|
|
||
|
#ifdef CONFIG_CARL9170FW_DEBUG
|
||
|
|
||
|
BUG("TEST BUG");
|
||
|
BUG_ON(0x2b || !0x2b);
|
||
|
INFO("INFO MESSAGE");
|
||
|
|
||
|
/* a set of unique characters to detect transfer data corruptions */
|
||
|
DBG("AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"
|
||
|
" ~`!1@2#3$4%%5^6&7*8(9)0_-+={[}]|\\:;\"'<,>.?/");
|
||
|
#endif /* CONFIG_CARL9170FW_DEBUG */
|
||
|
|
||
|
/*
|
||
|
* Tell the host, that the firmware has booted and is
|
||
|
* now ready to process requests.
|
||
|
*/
|
||
|
send_cmd_to_host(0, CARL9170_RSP_BOOT, 0x00, NULL);
|
||
|
main_loop();
|
||
|
}
|