* Copyright (c) 2000-2005 ZyDAS Technology Corporation
* Copyright (c) 2007-2009 Atheros Communications, Inc.
* Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
- * Copyright 2009 Christian Lamparter <chunkeey@googlemail.com>
+ * 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
* 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.
+ * with this program; If not, see <http://www.gnu.org/licenses/>.
*/
#include "carl9170.h"
+#include "shared/phy.h"
#include "hostif.h"
#include "printf.h"
#include "timer.h"
#include "rom.h"
-#include "gpio.h"
-#include "shared/phy.h"
+#include "wl.h"
+#include "wol.h"
#ifdef CONFIG_CARL9170FW_DEBUG_USB
void usb_putc(const char c)
{
struct carl9170_rsp *tmp;
- tmp = &fw.usb.int_buf[fw.usb.int_tail_index++];
+ /* fetch the _oldest_ buffer from the ring */
+ tmp = &fw.usb.int_buf[fw.usb.int_tail_index];
+
+ /* assign a unique sequence for every response/trap */
+ tmp->hdr.seq = fw.usb.int_tail_index;
+
+ fw.usb.int_tail_index++;
+
fw.usb.int_tail_index %= CARL9170_INT_RQ_CACHES;
if (fw.usb.int_pending != CARL9170_INT_RQ_CACHES)
fw.usb.int_pending++;
usb_trigger_in();
}
-/* Reset all the USB FIFO used for WLAN */
-static void usb_reset_FIFO(void)
-{
- uint32_t val;
-
- /*
- * of course,
- * simpley ORing AR9170_MAC_POWER_STATE_CTRL_RESET
- * would be... I dunno, maybe: just to simple?
- */
-
- val = get(AR9170_MAC_REG_POWER_STATE_CTRL);
- val |= AR9170_MAC_POWER_STATE_CTRL_RESET;
- set(AR9170_MAC_REG_POWER_STATE_CTRL, val);
-
- /* Reset USB FIFO */
- set(AR9170_PWR_REG_ADDA_BB, AR9170_PWR_ADDA_BB_USB_FIFO_RESET);
- set(AR9170_PWR_REG_ADDA_BB, 0x0);
-}
-
/* Turn off ADDA/RF power, PLL */
static void turn_power_off(void)
{
set(AR9170_PHY_REG_ADC_CTL, 0xa0000000 |
AR9170_PHY_ADC_CTL_OFF_PWDADC | AR9170_PHY_ADC_CTL_OFF_PWDDAC);
+ /* This will also turn-off the LEDs */
set(AR9170_GPIO_REG_PORT_DATA, 0);
set(AR9170_GPIO_REG_PORT_TYPE, 0xf);
set(AR9170_PWR_REG_BASE, 0x40021);
- set(AR9170_PWR_REG_ADDA_BB, 0);
- clock_set(false, AHB_20_22MHZ);
+ set(AR9170_MAC_REG_DMA_TRIGGER, 0);
+
+ andl(AR9170_USB_REG_DMA_CTL, ~(AR9170_USB_DMA_CTL_ENABLE_TO_DEVICE |
+ AR9170_USB_DMA_CTL_ENABLE_FROM_DEVICE |
+ AR9170_USB_DMA_CTL_UP_PACKET_MODE |
+ AR9170_USB_DMA_CTL_DOWN_STREAM));
+
+ /* Do a software reset to PTA component */
+ orl(AR9170_PTA_REG_DMA_MODE_CTRL, AR9170_PTA_DMA_MODE_CTRL_RESET);
+ andl(AR9170_PTA_REG_DMA_MODE_CTRL, ~AR9170_PTA_DMA_MODE_CTRL_RESET);
+
+ orl(AR9170_PTA_REG_DMA_MODE_CTRL, AR9170_PTA_DMA_MODE_CTRL_DISABLE_USB);
+
+ set(AR9170_MAC_REG_POWER_STATE_CTRL,
+ AR9170_MAC_POWER_STATE_CTRL_RESET);
+
+ /* Reset USB FIFO */
+ set(AR9170_PWR_REG_RESET, AR9170_PWR_RESET_COMMIT_RESET_MASK |
+ AR9170_PWR_RESET_DMA_MASK |
+ AR9170_PWR_RESET_WLAN_MASK);
+ set(AR9170_PWR_REG_RESET, 0x0);
+
+ clock_set(AHB_20_22MHZ, false);
set(AR9170_PWR_REG_PLL_ADDAC, 0x5163); /* 0x502b; */
set(AR9170_PHY_REG_ADC_SERIAL_CTL, AR9170_PHY_ADC_SCTL_SEL_EXTERNAL_RADIO);
set(AR9170_PHY_REG_ADC_SERIAL_CTL, AR9170_PHY_ADC_SCTL_SEL_INTERNAL_ADDAC);
}
-void __attribute__((noreturn)) reboot(void)
+static void disable_watchdog(void)
{
- /* turn off leds */
- led_set(0);
+ if (!fw.watchdog_enable)
+ return;
/* write watchdog magic pattern for suspend */
andl(AR9170_PWR_REG_WATCH_DOG_MAGIC, 0xffff);
orl(AR9170_PWR_REG_WATCH_DOG_MAGIC, 0x98760000);
/* Disable watchdog */
- orl(AR9170_TIMER_REG_WATCH_DOG, 0xffff);
+ set(AR9170_TIMER_REG_WATCH_DOG, 0xffff);
+}
- /* Reset USB FIFO */
- usb_reset_FIFO();
+void __noreturn reboot(void)
+{
+ disable_watchdog();
/* Turn off power */
turn_power_off();
+ /* clean bootloader workspace */
+ memset(&dma_mem, 0, sizeof(dma_mem));
+
/* add by ygwei for work around USB PHY chirp sequence problem */
set(0x10f100, 0x12345678);
if (usb_interrupt_level1 & BIT(0)) {
usb_interrupt_level2 = getb(AR9170_USB_REG_INTR_SOURCE_0);
- if (usb_interrupt_level2 & BIT(0))
+ if (usb_interrupt_level2 & AR9170_USB_INTR_SRC0_SETUP)
usb_ep0setup();
- if (usb_interrupt_level2 & BIT(1))
+ if (usb_interrupt_level2 & AR9170_USB_INTR_SRC0_IN)
usb_ep0tx();
- if (usb_interrupt_level2 & BIT(2))
+ if (usb_interrupt_level2 & AR9170_USB_INTR_SRC0_OUT)
usb_ep0rx();
- if (usb_interrupt_level2 & BIT(7)) {
+ if (usb_interrupt_level2 & AR9170_USB_INTR_SRC0_ABORT) {
/* Clear the command abort interrupt */
- andb(AR9170_USB_REG_INTR_SOURCE_0, 0x7f);
+ andb(AR9170_USB_REG_INTR_SOURCE_0, (uint8_t)
+ ~AR9170_USB_INTR_SRC0_ABORT);
}
- if (usb_interrupt_level2 & BIT(3) ||
+ if (usb_interrupt_level2 & AR9170_USB_INTR_SRC0_FAIL ||
fw.usb.ep0_action & CARL9170_EP0_STALL) {
/*
* transmission failure.
fw.usb.ep0_action &= ~CARL9170_EP0_STALL;
}
- if (usb_interrupt_level2 & BIT(4) ||
+ if (usb_interrupt_level2 & AR9170_USB_INTR_SRC0_END ||
fw.usb.ep0_action & CARL9170_EP0_TRIGGER) {
/*
* transmission done.
if (usb_interrupt_level1 & BIT(7)) {
usb_interrupt_level2 = getb(AR9170_USB_REG_INTR_SOURCE_7);
- if (usb_interrupt_level2 & BIT(7))
+ if (usb_interrupt_level2 & AR9170_USB_INTR_SRC7_RX0BYTE)
usb_data_out0Byte();
- if (usb_interrupt_level2 & BIT(6))
+ if (usb_interrupt_level2 & AR9170_USB_INTR_SRC7_TX0BYTE)
usb_data_in0Byte();
- if (usb_interrupt_level2 & BIT(1)) {
+ if (usb_interrupt_level2 & AR9170_USB_INTR_SRC7_USB_RESET) {
usb_reset_ack();
+ usb_reset_eps();
reboot();
}
- if (usb_interrupt_level2 & BIT(2)) {
- /* ACK USB suspend interrupt */
+ if (usb_interrupt_level2 & AR9170_USB_INTR_SRC7_USB_SUSPEND) {
usb_suspend_ack();
- /* Set GO_TO_SUSPEND bit to USB main control register */
- setb(AR9170_USB_REG_MAIN_CTRL, BIT(3));
+ fw.suspend_mode = CARL9170_HOST_SUSPENDED;
- /* add by ygwei for work around USB PHY chirp sequence problem */
- set(0x10f100, 0x12345678);
+#ifdef CONFIG_CARL9170FW_WOL
+ if (!(fw.usb.device_feature & USB_DEVICE_REMOTE_WAKEUP) ||
+ !fw.wol.cmd.flags) {
+ disable_watchdog();
- reboot();
+ /* GO_TO_SUSPEND stops the CPU clock too. */
+ orb(AR9170_USB_REG_MAIN_CTRL, AR9170_USB_MAIN_CTRL_GO_TO_SUSPEND);
+ } else {
+ wol_prepare();
+ }
+#else /* CONFIG_CARL9170FW_WOL */
+ disable_watchdog();
+
+ /* GO_TO_SUSPEND stops the CPU clock too. */
+ orb(AR9170_USB_REG_MAIN_CTRL, AR9170_USB_MAIN_CTRL_GO_TO_SUSPEND);
+#endif /* CONFIG_CARL9170FW_WOL */
}
- if (usb_interrupt_level2 & BIT(3))
+ if (usb_interrupt_level2 & AR9170_USB_INTR_SRC7_USB_RESUME) {
usb_resume_ack();
+
+ fw.suspend_mode = CARL9170_HOST_AWAKE;
+ set(AR9170_USB_REG_WAKE_UP, 0);
+
+ reboot();
+ }
}
}
usb_trigger_in();
}
-#ifdef CONFIG_CARL9170FW_USB_WATCHDOG
-void usb_watchdog_timer(void)
+void usb_timer(void)
{
- if (fw.usb.watchdog.state == cpu_to_le32(CARL9170_USB_WATCHDOG_INACTIVE))
- return;
-
- fw.usb.watchdog.state++;
-
- if (le32_to_cpu(fw.usb.watchdog.state) >= CARL9170_USB_WATCHDOG_TRIGGER_THRESHOLD) {
- for (;;) {
- /*
- * Simply wait until the HW watchdog
- * timer has elapsed.
- */
- }
- }
-
- send_cmd_to_host(sizeof(fw.usb.watchdog), CARL9170_RSP_USB_WD,
- 0x80, (uint8_t *) &fw.usb.watchdog);
}
-#endif /* CONFIG_CARL9170FW_USB_WATCHDOG */
-