linux/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
<<
>>
Prefs
   1/*
   2 * aQuantia Corporation Network Driver
   3 * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms and conditions of the GNU General Public License,
   7 * version 2, as published by the Free Software Foundation.
   8 */
   9
  10/* File hw_atl_utils.c: Definition of common functions for Atlantic hardware
  11 * abstraction layer.
  12 */
  13
  14#include "../aq_hw.h"
  15#include "../aq_hw_utils.h"
  16#include "../aq_pci_func.h"
  17#include "../aq_ring.h"
  18#include "../aq_vec.h"
  19#include "hw_atl_utils.h"
  20#include "hw_atl_llh.h"
  21
  22#include <linux/random.h>
  23
  24#define HW_ATL_UCP_0X370_REG    0x0370U
  25
  26#define HW_ATL_FW_SM_RAM        0x2U
  27#define HW_ATL_MPI_CONTROL_ADR  0x0368U
  28#define HW_ATL_MPI_STATE_ADR    0x036CU
  29
  30#define HW_ATL_MPI_STATE_MSK    0x00FFU
  31#define HW_ATL_MPI_STATE_SHIFT  0U
  32#define HW_ATL_MPI_SPEED_MSK    0xFFFFU
  33#define HW_ATL_MPI_SPEED_SHIFT  16U
  34
  35static int hw_atl_utils_fw_downld_dwords(struct aq_hw_s *self, u32 a,
  36                                         u32 *p, u32 cnt)
  37{
  38        int err = 0;
  39
  40        AQ_HW_WAIT_FOR(reg_glb_cpu_sem_get(self,
  41                                           HW_ATL_FW_SM_RAM) == 1U,
  42                                           1U, 10000U);
  43
  44        if (err < 0) {
  45                bool is_locked;
  46
  47                reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM);
  48                is_locked = reg_glb_cpu_sem_get(self, HW_ATL_FW_SM_RAM);
  49                if (!is_locked) {
  50                        err = -ETIME;
  51                        goto err_exit;
  52                }
  53        }
  54
  55        aq_hw_write_reg(self, 0x00000208U, a);
  56
  57        for (++cnt; --cnt;) {
  58                u32 i = 0U;
  59
  60                aq_hw_write_reg(self, 0x00000200U, 0x00008000U);
  61
  62                for (i = 1024U;
  63                        (0x100U & aq_hw_read_reg(self, 0x00000200U)) && --i;) {
  64                }
  65
  66                *(p++) = aq_hw_read_reg(self, 0x0000020CU);
  67        }
  68
  69        reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM);
  70
  71err_exit:
  72        return err;
  73}
  74
  75static int hw_atl_utils_fw_upload_dwords(struct aq_hw_s *self, u32 a, u32 *p,
  76                                         u32 cnt)
  77{
  78        int err = 0;
  79        bool is_locked;
  80
  81        is_locked = reg_glb_cpu_sem_get(self, HW_ATL_FW_SM_RAM);
  82        if (!is_locked) {
  83                err = -ETIME;
  84                goto err_exit;
  85        }
  86
  87        aq_hw_write_reg(self, 0x00000208U, a);
  88
  89        for (++cnt; --cnt;) {
  90                u32 i = 0U;
  91
  92                aq_hw_write_reg(self, 0x0000020CU, *(p++));
  93                aq_hw_write_reg(self, 0x00000200U, 0xC000U);
  94
  95                for (i = 1024U;
  96                        (0x100U & aq_hw_read_reg(self, 0x00000200U)) && --i;) {
  97                }
  98        }
  99
 100        reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM);
 101
 102err_exit:
 103        return err;
 104}
 105
 106static int hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual)
 107{
 108        int err = 0;
 109        const u32 dw_major_mask = 0xff000000U;
 110        const u32 dw_minor_mask = 0x00ffffffU;
 111
 112        err = (dw_major_mask & (ver_expected ^ ver_actual)) ? -EOPNOTSUPP : 0;
 113        if (err < 0)
 114                goto err_exit;
 115        err = ((dw_minor_mask & ver_expected) > (dw_minor_mask & ver_actual)) ?
 116                -EOPNOTSUPP : 0;
 117err_exit:
 118        return err;
 119}
 120
 121static int hw_atl_utils_init_ucp(struct aq_hw_s *self,
 122                                 struct aq_hw_caps_s *aq_hw_caps)
 123{
 124        int err = 0;
 125
 126        if (!aq_hw_read_reg(self, 0x370U)) {
 127                unsigned int rnd = 0U;
 128                unsigned int ucp_0x370 = 0U;
 129
 130                get_random_bytes(&rnd, sizeof(unsigned int));
 131
 132                ucp_0x370 = 0x02020202U | (0xFEFEFEFEU & rnd);
 133                aq_hw_write_reg(self, HW_ATL_UCP_0X370_REG, ucp_0x370);
 134        }
 135
 136        reg_glb_cpu_scratch_scp_set(self, 0x00000000U, 25U);
 137
 138        /* check 10 times by 1ms */
 139        AQ_HW_WAIT_FOR(0U != (PHAL_ATLANTIC_A0->mbox_addr =
 140                        aq_hw_read_reg(self, 0x360U)), 1000U, 10U);
 141
 142        err = hw_atl_utils_ver_match(aq_hw_caps->fw_ver_expected,
 143                                     aq_hw_read_reg(self, 0x18U));
 144
 145        if (err < 0)
 146                pr_err("%s: Bad FW version detected: expected=%x, actual=%x\n",
 147                       AQ_CFG_DRV_NAME,
 148                       aq_hw_caps->fw_ver_expected,
 149                       aq_hw_read_reg(self, 0x18U));
 150        return err;
 151}
 152
 153#define HW_ATL_RPC_CONTROL_ADR 0x0338U
 154#define HW_ATL_RPC_STATE_ADR   0x033CU
 155
 156struct aq_hw_atl_utils_fw_rpc_tid_s {
 157        union {
 158                u32 val;
 159                struct {
 160                        u16 tid;
 161                        u16 len;
 162                };
 163        };
 164};
 165
 166#define hw_atl_utils_fw_rpc_init(_H_) hw_atl_utils_fw_rpc_wait(_H_, NULL)
 167
 168static int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int rpc_size)
 169{
 170        int err = 0;
 171        struct aq_hw_atl_utils_fw_rpc_tid_s sw;
 172
 173        if (!IS_CHIP_FEATURE(MIPS)) {
 174                err = -1;
 175                goto err_exit;
 176        }
 177        err = hw_atl_utils_fw_upload_dwords(self, PHAL_ATLANTIC->rpc_addr,
 178                                            (u32 *)(void *)&PHAL_ATLANTIC->rpc,
 179                                            (rpc_size + sizeof(u32) -
 180                                            sizeof(u8)) / sizeof(u32));
 181        if (err < 0)
 182                goto err_exit;
 183
 184        sw.tid = 0xFFFFU & (++PHAL_ATLANTIC->rpc_tid);
 185        sw.len = (u16)rpc_size;
 186        aq_hw_write_reg(self, HW_ATL_RPC_CONTROL_ADR, sw.val);
 187
 188err_exit:
 189        return err;
 190}
 191
 192static int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self,
 193                                    struct hw_aq_atl_utils_fw_rpc **rpc)
 194{
 195        int err = 0;
 196        struct aq_hw_atl_utils_fw_rpc_tid_s sw;
 197        struct aq_hw_atl_utils_fw_rpc_tid_s fw;
 198
 199        do {
 200                sw.val = aq_hw_read_reg(self, HW_ATL_RPC_CONTROL_ADR);
 201
 202                PHAL_ATLANTIC->rpc_tid = sw.tid;
 203
 204                AQ_HW_WAIT_FOR(sw.tid ==
 205                                (fw.val =
 206                                aq_hw_read_reg(self, HW_ATL_RPC_STATE_ADR),
 207                                fw.tid), 1000U, 100U);
 208                if (err < 0)
 209                        goto err_exit;
 210
 211                if (fw.len == 0xFFFFU) {
 212                        err = hw_atl_utils_fw_rpc_call(self, sw.len);
 213                        if (err < 0)
 214                                goto err_exit;
 215                }
 216        } while (sw.tid != fw.tid || 0xFFFFU == fw.len);
 217        if (err < 0)
 218                goto err_exit;
 219
 220        if (rpc) {
 221                if (fw.len) {
 222                        err =
 223                        hw_atl_utils_fw_downld_dwords(self,
 224                                                      PHAL_ATLANTIC->rpc_addr,
 225                                                      (u32 *)(void *)
 226                                                      &PHAL_ATLANTIC->rpc,
 227                                                      (fw.len + sizeof(u32) -
 228                                                      sizeof(u8)) /
 229                                                      sizeof(u32));
 230                        if (err < 0)
 231                                goto err_exit;
 232                }
 233
 234                *rpc = &PHAL_ATLANTIC->rpc;
 235        }
 236
 237err_exit:
 238        return err;
 239}
 240
 241static int hw_atl_utils_mpi_create(struct aq_hw_s *self,
 242                                   struct aq_hw_caps_s *aq_hw_caps)
 243{
 244        int err = 0;
 245
 246        err = hw_atl_utils_init_ucp(self, aq_hw_caps);
 247        if (err < 0)
 248                goto err_exit;
 249
 250        err = hw_atl_utils_fw_rpc_init(self);
 251        if (err < 0)
 252                goto err_exit;
 253
 254err_exit:
 255        return err;
 256}
 257
 258int hw_atl_utils_mpi_read_mbox(struct aq_hw_s *self,
 259                               struct hw_aq_atl_utils_mbox_header *pmbox)
 260{
 261        return hw_atl_utils_fw_downld_dwords(self,
 262                                      PHAL_ATLANTIC->mbox_addr,
 263                                      (u32 *)(void *)pmbox,
 264                                      sizeof(*pmbox) / sizeof(u32));
 265}
 266
 267void hw_atl_utils_mpi_read_stats(struct aq_hw_s *self,
 268                                 struct hw_aq_atl_utils_mbox *pmbox)
 269{
 270        int err = 0;
 271
 272        err = hw_atl_utils_fw_downld_dwords(self,
 273                                            PHAL_ATLANTIC->mbox_addr,
 274                                            (u32 *)(void *)pmbox,
 275                                            sizeof(*pmbox) / sizeof(u32));
 276        if (err < 0)
 277                goto err_exit;
 278
 279        if (IS_CHIP_FEATURE(REVISION_A0)) {
 280                unsigned int mtu = self->aq_nic_cfg ?
 281                                        self->aq_nic_cfg->mtu : 1514U;
 282                pmbox->stats.ubrc = pmbox->stats.uprc * mtu;
 283                pmbox->stats.ubtc = pmbox->stats.uptc * mtu;
 284                pmbox->stats.dpc = atomic_read(&PHAL_ATLANTIC_A0->dpc);
 285        } else {
 286                pmbox->stats.dpc = reg_rx_dma_stat_counter7get(self);
 287        }
 288
 289err_exit:;
 290}
 291
 292int hw_atl_utils_mpi_set_speed(struct aq_hw_s *self, u32 speed,
 293                               enum hal_atl_utils_fw_state_e state)
 294{
 295        u32 ucp_0x368 = 0;
 296
 297        ucp_0x368 = (speed << HW_ATL_MPI_SPEED_SHIFT) | state;
 298        aq_hw_write_reg(self, HW_ATL_MPI_CONTROL_ADR, ucp_0x368);
 299
 300        return 0;
 301}
 302
 303void hw_atl_utils_mpi_set(struct aq_hw_s *self,
 304                          enum hal_atl_utils_fw_state_e state, u32 speed)
 305{
 306        int err = 0;
 307        u32 transaction_id = 0;
 308        struct hw_aq_atl_utils_mbox_header mbox;
 309
 310        if (state == MPI_RESET) {
 311                hw_atl_utils_mpi_read_mbox(self, &mbox);
 312
 313                transaction_id = mbox.transaction_id;
 314
 315                AQ_HW_WAIT_FOR(transaction_id !=
 316                                (hw_atl_utils_mpi_read_mbox(self, &mbox),
 317                                 mbox.transaction_id),
 318                               1000U, 100U);
 319                if (err < 0)
 320                        goto err_exit;
 321        }
 322
 323        err = hw_atl_utils_mpi_set_speed(self, speed, state);
 324
 325err_exit:;
 326}
 327
 328int hw_atl_utils_mpi_get_link_status(struct aq_hw_s *self)
 329{
 330        u32 cp0x036C = aq_hw_read_reg(self, HW_ATL_MPI_STATE_ADR);
 331        u32 link_speed_mask = cp0x036C >> HW_ATL_MPI_SPEED_SHIFT;
 332        struct aq_hw_link_status_s *link_status = &self->aq_link_status;
 333
 334        if (!link_speed_mask) {
 335                link_status->mbps = 0U;
 336        } else {
 337                switch (link_speed_mask) {
 338                case HAL_ATLANTIC_RATE_10G:
 339                        link_status->mbps = 10000U;
 340                        break;
 341
 342                case HAL_ATLANTIC_RATE_5G:
 343                case HAL_ATLANTIC_RATE_5GSR:
 344                        link_status->mbps = 5000U;
 345                        break;
 346
 347                case HAL_ATLANTIC_RATE_2GS:
 348                        link_status->mbps = 2500U;
 349                        break;
 350
 351                case HAL_ATLANTIC_RATE_1G:
 352                        link_status->mbps = 1000U;
 353                        break;
 354
 355                case HAL_ATLANTIC_RATE_100M:
 356                        link_status->mbps = 100U;
 357                        break;
 358
 359                default:
 360                        return -EBUSY;
 361                }
 362        }
 363
 364        return 0;
 365}
 366
 367int hw_atl_utils_get_mac_permanent(struct aq_hw_s *self,
 368                                   struct aq_hw_caps_s *aq_hw_caps,
 369                                   u8 *mac)
 370{
 371        int err = 0;
 372        u32 h = 0U;
 373        u32 l = 0U;
 374        u32 mac_addr[2];
 375
 376        self->mmio = aq_pci_func_get_mmio(self->aq_pci_func);
 377
 378        hw_atl_utils_hw_chip_features_init(self,
 379                                           &PHAL_ATLANTIC_A0->chip_features);
 380
 381        err = hw_atl_utils_mpi_create(self, aq_hw_caps);
 382        if (err < 0)
 383                goto err_exit;
 384
 385        if (!aq_hw_read_reg(self, HW_ATL_UCP_0X370_REG)) {
 386                unsigned int rnd = 0;
 387                unsigned int ucp_0x370 = 0;
 388
 389                get_random_bytes(&rnd, sizeof(unsigned int));
 390
 391                ucp_0x370 = 0x02020202 | (0xFEFEFEFE & rnd);
 392                aq_hw_write_reg(self, HW_ATL_UCP_0X370_REG, ucp_0x370);
 393        }
 394
 395        err = hw_atl_utils_fw_downld_dwords(self,
 396                                            aq_hw_read_reg(self, 0x00000374U) +
 397                                            (40U * 4U),
 398                                            mac_addr,
 399                                            AQ_DIMOF(mac_addr));
 400        if (err < 0) {
 401                mac_addr[0] = 0U;
 402                mac_addr[1] = 0U;
 403                err = 0;
 404        } else {
 405                mac_addr[0] = __swab32(mac_addr[0]);
 406                mac_addr[1] = __swab32(mac_addr[1]);
 407        }
 408
 409        ether_addr_copy(mac, (u8 *)mac_addr);
 410
 411        if ((mac[0] & 0x01U) || ((mac[0] | mac[1] | mac[2]) == 0x00U)) {
 412                /* chip revision */
 413                l = 0xE3000000U
 414                        | (0xFFFFU & aq_hw_read_reg(self, HW_ATL_UCP_0X370_REG))
 415                        | (0x00 << 16);
 416                h = 0x8001300EU;
 417
 418                mac[5] = (u8)(0xFFU & l);
 419                l >>= 8;
 420                mac[4] = (u8)(0xFFU & l);
 421                l >>= 8;
 422                mac[3] = (u8)(0xFFU & l);
 423                l >>= 8;
 424                mac[2] = (u8)(0xFFU & l);
 425                mac[1] = (u8)(0xFFU & h);
 426                h >>= 8;
 427                mac[0] = (u8)(0xFFU & h);
 428        }
 429
 430err_exit:
 431        return err;
 432}
 433
 434unsigned int hw_atl_utils_mbps_2_speed_index(unsigned int mbps)
 435{
 436        unsigned int ret = 0U;
 437
 438        switch (mbps) {
 439        case 100U:
 440                ret = 5U;
 441                break;
 442
 443        case 1000U:
 444                ret = 4U;
 445                break;
 446
 447        case 2500U:
 448                ret = 3U;
 449                break;
 450
 451        case 5000U:
 452                ret = 1U;
 453                break;
 454
 455        case 10000U:
 456                ret = 0U;
 457                break;
 458
 459        default:
 460                break;
 461        }
 462        return ret;
 463}
 464
 465void hw_atl_utils_hw_chip_features_init(struct aq_hw_s *self, u32 *p)
 466{
 467        u32 chip_features = 0U;
 468        u32 val = reg_glb_mif_id_get(self);
 469        u32 mif_rev = val & 0xFFU;
 470
 471        if ((3U & mif_rev) == 1U) {
 472                chip_features |=
 473                        HAL_ATLANTIC_UTILS_CHIP_REVISION_A0 |
 474                        HAL_ATLANTIC_UTILS_CHIP_MPI_AQ |
 475                        HAL_ATLANTIC_UTILS_CHIP_MIPS;
 476        } else if ((3U & mif_rev) == 2U) {
 477                chip_features |=
 478                        HAL_ATLANTIC_UTILS_CHIP_REVISION_B0 |
 479                        HAL_ATLANTIC_UTILS_CHIP_MPI_AQ |
 480                        HAL_ATLANTIC_UTILS_CHIP_MIPS |
 481                        HAL_ATLANTIC_UTILS_CHIP_TPO2 |
 482                        HAL_ATLANTIC_UTILS_CHIP_RPF2;
 483        }
 484
 485        *p = chip_features;
 486}
 487
 488int hw_atl_utils_hw_deinit(struct aq_hw_s *self)
 489{
 490        hw_atl_utils_mpi_set(self, MPI_DEINIT, 0x0U);
 491        return 0;
 492}
 493
 494int hw_atl_utils_hw_set_power(struct aq_hw_s *self,
 495                              unsigned int power_state)
 496{
 497        hw_atl_utils_mpi_set(self, MPI_POWER, 0x0U);
 498        return 0;
 499}
 500
 501int hw_atl_utils_update_stats(struct aq_hw_s *self)
 502{
 503        struct hw_atl_s *hw_self = PHAL_ATLANTIC;
 504        struct hw_aq_atl_utils_mbox mbox;
 505
 506        if (!self->aq_link_status.mbps)
 507                return 0;
 508
 509        hw_atl_utils_mpi_read_stats(self, &mbox);
 510
 511#define AQ_SDELTA(_N_) (hw_self->curr_stats._N_ += \
 512                        mbox.stats._N_ - hw_self->last_stats._N_)
 513
 514        AQ_SDELTA(uprc);
 515        AQ_SDELTA(mprc);
 516        AQ_SDELTA(bprc);
 517        AQ_SDELTA(erpt);
 518
 519        AQ_SDELTA(uptc);
 520        AQ_SDELTA(mptc);
 521        AQ_SDELTA(bptc);
 522        AQ_SDELTA(erpr);
 523
 524        AQ_SDELTA(ubrc);
 525        AQ_SDELTA(ubtc);
 526        AQ_SDELTA(mbrc);
 527        AQ_SDELTA(mbtc);
 528        AQ_SDELTA(bbrc);
 529        AQ_SDELTA(bbtc);
 530        AQ_SDELTA(dpc);
 531
 532#undef AQ_SDELTA
 533
 534        memcpy(&hw_self->last_stats, &mbox.stats, sizeof(mbox.stats));
 535
 536        return 0;
 537}
 538
 539int hw_atl_utils_get_hw_stats(struct aq_hw_s *self,
 540                              u64 *data, unsigned int *p_count)
 541{
 542        struct hw_atl_s *hw_self = PHAL_ATLANTIC;
 543        struct hw_atl_stats_s *stats = &hw_self->curr_stats;
 544        int i = 0;
 545
 546        data[i] = stats->uprc + stats->mprc + stats->bprc;
 547        data[++i] = stats->uprc;
 548        data[++i] = stats->mprc;
 549        data[++i] = stats->bprc;
 550        data[++i] = stats->erpt;
 551        data[++i] = stats->uptc + stats->mptc + stats->bptc;
 552        data[++i] = stats->uptc;
 553        data[++i] = stats->mptc;
 554        data[++i] = stats->bptc;
 555        data[++i] = stats->ubrc;
 556        data[++i] = stats->ubtc;
 557        data[++i] = stats->mbrc;
 558        data[++i] = stats->mbtc;
 559        data[++i] = stats->bbrc;
 560        data[++i] = stats->bbtc;
 561        data[++i] = stats->ubrc + stats->mbrc + stats->bbrc;
 562        data[++i] = stats->ubtc + stats->mbtc + stats->bbtc;
 563        data[++i] = stats_rx_dma_good_pkt_counterlsw_get(self);
 564        data[++i] = stats_tx_dma_good_pkt_counterlsw_get(self);
 565        data[++i] = stats_rx_dma_good_octet_counterlsw_get(self);
 566        data[++i] = stats_tx_dma_good_octet_counterlsw_get(self);
 567        data[++i] = stats->dpc;
 568
 569        if (p_count)
 570                *p_count = ++i;
 571
 572        return 0;
 573}
 574
 575static const u32 hw_atl_utils_hw_mac_regs[] = {
 576        0x00005580U, 0x00005590U, 0x000055B0U, 0x000055B4U,
 577        0x000055C0U, 0x00005B00U, 0x00005B04U, 0x00005B08U,
 578        0x00005B0CU, 0x00005B10U, 0x00005B14U, 0x00005B18U,
 579        0x00005B1CU, 0x00005B20U, 0x00005B24U, 0x00005B28U,
 580        0x00005B2CU, 0x00005B30U, 0x00005B34U, 0x00005B38U,
 581        0x00005B3CU, 0x00005B40U, 0x00005B44U, 0x00005B48U,
 582        0x00005B4CU, 0x00005B50U, 0x00005B54U, 0x00005B58U,
 583        0x00005B5CU, 0x00005B60U, 0x00005B64U, 0x00005B68U,
 584        0x00005B6CU, 0x00005B70U, 0x00005B74U, 0x00005B78U,
 585        0x00005B7CU, 0x00007C00U, 0x00007C04U, 0x00007C08U,
 586        0x00007C0CU, 0x00007C10U, 0x00007C14U, 0x00007C18U,
 587        0x00007C1CU, 0x00007C20U, 0x00007C40U, 0x00007C44U,
 588        0x00007C48U, 0x00007C4CU, 0x00007C50U, 0x00007C54U,
 589        0x00007C58U, 0x00007C5CU, 0x00007C60U, 0x00007C80U,
 590        0x00007C84U, 0x00007C88U, 0x00007C8CU, 0x00007C90U,
 591        0x00007C94U, 0x00007C98U, 0x00007C9CU, 0x00007CA0U,
 592        0x00007CC0U, 0x00007CC4U, 0x00007CC8U, 0x00007CCCU,
 593        0x00007CD0U, 0x00007CD4U, 0x00007CD8U, 0x00007CDCU,
 594        0x00007CE0U, 0x00000300U, 0x00000304U, 0x00000308U,
 595        0x0000030cU, 0x00000310U, 0x00000314U, 0x00000318U,
 596        0x0000031cU, 0x00000360U, 0x00000364U, 0x00000368U,
 597        0x0000036cU, 0x00000370U, 0x00000374U, 0x00006900U,
 598};
 599
 600int hw_atl_utils_hw_get_regs(struct aq_hw_s *self,
 601                             struct aq_hw_caps_s *aq_hw_caps,
 602                             u32 *regs_buff)
 603{
 604        unsigned int i = 0U;
 605
 606        for (i = 0; i < aq_hw_caps->mac_regs_count; i++)
 607                regs_buff[i] = aq_hw_read_reg(self,
 608                        hw_atl_utils_hw_mac_regs[i]);
 609        return 0;
 610}
 611
 612int hw_atl_utils_get_fw_version(struct aq_hw_s *self, u32 *fw_version)
 613{
 614        *fw_version = aq_hw_read_reg(self, 0x18U);
 615        return 0;
 616}
 617