1*b7d5e03cSMatthew Dillon /*
2*b7d5e03cSMatthew Dillon * Copyright (c) 2013 Qualcomm Atheros, Inc.
3*b7d5e03cSMatthew Dillon *
4*b7d5e03cSMatthew Dillon * Permission to use, copy, modify, and/or distribute this software for any
5*b7d5e03cSMatthew Dillon * purpose with or without fee is hereby granted, provided that the above
6*b7d5e03cSMatthew Dillon * copyright notice and this permission notice appear in all copies.
7*b7d5e03cSMatthew Dillon *
8*b7d5e03cSMatthew Dillon * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9*b7d5e03cSMatthew Dillon * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10*b7d5e03cSMatthew Dillon * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11*b7d5e03cSMatthew Dillon * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12*b7d5e03cSMatthew Dillon * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
13*b7d5e03cSMatthew Dillon * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14*b7d5e03cSMatthew Dillon * PERFORMANCE OF THIS SOFTWARE.
15*b7d5e03cSMatthew Dillon */
16*b7d5e03cSMatthew Dillon
17*b7d5e03cSMatthew Dillon #include "opt_ah.h"
18*b7d5e03cSMatthew Dillon
19*b7d5e03cSMatthew Dillon #include "ah.h"
20*b7d5e03cSMatthew Dillon #include "ah_internal.h"
21*b7d5e03cSMatthew Dillon
22*b7d5e03cSMatthew Dillon #include "ar9300/ar9300.h"
23*b7d5e03cSMatthew Dillon #include "ar9300/ar9300reg.h"
24*b7d5e03cSMatthew Dillon #include "ar9300/ar9300desc.h"
25*b7d5e03cSMatthew Dillon
26*b7d5e03cSMatthew Dillon typedef struct gen_timer_configuation {
27*b7d5e03cSMatthew Dillon u_int32_t next_addr;
28*b7d5e03cSMatthew Dillon u_int32_t period_addr;
29*b7d5e03cSMatthew Dillon u_int32_t mode_addr;
30*b7d5e03cSMatthew Dillon u_int32_t mode_mask;
31*b7d5e03cSMatthew Dillon } GEN_TIMER_CONFIGURATION;
32*b7d5e03cSMatthew Dillon
33*b7d5e03cSMatthew Dillon #define AR_GEN_TIMERS2_CFG(num) \
34*b7d5e03cSMatthew Dillon AR_GEN_TIMERS2_ ## num ## _NEXT, \
35*b7d5e03cSMatthew Dillon AR_GEN_TIMERS2_ ## num ## _PERIOD, \
36*b7d5e03cSMatthew Dillon AR_GEN_TIMERS2_MODE, \
37*b7d5e03cSMatthew Dillon (1 << num)
38*b7d5e03cSMatthew Dillon static const GEN_TIMER_CONFIGURATION gen_timer_configuration[] =
39*b7d5e03cSMatthew Dillon {
40*b7d5e03cSMatthew Dillon {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
41*b7d5e03cSMatthew Dillon {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
42*b7d5e03cSMatthew Dillon {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
43*b7d5e03cSMatthew Dillon {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
44*b7d5e03cSMatthew Dillon {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
45*b7d5e03cSMatthew Dillon {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
46*b7d5e03cSMatthew Dillon {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
47*b7d5e03cSMatthew Dillon {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
48*b7d5e03cSMatthew Dillon {AR_GEN_TIMERS2_CFG(0)},
49*b7d5e03cSMatthew Dillon {AR_GEN_TIMERS2_CFG(1)},
50*b7d5e03cSMatthew Dillon {AR_GEN_TIMERS2_CFG(2)},
51*b7d5e03cSMatthew Dillon {AR_GEN_TIMERS2_CFG(3)},
52*b7d5e03cSMatthew Dillon {AR_GEN_TIMERS2_CFG(4)},
53*b7d5e03cSMatthew Dillon {AR_GEN_TIMERS2_CFG(5)},
54*b7d5e03cSMatthew Dillon {AR_GEN_TIMERS2_CFG(6)},
55*b7d5e03cSMatthew Dillon {AR_GEN_TIMERS2_CFG(7)}
56*b7d5e03cSMatthew Dillon };
57*b7d5e03cSMatthew Dillon
58*b7d5e03cSMatthew Dillon #define AR_GENTMR_BIT(_index) (1 << (_index))
59*b7d5e03cSMatthew Dillon
60*b7d5e03cSMatthew Dillon int
ar9300_alloc_generic_timer(struct ath_hal * ah,HAL_GEN_TIMER_DOMAIN tsf)61*b7d5e03cSMatthew Dillon ar9300_alloc_generic_timer(struct ath_hal *ah, HAL_GEN_TIMER_DOMAIN tsf)
62*b7d5e03cSMatthew Dillon {
63*b7d5e03cSMatthew Dillon struct ath_hal_9300 *ahp = AH9300(ah);
64*b7d5e03cSMatthew Dillon u_int32_t i, mask;
65*b7d5e03cSMatthew Dillon u_int32_t avail_timer_start, avail_timer_end;
66*b7d5e03cSMatthew Dillon
67*b7d5e03cSMatthew Dillon if (tsf == HAL_GEN_TIMER_TSF) {
68*b7d5e03cSMatthew Dillon avail_timer_start = AR_FIRST_NDP_TIMER;
69*b7d5e03cSMatthew Dillon avail_timer_end = AR_GEN_TIMER_BANK_1_LEN;
70*b7d5e03cSMatthew Dillon } else {
71*b7d5e03cSMatthew Dillon avail_timer_start = AR_GEN_TIMER_BANK_1_LEN;
72*b7d5e03cSMatthew Dillon avail_timer_end = AR_NUM_GEN_TIMERS;
73*b7d5e03cSMatthew Dillon }
74*b7d5e03cSMatthew Dillon
75*b7d5e03cSMatthew Dillon /* Find the first availabe timer index */
76*b7d5e03cSMatthew Dillon i = avail_timer_start;
77*b7d5e03cSMatthew Dillon mask = ahp->ah_avail_gen_timers >> i;
78*b7d5e03cSMatthew Dillon for ( ; mask && (i < avail_timer_end) ; mask >>= 1, i++ ) {
79*b7d5e03cSMatthew Dillon if (mask & 0x1) {
80*b7d5e03cSMatthew Dillon ahp->ah_avail_gen_timers &= ~(AR_GENTMR_BIT(i));
81*b7d5e03cSMatthew Dillon
82*b7d5e03cSMatthew Dillon if ((tsf == HAL_GEN_TIMER_TSF2) && !ahp->ah_enable_tsf2) {
83*b7d5e03cSMatthew Dillon ahp->ah_enable_tsf2 = AH_TRUE;
84*b7d5e03cSMatthew Dillon ar9300_start_tsf2(ah);
85*b7d5e03cSMatthew Dillon }
86*b7d5e03cSMatthew Dillon return i;
87*b7d5e03cSMatthew Dillon }
88*b7d5e03cSMatthew Dillon }
89*b7d5e03cSMatthew Dillon return -1;
90*b7d5e03cSMatthew Dillon }
91*b7d5e03cSMatthew Dillon
ar9300_start_tsf2(struct ath_hal * ah)92*b7d5e03cSMatthew Dillon void ar9300_start_tsf2(struct ath_hal *ah)
93*b7d5e03cSMatthew Dillon {
94*b7d5e03cSMatthew Dillon struct ath_hal_9300 *ahp = AH9300(ah);
95*b7d5e03cSMatthew Dillon
96*b7d5e03cSMatthew Dillon if (ahp->ah_enable_tsf2) {
97*b7d5e03cSMatthew Dillon /* Delay might be needed after TSF2 reset */
98*b7d5e03cSMatthew Dillon OS_REG_SET_BIT(ah, AR_DIRECT_CONNECT, AR_DC_AP_STA_EN);
99*b7d5e03cSMatthew Dillon OS_REG_SET_BIT(ah, AR_RESET_TSF, AR_RESET_TSF2_ONCE);
100*b7d5e03cSMatthew Dillon }
101*b7d5e03cSMatthew Dillon }
102*b7d5e03cSMatthew Dillon
103*b7d5e03cSMatthew Dillon void
ar9300_free_generic_timer(struct ath_hal * ah,int index)104*b7d5e03cSMatthew Dillon ar9300_free_generic_timer(struct ath_hal *ah, int index)
105*b7d5e03cSMatthew Dillon {
106*b7d5e03cSMatthew Dillon struct ath_hal_9300 *ahp = AH9300(ah);
107*b7d5e03cSMatthew Dillon
108*b7d5e03cSMatthew Dillon ar9300_stop_generic_timer(ah, index);
109*b7d5e03cSMatthew Dillon ahp->ah_avail_gen_timers |= AR_GENTMR_BIT(index);
110*b7d5e03cSMatthew Dillon }
111*b7d5e03cSMatthew Dillon
112*b7d5e03cSMatthew Dillon void
ar9300_start_generic_timer(struct ath_hal * ah,int index,u_int32_t timer_next,u_int32_t timer_period)113*b7d5e03cSMatthew Dillon ar9300_start_generic_timer(
114*b7d5e03cSMatthew Dillon struct ath_hal *ah,
115*b7d5e03cSMatthew Dillon int index,
116*b7d5e03cSMatthew Dillon u_int32_t timer_next,
117*b7d5e03cSMatthew Dillon u_int32_t timer_period)
118*b7d5e03cSMatthew Dillon {
119*b7d5e03cSMatthew Dillon if ((index < AR_FIRST_NDP_TIMER) || (index >= AR_NUM_GEN_TIMERS)) {
120*b7d5e03cSMatthew Dillon return;
121*b7d5e03cSMatthew Dillon }
122*b7d5e03cSMatthew Dillon
123*b7d5e03cSMatthew Dillon /*
124*b7d5e03cSMatthew Dillon * Program generic timer registers
125*b7d5e03cSMatthew Dillon */
126*b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, gen_timer_configuration[index].next_addr, timer_next);
127*b7d5e03cSMatthew Dillon OS_REG_WRITE(ah, gen_timer_configuration[index].period_addr, timer_period);
128*b7d5e03cSMatthew Dillon OS_REG_SET_BIT(ah,
129*b7d5e03cSMatthew Dillon gen_timer_configuration[index].mode_addr,
130*b7d5e03cSMatthew Dillon gen_timer_configuration[index].mode_mask);
131*b7d5e03cSMatthew Dillon
132*b7d5e03cSMatthew Dillon if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) {
133*b7d5e03cSMatthew Dillon /*
134*b7d5e03cSMatthew Dillon * Starting from Jupiter, each generic timer can select which tsf to
135*b7d5e03cSMatthew Dillon * use. But we still follow the old rule, 0 - 7 use tsf and 8 - 15
136*b7d5e03cSMatthew Dillon * use tsf2.
137*b7d5e03cSMatthew Dillon */
138*b7d5e03cSMatthew Dillon if ((index < AR_GEN_TIMER_BANK_1_LEN)) {
139*b7d5e03cSMatthew Dillon OS_REG_CLR_BIT(ah, AR_MAC_PCU_GEN_TIMER_TSF_SEL, (1 << index));
140*b7d5e03cSMatthew Dillon }
141*b7d5e03cSMatthew Dillon else {
142*b7d5e03cSMatthew Dillon OS_REG_SET_BIT(ah, AR_MAC_PCU_GEN_TIMER_TSF_SEL, (1 << index));
143*b7d5e03cSMatthew Dillon }
144*b7d5e03cSMatthew Dillon }
145*b7d5e03cSMatthew Dillon
146*b7d5e03cSMatthew Dillon /* Enable both trigger and thresh interrupt masks */
147*b7d5e03cSMatthew Dillon OS_REG_SET_BIT(ah, AR_IMR_S5,
148*b7d5e03cSMatthew Dillon (SM(AR_GENTMR_BIT(index), AR_IMR_S5_GENTIMER_THRESH) |
149*b7d5e03cSMatthew Dillon SM(AR_GENTMR_BIT(index), AR_IMR_S5_GENTIMER_TRIG)));
150*b7d5e03cSMatthew Dillon }
151*b7d5e03cSMatthew Dillon
152*b7d5e03cSMatthew Dillon void
ar9300_stop_generic_timer(struct ath_hal * ah,int index)153*b7d5e03cSMatthew Dillon ar9300_stop_generic_timer(struct ath_hal *ah, int index)
154*b7d5e03cSMatthew Dillon {
155*b7d5e03cSMatthew Dillon if ((index < AR_FIRST_NDP_TIMER) || (index >= AR_NUM_GEN_TIMERS)) {
156*b7d5e03cSMatthew Dillon return;
157*b7d5e03cSMatthew Dillon }
158*b7d5e03cSMatthew Dillon
159*b7d5e03cSMatthew Dillon /*
160*b7d5e03cSMatthew Dillon * Clear generic timer enable bits.
161*b7d5e03cSMatthew Dillon */
162*b7d5e03cSMatthew Dillon OS_REG_CLR_BIT(ah,
163*b7d5e03cSMatthew Dillon gen_timer_configuration[index].mode_addr,
164*b7d5e03cSMatthew Dillon gen_timer_configuration[index].mode_mask);
165*b7d5e03cSMatthew Dillon
166*b7d5e03cSMatthew Dillon /* Disable both trigger and thresh interrupt masks */
167*b7d5e03cSMatthew Dillon OS_REG_CLR_BIT(ah, AR_IMR_S5,
168*b7d5e03cSMatthew Dillon (SM(AR_GENTMR_BIT(index), AR_IMR_S5_GENTIMER_THRESH) |
169*b7d5e03cSMatthew Dillon SM(AR_GENTMR_BIT(index), AR_IMR_S5_GENTIMER_TRIG)));
170*b7d5e03cSMatthew Dillon }
171*b7d5e03cSMatthew Dillon
172*b7d5e03cSMatthew Dillon void
ar9300_get_gen_timer_interrupts(struct ath_hal * ah,u_int32_t * trigger,u_int32_t * thresh)173*b7d5e03cSMatthew Dillon ar9300_get_gen_timer_interrupts(
174*b7d5e03cSMatthew Dillon struct ath_hal *ah,
175*b7d5e03cSMatthew Dillon u_int32_t *trigger,
176*b7d5e03cSMatthew Dillon u_int32_t *thresh)
177*b7d5e03cSMatthew Dillon {
178*b7d5e03cSMatthew Dillon struct ath_hal_9300 *ahp = AH9300(ah);
179*b7d5e03cSMatthew Dillon *trigger = ahp->ah_intr_gen_timer_trigger;
180*b7d5e03cSMatthew Dillon *thresh = ahp->ah_intr_gen_timer_thresh;
181*b7d5e03cSMatthew Dillon }
182