ath9k: Enable TSF2 for generic HW timers
authorSujith Manoharan <c_manoha@qca.qualcomm.com>
Sun, 16 Nov 2014 00:41:03 +0000 (06:11 +0530)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 17 Nov 2014 20:32:16 +0000 (15:32 -0500)
The base TSF is used for HW timers 0..7, but chips
in the AR9003 family and above can support more generic
timers. To use them, however, a second HW TSF needs to
be enabled. This patch allows usage of the extra
timers by starting the second TSF properly.

The extra set of HW timers is apparently also present
in AR9287, but we enable it only for the AR9003 family.

Cc: Kobi Cohen-Arazi <kobic@qti.qualcomm.com>
Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/reg.h

index fa9e5e9..19004dd 100644 (file)
@@ -1960,6 +1960,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 
        REGWRITE_BUFFER_FLUSH(ah);
 
+       ath9k_hw_gen_timer_start_tsf2(ah);
+
        ath9k_hw_init_desc(ah);
 
        if (ath9k_hw_btcoex_is_enabled(ah))
@@ -2924,6 +2926,16 @@ u32 ath9k_hw_gettsf32(struct ath_hw *ah)
 }
 EXPORT_SYMBOL(ath9k_hw_gettsf32);
 
+void ath9k_hw_gen_timer_start_tsf2(struct ath_hw *ah)
+{
+       struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
+
+       if (timer_table->tsf2_enabled) {
+               REG_SET_BIT(ah, AR_DIRECT_CONNECT, AR_DC_AP_STA_EN);
+               REG_SET_BIT(ah, AR_RESET_TSF, AR_RESET_TSF2_ONCE);
+       }
+}
+
 struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
                                          void (*trigger)(void *),
                                          void (*overflow)(void *),
@@ -2934,7 +2946,11 @@ struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
        struct ath_gen_timer *timer;
 
        if ((timer_index < AR_FIRST_NDP_TIMER) ||
-               (timer_index >= ATH_MAX_GEN_TIMER))
+           (timer_index >= ATH_MAX_GEN_TIMER))
+               return NULL;
+
+       if ((timer_index > AR_FIRST_NDP_TIMER) &&
+           !AR_SREV_9300_20_OR_LATER(ah))
                return NULL;
 
        timer = kzalloc(sizeof(struct ath_gen_timer), GFP_KERNEL);
@@ -2948,6 +2964,11 @@ struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
        timer->overflow = overflow;
        timer->arg = arg;
 
+       if ((timer_index > AR_FIRST_NDP_TIMER) && !timer_table->tsf2_enabled) {
+               timer_table->tsf2_enabled = true;
+               ath9k_hw_gen_timer_start_tsf2(ah);
+       }
+
        return timer;
 }
 EXPORT_SYMBOL(ath_gen_timer_alloc);
index d2c0448..893584b 100644 (file)
@@ -525,6 +525,7 @@ struct ath_gen_timer {
 struct ath_gen_timer_table {
        struct ath_gen_timer *timers[ATH_MAX_GEN_TIMER];
        u16 timer_mask;
+       bool tsf2_enabled;
 };
 
 struct ath_hw_antcomb_conf {
@@ -1037,6 +1038,7 @@ void ath9k_hw_gen_timer_start(struct ath_hw *ah,
                              struct ath_gen_timer *timer,
                              u32 timer_next,
                              u32 timer_period);
+void ath9k_hw_gen_timer_start_tsf2(struct ath_hw *ah);
 void ath9k_hw_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer);
 
 void ath_gen_timer_free(struct ath_hw *ah, struct ath_gen_timer *timer);
index 1c0b1c1..ced36b4 100644 (file)
@@ -1605,6 +1605,7 @@ enum {
 
 #define AR_RESET_TSF        0x8020
 #define AR_RESET_TSF_ONCE   0x01000000
+#define AR_RESET_TSF2_ONCE  0x02000000
 
 #define AR_MAX_CFP_DUR      0x8038
 #define AR_CFP_VAL          0x0000FFFF
@@ -1966,6 +1967,8 @@ enum {
 #define AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET          0x80000000
 #define AR_MAC_PCU_GEN_TIMER_TSF_SEL                   0x83d8
 
+#define AR_DIRECT_CONNECT                              0x83a0
+#define AR_DC_AP_STA_EN                                0x00000001
 
 #define AR_AES_MUTE_MASK0       0x805c
 #define AR_AES_MUTE_MASK0_FC    0x0000FFFF