carl9170 firmware: Wake-on-LAN support
[carl9170fw.git] / carlfw / usb / main.c
index fac37805be7f555a90f5ef128e258932bf1fee5e..c2ad6c3d71fcc79fc4b1bc082430f796931745cd 100644 (file)
@@ -27,6 +27,7 @@
 #include "printf.h"
 #include "timer.h"
 #include "rom.h"
+#include "wl.h"
 #include "shared/phy.h"
 
 #ifdef CONFIG_CARL9170FW_DEBUG_USB
@@ -224,6 +225,17 @@ static void turn_power_off(void)
 
        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);
 
@@ -233,7 +245,7 @@ static void turn_power_off(void)
                                  AR9170_PWR_RESET_WLAN_MASK);
        set(AR9170_PWR_REG_RESET, 0x0);
 
-       clock_set(false, AHB_20_22MHZ);
+       set(AR9170_PWR_REG_CLOCK_SEL, AHB_40MHZ_OSC);
 
        set(AR9170_PWR_REG_PLL_ADDAC, 0x5163);  /* 0x502b; */
        set(AR9170_PHY_REG_ADC_SERIAL_CTL, AR9170_PHY_ADC_SCTL_SEL_EXTERNAL_RADIO);
@@ -270,9 +282,10 @@ static void turn_power_off(void)
        set(AR9170_PHY_REG_ADC_SERIAL_CTL, AR9170_PHY_ADC_SCTL_SEL_INTERNAL_ADDAC);
 }
 
-void __noreturn reboot(void)
+static void disable_watchdog(void)
 {
-       set(AR9170_MAC_REG_DMA_TRIGGER, 0);
+       if (!fw.watchdog_enable)
+               return;
 
        /* write watchdog magic pattern for suspend  */
        andl(AR9170_PWR_REG_WATCH_DOG_MAGIC, 0xffff);
@@ -280,10 +293,18 @@ void __noreturn reboot(void)
 
        /* Disable watchdog */
        set(AR9170_TIMER_REG_WATCH_DOG, 0xffff);
+}
+
+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);
 
@@ -308,21 +329,22 @@ static void usb_handler(uint8_t usb_interrupt_level1)
        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.
@@ -332,7 +354,7 @@ static void usb_handler(uint8_t usb_interrupt_level1)
                        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.
@@ -346,32 +368,39 @@ static void usb_handler(uint8_t usb_interrupt_level1)
        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();
                        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);
+                       if (!(fw.usb.device_feature & USB_DEVICE_REMOTE_WAKEUP)) {
+                               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 {
+                               wlan_prepare_wol();
+                       }
                }
 
-               if (usb_interrupt_level2 & BIT(3))
+               if (usb_interrupt_level2 & AR9170_USB_INTR_SRC7_USB_RESUME) {
+                       fw.suspend_mode = CARL9170_HOST_AWAKE;
+                       andl(AR9170_USB_REG_WAKE_UP, AR9170_USB_WAKE_UP_WAKE);
+
                        usb_resume_ack();
+                       reboot();
+               }
        }
 }
 
@@ -388,3 +417,11 @@ void handle_usb(void)
                usb_trigger_in();
 }
 
+void usb_timer(void)
+{
+#ifdef CONFIG_CARL9170FW_WOL
+       if (fw.suspend_mode == CARL9170_AWAKE_HOST) {
+               orl(AR9170_USB_REG_WAKE_UP, AR9170_USB_WAKE_UP_WAKE);
+       }
+#endif /* CONFIG_CARL9170FW_WOL */
+}