ar9300_radio.c revision 250172
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#include "ah.h"
20#include "ah_internal.h"
21
22#include "ar9300/ar9300.h"
23#include "ar9300/ar9300reg.h"
24#include "ar9300/ar9300phy.h"
25
26/* chansel table, used by Hornet and Poseidon */
27static const u_int32_t ar9300_chansel_xtal_25M[] = {
28    0x101479e, /* Freq 2412 - (128 << 17) + 83870  */
29    0x101d027, /* Freq 2417 - (128 << 17) + 118823 */
30    0x10258af, /* Freq 2422 - (129 << 17) + 22703  */
31    0x102e138, /* Freq 2427 - (129 << 17) + 57656  */
32    0x10369c0, /* Freq 2432 - (129 << 17) + 92608  */
33    0x103f249, /* Freq 2437 - (129 << 17) + 127561 */
34    0x1047ad1, /* Freq 2442 - (130 << 17) + 31441  */
35    0x105035a, /* Freq 2447 - (130 << 17) + 66394  */
36    0x1058be2, /* Freq 2452 - (130 << 17) + 101346 */
37    0x106146b, /* Freq 2457 - (131 << 17) + 5227   */
38    0x1069cf3, /* Freq 2462 - (131 << 17) + 40179  */
39    0x107257c, /* Freq 2467 - (131 << 17) + 75132  */
40    0x107ae04, /* Freq 2472 - (131 << 17) + 110084 */
41    0x108f5b2, /* Freq 2484 - (132 << 17) + 62898  */
42};
43
44static const u_int32_t ar9300_chansel_xtal_40M[] = {
45    0xa0ccbe, /* Freq 2412 - (80 << 17) + 52414  */
46    0xa12213, /* Freq 2417 - (80 << 17) + 74259  */
47    0xa17769, /* Freq 2422 - (80 << 17) + 96105  */
48    0xa1ccbe, /* Freq 2427 - (80 << 17) + 117950 */
49    0xa22213, /* Freq 2432 - (81 << 17) + 8723   */
50    0xa27769, /* Freq 2437 - (81 << 17) + 30569  */
51    0xa2ccbe, /* Freq 2442 - (81 << 17) + 52414  */
52    0xa32213, /* Freq 2447 - (81 << 17) + 74259  */
53    0xa37769, /* Freq 2452 - (81 << 17) + 96105  */
54    0xa3ccbe, /* Freq 2457 - (81 << 17) + 117950 */
55    0xa42213, /* Freq 2462 - (82 << 17) + 8723   */
56    0xa47769, /* Freq 2467 - (82 << 17) + 30569  */
57    0xa4ccbe, /* Freq 2472 - (82 << 17) + 52414  */
58    0xa5998b, /* Freq 2484 - (82 << 17) + 104843 */
59};
60
61
62/*
63 * Take the MHz channel value and set the Channel value
64 *
65 * ASSUMES: Writes enabled to analog bus
66 *
67 * Actual Expression,
68 *
69 * For 2GHz channel,
70 * Channel Frequency = (3/4) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^17)
71 * (freq_ref = 40MHz)
72 *
73 * For 5GHz channel,
74 * Channel Frequency = (3/2) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^10)
75 * (freq_ref = 40MHz/(24>>amode_ref_sel))
76 *
77 * For 5GHz channels which are 5MHz spaced,
78 * Channel Frequency = (3/2) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^17)
79 * (freq_ref = 40MHz)
80 */
81static HAL_BOOL
82ar9300_set_channel(struct ath_hal *ah, struct ieee80211_channel *chan)
83{
84    u_int16_t b_mode, frac_mode = 0, a_mode_ref_sel = 0;
85    u_int32_t freq, channel_sel, reg32;
86    u_int8_t clk_25mhz = AH9300(ah)->clk_25mhz;
87    CHAN_CENTERS centers;
88    int load_synth_channel;
89#ifdef	AH_DEBUG_ALQ
90    HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
91#endif
92
93    /*
94     * Put this behind AH_DEBUG_ALQ for now until the Hornet
95     * channel_sel code below is made to work.
96     */
97#ifdef	AH_DEBUG_ALQ
98    OS_MARK(ah, AH_MARK_SETCHANNEL, ichan->channel);
99#endif
100
101    ar9300_get_channel_centers(ah, chan, &centers);
102    freq = centers.synth_center;
103
104
105    if (freq < 4800) {     /* 2 GHz, fractional mode */
106        b_mode = 1; /* 2 GHz */
107
108        if (AR_SREV_HORNET(ah)) {
109            /*
110             * XXX TODO: this should call ieee80211_mhz2ieee which will
111             * take care of the up/down conversion and GSM mapping.
112             * However, the HAL _can't_ call that, so we'll need to
113             * introduce it in ah_osdep or something.
114             */
115#if 0
116            u_int32_t ichan =
117              ieee80211_mhz2ieee(ah, chan->ic_freq, chan->ic_flags);
118            HALASSERT(ichan > 0 && ichan <= 14);
119            if (clk_25mhz) {
120                channel_sel = ar9300_chansel_xtal_25M[ichan - 1];
121            } else {
122                channel_sel = ar9300_chansel_xtal_40M[ichan - 1];
123            }
124#else
125            ath_hal_printf(ah, "%s: unimplemented, implement!\n", __func__);
126            return AH_FALSE;
127#endif
128        } else if (AR_SREV_POSEIDON(ah) || AR_SREV_APHRODITE(ah)) {
129            u_int32_t channel_frac;
130            /*
131             * freq_ref = (40 / (refdiva >> a_mode_ref_sel));
132             *     (where refdiva = 1 and amoderefsel = 0)
133             * ndiv = ((chan_mhz * 4) / 3) / freq_ref;
134             * chansel = int(ndiv),  chanfrac = (ndiv - chansel) * 0x20000
135             */
136            channel_sel = (freq * 4) / 120;
137            channel_frac = (((freq * 4) % 120) * 0x20000) / 120;
138            channel_sel = (channel_sel << 17) | (channel_frac);
139        } else if (AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) {
140            u_int32_t channel_frac;
141            if (clk_25mhz) {
142                /*
143                 * freq_ref = (50 / (refdiva >> a_mode_ref_sel));
144                 *     (where refdiva = 1 and amoderefsel = 0)
145                 * ndiv = ((chan_mhz * 4) / 3) / freq_ref;
146                 * chansel = int(ndiv),  chanfrac = (ndiv - chansel) * 0x20000
147                 */
148                if (AR_SREV_SCORPION(ah)) {
149                    /* Doubler is off for Scorpion */
150                    channel_sel = (freq * 4) / 75;
151                    channel_frac = (((freq * 4) % 75) * 0x20000) / 75;
152                } else {
153                    channel_sel = (freq * 2) / 75;
154                    channel_frac = (((freq * 2) % 75) * 0x20000) / 75;
155                }
156            } else {
157                /*
158                 * freq_ref = (50 / (refdiva >> a_mode_ref_sel));
159                 *     (where refdiva = 1 and amoderefsel = 0)
160                 * ndiv = ((chan_mhz * 4) / 3) / freq_ref;
161                 * chansel = int(ndiv),  chanfrac = (ndiv - chansel) * 0x20000
162                 */
163                if (AR_SREV_SCORPION(ah)) {
164                    /* Doubler is off for Scorpion */
165                    channel_sel = (freq * 4) / 120;
166                    channel_frac = (((freq * 4) % 120) * 0x20000) / 120;
167                } else {
168                    channel_sel = (freq * 2) / 120;
169                    channel_frac = (((freq * 2) % 120) * 0x20000) / 120;
170                }
171            }
172            channel_sel = (channel_sel << 17) | (channel_frac);
173        } else {
174            channel_sel = CHANSEL_2G(freq);
175        }
176    } else {
177        b_mode = 0; /* 5 GHz */
178        if ((AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) && clk_25mhz){
179            u_int32_t channel_frac;
180            /*
181             * freq_ref = (50 / (refdiva >> amoderefsel));
182             *     (refdiva = 1, amoderefsel = 0)
183             * ndiv = ((chan_mhz * 2) / 3) / freq_ref;
184             * chansel = int(ndiv),  chanfrac = (ndiv - chansel) * 0x20000
185             */
186            channel_sel = freq / 75 ;
187            channel_frac = ((freq % 75) * 0x20000) / 75;
188            channel_sel = (channel_sel << 17) | (channel_frac);
189        } else {
190            channel_sel = CHANSEL_5G(freq);
191            /* Doubler is ON, so, divide channel_sel by 2. */
192            channel_sel >>= 1;
193        }
194    }
195
196
197	/* Enable fractional mode for all channels */
198    frac_mode = 1;
199    a_mode_ref_sel = 0;
200    load_synth_channel = 0;
201
202    reg32 = (b_mode << 29);
203    OS_REG_WRITE(ah, AR_PHY_SYNTH_CONTROL, reg32);
204
205	/* Enable Long shift Select for Synthesizer */
206    OS_REG_RMW_FIELD(ah,
207        AR_PHY_65NM_CH0_SYNTH4, AR_PHY_SYNTH4_LONG_SHIFT_SELECT, 1);
208
209    /* program synth. setting */
210    reg32 =
211        (channel_sel       <<  2) |
212        (a_mode_ref_sel      << 28) |
213        (frac_mode         << 30) |
214        (load_synth_channel << 31);
215    if (IEEE80211_IS_CHAN_QUARTER(chan)) {
216        reg32 += CHANSEL_5G_DOT5MHZ;
217    }
218    OS_REG_WRITE(ah, AR_PHY_65NM_CH0_SYNTH7, reg32);
219    /* Toggle Load Synth channel bit */
220    load_synth_channel = 1;
221    reg32 |= load_synth_channel << 31;
222    OS_REG_WRITE(ah, AR_PHY_65NM_CH0_SYNTH7, reg32);
223
224
225    AH_PRIVATE(ah)->ah_curchan = chan;
226
227    return AH_TRUE;
228}
229
230
231#if 0
232static HAL_BOOL
233ar9300_get_chip_power_limits(struct ath_hal *ah, HAL_CHANNEL *chans,
234                         u_int32_t nchans)
235{
236    int i;
237
238    for (i = 0; i < nchans; i++) {
239        chans[i].max_tx_power = AR9300_MAX_RATE_POWER;
240        chans[i].min_tx_power = AR9300_MAX_RATE_POWER;
241    }
242    return AH_TRUE;
243}
244#endif
245
246/* XXX FreeBSD */
247static HAL_BOOL
248ar9300_get_chip_power_limits(struct ath_hal *ah,
249    struct ieee80211_channel *chan)
250{
251        /* XXX ? */
252        chan->ic_minpower = 0;
253        chan->ic_maxpower = AR9300_MAX_RATE_POWER;
254
255        return AH_TRUE;
256}
257
258HAL_BOOL
259ar9300_rf_attach(struct ath_hal *ah, HAL_STATUS *status)
260{
261    struct ath_hal_9300 *ahp = AH9300(ah);
262
263    ahp->ah_rf_hal.set_channel    = ar9300_set_channel;
264    ahp->ah_rf_hal.get_chip_power_lim   = ar9300_get_chip_power_limits;
265
266    *status = HAL_OK;
267
268    return AH_TRUE;
269}
270