source: mainline/uspace/drv/nic/ar9271/hw.c@ 05882233

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 05882233 was 3bacee1, checked in by Jiri Svoboda <jiri@…>, 7 years ago

Make ccheck-fix again and commit more good files.

  • Property mode set to 100644
File size: 16.2 KB
RevLine 
[59fa7ab]1/*
2 * Copyright (c) 2015 Jan Kolarik
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @file hw.c
30 *
31 * AR9271 hardware related functions implementation.
32 *
33 */
34
35#include <macros.h>
36#include <usb/debug.h>
[fb1007ef]37#include <errno.h>
[59fa7ab]38#include <nic.h>
39#include <ieee80211.h>
40#include "hw.h"
41#include "wmi.h"
42
[8a64320e]43/** Try to wait for register value repeatedly until timeout is reached.
44 *
[59fa7ab]45 * @param ar9271 Device structure.
46 * @param offset Registry offset (address) to be read.
[8a64320e]47 * @param mask Mask to apply on read result.
48 * @param value Required value we are waiting for.
49 *
50 * @return EOK if succeed, ETIMEOUT on timeout,
[cde999a]51 * error code otherwise.
[8a64320e]52 *
[59fa7ab]53 */
[b7fd2a0]54static errno_t hw_read_wait(ar9271_t *ar9271, uint32_t offset, uint32_t mask,
[8a64320e]55 uint32_t value)
[59fa7ab]56{
[8a64320e]57 for (size_t i = 0; i < HW_WAIT_LOOPS; i++) {
[59fa7ab]58 udelay(HW_WAIT_TIME_US);
[a35b458]59
[8a64320e]60 uint32_t result;
[59fa7ab]61 wmi_reg_read(ar9271->htc_device, offset, &result);
[8a64320e]62 if ((result & mask) == value)
[59fa7ab]63 return EOK;
64 }
[a35b458]65
[59fa7ab]66 return ETIMEOUT;
67}
68
[b7fd2a0]69static errno_t hw_reset_power_on(ar9271_t *ar9271)
[59fa7ab]70{
71 wmi_reg_t buffer[] = {
72 {
73 .offset = AR9271_RTC_FORCE_WAKE,
[8a64320e]74 .value = AR9271_RTC_FORCE_WAKE_ENABLE |
75 AR9271_RTC_FORCE_WAKE_ON_INT
[59fa7ab]76 },
77 {
78 .offset = AR9271_RC,
79 .value = AR9271_RC_AHB
80 },
81 {
82 .offset = AR9271_RTC_RESET,
83 .value = 0
84 }
85 };
[a35b458]86
[59fa7ab]87 wmi_reg_buffer_write(ar9271->htc_device, buffer,
[8a64320e]88 sizeof(buffer) / sizeof(wmi_reg_t));
[a35b458]89
[59fa7ab]90 udelay(2);
[a35b458]91
[59fa7ab]92 wmi_reg_write(ar9271->htc_device, AR9271_RC, 0);
93 wmi_reg_write(ar9271->htc_device, AR9271_RTC_RESET, 1);
[a35b458]94
[b7fd2a0]95 errno_t rc = hw_read_wait(ar9271,
[8a64320e]96 AR9271_RTC_STATUS,
97 AR9271_RTC_STATUS_MASK,
98 AR9271_RTC_STATUS_ON);
99 if (rc != EOK) {
[59fa7ab]100 usb_log_error("Failed to wait for RTC wake up register.\n");
101 return rc;
102 }
[a35b458]103
[59fa7ab]104 return EOK;
105}
106
[b7fd2a0]107static errno_t hw_set_reset(ar9271_t *ar9271, bool cold)
[59fa7ab]108{
109 uint32_t reset_value = AR9271_RTC_RC_MAC_WARM;
[a35b458]110
[8a64320e]111 if (cold)
[59fa7ab]112 reset_value |= AR9271_RTC_RC_MAC_COLD;
[a35b458]113
[59fa7ab]114 wmi_reg_t buffer[] = {
115 {
116 .offset = AR9271_RTC_FORCE_WAKE,
[8a64320e]117 .value = AR9271_RTC_FORCE_WAKE_ENABLE |
118 AR9271_RTC_FORCE_WAKE_ON_INT
[59fa7ab]119 },
120 {
121 .offset = AR9271_RC,
122 .value = AR9271_RC_AHB
123 },
124 {
125 .offset = AR9271_RTC_RC,
126 .value = reset_value
127 }
128 };
[a35b458]129
[8a64320e]130 wmi_reg_buffer_write(ar9271->htc_device, buffer,
131 sizeof(buffer) / sizeof(wmi_reg_t));
[a35b458]132
[59fa7ab]133 udelay(100);
[a35b458]134
[59fa7ab]135 wmi_reg_write(ar9271->htc_device, AR9271_RTC_RC, 0);
[a35b458]136
[b7fd2a0]137 errno_t rc = hw_read_wait(ar9271, AR9271_RTC_RC, AR9271_RTC_RC_MASK, 0);
[8a64320e]138 if (rc != EOK) {
[59fa7ab]139 usb_log_error("Failed to wait for RTC RC register.\n");
140 return rc;
141 }
[a35b458]142
[59fa7ab]143 wmi_reg_write(ar9271->htc_device, AR9271_RC, 0);
[8a64320e]144 wmi_reg_clear_bit(ar9271->htc_device, AR9271_STATION_ID1,
145 AR9271_STATION_ID1_POWER_SAVING);
[a35b458]146
[59fa7ab]147 return EOK;
148}
149
[b7fd2a0]150static errno_t hw_addr_init(ar9271_t *ar9271)
[59fa7ab]151{
152 uint32_t value;
153 nic_address_t ar9271_address;
[a35b458]154
[8a64320e]155 for (unsigned int i = 0; i < 3; i++) {
156 wmi_reg_read(ar9271->htc_device,
157 AR9271_EEPROM_MAC_ADDR_START + i * 4, &value);
[a35b458]158
[59fa7ab]159 uint16_t two_bytes = uint16_t_be2host(value);
[3bacee1]160 ar9271_address.address[2 * i] = two_bytes >> 8;
161 ar9271_address.address[2 * i + 1] = two_bytes & 0xff;
[59fa7ab]162 }
[a35b458]163
[59fa7ab]164 nic_t *nic = nic_get_from_ddf_dev(ar9271->ddf_dev);
[a35b458]165
[b7fd2a0]166 errno_t rc = nic_report_address(nic, &ar9271_address);
[8a64320e]167 if (rc != EOK) {
[59fa7ab]168 usb_log_error("Failed to report NIC HW address.\n");
169 return rc;
170 }
[a35b458]171
[59fa7ab]172 return EOK;
173}
174
[b7fd2a0]175static errno_t hw_gpio_set_output(ar9271_t *ar9271, uint32_t gpio, uint32_t type)
[59fa7ab]176{
[8a64320e]177 uint32_t address;
[a35b458]178
[8a64320e]179 if (gpio > 11)
[59fa7ab]180 address = AR9271_GPIO_OUT_MUX3;
[8a64320e]181 else if (gpio > 5)
[59fa7ab]182 address = AR9271_GPIO_OUT_MUX2;
[8a64320e]183 else
[59fa7ab]184 address = AR9271_GPIO_OUT_MUX1;
[a35b458]185
[8a64320e]186 uint32_t gpio_shift = (gpio % 6) * 5;
[a35b458]187
[8a64320e]188 uint32_t temp;
[59fa7ab]189 wmi_reg_read(ar9271->htc_device, address, &temp);
[a35b458]190
[8a64320e]191 temp = ((temp & 0x1f0) << 1) | (temp & ~0x1f0);
[59fa7ab]192 temp &= ~(0x1f << gpio_shift);
193 temp |= (type << gpio_shift);
[a35b458]194
[59fa7ab]195 wmi_reg_write(ar9271->htc_device, address, temp);
[a35b458]196
[59fa7ab]197 gpio_shift = 2 * gpio;
[a35b458]198
[59fa7ab]199 wmi_reg_set_clear_bit(ar9271->htc_device, AR9271_GPIO_OE_OUT,
[8a64320e]200 AR9271_GPIO_OE_OUT_ALWAYS << gpio_shift,
201 AR9271_GPIO_OE_OUT_ALWAYS << gpio_shift);
[a35b458]202
[59fa7ab]203 return EOK;
204}
205
[b7fd2a0]206static errno_t hw_gpio_set_value(ar9271_t *ar9271, uint32_t gpio, uint32_t value)
[59fa7ab]207{
208 wmi_reg_set_clear_bit(ar9271->htc_device, AR9271_GPIO_IN_OUT,
[8a64320e]209 (~value & 1) << gpio, 1 << gpio);
[59fa7ab]210 return EOK;
211}
212
[8a64320e]213/**Hardware init procedure of AR9271 device.
214 *
[59fa7ab]215 * @param ar9271 Device structure.
[8a64320e]216 *
[cde999a]217 * @return EOK if succeed, error code otherwise.
[8a64320e]218 *
[59fa7ab]219 */
[b7fd2a0]220static errno_t hw_init_proc(ar9271_t *ar9271)
[59fa7ab]221{
[b7fd2a0]222 errno_t rc = hw_reset_power_on(ar9271);
[8a64320e]223 if (rc != EOK) {
[59fa7ab]224 usb_log_error("Failed to HW reset power on.\n");
225 return rc;
226 }
[a35b458]227
[59fa7ab]228 rc = hw_set_reset(ar9271, false);
[8a64320e]229 if (rc != EOK) {
[59fa7ab]230 usb_log_error("Failed to HW warm reset.\n");
231 return rc;
232 }
[a35b458]233
[59fa7ab]234 rc = hw_addr_init(ar9271);
[8a64320e]235 if (rc != EOK) {
[59fa7ab]236 usb_log_error("Failed to init HW addr.\n");
237 return rc;
238 }
[a35b458]239
[59fa7ab]240 return EOK;
241}
242
[b7fd2a0]243static errno_t hw_init_led(ar9271_t *ar9271)
[59fa7ab]244{
[b7fd2a0]245 errno_t rc = hw_gpio_set_output(ar9271, AR9271_LED_PIN,
[8a64320e]246 AR9271_GPIO_OUT_MUX_AS_OUT);
247 if (rc != EOK) {
[59fa7ab]248 usb_log_error("Failed to set led GPIO to output.\n");
249 return rc;
250 }
[a35b458]251
[59fa7ab]252 rc = hw_gpio_set_value(ar9271, AR9271_LED_PIN, 0);
[8a64320e]253 if (rc != EOK) {
[59fa7ab]254 usb_log_error("Failed to init bring up GPIO led.\n");
255 return rc;
256 }
[a35b458]257
[59fa7ab]258 return EOK;
259}
260
[b7fd2a0]261static errno_t hw_activate_phy(ar9271_t *ar9271)
[1dcc0b9]262{
263 wmi_reg_write(ar9271->htc_device, AR9271_PHY_ACTIVE, 1);
264 udelay(1000);
[a35b458]265
[1dcc0b9]266 return EOK;
267}
268
[b7fd2a0]269static errno_t hw_set_operating_mode(ar9271_t *ar9271,
[8a64320e]270 ieee80211_operating_mode_t op_mode)
[59fa7ab]271{
272 uint32_t set_bit = 0x10000000;
[a35b458]273
[3bacee1]274 switch (op_mode) {
[8a64320e]275 case IEEE80211_OPMODE_ADHOC:
276 set_bit |= AR9271_OPMODE_ADHOC_MASK;
277 wmi_reg_set_bit(ar9271->htc_device, AR9271_CONFIG,
278 AR9271_CONFIG_ADHOC);
279 break;
280 case IEEE80211_OPMODE_MESH:
281 case IEEE80211_OPMODE_AP:
282 set_bit |= AR9271_OPMODE_STATION_AP_MASK;
[dc12262]283 /* Fallthrough */
[8a64320e]284 case IEEE80211_OPMODE_STATION:
285 wmi_reg_clear_bit(ar9271->htc_device, AR9271_CONFIG,
286 AR9271_CONFIG_ADHOC);
[59fa7ab]287 }
[a35b458]288
[59fa7ab]289 wmi_reg_set_clear_bit(ar9271->htc_device, AR9271_STATION_ID1,
[8a64320e]290 set_bit, AR9271_OPMODE_STATION_AP_MASK | AR9271_OPMODE_ADHOC_MASK);
[a35b458]291
[59fa7ab]292 ieee80211_report_current_op_mode(ar9271->ieee80211_dev, op_mode);
[a35b458]293
[59fa7ab]294 return EOK;
295}
296
[b7fd2a0]297static errno_t hw_reset_operating_mode(ar9271_t *ar9271)
[59fa7ab]298{
[b7fd2a0]299 errno_t rc = hw_set_operating_mode(ar9271, IEEE80211_OPMODE_STATION);
[8a64320e]300 if (rc != EOK) {
[59fa7ab]301 usb_log_error("Failed to set opmode to station.\n");
302 return rc;
303 }
[a35b458]304
[59fa7ab]305 return EOK;
306}
307
[b7fd2a0]308static errno_t hw_noise_floor_calibration(ar9271_t *ar9271)
[59fa7ab]309{
[1dcc0b9]310 uint32_t value;
311 wmi_reg_read(ar9271->htc_device, AR9271_PHY_CAL, &value);
[a35b458]312
[8a64320e]313 value &= 0xfffffe00;
314 value |= (((uint32_t) AR9271_CALIB_NOMINAL_VALUE_2GHZ << 1) & 0x1ff);
[a35b458]315
[1dcc0b9]316 wmi_reg_write(ar9271->htc_device, AR9271_PHY_CAL, value);
[a35b458]317
[8a64320e]318 wmi_reg_clear_bit(ar9271->htc_device, AR9271_AGC_CONTROL,
319 AR9271_AGC_CONTROL_NF_CALIB_EN);
[a35b458]320
[8a64320e]321 wmi_reg_clear_bit(ar9271->htc_device, AR9271_AGC_CONTROL,
322 AR9271_AGC_CONTROL_NF_NOT_UPDATE);
[a35b458]323
[8a64320e]324 wmi_reg_set_bit(ar9271->htc_device, AR9271_AGC_CONTROL,
325 AR9271_AGC_CONTROL_NF_CALIB);
[a35b458]326
[b7fd2a0]327 errno_t rc = hw_read_wait(ar9271, AR9271_AGC_CONTROL,
[8a64320e]328 AR9271_AGC_CONTROL_NF_CALIB, 0);
329 if (rc != EOK) {
[1dcc0b9]330 usb_log_error("Failed to wait for NF calibration.\n");
331 return rc;
332 }
[a35b458]333
[8a64320e]334 wmi_reg_set_bit(ar9271->htc_device, AR9271_AGC_CONTROL,
335 AR9271_AGC_CONTROL_NF_CALIB_EN);
[a35b458]336
[8a64320e]337 wmi_reg_clear_bit(ar9271->htc_device, AR9271_AGC_CONTROL,
338 AR9271_AGC_CONTROL_NF_NOT_UPDATE);
[a35b458]339
[8a64320e]340 wmi_reg_set_bit(ar9271->htc_device, AR9271_AGC_CONTROL,
341 AR9271_AGC_CONTROL_NF_CALIB);
[a35b458]342
[59fa7ab]343 return EOK;
344}
345
[b7fd2a0]346static errno_t hw_set_freq(ar9271_t *ar9271, uint16_t freq)
[59fa7ab]347{
348 /* Not supported channel frequency. */
[8a64320e]349 if ((freq < IEEE80211_FIRST_FREQ) || (freq > IEEE80211_MAX_FREQ))
[59fa7ab]350 return EINVAL;
[a35b458]351
[59fa7ab]352 /* Not supported channel frequency. */
[8a64320e]353 if ((freq - IEEE80211_FIRST_FREQ) % IEEE80211_CHANNEL_GAP != 0)
[59fa7ab]354 return EINVAL;
[a35b458]355
[59fa7ab]356 uint32_t tx_control;
357 wmi_reg_read(ar9271->htc_device, AR9271_PHY_CCK_TX_CTRL, &tx_control);
358 wmi_reg_write(ar9271->htc_device, AR9271_PHY_CCK_TX_CTRL,
[8a64320e]359 tx_control & ~AR9271_PHY_CCK_TX_CTRL_JAPAN);
[a35b458]360
[59fa7ab]361 /* Some magic here. */
362 uint32_t synth_ctl;
363 wmi_reg_read(ar9271->htc_device, AR9271_PHY_SYNTH_CONTROL, &synth_ctl);
[8a64320e]364 synth_ctl &= 0xc0000000;
[59fa7ab]365 uint32_t channel_select = (freq * 0x10000) / 15;
366 synth_ctl = synth_ctl | (1 << 29) | (1 << 28) | channel_select;
[a35b458]367
[59fa7ab]368 wmi_reg_write(ar9271->htc_device, AR9271_PHY_SYNTH_CONTROL, synth_ctl);
[a35b458]369
[59fa7ab]370 ieee80211_report_current_freq(ar9271->ieee80211_dev, freq);
[a35b458]371
[59fa7ab]372 return EOK;
373}
374
[b7fd2a0]375errno_t hw_freq_switch(ar9271_t *ar9271, uint16_t freq)
[59fa7ab]376{
377 wmi_reg_write(ar9271->htc_device, AR9271_PHY_RFBUS_KILL, 0x1);
[a35b458]378
[b7fd2a0]379 errno_t rc = hw_read_wait(ar9271, AR9271_PHY_RFBUS_GRANT, 0x1, 0x1);
[8a64320e]380 if (rc != EOK) {
[59fa7ab]381 usb_log_error("Failed to kill RF bus.\n");
382 return rc;
383 }
[a35b458]384
[59fa7ab]385 rc = hw_set_freq(ar9271, freq);
[8a64320e]386 if (rc != EOK) {
[59fa7ab]387 usb_log_error("Failed to HW set frequency.\n");
388 return rc;
389 }
[a35b458]390
[1dcc0b9]391 rc = hw_activate_phy(ar9271);
[8a64320e]392 if (rc != EOK) {
[1dcc0b9]393 usb_log_error("Failed to activate physical layer.\n");
394 return rc;
395 }
[a35b458]396
[59fa7ab]397 udelay(1000);
398 wmi_reg_write(ar9271->htc_device, AR9271_PHY_RFBUS_KILL, 0x0);
[a35b458]399
[59fa7ab]400 rc = hw_noise_floor_calibration(ar9271);
[8a64320e]401 if (rc != EOK) {
[59fa7ab]402 usb_log_error("Failed to do NF calibration.\n");
403 return rc;
404 }
[a35b458]405
[59fa7ab]406 return EOK;
407}
408
[b7fd2a0]409errno_t hw_set_rx_filter(ar9271_t *ar9271, bool assoc)
[59fa7ab]410{
[1dcc0b9]411 uint32_t additional_bits = 0;
[a35b458]412
[8a64320e]413 if (assoc)
[1dcc0b9]414 additional_bits |= AR9271_RX_FILTER_MYBEACON;
[8a64320e]415 else
[1dcc0b9]416 additional_bits |= AR9271_RX_FILTER_BEACON;
[a35b458]417
[8a64320e]418 uint32_t filter_bits = AR9271_RX_FILTER_UNI |
419 AR9271_RX_FILTER_MULTI | AR9271_RX_FILTER_BROAD |
420 additional_bits;
[a35b458]421
[59fa7ab]422 wmi_reg_write(ar9271->htc_device, AR9271_RX_FILTER, filter_bits);
[a35b458]423
[59fa7ab]424 return EOK;
425}
426
[b7fd2a0]427errno_t hw_set_bssid(ar9271_t *ar9271)
[1dcc0b9]428{
429 ieee80211_dev_t *ieee80211_dev = ar9271->ieee80211_dev;
[a35b458]430
[1dcc0b9]431 nic_address_t bssid;
432 ieee80211_query_bssid(ieee80211_dev, &bssid);
[a35b458]433
[1dcc0b9]434 uint32_t *first_4bytes = (uint32_t *) &bssid.address;
435 uint16_t *last_2bytes = (uint16_t *) &bssid.address[4];
[a35b458]436
[8a64320e]437 wmi_reg_write(ar9271->htc_device, AR9271_BSSID0,
438 uint32_t_le2host(*first_4bytes));
[a35b458]439
[8a64320e]440 wmi_reg_write(ar9271->htc_device, AR9271_BSSID1,
441 uint16_t_le2host(*last_2bytes) |
442 ((ieee80211_get_aid(ieee80211_dev) & 0x3fff) << 16));
[a35b458]443
[1dcc0b9]444 return EOK;
445}
446
[b7fd2a0]447errno_t hw_rx_init(ar9271_t *ar9271)
[59fa7ab]448{
[8a64320e]449 wmi_reg_write(ar9271->htc_device, AR9271_COMMAND,
450 AR9271_COMMAND_RX_ENABLE);
[a35b458]451
[b7fd2a0]452 errno_t rc = hw_set_rx_filter(ar9271, false);
[8a64320e]453 if (rc != EOK) {
[59fa7ab]454 usb_log_error("Failed to set RX filtering.\n");
455 return rc;
456 }
[a35b458]457
[59fa7ab]458 wmi_reg_write(ar9271->htc_device, AR9271_MULTICAST_FILTER1, ~0);
459 wmi_reg_write(ar9271->htc_device, AR9271_MULTICAST_FILTER2, ~0);
[a35b458]460
[59fa7ab]461 /* Disable RX blocking. */
462 wmi_reg_clear_bit(ar9271->htc_device, AR9271_DIAG, (0x20 | 0x02000000));
[a35b458]463
[59fa7ab]464 return EOK;
465}
466
[b7fd2a0]467static errno_t hw_init_pll(ar9271_t *ar9271)
[59fa7ab]468{
469 /* Some magic here (set for 2GHz channels). But VERY important :-) */
[8a64320e]470 uint32_t pll = (0x5 << 10) | 0x2c;
[a35b458]471
[59fa7ab]472 wmi_reg_write(ar9271->htc_device, AR9271_RTC_PLL_CONTROL, pll);
[a35b458]473
[1dcc0b9]474 wmi_reg_write(ar9271->htc_device, AR9271_RTC_SLEEP_CLOCK,
[8a64320e]475 AR9271_RTC_SLEEP_CLOCK_FORCE_DERIVED);
[1dcc0b9]476 wmi_reg_set_bit(ar9271->htc_device, AR9271_RTC_FORCE_WAKE,
[8a64320e]477 AR9271_RTC_FORCE_WAKE_ENABLE);
[a35b458]478
[59fa7ab]479 return EOK;
480}
481
[1dcc0b9]482static void hw_set_init_values(ar9271_t *ar9271)
[59fa7ab]483{
[8a64320e]484 uint32_t reg_offset;
485 uint32_t reg_value;
[a35b458]486
[8a64320e]487 size_t size = ARRAY_SIZE(ar9271_2g_mode_array);
[a35b458]488
[8a64320e]489 for (size_t i = 0; i < size; i++) {
[59fa7ab]490 reg_offset = ar9271_2g_mode_array[i][0];
491 reg_value = ar9271_2g_mode_array[i][1];
492 wmi_reg_write(ar9271->htc_device, reg_offset, reg_value);
493 }
[a35b458]494
[59fa7ab]495 size = ARRAY_SIZE(ar9271_2g_tx_array);
[a35b458]496
[8a64320e]497 for (size_t i = 0; i < size; i++) {
[59fa7ab]498 reg_offset = ar9271_2g_tx_array[i][0];
499 reg_value = ar9271_2g_tx_array[i][1];
500 wmi_reg_write(ar9271->htc_device, reg_offset, reg_value);
501 }
[a35b458]502
[59fa7ab]503 size = ARRAY_SIZE(ar9271_init_array);
[a35b458]504
[8a64320e]505 for (size_t i = 0; i < size; i++) {
[59fa7ab]506 reg_offset = ar9271_init_array[i][0];
507 reg_value = ar9271_init_array[i][1];
508 wmi_reg_write(ar9271->htc_device, reg_offset, reg_value);
509 }
510}
511
[b7fd2a0]512static errno_t hw_calibration(ar9271_t *ar9271)
[59fa7ab]513{
514 wmi_reg_set_bit(ar9271->htc_device, AR9271_CARRIER_LEAK_CONTROL,
[8a64320e]515 AR9271_CARRIER_LEAK_CALIB);
[59fa7ab]516 wmi_reg_clear_bit(ar9271->htc_device, AR9271_ADC_CONTROL,
[8a64320e]517 AR9271_ADC_CONTROL_OFF_PWDADC);
[59fa7ab]518 wmi_reg_set_bit(ar9271->htc_device, AR9271_AGC_CONTROL,
[8a64320e]519 AR9271_AGC_CONTROL_TX_CALIB);
[59fa7ab]520 wmi_reg_set_bit(ar9271->htc_device, AR9271_PHY_TPCRG1,
[8a64320e]521 AR9271_PHY_TPCRG1_PD_CALIB);
[59fa7ab]522 wmi_reg_set_bit(ar9271->htc_device, AR9271_AGC_CONTROL,
[8a64320e]523 AR9271_AGC_CONTROL_CALIB);
[a35b458]524
[b7fd2a0]525 errno_t rc = hw_read_wait(ar9271, AR9271_AGC_CONTROL,
[8a64320e]526 AR9271_AGC_CONTROL_CALIB, 0);
527 if (rc != EOK) {
[59fa7ab]528 usb_log_error("Failed to wait on calibrate completion.\n");
529 return rc;
530 }
[a35b458]531
[59fa7ab]532 wmi_reg_set_bit(ar9271->htc_device, AR9271_ADC_CONTROL,
[8a64320e]533 AR9271_ADC_CONTROL_OFF_PWDADC);
[59fa7ab]534 wmi_reg_clear_bit(ar9271->htc_device, AR9271_CARRIER_LEAK_CONTROL,
[8a64320e]535 AR9271_CARRIER_LEAK_CALIB);
[59fa7ab]536 wmi_reg_clear_bit(ar9271->htc_device, AR9271_AGC_CONTROL,
[8a64320e]537 AR9271_AGC_CONTROL_TX_CALIB);
[a35b458]538
[59fa7ab]539 return EOK;
540}
541
[b7fd2a0]542errno_t hw_reset(ar9271_t *ar9271)
[59fa7ab]543{
544 /* Set physical layer as deactivated. */
545 wmi_reg_write(ar9271->htc_device, AR9271_PHY_ACTIVE, 0);
[a35b458]546
[3bacee1]547 if (ar9271->starting_up) {
[8a64320e]548 wmi_reg_write(ar9271->htc_device,
549 AR9271_RESET_POWER_DOWN_CONTROL,
550 AR9271_RADIO_RF_RESET);
[a35b458]551
[59fa7ab]552 udelay(50);
553 }
[a35b458]554
[59fa7ab]555 /* Cold reset when RX is enabled. */
556 uint32_t config_reg;
557 wmi_reg_read(ar9271->htc_device, AR9271_COMMAND, &config_reg);
[8a64320e]558 if (config_reg & AR9271_COMMAND_RX_ENABLE)
[59fa7ab]559 hw_set_reset(ar9271, true);
[a35b458]560
[b7fd2a0]561 errno_t rc = hw_init_pll(ar9271);
[8a64320e]562 if (rc != EOK) {
[59fa7ab]563 usb_log_error("Failed to init PLL.\n");
564 return rc;
565 }
[a35b458]566
[59fa7ab]567 udelay(500);
[a35b458]568
[8a64320e]569 wmi_reg_write(ar9271->htc_device, AR9271_CLOCK_CONTROL,
570 AR9271_MAX_CPU_CLOCK);
[a35b458]571
[59fa7ab]572 udelay(100);
[a35b458]573
[8a64320e]574 if (ar9271->starting_up) {
575 wmi_reg_write(ar9271->htc_device,
576 AR9271_RESET_POWER_DOWN_CONTROL,
577 AR9271_GATE_MAC_CONTROL);
[a35b458]578
[59fa7ab]579 udelay(50);
580 }
[a35b458]581
[1dcc0b9]582 hw_set_init_values(ar9271);
[a35b458]583
[59fa7ab]584 /* Set physical layer mode. */
[8a64320e]585 wmi_reg_write(ar9271->htc_device, AR9271_PHY_MODE,
586 AR9271_PHY_MODE_DYNAMIC);
[a35b458]587
[59fa7ab]588 /* Reset device operating mode. */
589 rc = hw_reset_operating_mode(ar9271);
[8a64320e]590 if (rc != EOK) {
[59fa7ab]591 usb_log_error("Failed to reset operating mode.\n");
592 return rc;
593 }
[a35b458]594
[59fa7ab]595 /* Set initial channel frequency. */
596 rc = hw_set_freq(ar9271, IEEE80211_FIRST_FREQ);
[8a64320e]597 if (rc != EOK) {
[59fa7ab]598 usb_log_error("Failed to set channel.\n");
599 return rc;
600 }
[a35b458]601
[59fa7ab]602 /* Initialize transmission queues. */
[8a64320e]603 for (unsigned int i = 0; i < AR9271_QUEUES_COUNT; i++) {
604 wmi_reg_write(ar9271->htc_device,
605 AR9271_QUEUE_BASE_MASK + (i << 2), 1 << i);
[59fa7ab]606 }
[a35b458]607
[59fa7ab]608 /* Activate physical layer. */
609 rc = hw_activate_phy(ar9271);
[8a64320e]610 if (rc != EOK) {
[59fa7ab]611 usb_log_error("Failed to activate physical layer.\n");
612 return rc;
613 }
[a35b458]614
[59fa7ab]615 /* Calibration. */
616 rc = hw_calibration(ar9271);
[8a64320e]617 if (rc != EOK) {
[59fa7ab]618 usb_log_error("Failed to calibrate device.\n");
619 return rc;
620 }
[a35b458]621
[59fa7ab]622 rc = hw_noise_floor_calibration(ar9271);
[8a64320e]623 if (rc != EOK) {
[59fa7ab]624 usb_log_error("Failed to calibrate noise floor.\n");
625 return rc;
626 }
[a35b458]627
[59fa7ab]628 /* Byteswap TX and RX data buffer words. */
629 wmi_reg_write(ar9271->htc_device, AR9271_CONFIG, 0xA);
[a35b458]630
[59fa7ab]631 return EOK;
632}
633
[8a64320e]634/** Initialize hardware of AR9271 device.
635 *
[59fa7ab]636 * @param ar9271 Device structure.
[8a64320e]637 *
[cde999a]638 * @return EOK if succeed, error code otherwise.
[59fa7ab]639 */
[b7fd2a0]640errno_t hw_init(ar9271_t *ar9271)
[59fa7ab]641{
[b7fd2a0]642 errno_t rc = hw_init_proc(ar9271);
[8a64320e]643 if (rc != EOK) {
[59fa7ab]644 usb_log_error("Failed to HW reset device.\n");
645 return rc;
646 }
[a35b458]647
[59fa7ab]648 rc = hw_init_led(ar9271);
[8a64320e]649 if (rc != EOK) {
[59fa7ab]650 usb_log_error("Failed to HW init led.\n");
651 return rc;
652 }
[a35b458]653
[59fa7ab]654 usb_log_info("HW initialization finished successfully.\n");
[a35b458]655
[59fa7ab]656 return EOK;
[8a64320e]657}
Note: See TracBrowser for help on using the repository browser.