linux/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/* Atlantic Network Driver
   3 *
   4 * Copyright (C) 2014-2019 aQuantia Corporation
   5 * Copyright (C) 2019-2020 Marvell International Ltd.
   6 */
   7
   8/* File hw_atl_utils_fw2x.c: Definition of firmware 2.x functions for
   9 * Atlantic hardware abstraction layer.
  10 */
  11
  12#include "../aq_hw.h"
  13#include "../aq_hw_utils.h"
  14#include "../aq_pci_func.h"
  15#include "../aq_ring.h"
  16#include "../aq_vec.h"
  17#include "../aq_nic.h"
  18#include "hw_atl_utils.h"
  19#include "hw_atl_llh.h"
  20
  21#define HW_ATL_FW2X_MPI_LED_ADDR         0x31c
  22#define HW_ATL_FW2X_MPI_RPC_ADDR         0x334
  23
  24#define HW_ATL_FW2X_MPI_MBOX_ADDR        0x360
  25#define HW_ATL_FW2X_MPI_EFUSE_ADDR       0x364
  26#define HW_ATL_FW2X_MPI_CONTROL_ADDR     0x368
  27#define HW_ATL_FW2X_MPI_CONTROL2_ADDR    0x36C
  28#define HW_ATL_FW2X_MPI_STATE_ADDR       0x370
  29#define HW_ATL_FW2X_MPI_STATE2_ADDR      0x374
  30
  31#define HW_ATL_FW3X_EXT_CONTROL_ADDR     0x378
  32#define HW_ATL_FW3X_EXT_STATE_ADDR       0x37c
  33
  34#define HW_ATL_FW3X_PTP_ADJ_LSW_ADDR     0x50a0
  35#define HW_ATL_FW3X_PTP_ADJ_MSW_ADDR     0x50a4
  36
  37#define HW_ATL_FW2X_CAP_PAUSE            BIT(CAPS_HI_PAUSE)
  38#define HW_ATL_FW2X_CAP_ASYM_PAUSE       BIT(CAPS_HI_ASYMMETRIC_PAUSE)
  39#define HW_ATL_FW2X_CAP_SLEEP_PROXY      BIT(CAPS_HI_SLEEP_PROXY)
  40#define HW_ATL_FW2X_CAP_WOL              BIT(CAPS_HI_WOL)
  41
  42#define HW_ATL_FW2X_CTRL_WAKE_ON_LINK     BIT(CTRL_WAKE_ON_LINK)
  43#define HW_ATL_FW2X_CTRL_SLEEP_PROXY      BIT(CTRL_SLEEP_PROXY)
  44#define HW_ATL_FW2X_CTRL_WOL              BIT(CTRL_WOL)
  45#define HW_ATL_FW2X_CTRL_LINK_DROP        BIT(CTRL_LINK_DROP)
  46#define HW_ATL_FW2X_CTRL_PAUSE            BIT(CTRL_PAUSE)
  47#define HW_ATL_FW2X_CTRL_TEMPERATURE      BIT(CTRL_TEMPERATURE)
  48#define HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE BIT(CTRL_ASYMMETRIC_PAUSE)
  49#define HW_ATL_FW2X_CTRL_INT_LOOPBACK     BIT(CTRL_INT_LOOPBACK)
  50#define HW_ATL_FW2X_CTRL_EXT_LOOPBACK     BIT(CTRL_EXT_LOOPBACK)
  51#define HW_ATL_FW2X_CTRL_DOWNSHIFT        BIT(CTRL_DOWNSHIFT)
  52#define HW_ATL_FW2X_CTRL_FORCE_RECONNECT  BIT(CTRL_FORCE_RECONNECT)
  53
  54#define HW_ATL_FW2X_CAP_EEE_1G_MASK      BIT(CAPS_HI_1000BASET_FD_EEE)
  55#define HW_ATL_FW2X_CAP_EEE_2G5_MASK     BIT(CAPS_HI_2P5GBASET_FD_EEE)
  56#define HW_ATL_FW2X_CAP_EEE_5G_MASK      BIT(CAPS_HI_5GBASET_FD_EEE)
  57#define HW_ATL_FW2X_CAP_EEE_10G_MASK     BIT(CAPS_HI_10GBASET_FD_EEE)
  58
  59#define HAL_ATLANTIC_WOL_FILTERS_COUNT   8
  60#define HAL_ATLANTIC_UTILS_FW2X_MSG_WOL  0x0E
  61
  62#define HW_ATL_FW_VER_LED                0x03010026U
  63#define HW_ATL_FW_VER_MEDIA_CONTROL      0x0301005aU
  64
  65struct __packed fw2x_msg_wol_pattern {
  66        u8 mask[16];
  67        u32 crc;
  68};
  69
  70struct __packed fw2x_msg_wol {
  71        u32 msg_id;
  72        u8 hw_addr[ETH_ALEN];
  73        u8 magic_packet_enabled;
  74        u8 filter_count;
  75        struct fw2x_msg_wol_pattern filter[HAL_ATLANTIC_WOL_FILTERS_COUNT];
  76        u8 link_up_enabled;
  77        u8 link_down_enabled;
  78        u16 reserved;
  79        u32 link_up_timeout;
  80        u32 link_down_timeout;
  81};
  82
  83static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed);
  84static int aq_fw2x_set_state(struct aq_hw_s *self,
  85                             enum hal_atl_utils_fw_state_e state);
  86
  87static u32 aq_fw2x_mbox_get(struct aq_hw_s *self);
  88static u32 aq_fw2x_rpc_get(struct aq_hw_s *self);
  89static int aq_fw2x_settings_get(struct aq_hw_s *self, u32 *addr);
  90static u32 aq_fw2x_state2_get(struct aq_hw_s *self);
  91
  92static int aq_fw2x_init(struct aq_hw_s *self)
  93{
  94        int err = 0;
  95
  96        /* check 10 times by 1ms */
  97        err = readx_poll_timeout_atomic(aq_fw2x_mbox_get,
  98                                        self, self->mbox_addr,
  99                                        self->mbox_addr != 0U,
 100                                        1000U, 10000U);
 101
 102        err = readx_poll_timeout_atomic(aq_fw2x_rpc_get,
 103                                        self, self->rpc_addr,
 104                                        self->rpc_addr != 0U,
 105                                        1000U, 100000U);
 106
 107        err = aq_fw2x_settings_get(self, &self->settings_addr);
 108
 109        return err;
 110}
 111
 112static int aq_fw2x_deinit(struct aq_hw_s *self)
 113{
 114        int err = aq_fw2x_set_link_speed(self, 0);
 115
 116        if (!err)
 117                err = aq_fw2x_set_state(self, MPI_DEINIT);
 118
 119        return err;
 120}
 121
 122static enum hw_atl_fw2x_rate link_speed_mask_2fw2x_ratemask(u32 speed)
 123{
 124        enum hw_atl_fw2x_rate rate = 0;
 125
 126        if (speed & AQ_NIC_RATE_10G)
 127                rate |= FW2X_RATE_10G;
 128
 129        if (speed & AQ_NIC_RATE_5G)
 130                rate |= FW2X_RATE_5G;
 131
 132        if (speed & AQ_NIC_RATE_5GSR)
 133                rate |= FW2X_RATE_5G;
 134
 135        if (speed & AQ_NIC_RATE_2G5)
 136                rate |= FW2X_RATE_2G5;
 137
 138        if (speed & AQ_NIC_RATE_1G)
 139                rate |= FW2X_RATE_1G;
 140
 141        if (speed & AQ_NIC_RATE_100M)
 142                rate |= FW2X_RATE_100M;
 143
 144        return rate;
 145}
 146
 147static u32 fw2x_to_eee_mask(u32 speed)
 148{
 149        u32 rate = 0;
 150
 151        if (speed & HW_ATL_FW2X_CAP_EEE_10G_MASK)
 152                rate |= AQ_NIC_RATE_EEE_10G;
 153        if (speed & HW_ATL_FW2X_CAP_EEE_5G_MASK)
 154                rate |= AQ_NIC_RATE_EEE_5G;
 155        if (speed & HW_ATL_FW2X_CAP_EEE_2G5_MASK)
 156                rate |= AQ_NIC_RATE_EEE_2G5;
 157        if (speed & HW_ATL_FW2X_CAP_EEE_1G_MASK)
 158                rate |= AQ_NIC_RATE_EEE_1G;
 159
 160        return rate;
 161}
 162
 163static u32 eee_mask_to_fw2x(u32 speed)
 164{
 165        u32 rate = 0;
 166
 167        if (speed & AQ_NIC_RATE_EEE_10G)
 168                rate |= HW_ATL_FW2X_CAP_EEE_10G_MASK;
 169        if (speed & AQ_NIC_RATE_EEE_5G)
 170                rate |= HW_ATL_FW2X_CAP_EEE_5G_MASK;
 171        if (speed & AQ_NIC_RATE_EEE_2G5)
 172                rate |= HW_ATL_FW2X_CAP_EEE_2G5_MASK;
 173        if (speed & AQ_NIC_RATE_EEE_1G)
 174                rate |= HW_ATL_FW2X_CAP_EEE_1G_MASK;
 175
 176        return rate;
 177}
 178
 179static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed)
 180{
 181        u32 val = link_speed_mask_2fw2x_ratemask(speed);
 182
 183        aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL_ADDR, val);
 184
 185        return 0;
 186}
 187
 188static void aq_fw2x_upd_flow_control_bits(struct aq_hw_s *self,
 189                                          u32 *mpi_state, u32 fc)
 190{
 191        *mpi_state &= ~(HW_ATL_FW2X_CTRL_PAUSE |
 192                        HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE);
 193
 194        switch (fc) {
 195        /* There is not explicit mode of RX only pause frames,
 196         * thus, we join this mode with FC full.
 197         * FC full is either Rx, either Tx, or both.
 198         */
 199        case AQ_NIC_FC_FULL:
 200        case AQ_NIC_FC_RX:
 201                *mpi_state |= HW_ATL_FW2X_CTRL_PAUSE |
 202                              HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE;
 203                break;
 204        case AQ_NIC_FC_TX:
 205                *mpi_state |= HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE;
 206                break;
 207        }
 208}
 209
 210static void aq_fw2x_upd_eee_rate_bits(struct aq_hw_s *self, u32 *mpi_opts,
 211                                      u32 eee_speeds)
 212{
 213        *mpi_opts &= ~(HW_ATL_FW2X_CAP_EEE_1G_MASK |
 214                       HW_ATL_FW2X_CAP_EEE_2G5_MASK |
 215                       HW_ATL_FW2X_CAP_EEE_5G_MASK |
 216                       HW_ATL_FW2X_CAP_EEE_10G_MASK);
 217
 218        *mpi_opts |= eee_mask_to_fw2x(eee_speeds);
 219}
 220
 221static int aq_fw2x_set_state(struct aq_hw_s *self,
 222                             enum hal_atl_utils_fw_state_e state)
 223{
 224        u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
 225        struct aq_nic_cfg_s *cfg = self->aq_nic_cfg;
 226
 227        switch (state) {
 228        case MPI_INIT:
 229                mpi_state &= ~BIT(CAPS_HI_LINK_DROP);
 230                aq_fw2x_upd_eee_rate_bits(self, &mpi_state, cfg->eee_speeds);
 231                aq_fw2x_upd_flow_control_bits(self, &mpi_state,
 232                                              self->aq_nic_cfg->fc.req);
 233                break;
 234        case MPI_DEINIT:
 235                mpi_state |= BIT(CAPS_HI_LINK_DROP);
 236                break;
 237        case MPI_RESET:
 238        case MPI_POWER:
 239                /* No actions */
 240                break;
 241        }
 242        aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_state);
 243
 244        return 0;
 245}
 246
 247static int aq_fw2x_update_link_status(struct aq_hw_s *self)
 248{
 249        struct aq_hw_link_status_s *link_status = &self->aq_link_status;
 250        u32 mpi_state;
 251        u32 speed;
 252
 253        mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE_ADDR);
 254        speed = mpi_state & (FW2X_RATE_100M | FW2X_RATE_1G |
 255                             FW2X_RATE_2G5 | FW2X_RATE_5G |
 256                             FW2X_RATE_10G);
 257
 258        if (speed) {
 259                if (speed & FW2X_RATE_10G)
 260                        link_status->mbps = 10000;
 261                else if (speed & FW2X_RATE_5G)
 262                        link_status->mbps = 5000;
 263                else if (speed & FW2X_RATE_2G5)
 264                        link_status->mbps = 2500;
 265                else if (speed & FW2X_RATE_1G)
 266                        link_status->mbps = 1000;
 267                else if (speed & FW2X_RATE_100M)
 268                        link_status->mbps = 100;
 269                else
 270                        link_status->mbps = 10000;
 271        } else {
 272                link_status->mbps = 0;
 273        }
 274        link_status->full_duplex = true;
 275
 276        return 0;
 277}
 278
 279static int aq_fw2x_get_mac_permanent(struct aq_hw_s *self, u8 *mac)
 280{
 281        u32 efuse_addr = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_EFUSE_ADDR);
 282        u32 mac_addr[2] = { 0 };
 283        int err = 0;
 284
 285        if (efuse_addr != 0) {
 286                err = hw_atl_utils_fw_downld_dwords(self,
 287                                                    efuse_addr + (40U * 4U),
 288                                                    mac_addr,
 289                                                    ARRAY_SIZE(mac_addr));
 290                if (err)
 291                        return err;
 292                mac_addr[0] = __swab32(mac_addr[0]);
 293                mac_addr[1] = __swab32(mac_addr[1]);
 294        }
 295
 296        ether_addr_copy(mac, (u8 *)mac_addr);
 297
 298        return err;
 299}
 300
 301static int aq_fw2x_update_stats(struct aq_hw_s *self)
 302{
 303        u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
 304        u32 orig_stats_val = mpi_opts & BIT(CAPS_HI_STATISTICS);
 305        u32 stats_val;
 306        int err = 0;
 307
 308        /* Toggle statistics bit for FW to update */
 309        mpi_opts = mpi_opts ^ BIT(CAPS_HI_STATISTICS);
 310        aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
 311
 312        /* Wait FW to report back */
 313        err = readx_poll_timeout_atomic(aq_fw2x_state2_get,
 314                                        self, stats_val,
 315                                        orig_stats_val != (stats_val &
 316                                        BIT(CAPS_HI_STATISTICS)),
 317                                        1U, 10000U);
 318        if (err)
 319                return err;
 320
 321        return hw_atl_utils_update_stats(self);
 322}
 323
 324static int aq_fw2x_get_phy_temp(struct aq_hw_s *self, int *temp)
 325{
 326        u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
 327        u32 temp_val = mpi_opts & HW_ATL_FW2X_CTRL_TEMPERATURE;
 328        u32 phy_temp_offset;
 329        u32 temp_res;
 330        int err = 0;
 331        u32 val;
 332
 333        phy_temp_offset = self->mbox_addr + offsetof(struct hw_atl_utils_mbox,
 334                                                     info.phy_temperature);
 335
 336        /* Toggle statistics bit for FW to 0x36C.18 (CTRL_TEMPERATURE) */
 337        mpi_opts = mpi_opts ^ HW_ATL_FW2X_CTRL_TEMPERATURE;
 338        aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
 339        /* Wait FW to report back */
 340        err = readx_poll_timeout_atomic(aq_fw2x_state2_get, self, val,
 341                                        temp_val !=
 342                                        (val & HW_ATL_FW2X_CTRL_TEMPERATURE),
 343                                        1U, 10000U);
 344        err = hw_atl_utils_fw_downld_dwords(self, phy_temp_offset,
 345                                            &temp_res, 1);
 346
 347        if (err)
 348                return err;
 349
 350        /* Convert PHY temperature from 1/256 degree Celsius
 351         * to 1/1000 degree Celsius.
 352         */
 353        *temp = (int16_t)(temp_res & 0xFFFF) * 1000 / 256;
 354
 355        return 0;
 356}
 357
 358static int aq_fw2x_set_wol(struct aq_hw_s *self, u8 *mac)
 359{
 360        struct hw_atl_utils_fw_rpc *rpc = NULL;
 361        struct offload_info *info = NULL;
 362        u32 wol_bits = 0;
 363        u32 rpc_size;
 364        int err = 0;
 365        u32 val;
 366
 367        if (self->aq_nic_cfg->wol & WAKE_PHY) {
 368                aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR,
 369                                HW_ATL_FW2X_CTRL_LINK_DROP);
 370                readx_poll_timeout_atomic(aq_fw2x_state2_get, self, val,
 371                                          (val &
 372                                           HW_ATL_FW2X_CTRL_LINK_DROP) != 0,
 373                                          1000, 100000);
 374                wol_bits |= HW_ATL_FW2X_CTRL_WAKE_ON_LINK;
 375        }
 376
 377        if (self->aq_nic_cfg->wol & WAKE_MAGIC) {
 378                wol_bits |= HW_ATL_FW2X_CTRL_SLEEP_PROXY |
 379                            HW_ATL_FW2X_CTRL_WOL;
 380
 381                err = hw_atl_utils_fw_rpc_wait(self, &rpc);
 382                if (err < 0)
 383                        goto err_exit;
 384
 385                rpc_size = sizeof(*info) +
 386                           offsetof(struct hw_atl_utils_fw_rpc, fw2x_offloads);
 387                memset(rpc, 0, rpc_size);
 388                info = &rpc->fw2x_offloads;
 389                memcpy(info->mac_addr, mac, ETH_ALEN);
 390                info->len = sizeof(*info);
 391
 392                err = hw_atl_utils_fw_rpc_call(self, rpc_size);
 393                if (err < 0)
 394                        goto err_exit;
 395        }
 396
 397        aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, wol_bits);
 398
 399err_exit:
 400        return err;
 401}
 402
 403static int aq_fw2x_set_power(struct aq_hw_s *self, unsigned int power_state,
 404                             u8 *mac)
 405{
 406        int err = 0;
 407
 408        if (self->aq_nic_cfg->wol)
 409                err = aq_fw2x_set_wol(self, mac);
 410
 411        return err;
 412}
 413
 414static int aq_fw2x_send_fw_request(struct aq_hw_s *self,
 415                                   const struct hw_fw_request_iface *fw_req,
 416                                   size_t size)
 417{
 418        u32 ctrl2, orig_ctrl2;
 419        u32 dword_cnt;
 420        int err = 0;
 421        u32 val;
 422
 423        /* Write data to drvIface Mailbox */
 424        dword_cnt = size / sizeof(u32);
 425        if (size % sizeof(u32))
 426                dword_cnt++;
 427        err = hw_atl_write_fwcfg_dwords(self, (void *)fw_req, dword_cnt);
 428        if (err < 0)
 429                goto err_exit;
 430
 431        /* Toggle statistics bit for FW to update */
 432        ctrl2 = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
 433        orig_ctrl2 = ctrl2 & BIT(CAPS_HI_FW_REQUEST);
 434        ctrl2 = ctrl2 ^ BIT(CAPS_HI_FW_REQUEST);
 435        aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, ctrl2);
 436
 437        /* Wait FW to report back */
 438        err = readx_poll_timeout_atomic(aq_fw2x_state2_get, self, val,
 439                                        orig_ctrl2 != (val &
 440                                                       BIT(CAPS_HI_FW_REQUEST)),
 441                                        1U, 10000U);
 442
 443err_exit:
 444        return err;
 445}
 446
 447static void aq_fw3x_enable_ptp(struct aq_hw_s *self, int enable)
 448{
 449        u32 ptp_opts = aq_hw_read_reg(self, HW_ATL_FW3X_EXT_STATE_ADDR);
 450        u32 all_ptp_features = BIT(CAPS_EX_PHY_PTP_EN) |
 451                                                   BIT(CAPS_EX_PTP_GPIO_EN);
 452
 453        if (enable)
 454                ptp_opts |= all_ptp_features;
 455        else
 456                ptp_opts &= ~all_ptp_features;
 457
 458        aq_hw_write_reg(self, HW_ATL_FW3X_EXT_CONTROL_ADDR, ptp_opts);
 459}
 460
 461static void aq_fw3x_adjust_ptp(struct aq_hw_s *self, uint64_t adj)
 462{
 463        aq_hw_write_reg(self, HW_ATL_FW3X_PTP_ADJ_LSW_ADDR,
 464                        (adj >>  0) & 0xffffffff);
 465        aq_hw_write_reg(self, HW_ATL_FW3X_PTP_ADJ_MSW_ADDR,
 466                        (adj >> 32) & 0xffffffff);
 467}
 468
 469static int aq_fw2x_led_control(struct aq_hw_s *self, u32 mode)
 470{
 471        if (self->fw_ver_actual < HW_ATL_FW_VER_LED)
 472                return -EOPNOTSUPP;
 473
 474        aq_hw_write_reg(self, HW_ATL_FW2X_MPI_LED_ADDR, mode);
 475
 476        return 0;
 477}
 478
 479static int aq_fw2x_set_eee_rate(struct aq_hw_s *self, u32 speed)
 480{
 481        u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
 482
 483        aq_fw2x_upd_eee_rate_bits(self, &mpi_opts, speed);
 484
 485        aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
 486
 487        return 0;
 488}
 489
 490static int aq_fw2x_get_eee_rate(struct aq_hw_s *self, u32 *rate,
 491                                u32 *supported_rates)
 492{
 493        u32 mpi_state;
 494        u32 caps_hi;
 495        int err = 0;
 496        u32 offset;
 497
 498        offset = self->mbox_addr + offsetof(struct hw_atl_utils_mbox,
 499                                            info.caps_hi);
 500
 501        err = hw_atl_utils_fw_downld_dwords(self, offset, &caps_hi, 1);
 502
 503        if (err)
 504                return err;
 505
 506        *supported_rates = fw2x_to_eee_mask(caps_hi);
 507
 508        mpi_state = aq_fw2x_state2_get(self);
 509        *rate = fw2x_to_eee_mask(mpi_state);
 510
 511        return err;
 512}
 513
 514static int aq_fw2x_renegotiate(struct aq_hw_s *self)
 515{
 516        u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
 517
 518        mpi_opts |= BIT(CTRL_FORCE_RECONNECT);
 519
 520        aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
 521
 522        return 0;
 523}
 524
 525static int aq_fw2x_set_flow_control(struct aq_hw_s *self)
 526{
 527        u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
 528
 529        aq_fw2x_upd_flow_control_bits(self, &mpi_state,
 530                                      self->aq_nic_cfg->fc.req);
 531
 532        aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_state);
 533
 534        return 0;
 535}
 536
 537static u32 aq_fw2x_get_flow_control(struct aq_hw_s *self, u32 *fcmode)
 538{
 539        u32 mpi_state = aq_fw2x_state2_get(self);
 540        *fcmode = 0;
 541
 542        if (mpi_state & HW_ATL_FW2X_CAP_PAUSE)
 543                *fcmode |= AQ_NIC_FC_RX;
 544
 545        if (mpi_state & HW_ATL_FW2X_CAP_ASYM_PAUSE)
 546                *fcmode |= AQ_NIC_FC_TX;
 547
 548        return 0;
 549}
 550
 551static int aq_fw2x_set_phyloopback(struct aq_hw_s *self, u32 mode, bool enable)
 552{
 553        u32 mpi_opts;
 554
 555        switch (mode) {
 556        case AQ_HW_LOOPBACK_PHYINT_SYS:
 557                mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
 558                if (enable)
 559                        mpi_opts |= HW_ATL_FW2X_CTRL_INT_LOOPBACK;
 560                else
 561                        mpi_opts &= ~HW_ATL_FW2X_CTRL_INT_LOOPBACK;
 562                aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
 563                break;
 564        case AQ_HW_LOOPBACK_PHYEXT_SYS:
 565                mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
 566                if (enable)
 567                        mpi_opts |= HW_ATL_FW2X_CTRL_EXT_LOOPBACK;
 568                else
 569                        mpi_opts &= ~HW_ATL_FW2X_CTRL_EXT_LOOPBACK;
 570                aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
 571                break;
 572        default:
 573                return -EINVAL;
 574        }
 575
 576        return 0;
 577}
 578
 579static u32 aq_fw2x_mbox_get(struct aq_hw_s *self)
 580{
 581        return aq_hw_read_reg(self, HW_ATL_FW2X_MPI_MBOX_ADDR);
 582}
 583
 584static u32 aq_fw2x_rpc_get(struct aq_hw_s *self)
 585{
 586        return aq_hw_read_reg(self, HW_ATL_FW2X_MPI_RPC_ADDR);
 587}
 588
 589static int aq_fw2x_settings_get(struct aq_hw_s *self, u32 *addr)
 590{
 591        int err = 0;
 592        u32 offset;
 593
 594        offset = self->mbox_addr + offsetof(struct hw_atl_utils_mbox,
 595                                            info.setting_address);
 596
 597        err = hw_atl_utils_fw_downld_dwords(self, offset, addr, 1);
 598
 599        return err;
 600}
 601
 602static u32 aq_fw2x_state2_get(struct aq_hw_s *self)
 603{
 604        return aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR);
 605}
 606
 607const struct aq_fw_ops aq_fw_2x_ops = {
 608        .init               = aq_fw2x_init,
 609        .deinit             = aq_fw2x_deinit,
 610        .reset              = NULL,
 611        .renegotiate        = aq_fw2x_renegotiate,
 612        .get_mac_permanent  = aq_fw2x_get_mac_permanent,
 613        .set_link_speed     = aq_fw2x_set_link_speed,
 614        .set_state          = aq_fw2x_set_state,
 615        .update_link_status = aq_fw2x_update_link_status,
 616        .update_stats       = aq_fw2x_update_stats,
 617        .get_mac_temp       = NULL,
 618        .get_phy_temp       = aq_fw2x_get_phy_temp,
 619        .set_power          = aq_fw2x_set_power,
 620        .set_eee_rate       = aq_fw2x_set_eee_rate,
 621        .get_eee_rate       = aq_fw2x_get_eee_rate,
 622        .set_flow_control   = aq_fw2x_set_flow_control,
 623        .get_flow_control   = aq_fw2x_get_flow_control,
 624        .send_fw_request    = aq_fw2x_send_fw_request,
 625        .enable_ptp         = aq_fw3x_enable_ptp,
 626        .led_control        = aq_fw2x_led_control,
 627        .set_phyloopback    = aq_fw2x_set_phyloopback,
 628        .adjust_ptp         = aq_fw3x_adjust_ptp,
 629};
 630