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#include "ar9300/ar9300phy.h"
25250003Sadrian
26250003Sadrian/* chansel table, used by Hornet and Poseidon */
27250003Sadrianstatic const u_int32_t ar9300_chansel_xtal_25M[] = {
28250003Sadrian    0x101479e, /* Freq 2412 - (128 << 17) + 83870  */
29250003Sadrian    0x101d027, /* Freq 2417 - (128 << 17) + 118823 */
30250003Sadrian    0x10258af, /* Freq 2422 - (129 << 17) + 22703  */
31250003Sadrian    0x102e138, /* Freq 2427 - (129 << 17) + 57656  */
32250003Sadrian    0x10369c0, /* Freq 2432 - (129 << 17) + 92608  */
33250003Sadrian    0x103f249, /* Freq 2437 - (129 << 17) + 127561 */
34250003Sadrian    0x1047ad1, /* Freq 2442 - (130 << 17) + 31441  */
35250003Sadrian    0x105035a, /* Freq 2447 - (130 << 17) + 66394  */
36250003Sadrian    0x1058be2, /* Freq 2452 - (130 << 17) + 101346 */
37250003Sadrian    0x106146b, /* Freq 2457 - (131 << 17) + 5227   */
38250003Sadrian    0x1069cf3, /* Freq 2462 - (131 << 17) + 40179  */
39250003Sadrian    0x107257c, /* Freq 2467 - (131 << 17) + 75132  */
40250003Sadrian    0x107ae04, /* Freq 2472 - (131 << 17) + 110084 */
41250003Sadrian    0x108f5b2, /* Freq 2484 - (132 << 17) + 62898  */
42250003Sadrian};
43250003Sadrian
44250003Sadrianstatic const u_int32_t ar9300_chansel_xtal_40M[] = {
45250003Sadrian    0xa0ccbe, /* Freq 2412 - (80 << 17) + 52414  */
46250003Sadrian    0xa12213, /* Freq 2417 - (80 << 17) + 74259  */
47250003Sadrian    0xa17769, /* Freq 2422 - (80 << 17) + 96105  */
48250003Sadrian    0xa1ccbe, /* Freq 2427 - (80 << 17) + 117950 */
49250003Sadrian    0xa22213, /* Freq 2432 - (81 << 17) + 8723   */
50250003Sadrian    0xa27769, /* Freq 2437 - (81 << 17) + 30569  */
51250003Sadrian    0xa2ccbe, /* Freq 2442 - (81 << 17) + 52414  */
52250003Sadrian    0xa32213, /* Freq 2447 - (81 << 17) + 74259  */
53250003Sadrian    0xa37769, /* Freq 2452 - (81 << 17) + 96105  */
54250003Sadrian    0xa3ccbe, /* Freq 2457 - (81 << 17) + 117950 */
55250003Sadrian    0xa42213, /* Freq 2462 - (82 << 17) + 8723   */
56250003Sadrian    0xa47769, /* Freq 2467 - (82 << 17) + 30569  */
57250003Sadrian    0xa4ccbe, /* Freq 2472 - (82 << 17) + 52414  */
58250003Sadrian    0xa5998b, /* Freq 2484 - (82 << 17) + 104843 */
59250003Sadrian};
60250003Sadrian
61250003Sadrian
62250003Sadrian/*
63250003Sadrian * Take the MHz channel value and set the Channel value
64250003Sadrian *
65250003Sadrian * ASSUMES: Writes enabled to analog bus
66250003Sadrian *
67250003Sadrian * Actual Expression,
68250003Sadrian *
69250003Sadrian * For 2GHz channel,
70250003Sadrian * Channel Frequency = (3/4) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^17)
71250003Sadrian * (freq_ref = 40MHz)
72250003Sadrian *
73250003Sadrian * For 5GHz channel,
74250003Sadrian * Channel Frequency = (3/2) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^10)
75250003Sadrian * (freq_ref = 40MHz/(24>>amode_ref_sel))
76250003Sadrian *
77250003Sadrian * For 5GHz channels which are 5MHz spaced,
78250003Sadrian * Channel Frequency = (3/2) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^17)
79250003Sadrian * (freq_ref = 40MHz)
80250003Sadrian */
81250003Sadrianstatic HAL_BOOL
82250008Sadrianar9300_set_channel(struct ath_hal *ah, struct ieee80211_channel *chan)
83250003Sadrian{
84250003Sadrian    u_int16_t b_mode, frac_mode = 0, a_mode_ref_sel = 0;
85250003Sadrian    u_int32_t freq, channel_sel, reg32;
86250003Sadrian    u_int8_t clk_25mhz = AH9300(ah)->clk_25mhz;
87250003Sadrian    CHAN_CENTERS centers;
88250003Sadrian    int load_synth_channel;
89291472Sngie#ifdef	AH_DEBUG_ALQ
90250008Sadrian    HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
91291472Sngie#endif
92250003Sadrian
93250172Sadrian    /*
94250172Sadrian     * Put this behind AH_DEBUG_ALQ for now until the Hornet
95250172Sadrian     * channel_sel code below is made to work.
96250172Sadrian     */
97250172Sadrian#ifdef	AH_DEBUG_ALQ
98250008Sadrian    OS_MARK(ah, AH_MARK_SETCHANNEL, ichan->channel);
99250008Sadrian#endif
100250003Sadrian
101250003Sadrian    ar9300_get_channel_centers(ah, chan, &centers);
102250003Sadrian    freq = centers.synth_center;
103250003Sadrian
104250003Sadrian    if (freq < 4800) {     /* 2 GHz, fractional mode */
105250003Sadrian        b_mode = 1; /* 2 GHz */
106250003Sadrian
107250003Sadrian        if (AR_SREV_HORNET(ah)) {
108250008Sadrian#if 0
109250008Sadrian            u_int32_t ichan =
110250008Sadrian              ieee80211_mhz2ieee(ah, chan->ic_freq, chan->ic_flags);
111250003Sadrian            HALASSERT(ichan > 0 && ichan <= 14);
112250003Sadrian            if (clk_25mhz) {
113250003Sadrian                channel_sel = ar9300_chansel_xtal_25M[ichan - 1];
114250003Sadrian            } else {
115250003Sadrian                channel_sel = ar9300_chansel_xtal_40M[ichan - 1];
116250003Sadrian            }
117250008Sadrian#endif
118252237Sadrian            uint32_t i;
119252237Sadrian
120291469Sadrian            /*
121291469Sadrian             * Pay close attention to this bit!
122291469Sadrian             *
123291469Sadrian             * We need to map the actual desired synth frequency to
124291469Sadrian             * one of the channel select array entries.
125291469Sadrian             *
126291469Sadrian             * For HT20, it'll align with the channel we select.
127291469Sadrian             *
128291469Sadrian             * For HT40 though it won't - the centre frequency
129291469Sadrian             * will not be the frequency of chan->ic_freq or ichan->freq;
130291469Sadrian             * it needs to be whatever frequency maps to 'freq'.
131291469Sadrian             */
132291469Sadrian            i = ath_hal_mhz2ieee_2ghz(ah, freq);
133252237Sadrian            HALASSERT(i > 0 && i <= 14);
134252237Sadrian            if (clk_25mhz) {
135252237Sadrian                channel_sel = ar9300_chansel_xtal_25M[i - 1];
136252237Sadrian            } else {
137252237Sadrian                channel_sel = ar9300_chansel_xtal_40M[i - 1];
138252237Sadrian            }
139250003Sadrian        } else if (AR_SREV_POSEIDON(ah) || AR_SREV_APHRODITE(ah)) {
140250003Sadrian            u_int32_t channel_frac;
141250003Sadrian            /*
142250003Sadrian             * freq_ref = (40 / (refdiva >> a_mode_ref_sel));
143250003Sadrian             *     (where refdiva = 1 and amoderefsel = 0)
144250003Sadrian             * ndiv = ((chan_mhz * 4) / 3) / freq_ref;
145250003Sadrian             * chansel = int(ndiv),  chanfrac = (ndiv - chansel) * 0x20000
146250003Sadrian             */
147250003Sadrian            channel_sel = (freq * 4) / 120;
148250003Sadrian            channel_frac = (((freq * 4) % 120) * 0x20000) / 120;
149250003Sadrian            channel_sel = (channel_sel << 17) | (channel_frac);
150291437Sadrian        } else if (AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah) || AR_SREV_HONEYBEE(ah)) {
151250003Sadrian            u_int32_t channel_frac;
152250003Sadrian            if (clk_25mhz) {
153250003Sadrian                /*
154250003Sadrian                 * freq_ref = (50 / (refdiva >> a_mode_ref_sel));
155250003Sadrian                 *     (where refdiva = 1 and amoderefsel = 0)
156250003Sadrian                 * ndiv = ((chan_mhz * 4) / 3) / freq_ref;
157250003Sadrian                 * chansel = int(ndiv),  chanfrac = (ndiv - chansel) * 0x20000
158250003Sadrian                 */
159291437Sadrian                if (AR_SREV_SCORPION(ah) || AR_SREV_HONEYBEE(ah)) {
160250003Sadrian                    /* Doubler is off for Scorpion */
161250003Sadrian                    channel_sel = (freq * 4) / 75;
162250003Sadrian                    channel_frac = (((freq * 4) % 75) * 0x20000) / 75;
163250003Sadrian                } else {
164250003Sadrian                    channel_sel = (freq * 2) / 75;
165250003Sadrian                    channel_frac = (((freq * 2) % 75) * 0x20000) / 75;
166250003Sadrian                }
167250003Sadrian            } else {
168250003Sadrian                /*
169250003Sadrian                 * freq_ref = (50 / (refdiva >> a_mode_ref_sel));
170250003Sadrian                 *     (where refdiva = 1 and amoderefsel = 0)
171250003Sadrian                 * ndiv = ((chan_mhz * 4) / 3) / freq_ref;
172250003Sadrian                 * chansel = int(ndiv),  chanfrac = (ndiv - chansel) * 0x20000
173250003Sadrian                 */
174250003Sadrian                if (AR_SREV_SCORPION(ah)) {
175250003Sadrian                    /* Doubler is off for Scorpion */
176250003Sadrian                    channel_sel = (freq * 4) / 120;
177250003Sadrian                    channel_frac = (((freq * 4) % 120) * 0x20000) / 120;
178250003Sadrian                } else {
179250003Sadrian                    channel_sel = (freq * 2) / 120;
180250003Sadrian                    channel_frac = (((freq * 2) % 120) * 0x20000) / 120;
181250003Sadrian                }
182250003Sadrian            }
183250003Sadrian            channel_sel = (channel_sel << 17) | (channel_frac);
184250003Sadrian        } else {
185250003Sadrian            channel_sel = CHANSEL_2G(freq);
186250003Sadrian        }
187250003Sadrian    } else {
188250003Sadrian        b_mode = 0; /* 5 GHz */
189250003Sadrian        if ((AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) && clk_25mhz){
190250003Sadrian            u_int32_t channel_frac;
191250003Sadrian            /*
192250003Sadrian             * freq_ref = (50 / (refdiva >> amoderefsel));
193250003Sadrian             *     (refdiva = 1, amoderefsel = 0)
194250003Sadrian             * ndiv = ((chan_mhz * 2) / 3) / freq_ref;
195250003Sadrian             * chansel = int(ndiv),  chanfrac = (ndiv - chansel) * 0x20000
196250003Sadrian             */
197250003Sadrian            channel_sel = freq / 75 ;
198250003Sadrian            channel_frac = ((freq % 75) * 0x20000) / 75;
199250003Sadrian            channel_sel = (channel_sel << 17) | (channel_frac);
200250003Sadrian        } else {
201250003Sadrian            channel_sel = CHANSEL_5G(freq);
202250003Sadrian            /* Doubler is ON, so, divide channel_sel by 2. */
203250003Sadrian            channel_sel >>= 1;
204250003Sadrian        }
205250003Sadrian    }
206250003Sadrian
207250003Sadrian
208250003Sadrian	/* Enable fractional mode for all channels */
209250003Sadrian    frac_mode = 1;
210250003Sadrian    a_mode_ref_sel = 0;
211250003Sadrian    load_synth_channel = 0;
212250003Sadrian
213250003Sadrian    reg32 = (b_mode << 29);
214250003Sadrian    OS_REG_WRITE(ah, AR_PHY_SYNTH_CONTROL, reg32);
215250003Sadrian
216250003Sadrian	/* Enable Long shift Select for Synthesizer */
217250003Sadrian    OS_REG_RMW_FIELD(ah,
218250003Sadrian        AR_PHY_65NM_CH0_SYNTH4, AR_PHY_SYNTH4_LONG_SHIFT_SELECT, 1);
219250003Sadrian
220250003Sadrian    /* program synth. setting */
221250003Sadrian    reg32 =
222250003Sadrian        (channel_sel       <<  2) |
223250003Sadrian        (a_mode_ref_sel      << 28) |
224250003Sadrian        (frac_mode         << 30) |
225250003Sadrian        (load_synth_channel << 31);
226250008Sadrian    if (IEEE80211_IS_CHAN_QUARTER(chan)) {
227250003Sadrian        reg32 += CHANSEL_5G_DOT5MHZ;
228250003Sadrian    }
229250003Sadrian    OS_REG_WRITE(ah, AR_PHY_65NM_CH0_SYNTH7, reg32);
230250003Sadrian    /* Toggle Load Synth channel bit */
231250003Sadrian    load_synth_channel = 1;
232250003Sadrian    reg32 |= load_synth_channel << 31;
233250003Sadrian    OS_REG_WRITE(ah, AR_PHY_65NM_CH0_SYNTH7, reg32);
234250003Sadrian
235250003Sadrian
236250003Sadrian    AH_PRIVATE(ah)->ah_curchan = chan;
237250003Sadrian
238250003Sadrian    return AH_TRUE;
239250003Sadrian}
240250003Sadrian
241250003Sadrian
242250008Sadrian#if 0
243250003Sadrianstatic HAL_BOOL
244250003Sadrianar9300_get_chip_power_limits(struct ath_hal *ah, HAL_CHANNEL *chans,
245250003Sadrian                         u_int32_t nchans)
246250003Sadrian{
247250003Sadrian    int i;
248250003Sadrian
249250003Sadrian    for (i = 0; i < nchans; i++) {
250250003Sadrian        chans[i].max_tx_power = AR9300_MAX_RATE_POWER;
251250003Sadrian        chans[i].min_tx_power = AR9300_MAX_RATE_POWER;
252250003Sadrian    }
253250003Sadrian    return AH_TRUE;
254250003Sadrian}
255250008Sadrian#endif
256250003Sadrian
257250008Sadrian/* XXX FreeBSD */
258250008Sadrianstatic HAL_BOOL
259250008Sadrianar9300_get_chip_power_limits(struct ath_hal *ah,
260250008Sadrian    struct ieee80211_channel *chan)
261250008Sadrian{
262250008Sadrian        /* XXX ? */
263250008Sadrian        chan->ic_minpower = 0;
264250008Sadrian        chan->ic_maxpower = AR9300_MAX_RATE_POWER;
265250008Sadrian
266250008Sadrian        return AH_TRUE;
267250008Sadrian}
268250008Sadrian
269250003SadrianHAL_BOOL
270250003Sadrianar9300_rf_attach(struct ath_hal *ah, HAL_STATUS *status)
271250003Sadrian{
272250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
273250003Sadrian
274250003Sadrian    ahp->ah_rf_hal.set_channel    = ar9300_set_channel;
275250003Sadrian    ahp->ah_rf_hal.get_chip_power_lim   = ar9300_get_chip_power_limits;
276250003Sadrian
277250003Sadrian    *status = HAL_OK;
278250003Sadrian
279250003Sadrian    return AH_TRUE;
280250003Sadrian}
281