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