1250003Sadrian/*
2250003Sadrian * Copyright (c) 2013 Qualcomm Atheros, Inc.
3250003Sadrian *
4250003Sadrian * Permission to use, copy, modify, and/or distribute this software for any
5250003Sadrian * purpose with or without fee is hereby granted, provided that the above
6250003Sadrian * copyright notice and this permission notice appear in all copies.
7250003Sadrian *
8250003Sadrian * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9250003Sadrian * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10250003Sadrian * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11250003Sadrian * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12250003Sadrian * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
13250003Sadrian * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14250003Sadrian * PERFORMANCE OF THIS SOFTWARE.
15250003Sadrian */
16250003Sadrian
17250003Sadrian#include "opt_ah.h"
18250003Sadrian
19250003Sadrian#include "ah.h"
20250003Sadrian#include "ah_internal.h"
21250003Sadrian
22250003Sadrian#include "ar9300/ar9300.h"
23250003Sadrian#include "ar9300/ar9300reg.h"
24250003Sadrian
25250003Sadrian#define TU_TO_USEC(_tu) ((_tu) << 10)
26250008Sadrian#define	ONE_EIGHTH_TU_TO_USEC(_tu8) ((_tu8) << 7)
27250003Sadrian
28250003Sadrianextern u_int32_t ar9300_num_tx_pending(struct ath_hal *ah, u_int q);
29250003Sadrian
30250003Sadrian/*
31250003Sadrian * Initializes all of the hardware registers used to
32250003Sadrian * send beacons.  Note that for station operation the
33250003Sadrian * driver calls ar9300_set_sta_beacon_timers instead.
34250003Sadrian */
35250003Sadrianvoid
36250003Sadrianar9300_beacon_init(struct ath_hal *ah,
37278741Sadrian    u_int32_t next_beacon, u_int32_t beacon_period,
38278741Sadrian    u_int32_t beacon_period_fraction, HAL_OPMODE opmode)
39250003Sadrian{
40250003Sadrian    u_int32_t               beacon_period_usec;
41250003Sadrian
42250003Sadrian    HALASSERT(opmode == HAL_M_IBSS || opmode == HAL_M_HOSTAP);
43250003Sadrian    if (opmode == HAL_M_IBSS) {
44250003Sadrian        OS_REG_SET_BIT(ah, AR_TXCFG, AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY);
45250003Sadrian    }
46250003Sadrian    OS_REG_WRITE(ah, AR_NEXT_TBTT_TIMER, ONE_EIGHTH_TU_TO_USEC(next_beacon));
47250003Sadrian    OS_REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT,
48250003Sadrian        (ONE_EIGHTH_TU_TO_USEC(next_beacon) -
49250008Sadrian        ah->ah_config.ah_dma_beacon_response_time));
50250003Sadrian    OS_REG_WRITE(ah, AR_NEXT_SWBA,
51250003Sadrian        (ONE_EIGHTH_TU_TO_USEC(next_beacon) -
52250008Sadrian        ah->ah_config.ah_sw_beacon_response_time));
53250003Sadrian
54250003Sadrian    beacon_period_usec =
55250003Sadrian        ONE_EIGHTH_TU_TO_USEC(beacon_period & HAL_BEACON_PERIOD_TU8);
56278741Sadrian
57278741Sadrian    /* Add the fraction adjustment lost due to unit conversions. */
58278741Sadrian    beacon_period_usec += beacon_period_fraction;
59278741Sadrian
60278807Sadrian    HALDEBUG(ah, HAL_DEBUG_BEACON,
61278807Sadrian        "%s: next_beacon=0x%08x, beacon_period=%d, opmode=%d, beacon_period_usec=%d\n",
62278807Sadrian        __func__, next_beacon, beacon_period, opmode, beacon_period_usec);
63278741Sadrian
64250003Sadrian    OS_REG_WRITE(ah, AR_BEACON_PERIOD, beacon_period_usec);
65250003Sadrian    OS_REG_WRITE(ah, AR_DMA_BEACON_PERIOD, beacon_period_usec);
66250003Sadrian    OS_REG_WRITE(ah, AR_SWBA_PERIOD, beacon_period_usec);
67250003Sadrian
68250003Sadrian    /* reset TSF if required */
69250003Sadrian    if (beacon_period & HAL_BEACON_RESET_TSF) {
70250003Sadrian        ar9300_reset_tsf(ah);
71250003Sadrian    }
72250003Sadrian
73250003Sadrian    /* enable timers */
74250003Sadrian    OS_REG_SET_BIT(ah, AR_TIMER_MODE,
75250003Sadrian        AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN);
76250003Sadrian}
77250003Sadrian
78250003Sadrian/*
79250003Sadrian * Set all the beacon related bits on the h/w for stations
80250003Sadrian * i.e. initializes the corresponding h/w timers;
81250003Sadrian */
82250003Sadrianvoid
83250003Sadrianar9300_set_sta_beacon_timers(struct ath_hal *ah, const HAL_BEACON_STATE *bs)
84250003Sadrian{
85250003Sadrian    u_int32_t next_tbtt, beaconintval, dtimperiod, beacontimeout;
86250003Sadrian    HAL_CAPABILITIES *p_cap = &AH_PRIVATE(ah)->ah_caps;
87250003Sadrian
88250003Sadrian    HALASSERT(bs->bs_intval != 0);
89250003Sadrian
90250003Sadrian    /* no cfp setting since h/w automatically takes care */
91250003Sadrian    OS_REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(bs->bs_nexttbtt));
92250003Sadrian
93250003Sadrian    /*
94250003Sadrian     * Start the beacon timers by setting the BEACON register
95250003Sadrian     * to the beacon interval; no need to write tim offset since
96250003Sadrian     * h/w parses IEs.
97250003Sadrian     */
98250003Sadrian    OS_REG_WRITE(ah, AR_BEACON_PERIOD,
99250003Sadrian                 TU_TO_USEC(bs->bs_intval & HAL_BEACON_PERIOD));
100250003Sadrian    OS_REG_WRITE(ah, AR_DMA_BEACON_PERIOD,
101250003Sadrian                 TU_TO_USEC(bs->bs_intval & HAL_BEACON_PERIOD));
102250003Sadrian    /*
103250003Sadrian     * Configure the BMISS interrupt.  Note that we
104250003Sadrian     * assume the caller blocks interrupts while enabling
105250003Sadrian     * the threshold.
106250003Sadrian     */
107250003Sadrian    HALASSERT(bs->bs_bmissthreshold <=
108250003Sadrian        (AR_RSSI_THR_BM_THR >> AR_RSSI_THR_BM_THR_S));
109250003Sadrian    OS_REG_RMW_FIELD(ah, AR_RSSI_THR,
110250003Sadrian        AR_RSSI_THR_BM_THR, bs->bs_bmissthreshold);
111250003Sadrian
112250003Sadrian    /*
113250003Sadrian     * Program the sleep registers to correlate with the beacon setup.
114250003Sadrian     */
115250003Sadrian
116250003Sadrian    /*
117250003Sadrian     * Current implementation assumes sw processing of beacons -
118250003Sadrian     * assuming an interrupt is generated every beacon which
119250003Sadrian     * causes the hardware to become awake until the sw tells
120250003Sadrian     * it to go to sleep again; beacon timeout is to allow for
121250003Sadrian     * beacon jitter; cab timeout is max time to wait for cab
122250003Sadrian     * after seeing the last DTIM or MORE CAB bit
123250003Sadrian     */
124250003Sadrian#define CAB_TIMEOUT_VAL         10 /* in TU */
125250003Sadrian#define BEACON_TIMEOUT_VAL      10 /* in TU */
126250003Sadrian#define MIN_BEACON_TIMEOUT_VAL   1 /* in 1/8 TU */
127250003Sadrian#define SLEEP_SLOP               3 /* in TU */
128250003Sadrian
129250003Sadrian    /*
130250003Sadrian     * For max powersave mode we may want to sleep for longer than a
131250003Sadrian     * beacon period and not want to receive all beacons; modify the
132250003Sadrian     * timers accordingly; make sure to align the next TIM to the
133250003Sadrian     * next DTIM if we decide to wake for DTIMs only
134250003Sadrian     */
135250003Sadrian    beaconintval = bs->bs_intval & HAL_BEACON_PERIOD;
136250003Sadrian    HALASSERT(beaconintval != 0);
137250003Sadrian    if (bs->bs_sleepduration > beaconintval) {
138250003Sadrian        HALASSERT(roundup(bs->bs_sleepduration, beaconintval) ==
139250003Sadrian                bs->bs_sleepduration);
140250003Sadrian        beaconintval = bs->bs_sleepduration;
141250003Sadrian    }
142250003Sadrian    dtimperiod = bs->bs_dtimperiod;
143250003Sadrian    if (bs->bs_sleepduration > dtimperiod) {
144250003Sadrian        HALASSERT(dtimperiod == 0 ||
145250003Sadrian            roundup(bs->bs_sleepduration, dtimperiod) ==
146250003Sadrian                bs->bs_sleepduration);
147250003Sadrian        dtimperiod = bs->bs_sleepduration;
148250003Sadrian    }
149250003Sadrian    HALASSERT(beaconintval <= dtimperiod);
150250003Sadrian    if (beaconintval == dtimperiod) {
151250003Sadrian        next_tbtt = bs->bs_nextdtim;
152250003Sadrian    } else {
153250003Sadrian        next_tbtt = bs->bs_nexttbtt;
154250003Sadrian    }
155250003Sadrian
156250003Sadrian    HALDEBUG(ah, HAL_DEBUG_BEACON,
157250003Sadrian        "%s: next DTIM %d\n", __func__, bs->bs_nextdtim);
158250003Sadrian    HALDEBUG(ah, HAL_DEBUG_BEACON,
159250003Sadrian        "%s: next beacon %d\n", __func__, next_tbtt);
160250003Sadrian    HALDEBUG(ah, HAL_DEBUG_BEACON,
161250003Sadrian        "%s: beacon period %d\n", __func__, beaconintval);
162250003Sadrian    HALDEBUG(ah, HAL_DEBUG_BEACON,
163250003Sadrian        "%s: DTIM period %d\n", __func__, dtimperiod);
164250003Sadrian
165250003Sadrian    OS_REG_WRITE(ah, AR_NEXT_DTIM, TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP));
166250003Sadrian    OS_REG_WRITE(ah, AR_NEXT_TIM, TU_TO_USEC(next_tbtt - SLEEP_SLOP));
167250003Sadrian
168250003Sadrian    /* cab timeout is now in 1/8 TU */
169250003Sadrian    OS_REG_WRITE(ah, AR_SLEEP1,
170250003Sadrian        SM((CAB_TIMEOUT_VAL << 3), AR_SLEEP1_CAB_TIMEOUT)
171250003Sadrian        | AR_SLEEP1_ASSUME_DTIM);
172250003Sadrian
173250003Sadrian    /* beacon timeout is now in 1/8 TU */
174250008Sadrian    if (p_cap->halAutoSleepSupport) {
175250003Sadrian        beacontimeout = (BEACON_TIMEOUT_VAL << 3);
176250003Sadrian    } else {
177250003Sadrian        /*
178250003Sadrian         * Use a very small value to make sure the timeout occurs before
179250003Sadrian         * the TBTT.  In this case the chip will not go back to sleep
180250003Sadrian         * automatically, instead it will wait for the SW to explicitly
181250003Sadrian         * set it to that mode.
182250003Sadrian         */
183250003Sadrian        beacontimeout = MIN_BEACON_TIMEOUT_VAL;
184250003Sadrian    }
185250003Sadrian
186250003Sadrian    OS_REG_WRITE(ah, AR_SLEEP2,
187250003Sadrian        SM(beacontimeout, AR_SLEEP2_BEACON_TIMEOUT));
188250003Sadrian
189250003Sadrian    OS_REG_WRITE(ah, AR_TIM_PERIOD, TU_TO_USEC(beaconintval));
190250003Sadrian    OS_REG_WRITE(ah, AR_DTIM_PERIOD, TU_TO_USEC(dtimperiod));
191250003Sadrian
192250003Sadrian    /* clear HOST AP related timers first */
193250003Sadrian    OS_REG_CLR_BIT(ah, AR_TIMER_MODE, (AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN));
194250003Sadrian
195250003Sadrian    OS_REG_SET_BIT(ah, AR_TIMER_MODE, AR_TBTT_TIMER_EN | AR_TIM_TIMER_EN
196250003Sadrian                    | AR_DTIM_TIMER_EN);
197250003Sadrian
198250003Sadrian    /* TSF out of range threshold */
199250003Sadrian    OS_REG_WRITE(ah, AR_TSFOOR_THRESHOLD, bs->bs_tsfoor_threshold);
200250003Sadrian
201250003Sadrian#undef CAB_TIMEOUT_VAL
202250003Sadrian#undef BEACON_TIMEOUT_VAL
203250003Sadrian#undef SLEEP_SLOP
204250003Sadrian}
205