dpdk/drivers/net/ice/base/ice_ptp_hw.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2001-2021 Intel Corporation
   3 */
   4
   5#include "ice_type.h"
   6#include "ice_common.h"
   7#include "ice_ptp_hw.h"
   8#include "ice_ptp_consts.h"
   9#include "ice_cgu_regs.h"
  10
  11/* Low level functions for interacting with and managing the device clock used
  12 * for the Precision Time Protocol.
  13 *
  14 * The ice hardware represents the current time using three registers:
  15 *
  16 *    GLTSYN_TIME_H     GLTSYN_TIME_L     GLTSYN_TIME_R
  17 *  +---------------+ +---------------+ +---------------+
  18 *  |    32 bits    | |    32 bits    | |    32 bits    |
  19 *  +---------------+ +---------------+ +---------------+
  20 *
  21 * The registers are incremented every clock tick using a 40bit increment
  22 * value defined over two registers:
  23 *
  24 *                     GLTSYN_INCVAL_H   GLTSYN_INCVAL_L
  25 *                    +---------------+ +---------------+
  26 *                    |    8 bit s    | |    32 bits    |
  27 *                    +---------------+ +---------------+
  28 *
  29 * The increment value is added to the GLSTYN_TIME_R and GLSTYN_TIME_L
  30 * registers every clock source tick. Depending on the specific device
  31 * configuration, the clock source frequency could be one of a number of
  32 * values.
  33 *
  34 * For E810 devices, the increment frequency is 812.5 MHz
  35 *
  36 * For E822 devices the clock can be derived from different sources, and the
  37 * increment has an effective frequency of one of the following:
  38 * - 823.4375 MHz
  39 * - 783.36 MHz
  40 * - 796.875 MHz
  41 * - 816 MHz
  42 * - 830.078125 MHz
  43 * - 783.36 MHz
  44 *
  45 * The hardware captures timestamps in the PHY for incoming packets, and for
  46 * outgoing packets on request. To support this, the PHY maintains a timer
  47 * that matches the lower 64 bits of the global source timer.
  48 *
  49 * In order to ensure that the PHY timers and the source timer are equivalent,
  50 * shadow registers are used to prepare the desired initial values. A special
  51 * sync command is issued to trigger copying from the shadow registers into
  52 * the appropriate source and PHY registers simultaneously.
  53 *
  54 * The driver supports devices which have different PHYs with subtly different
  55 * mechanisms to program and control the timers. We divide the devices into
  56 * families named after the first major device, E810 and similar devices, and
  57 * E822 and similar devices.
  58 *
  59 * - E822 based devices have additional support for fine grained Vernier
  60 *   calibration which requires significant setup
  61 * - The layout of timestamp data in the PHY register blocks is different
  62 * - The way timer synchronization commands are issued is different.
  63 *
  64 * To support this, very low level functions have an e810 or e822 suffix
  65 * indicating what type of device they work on. Higher level abstractions for
  66 * tasks that can be done on both devices do not have the suffix and will
  67 * correctly look up the appropriate low level function when running.
  68 *
  69 * Functions which only make sense on a single device family may not have
  70 * a suitable generic implementation
  71 */
  72
  73/**
  74 * ice_get_ptp_src_clock_index - determine source clock index
  75 * @hw: pointer to HW struct
  76 *
  77 * Determine the source clock index currently in use, based on device
  78 * capabilities reported during initialization.
  79 */
  80u8 ice_get_ptp_src_clock_index(struct ice_hw *hw)
  81{
  82        return hw->func_caps.ts_func_info.tmr_index_assoc;
  83}
  84
  85/**
  86 * ice_ptp_read_src_incval - Read source timer increment value
  87 * @hw: pointer to HW struct
  88 *
  89 * Read the increment value of the source timer and return it.
  90 */
  91u64 ice_ptp_read_src_incval(struct ice_hw *hw)
  92{
  93        u32 lo, hi;
  94        u8 tmr_idx;
  95
  96        tmr_idx = ice_get_ptp_src_clock_index(hw);
  97
  98        lo = rd32(hw, GLTSYN_INCVAL_L(tmr_idx));
  99        hi = rd32(hw, GLTSYN_INCVAL_H(tmr_idx));
 100
 101        return ((u64)(hi & INCVAL_HIGH_M) << 32) | lo;
 102}
 103
 104/**
 105 * ice_ptp_exec_tmr_cmd - Execute all prepared timer commands
 106 * @hw: pointer to HW struct
 107 *
 108 * Write the SYNC_EXEC_CMD bit to the GLTSYN_CMD_SYNC register, and flush the
 109 * write immediately. This triggers the hardware to begin executing all of the
 110 * source and PHY timer commands synchronously.
 111 */
 112static void ice_ptp_exec_tmr_cmd(struct ice_hw *hw)
 113{
 114        wr32(hw, GLTSYN_CMD_SYNC, SYNC_EXEC_CMD);
 115        ice_flush(hw);
 116}
 117
 118/* E822 family functions
 119 *
 120 * The following functions operate on the E822 family of devices.
 121 */
 122
 123/**
 124 * ice_fill_phy_msg_e822 - Fill message data for a PHY register access
 125 * @msg: the PHY message buffer to fill in
 126 * @port: the port to access
 127 * @offset: the register offset
 128 */
 129static void
 130ice_fill_phy_msg_e822(struct ice_sbq_msg_input *msg, u8 port, u16 offset)
 131{
 132        int phy_port, phy, quadtype;
 133
 134        phy_port = port % ICE_PORTS_PER_PHY;
 135        phy = port / ICE_PORTS_PER_PHY;
 136        quadtype = (port / ICE_PORTS_PER_QUAD) % ICE_NUM_QUAD_TYPE;
 137
 138        if (quadtype == 0) {
 139                msg->msg_addr_low = P_Q0_L(P_0_BASE + offset, phy_port);
 140                msg->msg_addr_high = P_Q0_H(P_0_BASE + offset, phy_port);
 141        } else {
 142                msg->msg_addr_low = P_Q1_L(P_4_BASE + offset, phy_port);
 143                msg->msg_addr_high = P_Q1_H(P_4_BASE + offset, phy_port);
 144        }
 145
 146        if (phy == 0)
 147                msg->dest_dev = rmn_0;
 148        else if (phy == 1)
 149                msg->dest_dev = rmn_1;
 150        else
 151                msg->dest_dev = rmn_2;
 152}
 153
 154/**
 155 * ice_is_64b_phy_reg_e822 - Check if this is a 64bit PHY register
 156 * @low_addr: the low address to check
 157 * @high_addr: on return, contains the high address of the 64bit register
 158 *
 159 * Checks if the provided low address is one of the known 64bit PHY values
 160 * represented as two 32bit registers. If it is, return the appropriate high
 161 * register offset to use.
 162 */
 163static bool ice_is_64b_phy_reg_e822(u16 low_addr, u16 *high_addr)
 164{
 165        switch (low_addr) {
 166        case P_REG_PAR_PCS_TX_OFFSET_L:
 167                *high_addr = P_REG_PAR_PCS_TX_OFFSET_U;
 168                return true;
 169        case P_REG_PAR_PCS_RX_OFFSET_L:
 170                *high_addr = P_REG_PAR_PCS_RX_OFFSET_U;
 171                return true;
 172        case P_REG_PAR_TX_TIME_L:
 173                *high_addr = P_REG_PAR_TX_TIME_U;
 174                return true;
 175        case P_REG_PAR_RX_TIME_L:
 176                *high_addr = P_REG_PAR_RX_TIME_U;
 177                return true;
 178        case P_REG_TOTAL_TX_OFFSET_L:
 179                *high_addr = P_REG_TOTAL_TX_OFFSET_U;
 180                return true;
 181        case P_REG_TOTAL_RX_OFFSET_L:
 182                *high_addr = P_REG_TOTAL_RX_OFFSET_U;
 183                return true;
 184        case P_REG_UIX66_10G_40G_L:
 185                *high_addr = P_REG_UIX66_10G_40G_U;
 186                return true;
 187        case P_REG_UIX66_25G_100G_L:
 188                *high_addr = P_REG_UIX66_25G_100G_U;
 189                return true;
 190        case P_REG_TX_CAPTURE_L:
 191                *high_addr = P_REG_TX_CAPTURE_U;
 192                return true;
 193        case P_REG_RX_CAPTURE_L:
 194                *high_addr = P_REG_RX_CAPTURE_U;
 195                return true;
 196        case P_REG_TX_TIMER_INC_PRE_L:
 197                *high_addr = P_REG_TX_TIMER_INC_PRE_U;
 198                return true;
 199        case P_REG_RX_TIMER_INC_PRE_L:
 200                *high_addr = P_REG_RX_TIMER_INC_PRE_U;
 201                return true;
 202        default:
 203                return false;
 204        }
 205}
 206
 207/**
 208 * ice_is_40b_phy_reg_e822 - Check if this is a 40bit PHY register
 209 * @low_addr: the low address to check
 210 * @high_addr: on return, contains the high address of the 40bit value
 211 *
 212 * Checks if the provided low address is one of the known 40bit PHY values
 213 * split into two registers with the lower 8 bits in the low register and the
 214 * upper 32 bits in the high register. If it is, return the appropriate high
 215 * register offset to use.
 216 */
 217static bool ice_is_40b_phy_reg_e822(u16 low_addr, u16 *high_addr)
 218{
 219        switch (low_addr) {
 220        case P_REG_TIMETUS_L:
 221                *high_addr = P_REG_TIMETUS_U;
 222                return true;
 223        case P_REG_PAR_RX_TUS_L:
 224                *high_addr = P_REG_PAR_RX_TUS_U;
 225                return true;
 226        case P_REG_PAR_TX_TUS_L:
 227                *high_addr = P_REG_PAR_TX_TUS_U;
 228                return true;
 229        case P_REG_PCS_RX_TUS_L:
 230                *high_addr = P_REG_PCS_RX_TUS_U;
 231                return true;
 232        case P_REG_PCS_TX_TUS_L:
 233                *high_addr = P_REG_PCS_TX_TUS_U;
 234                return true;
 235        case P_REG_DESK_PAR_RX_TUS_L:
 236                *high_addr = P_REG_DESK_PAR_RX_TUS_U;
 237                return true;
 238        case P_REG_DESK_PAR_TX_TUS_L:
 239                *high_addr = P_REG_DESK_PAR_TX_TUS_U;
 240                return true;
 241        case P_REG_DESK_PCS_RX_TUS_L:
 242                *high_addr = P_REG_DESK_PCS_RX_TUS_U;
 243                return true;
 244        case P_REG_DESK_PCS_TX_TUS_L:
 245                *high_addr = P_REG_DESK_PCS_TX_TUS_U;
 246                return true;
 247        default:
 248                return false;
 249        }
 250}
 251
 252/**
 253 * ice_read_phy_reg_e822_lp - Read a PHY register
 254 * @hw: pointer to the HW struct
 255 * @port: PHY port to read from
 256 * @offset: PHY register offset to read
 257 * @val: on return, the contents read from the PHY
 258 * @lock_sbq: true if the sideband queue lock must be acquired
 259 *
 260 * Read a PHY register for the given port over the device sideband queue.
 261 */
 262static enum ice_status
 263ice_read_phy_reg_e822_lp(struct ice_hw *hw, u8 port, u16 offset, u32 *val,
 264                         bool lock_sbq)
 265{
 266        struct ice_sbq_msg_input msg = {0};
 267        enum ice_status status;
 268
 269        ice_fill_phy_msg_e822(&msg, port, offset);
 270        msg.opcode = ice_sbq_msg_rd;
 271
 272        status = ice_sbq_rw_reg_lp(hw, &msg, lock_sbq);
 273        if (status) {
 274                ice_debug(hw, ICE_DBG_PTP, "Failed to send message to phy, status %d\n",
 275                          status);
 276                return status;
 277        }
 278
 279        *val = msg.data;
 280
 281        return ICE_SUCCESS;
 282}
 283
 284enum ice_status
 285ice_read_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 *val)
 286{
 287        return ice_read_phy_reg_e822_lp(hw, port, offset, val, true);
 288}
 289
 290/**
 291 * ice_read_40b_phy_reg_e822 - Read a 40bit value from PHY registers
 292 * @hw: pointer to the HW struct
 293 * @port: PHY port to read from
 294 * @low_addr: offset of the lower register to read from
 295 * @val: on return, the contents of the 40bit value from the PHY registers
 296 *
 297 * Reads the two registers associated with a 40bit value and returns it in the
 298 * val pointer. The offset always specifies the lower register offset to use.
 299 * The high offset is looked up. This function only operates on registers
 300 * known to be split into a lower 8 bit chunk and an upper 32 bit chunk.
 301 */
 302static enum ice_status
 303ice_read_40b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 *val)
 304{
 305        enum ice_status status;
 306        u32 low, high;
 307        u16 high_addr;
 308
 309        /* Only operate on registers known to be split into two 32bit
 310         * registers.
 311         */
 312        if (!ice_is_40b_phy_reg_e822(low_addr, &high_addr)) {
 313                ice_debug(hw, ICE_DBG_PTP, "Invalid 64b register addr 0x%08x\n",
 314                          low_addr);
 315                return ICE_ERR_PARAM;
 316        }
 317
 318        status = ice_read_phy_reg_e822(hw, port, low_addr, &low);
 319        if (status) {
 320                ice_debug(hw, ICE_DBG_PTP, "Failed to read from low register 0x%08x\n, status %d",
 321                          low_addr, status);
 322                return status;
 323        }
 324
 325        status = ice_read_phy_reg_e822(hw, port, high_addr, &high);
 326        if (status) {
 327                ice_debug(hw, ICE_DBG_PTP, "Failed to read from high register 0x%08x\n, status %d",
 328                          high_addr, status);
 329                return status;
 330        }
 331
 332        *val = (u64)high << P_REG_40B_HIGH_S | (low & P_REG_40B_LOW_M);
 333
 334        return ICE_SUCCESS;
 335}
 336
 337/**
 338 * ice_read_64b_phy_reg_e822 - Read a 64bit value from PHY registers
 339 * @hw: pointer to the HW struct
 340 * @port: PHY port to read from
 341 * @low_addr: offset of the lower register to read from
 342 * @val: on return, the contents of the 64bit value from the PHY registers
 343 *
 344 * Reads the two registers associated with a 64bit value and returns it in the
 345 * val pointer. The offset always specifies the lower register offset to use.
 346 * The high offset is looked up. This function only operates on registers
 347 * known to be two parts of a 64bit value.
 348 */
 349static enum ice_status
 350ice_read_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 *val)
 351{
 352        enum ice_status status;
 353        u32 low, high;
 354        u16 high_addr;
 355
 356        /* Only operate on registers known to be split into two 32bit
 357         * registers.
 358         */
 359        if (!ice_is_64b_phy_reg_e822(low_addr, &high_addr)) {
 360                ice_debug(hw, ICE_DBG_PTP, "Invalid 64b register addr 0x%08x\n",
 361                          low_addr);
 362                return ICE_ERR_PARAM;
 363        }
 364
 365        status = ice_read_phy_reg_e822(hw, port, low_addr, &low);
 366        if (status) {
 367                ice_debug(hw, ICE_DBG_PTP, "Failed to read from low register 0x%08x\n, status %d",
 368                          low_addr, status);
 369                return status;
 370        }
 371
 372        status = ice_read_phy_reg_e822(hw, port, high_addr, &high);
 373        if (status) {
 374                ice_debug(hw, ICE_DBG_PTP, "Failed to read from high register 0x%08x\n, status %d",
 375                          high_addr, status);
 376                return status;
 377        }
 378
 379        *val = (u64)high << 32 | low;
 380
 381        return ICE_SUCCESS;
 382}
 383
 384/**
 385 * ice_write_phy_reg_e822_lp - Write a PHY register
 386 * @hw: pointer to the HW struct
 387 * @port: PHY port to write to
 388 * @offset: PHY register offset to write
 389 * @val: The value to write to the register
 390 * @lock_sbq: true if the sideband queue lock must be acquired
 391 *
 392 * Write a PHY register for the given port over the device sideband queue.
 393 */
 394static enum ice_status
 395ice_write_phy_reg_e822_lp(struct ice_hw *hw, u8 port, u16 offset, u32 val,
 396                          bool lock_sbq)
 397{
 398        struct ice_sbq_msg_input msg = {0};
 399        enum ice_status status;
 400
 401        ice_fill_phy_msg_e822(&msg, port, offset);
 402        msg.opcode = ice_sbq_msg_wr;
 403        msg.data = val;
 404
 405        status = ice_sbq_rw_reg_lp(hw, &msg, lock_sbq);
 406        if (status) {
 407                ice_debug(hw, ICE_DBG_PTP, "Failed to send message to phy, status %d\n",
 408                          status);
 409                return status;
 410        }
 411
 412        return ICE_SUCCESS;
 413}
 414
 415enum ice_status
 416ice_write_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 val)
 417{
 418        return ice_write_phy_reg_e822_lp(hw, port, offset, val, true);
 419}
 420
 421/**
 422 * ice_write_40b_phy_reg_e822 - Write a 40b value to the PHY
 423 * @hw: pointer to the HW struct
 424 * @port: port to write to
 425 * @low_addr: offset of the low register
 426 * @val: 40b value to write
 427 *
 428 * Write the provided 40b value to the two associated registers by splitting
 429 * it up into two chunks, the lower 8 bits and the upper 32 bits.
 430 */
 431static enum ice_status
 432ice_write_40b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val)
 433{
 434        enum ice_status status;
 435        u32 low, high;
 436        u16 high_addr;
 437
 438        /* Only operate on registers known to be split into a lower 8 bit
 439         * register and an upper 32 bit register.
 440         */
 441        if (!ice_is_40b_phy_reg_e822(low_addr, &high_addr)) {
 442                ice_debug(hw, ICE_DBG_PTP, "Invalid 40b register addr 0x%08x\n",
 443                          low_addr);
 444                return ICE_ERR_PARAM;
 445        }
 446
 447        low = (u32)(val & P_REG_40B_LOW_M);
 448        high = (u32)(val >> P_REG_40B_HIGH_S);
 449
 450        status = ice_write_phy_reg_e822(hw, port, low_addr, low);
 451        if (status) {
 452                ice_debug(hw, ICE_DBG_PTP, "Failed to write to low register 0x%08x\n, status %d",
 453                          low_addr, status);
 454                return status;
 455        }
 456
 457        status = ice_write_phy_reg_e822(hw, port, high_addr, high);
 458        if (status) {
 459                ice_debug(hw, ICE_DBG_PTP, "Failed to write to high register 0x%08x\n, status %d",
 460                          high_addr, status);
 461                return status;
 462        }
 463
 464        return ICE_SUCCESS;
 465}
 466
 467/**
 468 * ice_write_64b_phy_reg_e822 - Write a 64bit value to PHY registers
 469 * @hw: pointer to the HW struct
 470 * @port: PHY port to read from
 471 * @low_addr: offset of the lower register to read from
 472 * @val: the contents of the 64bit value to write to PHY
 473 *
 474 * Write the 64bit value to the two associated 32bit PHY registers. The offset
 475 * is always specified as the lower register, and the high address is looked
 476 * up. This function only operates on registers known to be two parts of
 477 * a 64bit value.
 478 */
 479static enum ice_status
 480ice_write_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val)
 481{
 482        enum ice_status status;
 483        u32 low, high;
 484        u16 high_addr;
 485
 486        /* Only operate on registers known to be split into two 32bit
 487         * registers.
 488         */
 489        if (!ice_is_64b_phy_reg_e822(low_addr, &high_addr)) {
 490                ice_debug(hw, ICE_DBG_PTP, "Invalid 64b register addr 0x%08x\n",
 491                          low_addr);
 492                return ICE_ERR_PARAM;
 493        }
 494
 495        low = ICE_LO_DWORD(val);
 496        high = ICE_HI_DWORD(val);
 497
 498        status = ice_write_phy_reg_e822(hw, port, low_addr, low);
 499        if (status) {
 500                ice_debug(hw, ICE_DBG_PTP, "Failed to write to low register 0x%08x\n, status %d",
 501                          low_addr, status);
 502                return status;
 503        }
 504
 505        status = ice_write_phy_reg_e822(hw, port, high_addr, high);
 506        if (status) {
 507                ice_debug(hw, ICE_DBG_PTP, "Failed to write to high register 0x%08x\n, status %d",
 508                          high_addr, status);
 509                return status;
 510        }
 511
 512        return ICE_SUCCESS;
 513}
 514
 515/**
 516 * ice_fill_quad_msg_e822 - Fill message data for quad register access
 517 * @msg: the PHY message buffer to fill in
 518 * @quad: the quad to access
 519 * @offset: the register offset
 520 *
 521 * Fill a message buffer for accessing a register in a quad shared between
 522 * multiple PHYs.
 523 */
 524static void
 525ice_fill_quad_msg_e822(struct ice_sbq_msg_input *msg, u8 quad, u16 offset)
 526{
 527        u32 addr;
 528
 529        msg->dest_dev = rmn_0;
 530
 531        if ((quad % ICE_NUM_QUAD_TYPE) == 0)
 532                addr = Q_0_BASE + offset;
 533        else
 534                addr = Q_1_BASE + offset;
 535
 536        msg->msg_addr_low = ICE_LO_WORD(addr);
 537        msg->msg_addr_high = ICE_HI_WORD(addr);
 538}
 539
 540/**
 541 * ice_read_quad_reg_e822_lp - Read a PHY quad register
 542 * @hw: pointer to the HW struct
 543 * @quad: quad to read from
 544 * @offset: quad register offset to read
 545 * @val: on return, the contents read from the quad
 546 * @lock_sbq: true if the sideband queue lock must be acquired
 547 *
 548 * Read a quad register over the device sideband queue. Quad registers are
 549 * shared between multiple PHYs.
 550 */
 551static enum ice_status
 552ice_read_quad_reg_e822_lp(struct ice_hw *hw, u8 quad, u16 offset, u32 *val,
 553                          bool lock_sbq)
 554{
 555        struct ice_sbq_msg_input msg = {0};
 556        enum ice_status status;
 557
 558        if (quad >= ICE_MAX_QUAD)
 559                return ICE_ERR_PARAM;
 560
 561        ice_fill_quad_msg_e822(&msg, quad, offset);
 562        msg.opcode = ice_sbq_msg_rd;
 563
 564        status = ice_sbq_rw_reg_lp(hw, &msg, lock_sbq);
 565        if (status) {
 566                ice_debug(hw, ICE_DBG_PTP, "Failed to send message to phy, status %d\n",
 567                          status);
 568                return status;
 569        }
 570
 571        *val = msg.data;
 572
 573        return ICE_SUCCESS;
 574}
 575
 576enum ice_status
 577ice_read_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 *val)
 578{
 579        return ice_read_quad_reg_e822_lp(hw, quad, offset, val, true);
 580}
 581
 582/**
 583 * ice_write_quad_reg_e822_lp - Write a PHY quad register
 584 * @hw: pointer to the HW struct
 585 * @quad: quad to write to
 586 * @offset: quad register offset to write
 587 * @val: The value to write to the register
 588 * @lock_sbq: true if the sideband queue lock must be acquired
 589 *
 590 * Write a quad register over the device sideband queue. Quad registers are
 591 * shared between multiple PHYs.
 592 */
 593static enum ice_status
 594ice_write_quad_reg_e822_lp(struct ice_hw *hw, u8 quad, u16 offset, u32 val,
 595                           bool lock_sbq)
 596{
 597        struct ice_sbq_msg_input msg = {0};
 598        enum ice_status status;
 599
 600        if (quad >= ICE_MAX_QUAD)
 601                return ICE_ERR_PARAM;
 602
 603        ice_fill_quad_msg_e822(&msg, quad, offset);
 604        msg.opcode = ice_sbq_msg_wr;
 605        msg.data = val;
 606
 607        status = ice_sbq_rw_reg_lp(hw, &msg, lock_sbq);
 608        if (status) {
 609                ice_debug(hw, ICE_DBG_PTP, "Failed to send message to phy, status %d\n",
 610                          status);
 611                return status;
 612        }
 613
 614        return ICE_SUCCESS;
 615}
 616
 617enum ice_status
 618ice_write_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 val)
 619{
 620        return ice_write_quad_reg_e822_lp(hw, quad, offset, val, true);
 621}
 622
 623/**
 624 * ice_read_phy_tstamp_e822 - Read a PHY timestamp out of the quad block
 625 * @hw: pointer to the HW struct
 626 * @quad: the quad to read from
 627 * @idx: the timestamp index to read
 628 * @tstamp: on return, the 40bit timestamp value
 629 *
 630 * Read a 40bit timestamp value out of the two associated registers in the
 631 * quad memory block that is shared between the internal PHYs of the E822
 632 * family of devices.
 633 */
 634static enum ice_status
 635ice_read_phy_tstamp_e822(struct ice_hw *hw, u8 quad, u8 idx, u64 *tstamp)
 636{
 637        enum ice_status status;
 638        u16 lo_addr, hi_addr;
 639        u32 lo, hi;
 640
 641        lo_addr = (u16)TS_L(Q_REG_TX_MEMORY_BANK_START, idx);
 642        hi_addr = (u16)TS_H(Q_REG_TX_MEMORY_BANK_START, idx);
 643
 644        status = ice_read_quad_reg_e822(hw, quad, lo_addr, &lo);
 645        if (status) {
 646                ice_debug(hw, ICE_DBG_PTP, "Failed to read low PTP timestamp register, status %d\n",
 647                          status);
 648                return status;
 649        }
 650
 651        status = ice_read_quad_reg_e822(hw, quad, hi_addr, &hi);
 652        if (status) {
 653                ice_debug(hw, ICE_DBG_PTP, "Failed to read high PTP timestamp register, status %d\n",
 654                          status);
 655                return status;
 656        }
 657
 658        /* For E822 based internal PHYs, the timestamp is reported with the
 659         * lower 8 bits in the low register, and the upper 32 bits in the high
 660         * register.
 661         */
 662        *tstamp = ((u64)hi) << TS_PHY_HIGH_S | ((u64)lo & TS_PHY_LOW_M);
 663
 664        return ICE_SUCCESS;
 665}
 666
 667/**
 668 * ice_clear_phy_tstamp_e822 - Clear a timestamp from the quad block
 669 * @hw: pointer to the HW struct
 670 * @quad: the quad to read from
 671 * @idx: the timestamp index to reset
 672 *
 673 * Clear a timestamp, resetting its valid bit, from the PHY quad block that is
 674 * shared between the internal PHYs on the E822 devices.
 675 */
 676static enum ice_status
 677ice_clear_phy_tstamp_e822(struct ice_hw *hw, u8 quad, u8 idx)
 678{
 679        enum ice_status status;
 680        u16 lo_addr, hi_addr;
 681
 682        lo_addr = (u16)TS_L(Q_REG_TX_MEMORY_BANK_START, idx);
 683        hi_addr = (u16)TS_H(Q_REG_TX_MEMORY_BANK_START, idx);
 684
 685        status = ice_write_quad_reg_e822(hw, quad, lo_addr, 0);
 686        if (status) {
 687                ice_debug(hw, ICE_DBG_PTP, "Failed to clear low PTP timestamp register, status %d\n",
 688                          status);
 689                return status;
 690        }
 691
 692        status = ice_write_quad_reg_e822(hw, quad, hi_addr, 0);
 693        if (status) {
 694                ice_debug(hw, ICE_DBG_PTP, "Failed to clear high PTP timestamp register, status %d\n",
 695                          status);
 696                return status;
 697        }
 698
 699        return ICE_SUCCESS;
 700}
 701
 702/**
 703 * ice_read_cgu_reg_e822 - Read a CGU register
 704 * @hw: pointer to the HW struct
 705 * @addr: Register address to read
 706 * @val: storage for register value read
 707 *
 708 * Read the contents of a register of the Clock Generation Unit. Only
 709 * applicable to E822 devices.
 710 */
 711static enum ice_status
 712ice_read_cgu_reg_e822(struct ice_hw *hw, u16 addr, u32 *val)
 713{
 714        struct ice_sbq_msg_input cgu_msg;
 715        enum ice_status status;
 716
 717        cgu_msg.opcode = ice_sbq_msg_rd;
 718        cgu_msg.dest_dev = cgu;
 719        cgu_msg.msg_addr_low = addr;
 720        cgu_msg.msg_addr_high = 0x0;
 721
 722        status = ice_sbq_rw_reg_lp(hw, &cgu_msg, true);
 723        if (status) {
 724                ice_debug(hw, ICE_DBG_PTP, "Failed to read CGU register 0x%04x, status %d\n",
 725                          addr, status);
 726                return status;
 727        }
 728
 729        *val = cgu_msg.data;
 730
 731        return status;
 732}
 733
 734/**
 735 * ice_write_cgu_reg_e822 - Write a CGU register
 736 * @hw: pointer to the HW struct
 737 * @addr: Register address to write
 738 * @val: value to write into the register
 739 *
 740 * Write the specified value to a register of the Clock Generation Unit. Only
 741 * applicable to E822 devices.
 742 */
 743static enum ice_status
 744ice_write_cgu_reg_e822(struct ice_hw *hw, u16 addr, u32 val)
 745{
 746        struct ice_sbq_msg_input cgu_msg;
 747        enum ice_status status;
 748
 749        cgu_msg.opcode = ice_sbq_msg_wr;
 750        cgu_msg.dest_dev = cgu;
 751        cgu_msg.msg_addr_low = addr;
 752        cgu_msg.msg_addr_high = 0x0;
 753        cgu_msg.data = val;
 754
 755        status = ice_sbq_rw_reg_lp(hw, &cgu_msg, true);
 756        if (status) {
 757                ice_debug(hw, ICE_DBG_PTP, "Failed to write CGU register 0x%04x, status %d\n",
 758                          addr, status);
 759                return status;
 760        }
 761
 762        return status;
 763}
 764
 765/**
 766 * ice_clk_freq_str - Convert time_ref_freq to string
 767 * @clk_freq: Clock frequency
 768 *
 769 * Convert the specified TIME_REF clock frequency to a string.
 770 */
 771static const char *ice_clk_freq_str(u8 clk_freq)
 772{
 773        switch ((enum ice_time_ref_freq)clk_freq) {
 774        case ICE_TIME_REF_FREQ_25_000:
 775                return "25 MHz";
 776        case ICE_TIME_REF_FREQ_122_880:
 777                return "122.88 MHz";
 778        case ICE_TIME_REF_FREQ_125_000:
 779                return "125 MHz";
 780        case ICE_TIME_REF_FREQ_153_600:
 781                return "153.6 MHz";
 782        case ICE_TIME_REF_FREQ_156_250:
 783                return "156.25 MHz";
 784        case ICE_TIME_REF_FREQ_245_760:
 785                return "245.76 MHz";
 786        default:
 787                return "Unknown";
 788        }
 789}
 790
 791/**
 792 * ice_clk_src_str - Convert time_ref_src to string
 793 * @clk_src: Clock source
 794 *
 795 * Convert the specified clock source to its string name.
 796 */
 797static const char *ice_clk_src_str(u8 clk_src)
 798{
 799        switch ((enum ice_clk_src)clk_src) {
 800        case ICE_CLK_SRC_TCX0:
 801                return "TCX0";
 802        case ICE_CLK_SRC_TIME_REF:
 803                return "TIME_REF";
 804        default:
 805                return "Unknown";
 806        }
 807}
 808
 809/**
 810 * ice_cfg_cgu_pll_e822 - Configure the Clock Generation Unit
 811 * @hw: pointer to the HW struct
 812 * @clk_freq: Clock frequency to program
 813 * @clk_src: Clock source to select (TIME_REF, or TCX0)
 814 *
 815 * Configure the Clock Generation Unit with the desired clock frequency and
 816 * time reference, enabling the PLL which drives the PTP hardware clock.
 817 */
 818enum ice_status
 819ice_cfg_cgu_pll_e822(struct ice_hw *hw, enum ice_time_ref_freq clk_freq,
 820                     enum ice_clk_src clk_src)
 821{
 822        union tspll_ro_bwm_lf bwm_lf;
 823        union nac_cgu_dword19 dw19;
 824        union nac_cgu_dword22 dw22;
 825        union nac_cgu_dword24 dw24;
 826        union nac_cgu_dword9 dw9;
 827        enum ice_status status;
 828
 829        if (clk_freq >= NUM_ICE_TIME_REF_FREQ) {
 830                ice_warn(hw, "Invalid TIME_REF frequency %u\n", clk_freq);
 831                return ICE_ERR_PARAM;
 832        }
 833
 834        if (clk_src >= NUM_ICE_CLK_SRC) {
 835                ice_warn(hw, "Invalid clock source %u\n", clk_src);
 836                return ICE_ERR_PARAM;
 837        }
 838
 839        if (clk_src == ICE_CLK_SRC_TCX0 &&
 840            clk_freq != ICE_TIME_REF_FREQ_25_000) {
 841                ice_warn(hw, "TCX0 only supports 25 MHz frequency\n");
 842                return ICE_ERR_PARAM;
 843        }
 844
 845        status = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD9, &dw9.val);
 846        if (status)
 847                return status;
 848
 849        status = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD24, &dw24.val);
 850        if (status)
 851                return status;
 852
 853        status = ice_read_cgu_reg_e822(hw, TSPLL_RO_BWM_LF, &bwm_lf.val);
 854        if (status)
 855                return status;
 856
 857        /* Log the current clock configuration */
 858        ice_debug(hw, ICE_DBG_PTP, "Current CGU configuration -- %s, clk_src %s, clk_freq %s, PLL %s\n",
 859                  dw24.field.ts_pll_enable ? "enabled" : "disabled",
 860                  ice_clk_src_str(dw24.field.time_ref_sel),
 861                  ice_clk_freq_str(dw9.field.time_ref_freq_sel),
 862                  bwm_lf.field.plllock_true_lock_cri ? "locked" : "unlocked");
 863
 864        /* Disable the PLL before changing the clock source or frequency */
 865        if (dw24.field.ts_pll_enable) {
 866                dw24.field.ts_pll_enable = 0;
 867
 868                status = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD24, dw24.val);
 869                if (status)
 870                        return status;
 871        }
 872
 873        /* Set the frequency */
 874        dw9.field.time_ref_freq_sel = clk_freq;
 875        status = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD9, dw9.val);
 876        if (status)
 877                return status;
 878
 879        /* Configure the TS PLL feedback divisor */
 880        status = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD19, &dw19.val);
 881        if (status)
 882                return status;
 883
 884        dw19.field.tspll_fbdiv_intgr = e822_cgu_params[clk_freq].feedback_div;
 885        dw19.field.tspll_ndivratio = 1;
 886
 887        status = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD19, dw19.val);
 888        if (status)
 889                return status;
 890
 891        /* Configure the TS PLL post divisor */
 892        status = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD22, &dw22.val);
 893        if (status)
 894                return status;
 895
 896        dw22.field.time1588clk_div = e822_cgu_params[clk_freq].post_pll_div;
 897        dw22.field.time1588clk_sel_div2 = 0;
 898
 899        status = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD22, dw22.val);
 900        if (status)
 901                return status;
 902
 903        /* Configure the TS PLL pre divisor and clock source */
 904        status = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD24, &dw24.val);
 905        if (status)
 906                return status;
 907
 908        dw24.field.ref1588_ck_div = e822_cgu_params[clk_freq].refclk_pre_div;
 909        dw24.field.tspll_fbdiv_frac = e822_cgu_params[clk_freq].frac_n_div;
 910        dw24.field.time_ref_sel = clk_src;
 911
 912        status = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD24, dw24.val);
 913        if (status)
 914                return status;
 915
 916        /* Finally, enable the PLL */
 917        dw24.field.ts_pll_enable = 1;
 918
 919        status = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD24, dw24.val);
 920        if (status)
 921                return status;
 922
 923        /* Wait to verify if the PLL locks */
 924        ice_msec_delay(1, true);
 925
 926        status = ice_read_cgu_reg_e822(hw, TSPLL_RO_BWM_LF, &bwm_lf.val);
 927        if (status)
 928                return status;
 929
 930        if (!bwm_lf.field.plllock_true_lock_cri) {
 931                ice_warn(hw, "CGU PLL failed to lock\n");
 932                return ICE_ERR_NOT_READY;
 933        }
 934
 935        /* Log the current clock configuration */
 936        ice_debug(hw, ICE_DBG_PTP, "New CGU configuration -- %s, clk_src %s, clk_freq %s, PLL %s\n",
 937                  dw24.field.ts_pll_enable ? "enabled" : "disabled",
 938                  ice_clk_src_str(dw24.field.time_ref_sel),
 939                  ice_clk_freq_str(dw9.field.time_ref_freq_sel),
 940                  bwm_lf.field.plllock_true_lock_cri ? "locked" : "unlocked");
 941
 942
 943        return ICE_SUCCESS;
 944}
 945
 946/**
 947 * ice_init_cgu_e822 - Initialize CGU with settings from firmware
 948 * @hw: pointer to the HW structure
 949 *
 950 * Initialize the Clock Generation Unit of the E822 device.
 951 */
 952static enum ice_status ice_init_cgu_e822(struct ice_hw *hw)
 953{
 954        struct ice_ts_func_info *ts_info = &hw->func_caps.ts_func_info;
 955        union tspll_cntr_bist_settings cntr_bist;
 956        enum ice_status status;
 957
 958        status = ice_read_cgu_reg_e822(hw, TSPLL_CNTR_BIST_SETTINGS,
 959                                       &cntr_bist.val);
 960        if (status)
 961                return status;
 962
 963        /* Disable sticky lock detection so lock status reported is accurate */
 964        cntr_bist.field.i_plllock_sel_0 = 0;
 965        cntr_bist.field.i_plllock_sel_1 = 0;
 966
 967        status = ice_write_cgu_reg_e822(hw, TSPLL_CNTR_BIST_SETTINGS,
 968                                        cntr_bist.val);
 969        if (status)
 970                return status;
 971
 972        /* Configure the CGU PLL using the parameters from the function
 973         * capabilities.
 974         */
 975        status = ice_cfg_cgu_pll_e822(hw, ts_info->time_ref,
 976                                      (enum ice_clk_src)ts_info->clk_src);
 977        if (status)
 978                return status;
 979
 980        return ICE_SUCCESS;
 981}
 982
 983/**
 984 * ice_ptp_init_phc_e822 - Perform E822 specific PHC initialization
 985 * @hw: pointer to HW struct
 986 *
 987 * Perform PHC initialization steps specific to E822 devices.
 988 */
 989static enum ice_status ice_ptp_init_phc_e822(struct ice_hw *hw)
 990{
 991        enum ice_status status;
 992        u32 regval;
 993
 994        /* Enable reading switch and PHY registers over the sideband queue */
 995#define PF_SB_REM_DEV_CTL_SWITCH_READ BIT(1)
 996#define PF_SB_REM_DEV_CTL_PHY0 BIT(2)
 997        regval = rd32(hw, PF_SB_REM_DEV_CTL);
 998        regval |= (PF_SB_REM_DEV_CTL_SWITCH_READ |
 999                   PF_SB_REM_DEV_CTL_PHY0);
1000        wr32(hw, PF_SB_REM_DEV_CTL, regval);
1001
1002        /* Initialize the Clock Generation Unit */
1003        status = ice_init_cgu_e822(hw);
1004        if (status)
1005                return status;
1006
1007        /* Set window length for all the ports */
1008        return ice_ptp_set_vernier_wl(hw);
1009}
1010
1011/**
1012 * ice_ptp_prep_phy_time_e822 - Prepare PHY port with initial time
1013 * @hw: pointer to the HW struct
1014 * @time: Time to initialize the PHY port clocks to
1015 *
1016 * Program the PHY port registers with a new initial time value. The port
1017 * clock will be initialized once the driver issues an INIT_TIME sync
1018 * command. The time value is the upper 32 bits of the PHY timer, usually in
1019 * units of nominal nanoseconds.
1020 */
1021static enum ice_status
1022ice_ptp_prep_phy_time_e822(struct ice_hw *hw, u32 time)
1023{
1024        enum ice_status status;
1025        u64 phy_time;
1026        u8 port;
1027
1028        /* The time represents the upper 32 bits of the PHY timer, so we need
1029         * to shift to account for this when programming.
1030         */
1031        phy_time = (u64)time << 32;
1032
1033        for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
1034
1035                /* Tx case */
1036                status = ice_write_64b_phy_reg_e822(hw, port,
1037                                                    P_REG_TX_TIMER_INC_PRE_L,
1038                                                    phy_time);
1039                if (status)
1040                        goto exit_err;
1041
1042                /* Rx case */
1043                status = ice_write_64b_phy_reg_e822(hw, port,
1044                                                    P_REG_RX_TIMER_INC_PRE_L,
1045                                                    phy_time);
1046                if (status)
1047                        goto exit_err;
1048        }
1049
1050        return ICE_SUCCESS;
1051
1052exit_err:
1053        ice_debug(hw, ICE_DBG_PTP, "Failed to write init time for port %u, status %d\n",
1054                  port, status);
1055
1056        return status;
1057}
1058
1059/**
1060 * ice_ptp_prep_port_adj_e822 - Prepare a single port for time adjust
1061 * @hw: pointer to HW struct
1062 * @port: Port number to be programmed
1063 * @time: time in cycles to adjust the port Tx and Rx clocks
1064 * @lock_sbq: true to lock the sbq sq_lock (the usual case); false if the
1065 *            sq_lock has already been locked at a higher level
1066 *
1067 * Program the port for an atomic adjustment by writing the Tx and Rx timer
1068 * registers. The atomic adjustment won't be completed until the driver issues
1069 * an ADJ_TIME command.
1070 *
1071 * Note that time is not in units of nanoseconds. It is in clock time
1072 * including the lower sub-nanosecond portion of the port timer.
1073 *
1074 * Negative adjustments are supported using 2s complement arithmetic.
1075 */
1076enum ice_status
1077ice_ptp_prep_port_adj_e822(struct ice_hw *hw, u8 port, s64 time,
1078                           bool lock_sbq)
1079{
1080        enum ice_status status;
1081        u32 l_time, u_time;
1082
1083        l_time = ICE_LO_DWORD(time);
1084        u_time = ICE_HI_DWORD(time);
1085
1086        /* Tx case */
1087        status = ice_write_phy_reg_e822_lp(hw, port, P_REG_TX_TIMER_INC_PRE_L,
1088                                           l_time, lock_sbq);
1089        if (status)
1090                goto exit_err;
1091
1092        status = ice_write_phy_reg_e822_lp(hw, port, P_REG_TX_TIMER_INC_PRE_U,
1093                                           u_time, lock_sbq);
1094        if (status)
1095                goto exit_err;
1096
1097        /* Rx case */
1098        status = ice_write_phy_reg_e822_lp(hw, port, P_REG_RX_TIMER_INC_PRE_L,
1099                                           l_time, lock_sbq);
1100        if (status)
1101                goto exit_err;
1102
1103        status = ice_write_phy_reg_e822_lp(hw, port, P_REG_RX_TIMER_INC_PRE_U,
1104                                           u_time, lock_sbq);
1105        if (status)
1106                goto exit_err;
1107
1108        return ICE_SUCCESS;
1109
1110exit_err:
1111        ice_debug(hw, ICE_DBG_PTP, "Failed to write time adjust for port %u, status %d\n",
1112                  port, status);
1113        return status;
1114}
1115
1116/**
1117 * ice_ptp_prep_phy_adj_e822 - Prep PHY ports for a time adjustment
1118 * @hw: pointer to HW struct
1119 * @adj: adjustment in nanoseconds
1120 * @lock_sbq: true to lock the sbq sq_lock (the usual case); false if the
1121 *            sq_lock has already been locked at a higher level
1122 *
1123 * Prepare the PHY ports for an atomic time adjustment by programming the PHY
1124 * Tx and Rx port registers. The actual adjustment is completed by issuing an
1125 * ADJ_TIME or ADJ_TIME_AT_TIME sync command.
1126 */
1127static enum ice_status
1128ice_ptp_prep_phy_adj_e822(struct ice_hw *hw, s32 adj, bool lock_sbq)
1129{
1130        s64 cycles;
1131        u8 port;
1132
1133        /* The port clock supports adjustment of the sub-nanosecond portion of
1134         * the clock. We shift the provided adjustment in nanoseconds to
1135         * calculate the appropriate adjustment to program into the PHY ports.
1136         */
1137        if (adj > 0)
1138                cycles = (s64)adj << 32;
1139        else
1140                cycles = -(((s64)-adj) << 32);
1141
1142        for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
1143                enum ice_status status;
1144
1145                status = ice_ptp_prep_port_adj_e822(hw, port, cycles,
1146                                                    lock_sbq);
1147                if (status)
1148                        return status;
1149        }
1150
1151        return ICE_SUCCESS;
1152}
1153
1154/**
1155 * ice_ptp_prep_phy_incval_e822 - Prepare PHY ports for time adjustment
1156 * @hw: pointer to HW struct
1157 * @incval: new increment value to prepare
1158 *
1159 * Prepare each of the PHY ports for a new increment value by programming the
1160 * port's TIMETUS registers. The new increment value will be updated after
1161 * issuing an INIT_INCVAL command.
1162 */
1163static enum ice_status
1164ice_ptp_prep_phy_incval_e822(struct ice_hw *hw, u64 incval)
1165{
1166        enum ice_status status;
1167        u8 port;
1168
1169        for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
1170                status = ice_write_40b_phy_reg_e822(hw, port, P_REG_TIMETUS_L,
1171                                                    incval);
1172                if (status)
1173                        goto exit_err;
1174        }
1175
1176        return ICE_SUCCESS;
1177
1178exit_err:
1179        ice_debug(hw, ICE_DBG_PTP, "Failed to write incval for port %u, status %d\n",
1180                  port, status);
1181
1182        return status;
1183}
1184
1185/**
1186 * ice_ptp_read_phy_incval_e822 - Read a PHY port's current incval
1187 * @hw: pointer to the HW struct
1188 * @port: the port to read
1189 * @incval: on return, the time_clk_cyc incval for this port
1190 *
1191 * Read the time_clk_cyc increment value for a given PHY port.
1192 */
1193enum ice_status
1194ice_ptp_read_phy_incval_e822(struct ice_hw *hw, u8 port, u64 *incval)
1195{
1196        enum ice_status status;
1197
1198        status = ice_read_40b_phy_reg_e822(hw, port, P_REG_TIMETUS_L, incval);
1199        if (status) {
1200                ice_debug(hw, ICE_DBG_PTP, "Failed to read TIMETUS_L, status %d\n",
1201                          status);
1202                return status;
1203        }
1204
1205        ice_debug(hw, ICE_DBG_PTP, "read INCVAL = 0x%016llx\n",
1206                  (unsigned long long)*incval);
1207
1208        return ICE_SUCCESS;
1209}
1210
1211/**
1212 * ice_ptp_prep_phy_adj_target_e822 - Prepare PHY for adjust at target time
1213 * @hw: pointer to HW struct
1214 * @target_time: target time to program
1215 *
1216 * Program the PHY port Tx and Rx TIMER_CNT_ADJ registers used for the
1217 * ADJ_TIME_AT_TIME command. This should be used in conjunction with
1218 * ice_ptp_prep_phy_adj_e822 to program an atomic adjustment that is
1219 * delayed until a specified target time.
1220 *
1221 * Note that a target time adjustment is not currently supported on E810
1222 * devices.
1223 */
1224static enum ice_status
1225ice_ptp_prep_phy_adj_target_e822(struct ice_hw *hw, u32 target_time)
1226{
1227        enum ice_status status;
1228        u8 port;
1229
1230        for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
1231
1232                /* Tx case */
1233                /* No sub-nanoseconds data */
1234                status = ice_write_phy_reg_e822_lp(hw, port,
1235                                                   P_REG_TX_TIMER_CNT_ADJ_L,
1236                                                   0, true);
1237                if (status)
1238                        goto exit_err;
1239
1240                status = ice_write_phy_reg_e822_lp(hw, port,
1241                                                   P_REG_TX_TIMER_CNT_ADJ_U,
1242                                                   target_time, true);
1243                if (status)
1244                        goto exit_err;
1245
1246                /* Rx case */
1247                /* No sub-nanoseconds data */
1248                status = ice_write_phy_reg_e822_lp(hw, port,
1249                                                   P_REG_RX_TIMER_CNT_ADJ_L,
1250                                                   0, true);
1251                if (status)
1252                        goto exit_err;
1253
1254                status = ice_write_phy_reg_e822_lp(hw, port,
1255                                                   P_REG_RX_TIMER_CNT_ADJ_U,
1256                                                   target_time, true);
1257                if (status)
1258                        goto exit_err;
1259        }
1260
1261        return ICE_SUCCESS;
1262
1263exit_err:
1264        ice_debug(hw, ICE_DBG_PTP, "Failed to write target time for port %u, status %d\n",
1265                  port, status);
1266
1267        return status;
1268}
1269
1270/**
1271 * ice_ptp_read_port_capture - Read a port's local time capture
1272 * @hw: pointer to HW struct
1273 * @port: Port number to read
1274 * @tx_ts: on return, the Tx port time capture
1275 * @rx_ts: on return, the Rx port time capture
1276 *
1277 * Read the port's Tx and Rx local time capture values.
1278 *
1279 * Note this has no equivalent for the E810 devices.
1280 */
1281enum ice_status
1282ice_ptp_read_port_capture(struct ice_hw *hw, u8 port, u64 *tx_ts, u64 *rx_ts)
1283{
1284        enum ice_status status;
1285
1286        /* Tx case */
1287        status = ice_read_64b_phy_reg_e822(hw, port, P_REG_TX_CAPTURE_L, tx_ts);
1288        if (status) {
1289                ice_debug(hw, ICE_DBG_PTP, "Failed to read REG_TX_CAPTURE, status %d\n",
1290                          status);
1291                return status;
1292        }
1293
1294        ice_debug(hw, ICE_DBG_PTP, "tx_init = 0x%016llx\n",
1295                  (unsigned long long)*tx_ts);
1296
1297        /* Rx case */
1298        status = ice_read_64b_phy_reg_e822(hw, port, P_REG_RX_CAPTURE_L, rx_ts);
1299        if (status) {
1300                ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_CAPTURE, status %d\n",
1301                          status);
1302                return status;
1303        }
1304
1305        ice_debug(hw, ICE_DBG_PTP, "rx_init = 0x%016llx\n",
1306                  (unsigned long long)*rx_ts);
1307
1308        return ICE_SUCCESS;
1309}
1310
1311/**
1312 * ice_ptp_one_port_cmd - Prepare a single PHY port for a timer command
1313 * @hw: pointer to HW struct
1314 * @port: Port to which cmd has to be sent
1315 * @cmd: Command to be sent to the port
1316 * @lock_sbq: true if the sideband queue lock must be acquired
1317 *
1318 * Prepare the requested port for an upcoming timer sync command.
1319 *
1320 * Note there is no equivalent of this operation on E810, as that device
1321 * always handles all external PHYs internally.
1322 */
1323enum ice_status
1324ice_ptp_one_port_cmd(struct ice_hw *hw, u8 port, enum ice_ptp_tmr_cmd cmd,
1325                     bool lock_sbq)
1326{
1327        enum ice_status status;
1328        u32 cmd_val, val;
1329        u8 tmr_idx;
1330
1331        tmr_idx = ice_get_ptp_src_clock_index(hw);
1332        cmd_val = tmr_idx << SEL_PHY_SRC;
1333        switch (cmd) {
1334        case INIT_TIME:
1335                cmd_val |= PHY_CMD_INIT_TIME;
1336                break;
1337        case INIT_INCVAL:
1338                cmd_val |= PHY_CMD_INIT_INCVAL;
1339                break;
1340        case ADJ_TIME:
1341                cmd_val |= PHY_CMD_ADJ_TIME;
1342                break;
1343        case ADJ_TIME_AT_TIME:
1344                cmd_val |= PHY_CMD_ADJ_TIME_AT_TIME;
1345                break;
1346        case READ_TIME:
1347                cmd_val |= PHY_CMD_READ_TIME;
1348                break;
1349        default:
1350                ice_warn(hw, "Unknown timer command %u\n", cmd);
1351                return ICE_ERR_PARAM;
1352        }
1353
1354        /* Tx case */
1355        /* Read, modify, write */
1356        status = ice_read_phy_reg_e822_lp(hw, port, P_REG_TX_TMR_CMD, &val,
1357                                          lock_sbq);
1358        if (status) {
1359                ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_TMR_CMD, status %d\n",
1360                          status);
1361                return status;
1362        }
1363
1364        /* Modify necessary bits only and perform write */
1365        val &= ~TS_CMD_MASK;
1366        val |= cmd_val;
1367
1368        status = ice_write_phy_reg_e822_lp(hw, port, P_REG_TX_TMR_CMD, val,
1369                                           lock_sbq);
1370        if (status) {
1371                ice_debug(hw, ICE_DBG_PTP, "Failed to write back TX_TMR_CMD, status %d\n",
1372                          status);
1373                return status;
1374        }
1375
1376        /* Rx case */
1377        /* Read, modify, write */
1378        status = ice_read_phy_reg_e822_lp(hw, port, P_REG_RX_TMR_CMD, &val,
1379                                          lock_sbq);
1380        if (status) {
1381                ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_TMR_CMD, status %d\n",
1382                          status);
1383                return status;
1384        }
1385
1386        /* Modify necessary bits only and perform write */
1387        val &= ~TS_CMD_MASK;
1388        val |= cmd_val;
1389
1390        status = ice_write_phy_reg_e822_lp(hw, port, P_REG_RX_TMR_CMD, val,
1391                                           lock_sbq);
1392        if (status) {
1393                ice_debug(hw, ICE_DBG_PTP, "Failed to write back RX_TMR_CMD, status %d\n",
1394                          status);
1395                return status;
1396        }
1397
1398        return ICE_SUCCESS;
1399}
1400
1401/**
1402 * ice_ptp_port_cmd_e822 - Prepare all ports for a timer command
1403 * @hw: pointer to the HW struct
1404 * @cmd: timer command to prepare
1405 * @lock_sbq: true if the sideband queue lock must  be acquired
1406 *
1407 * Prepare all ports connected to this device for an upcoming timer sync
1408 * command.
1409 */
1410static enum ice_status
1411ice_ptp_port_cmd_e822(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd,
1412                      bool lock_sbq)
1413{
1414        u8 port;
1415
1416        for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
1417                enum ice_status status;
1418
1419                status = ice_ptp_one_port_cmd(hw, port, cmd, lock_sbq);
1420                if (status)
1421                        return status;
1422        }
1423
1424        return ICE_SUCCESS;
1425}
1426
1427/* E822 Vernier calibration functions
1428 *
1429 * The following functions are used as part of the vernier calibration of
1430 * a port. This calibration increases the precision of the timestamps on the
1431 * port.
1432 */
1433
1434/**
1435 * ice_ptp_set_vernier_wl - Set the window length for vernier calibration
1436 * @hw: pointer to the HW struct
1437 *
1438 * Set the window length used for the vernier port calibration process.
1439 */
1440enum ice_status ice_ptp_set_vernier_wl(struct ice_hw *hw)
1441{
1442        u8 port;
1443
1444        for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
1445                enum ice_status status;
1446
1447                status = ice_write_phy_reg_e822_lp(hw, port, P_REG_WL,
1448                                                   PTP_VERNIER_WL, true);
1449                if (status) {
1450                        ice_debug(hw, ICE_DBG_PTP, "Failed to set vernier window length for port %u, status %d\n",
1451                                  port, status);
1452                        return status;
1453                }
1454        }
1455
1456        return ICE_SUCCESS;
1457}
1458
1459/**
1460 * ice_phy_get_speed_and_fec_e822 - Get link speed and FEC based on serdes mode
1461 * @hw: pointer to HW struct
1462 * @port: the port to read from
1463 * @link_out: if non-NULL, holds link speed on success
1464 * @fec_out: if non-NULL, holds FEC algorithm on success
1465 *
1466 * Read the serdes data for the PHY port and extract the link speed and FEC
1467 * algorithm.
1468 */
1469enum ice_status
1470ice_phy_get_speed_and_fec_e822(struct ice_hw *hw, u8 port,
1471                               enum ice_ptp_link_spd *link_out,
1472                               enum ice_ptp_fec_mode *fec_out)
1473{
1474        enum ice_ptp_link_spd link;
1475        enum ice_ptp_fec_mode fec;
1476        enum ice_status status;
1477        u32 serdes;
1478
1479        status = ice_read_phy_reg_e822(hw, port, P_REG_LINK_SPEED, &serdes);
1480        if (status) {
1481                ice_debug(hw, ICE_DBG_PTP, "Failed to read serdes info\n");
1482                return status;
1483        }
1484
1485        /* Determine the FEC algorithm */
1486        fec = (enum ice_ptp_fec_mode)P_REG_LINK_SPEED_FEC_MODE(serdes);
1487
1488        serdes &= P_REG_LINK_SPEED_SERDES_M;
1489
1490        /* Determine the link speed */
1491        if (fec == ICE_PTP_FEC_MODE_RS_FEC) {
1492                switch (serdes) {
1493                case ICE_PTP_SERDES_25G:
1494                        link = ICE_PTP_LNK_SPD_25G_RS;
1495                        break;
1496                case ICE_PTP_SERDES_50G:
1497                        link = ICE_PTP_LNK_SPD_50G_RS;
1498                        break;
1499                case ICE_PTP_SERDES_100G:
1500                        link = ICE_PTP_LNK_SPD_100G_RS;
1501                        break;
1502                default:
1503                        return ICE_ERR_OUT_OF_RANGE;
1504                }
1505        } else {
1506                switch (serdes) {
1507                case ICE_PTP_SERDES_1G:
1508                        link = ICE_PTP_LNK_SPD_1G;
1509                        break;
1510                case ICE_PTP_SERDES_10G:
1511                        link = ICE_PTP_LNK_SPD_10G;
1512                        break;
1513                case ICE_PTP_SERDES_25G:
1514                        link = ICE_PTP_LNK_SPD_25G;
1515                        break;
1516                case ICE_PTP_SERDES_40G:
1517                        link = ICE_PTP_LNK_SPD_40G;
1518                        break;
1519                case ICE_PTP_SERDES_50G:
1520                        link = ICE_PTP_LNK_SPD_50G;
1521                        break;
1522                default:
1523                        return ICE_ERR_OUT_OF_RANGE;
1524                }
1525        }
1526
1527        if (link_out)
1528                *link_out = link;
1529        if (fec_out)
1530                *fec_out = fec;
1531
1532        return ICE_SUCCESS;
1533}
1534
1535/**
1536 * ice_phy_cfg_lane_e822 - Configure PHY quad for single/multi-lane timestamp
1537 * @hw: pointer to HW struct
1538 * @port: to configure the quad for
1539 */
1540void ice_phy_cfg_lane_e822(struct ice_hw *hw, u8 port)
1541{
1542        enum ice_ptp_link_spd link_spd;
1543        enum ice_status status;
1544        u32 val;
1545        u8 quad;
1546
1547        status = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, NULL);
1548        if (status) {
1549                ice_debug(hw, ICE_DBG_PTP, "Failed to get PHY link speed, status %d\n",
1550                          status);
1551                return;
1552        }
1553
1554        quad = port / ICE_PORTS_PER_QUAD;
1555
1556        status = ice_read_quad_reg_e822(hw, quad, Q_REG_TX_MEM_GBL_CFG, &val);
1557        if (status) {
1558                ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_MEM_GLB_CFG, status %d\n",
1559                          status);
1560                return;
1561        }
1562
1563        if (link_spd >= ICE_PTP_LNK_SPD_40G)
1564                val &= ~Q_REG_TX_MEM_GBL_CFG_LANE_TYPE_M;
1565        else
1566                val |= Q_REG_TX_MEM_GBL_CFG_LANE_TYPE_M;
1567
1568        status = ice_write_quad_reg_e822(hw, quad, Q_REG_TX_MEM_GBL_CFG, val);
1569        if (status) {
1570                ice_debug(hw, ICE_DBG_PTP, "Failed to write back TX_MEM_GBL_CFG, status %d\n",
1571                          status);
1572                return;
1573        }
1574}
1575
1576/**
1577 * ice_phy_cfg_uix_e822 - Configure Serdes UI to TU conversion for E822
1578 * @hw: pointer to the HW structure
1579 * @port: the port to configure
1580 *
1581 * Program the conversion ration of Serdes clock "unit intervals" (UIs) to PHC
1582 * hardware clock time units (TUs). That is, determine the number of TUs per
1583 * serdes unit interval, and program the UIX registers with this conversion.
1584 *
1585 * This conversion is used as part of the calibration process when determining
1586 * the additional error of a timestamp vs the real time of transmission or
1587 * receipt of the packet.
1588 *
1589 * Hardware uses the number of TUs per 66 UIs, written to the UIX registers
1590 * for the two main serdes clock rates, 10G/40G and 25G/100G serdes clocks.
1591 *
1592 * To calculate the conversion ratio, we use the following facts:
1593 *
1594 * a) the clock frequency in Hz (cycles per second)
1595 * b) the number of TUs per cycle (the increment value of the clock)
1596 * c) 1 second per 1 billion nanoseconds
1597 * d) the duration of 66 UIs in nanoseconds
1598 *
1599 * Given these facts, we can use the following table to work out what ratios
1600 * to multiply in order to get the number of TUs per 66 UIs:
1601 *
1602 * cycles |   1 second   | incval (TUs) | nanoseconds
1603 * -------+--------------+--------------+-------------
1604 * second | 1 billion ns |    cycle     |   66 UIs
1605 *
1606 * To perform the multiplication using integers without too much loss of
1607 * precision, we can take use the following equation:
1608 *
1609 * (freq * incval * 6600 LINE_UI ) / ( 100 * 1 billion)
1610 *
1611 * We scale up to using 6600 UI instead of 66 in order to avoid fractional
1612 * nanosecond UIs (66 UI at 10G/40G is 6.4 ns)
1613 *
1614 * The increment value has a maximum expected range of about 34 bits, while
1615 * the frequency value is about 29 bits. Multiplying these values shouldn't
1616 * overflow the 64 bits. However, we must then further multiply them again by
1617 * the Serdes unit interval duration. To avoid overflow here, we split the
1618 * overall divide by 1e11 into a divide by 256 (shift down by 8 bits) and
1619 * a divide by 390,625,000. This does lose some precision, but avoids
1620 * miscalculation due to arithmetic overflow.
1621 */
1622static enum ice_status ice_phy_cfg_uix_e822(struct ice_hw *hw, u8 port)
1623{
1624        u64 cur_freq, clk_incval, tu_per_sec, uix;
1625        enum ice_status status;
1626
1627        cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw));
1628        clk_incval = ice_ptp_read_src_incval(hw);
1629
1630        /* Calculate TUs per second divided by 256 */
1631        tu_per_sec = (cur_freq * clk_incval) >> 8;
1632
1633#define LINE_UI_10G_40G 640 /* 6600 UIs is 640 nanoseconds at 10Gb/40Gb */
1634#define LINE_UI_25G_100G 256 /* 6600 UIs is 256 nanoseconds at 25Gb/100Gb */
1635
1636        /* Program the 10Gb/40Gb conversion ratio */
1637        uix = DIV_64BIT(tu_per_sec * LINE_UI_10G_40G, 390625000);
1638
1639        status = ice_write_64b_phy_reg_e822(hw, port, P_REG_UIX66_10G_40G_L,
1640                                            uix);
1641        if (status) {
1642                ice_debug(hw, ICE_DBG_PTP, "Failed to write UIX66_10G_40G, status %d\n",
1643                          status);
1644                return status;
1645        }
1646
1647        /* Program the 25Gb/100Gb conversion ratio */
1648        uix = DIV_64BIT(tu_per_sec * LINE_UI_25G_100G, 390625000);
1649
1650        status = ice_write_64b_phy_reg_e822(hw, port, P_REG_UIX66_25G_100G_L,
1651                                            uix);
1652        if (status) {
1653                ice_debug(hw, ICE_DBG_PTP, "Failed to write UIX66_25G_100G, status %d\n",
1654                          status);
1655                return status;
1656        }
1657
1658        return ICE_SUCCESS;
1659}
1660
1661/**
1662 * ice_phy_cfg_parpcs_e822 - Configure TUs per PAR/PCS clock cycle
1663 * @hw: pointer to the HW struct
1664 * @port: port to configure
1665 *
1666 * Configure the number of TUs for the PAR and PCS clocks used as part of the
1667 * timestamp calibration process. This depends on the link speed, as the PHY
1668 * uses different markers depending on the speed.
1669 *
1670 * 1Gb/10Gb/25Gb:
1671 * - Tx/Rx PAR/PCS markers
1672 *
1673 * 25Gb RS:
1674 * - Tx/Rx Reed Solomon gearbox PAR/PCS markers
1675 *
1676 * 40Gb/50Gb:
1677 * - Tx/Rx PAR/PCS markers
1678 * - Rx Deskew PAR/PCS markers
1679 *
1680 * 50G RS and 100GB RS:
1681 * - Tx/Rx Reed Solomon gearbox PAR/PCS markers
1682 * - Rx Deskew PAR/PCS markers
1683 * - Tx PAR/PCS markers
1684 *
1685 * To calculate the conversion, we use the PHC clock frequency (cycles per
1686 * second), the increment value (TUs per cycle), and the related PHY clock
1687 * frequency to calculate the TUs per unit of the PHY link clock. The
1688 * following table shows how the units convert:
1689 *
1690 * cycles |  TUs  | second
1691 * -------+-------+--------
1692 * second | cycle | cycles
1693 *
1694 * For each conversion register, look up the appropriate frequency from the
1695 * e822 PAR/PCS table and calculate the TUs per unit of that clock. Program
1696 * this to the appropriate register, preparing hardware to perform timestamp
1697 * calibration to calculate the total Tx or Rx offset to adjust the timestamp
1698 * in order to calibrate for the internal PHY delays.
1699 *
1700 * Note that the increment value ranges up to ~34 bits, and the clock
1701 * frequency is ~29 bits, so multiplying them together should fit within the
1702 * 64 bit arithmetic.
1703 */
1704static enum ice_status ice_phy_cfg_parpcs_e822(struct ice_hw *hw, u8 port)
1705{
1706        u64 cur_freq, clk_incval, tu_per_sec, phy_tus;
1707        enum ice_ptp_link_spd link_spd;
1708        enum ice_ptp_fec_mode fec_mode;
1709        enum ice_status status;
1710
1711        status = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode);
1712        if (status)
1713                return status;
1714
1715        cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw));
1716        clk_incval = ice_ptp_read_src_incval(hw);
1717
1718        /* Calculate TUs per cycle of the PHC clock */
1719        tu_per_sec = cur_freq * clk_incval;
1720
1721        /* For each PHY conversion register, look up the appropriate link
1722         * speed frequency and determine the TUs per that clock's cycle time.
1723         * Split this into a high and low value and then program the
1724         * appropriate register. If that link speed does not use the
1725         * associated register, write zeros to clear it instead.
1726         */
1727
1728        /* P_REG_PAR_TX_TUS */
1729        if (e822_vernier[link_spd].tx_par_clk)
1730                phy_tus = DIV_64BIT(tu_per_sec,
1731                                    e822_vernier[link_spd].tx_par_clk);
1732        else
1733                phy_tus = 0;
1734
1735        status = ice_write_40b_phy_reg_e822(hw, port, P_REG_PAR_TX_TUS_L,
1736                                            phy_tus);
1737        if (status)
1738                return status;
1739
1740        /* P_REG_PAR_RX_TUS */
1741        if (e822_vernier[link_spd].rx_par_clk)
1742                phy_tus = DIV_64BIT(tu_per_sec,
1743                                    e822_vernier[link_spd].rx_par_clk);
1744        else
1745                phy_tus = 0;
1746
1747        status = ice_write_40b_phy_reg_e822(hw, port, P_REG_PAR_RX_TUS_L,
1748                                            phy_tus);
1749        if (status)
1750                return status;
1751
1752        /* P_REG_PCS_TX_TUS */
1753        if (e822_vernier[link_spd].tx_pcs_clk)
1754                phy_tus = DIV_64BIT(tu_per_sec,
1755                                    e822_vernier[link_spd].tx_pcs_clk);
1756        else
1757                phy_tus = 0;
1758
1759        status = ice_write_40b_phy_reg_e822(hw, port, P_REG_PCS_TX_TUS_L,
1760                                            phy_tus);
1761        if (status)
1762                return status;
1763
1764        /* P_REG_PCS_RX_TUS */
1765        if (e822_vernier[link_spd].rx_pcs_clk)
1766                phy_tus = DIV_64BIT(tu_per_sec,
1767                                    e822_vernier[link_spd].rx_pcs_clk);
1768        else
1769                phy_tus = 0;
1770
1771        status = ice_write_40b_phy_reg_e822(hw, port, P_REG_PCS_RX_TUS_L,
1772                                            phy_tus);
1773        if (status)
1774                return status;
1775
1776        /* P_REG_DESK_PAR_TX_TUS */
1777        if (e822_vernier[link_spd].tx_desk_rsgb_par)
1778                phy_tus = DIV_64BIT(tu_per_sec,
1779                                    e822_vernier[link_spd].tx_desk_rsgb_par);
1780        else
1781                phy_tus = 0;
1782
1783        status = ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PAR_TX_TUS_L,
1784                                            phy_tus);
1785        if (status)
1786                return status;
1787
1788        /* P_REG_DESK_PAR_RX_TUS */
1789        if (e822_vernier[link_spd].rx_desk_rsgb_par)
1790                phy_tus = DIV_64BIT(tu_per_sec,
1791                                    e822_vernier[link_spd].rx_desk_rsgb_par);
1792        else
1793                phy_tus = 0;
1794
1795        status = ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PAR_RX_TUS_L,
1796                                            phy_tus);
1797        if (status)
1798                return status;
1799
1800        /* P_REG_DESK_PCS_TX_TUS */
1801        if (e822_vernier[link_spd].tx_desk_rsgb_pcs)
1802                phy_tus = DIV_64BIT(tu_per_sec,
1803                                    e822_vernier[link_spd].tx_desk_rsgb_pcs);
1804        else
1805                phy_tus = 0;
1806
1807        status = ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PCS_TX_TUS_L,
1808                                            phy_tus);
1809        if (status)
1810                return status;
1811
1812        /* P_REG_DESK_PCS_RX_TUS */
1813        if (e822_vernier[link_spd].rx_desk_rsgb_pcs)
1814                phy_tus = DIV_64BIT(tu_per_sec,
1815                                    e822_vernier[link_spd].rx_desk_rsgb_pcs);
1816        else
1817                phy_tus = 0;
1818
1819        return ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PCS_RX_TUS_L,
1820                                          phy_tus);
1821}
1822
1823/**
1824 * ice_calc_fixed_tx_offset_e822 - Calculated Fixed Tx offset for a port
1825 * @hw: pointer to the HW struct
1826 * @link_spd: the Link speed to calculate for
1827 *
1828 * Calculate the fixed offset due to known static latency data.
1829 */
1830static u64
1831ice_calc_fixed_tx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd)
1832{
1833        u64 cur_freq, clk_incval, tu_per_sec, fixed_offset;
1834
1835        cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw));
1836        clk_incval = ice_ptp_read_src_incval(hw);
1837
1838        /* Calculate TUs per second */
1839        tu_per_sec = cur_freq * clk_incval;
1840
1841        /* Calculate number of TUs to add for the fixed Tx latency. Since the
1842         * latency measurement is in 1/100th of a nanosecond, we need to
1843         * multiply by tu_per_sec and then divide by 1e11. This calculation
1844         * overflows 64 bit integer arithmetic, so break it up into two
1845         * divisions by 1e4 first then by 1e7.
1846         */
1847        fixed_offset = DIV_64BIT(tu_per_sec, 10000);
1848        fixed_offset *= e822_vernier[link_spd].tx_fixed_delay;
1849        fixed_offset = DIV_64BIT(fixed_offset, 10000000);
1850
1851        return fixed_offset;
1852}
1853
1854/**
1855 * ice_phy_cfg_tx_offset_e822 - Configure total Tx timestamp offset
1856 * @hw: pointer to the HW struct
1857 * @port: the PHY port to configure
1858 *
1859 * Program the P_REG_TOTAL_TX_OFFSET register with the total number of TUs to
1860 * adjust Tx timestamps by. This is calculated by combining some known static
1861 * latency along with the Vernier offset computations done by hardware.
1862 *
1863 * This function must be called only after the offset registers are valid,
1864 * i.e. after the Vernier calibration wait has passed, to ensure that the PHY
1865 * has measured the offset.
1866 *
1867 * To avoid overflow, when calculating the offset based on the known static
1868 * latency values, we use measurements in 1/100th of a nanosecond, and divide
1869 * the TUs per second up front. This avoids overflow while allowing
1870 * calculation of the adjustment using integer arithmetic.
1871 */
1872enum ice_status ice_phy_cfg_tx_offset_e822(struct ice_hw *hw, u8 port)
1873{
1874        enum ice_ptp_link_spd link_spd;
1875        enum ice_ptp_fec_mode fec_mode;
1876        enum ice_status status;
1877        u64 total_offset, val;
1878
1879        status = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode);
1880        if (status)
1881                return status;
1882
1883        total_offset = ice_calc_fixed_tx_offset_e822(hw, link_spd);
1884
1885        /* Read the first Vernier offset from the PHY register and add it to
1886         * the total offset.
1887         */
1888        if (link_spd == ICE_PTP_LNK_SPD_1G ||
1889            link_spd == ICE_PTP_LNK_SPD_10G ||
1890            link_spd == ICE_PTP_LNK_SPD_25G ||
1891            link_spd == ICE_PTP_LNK_SPD_25G_RS ||
1892            link_spd == ICE_PTP_LNK_SPD_40G ||
1893            link_spd == ICE_PTP_LNK_SPD_50G) {
1894                status = ice_read_64b_phy_reg_e822(hw, port,
1895                                                   P_REG_PAR_PCS_TX_OFFSET_L,
1896                                                   &val);
1897                if (status)
1898                        return status;
1899
1900                total_offset += val;
1901        }
1902
1903        /* For Tx, we only need to use the second Vernier offset for
1904         * multi-lane link speeds with RS-FEC. The lanes will always be
1905         * aligned.
1906         */
1907        if (link_spd == ICE_PTP_LNK_SPD_50G_RS ||
1908            link_spd == ICE_PTP_LNK_SPD_100G_RS) {
1909                status = ice_read_64b_phy_reg_e822(hw, port,
1910                                                   P_REG_PAR_TX_TIME_L,
1911                                                   &val);
1912                if (status)
1913                        return status;
1914
1915                total_offset += val;
1916        }
1917
1918        /* Now that the total offset has been calculated, program it to the
1919         * PHY and indicate that the Tx offset is ready. After this,
1920         * timestamps will be enabled.
1921         */
1922        status = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_TX_OFFSET_L,
1923                                            total_offset);
1924        if (status)
1925                return status;
1926
1927        status = ice_write_phy_reg_e822(hw, port, P_REG_TX_OR, 1);
1928        if (status)
1929                return status;
1930
1931        return ICE_SUCCESS;
1932}
1933
1934/**
1935 * ice_phy_cfg_fixed_tx_offset_e822 - Configure Tx offset for bypass mode
1936 * @hw: pointer to the HW struct
1937 * @port: the PHY port to configure
1938 *
1939 * Calculate and program the fixed Tx offset, and indicate that the offset is
1940 * ready. This can be used when operating in bypass mode.
1941 */
1942static enum ice_status
1943ice_phy_cfg_fixed_tx_offset_e822(struct ice_hw *hw, u8 port)
1944{
1945        enum ice_ptp_link_spd link_spd;
1946        enum ice_ptp_fec_mode fec_mode;
1947        enum ice_status status;
1948        u64 total_offset;
1949
1950        status = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode);
1951        if (status)
1952                return status;
1953
1954        total_offset = ice_calc_fixed_tx_offset_e822(hw, link_spd);
1955
1956        /* Program the fixed Tx offset into the P_REG_TOTAL_TX_OFFSET_L
1957         * register, then indicate that the Tx offset is ready. After this,
1958         * timestamps will be enabled.
1959         *
1960         * Note that this skips including the more precise offsets generated
1961         * by the Vernier calibration.
1962         */
1963        status = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_TX_OFFSET_L,
1964                                            total_offset);
1965        if (status)
1966                return status;
1967
1968        status = ice_write_phy_reg_e822(hw, port, P_REG_TX_OR, 1);
1969        if (status)
1970                return status;
1971
1972        return ICE_SUCCESS;
1973}
1974
1975/**
1976 * ice_phy_calc_pmd_adj_e822 - Calculate PMD adjustment for Rx
1977 * @hw: pointer to the HW struct
1978 * @port: the PHY port to adjust for
1979 * @link_spd: the current link speed of the PHY
1980 * @fec_mode: the current FEC mode of the PHY
1981 * @pmd_adj: on return, the amount to adjust the Rx total offset by
1982 *
1983 * Calculates the adjustment to Rx timestamps due to PMD alignment in the PHY.
1984 * This varies by link speed and FEC mode. The value calculated accounts for
1985 * various delays caused when receiving a packet.
1986 */
1987static enum ice_status
1988ice_phy_calc_pmd_adj_e822(struct ice_hw *hw, u8 port,
1989                          enum ice_ptp_link_spd link_spd,
1990                          enum ice_ptp_fec_mode fec_mode, u64 *pmd_adj)
1991{
1992        u64 cur_freq, clk_incval, tu_per_sec, mult, adj;
1993        u32 pmd_adj_divisor, val;
1994        enum ice_status status;
1995        u8 pmd_align;
1996
1997        status = ice_read_phy_reg_e822(hw, port, P_REG_PMD_ALIGNMENT, &val);
1998        if (status) {
1999                ice_debug(hw, ICE_DBG_PTP, "Failed to read PMD alignment, status %d\n",
2000                          status);
2001                return status;
2002        }
2003
2004        pmd_align = (u8)val;
2005
2006        cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw));
2007        clk_incval = ice_ptp_read_src_incval(hw);
2008
2009        /* Calculate TUs per second */
2010        tu_per_sec = cur_freq * clk_incval;
2011
2012        /* Get the link speed dependent PMD adjustment divisor */
2013        pmd_adj_divisor = e822_vernier[link_spd].pmd_adj_divisor;
2014
2015        /* The PMD alignment adjustment measurement depends on the link speed,
2016         * and whether FEC is enabled. For each link speed, the alignment
2017         * adjustment is calculated by dividing a value by the length of
2018         * a Time Unit in nanoseconds.
2019         *
2020         * 1G: align == 4 ? 10 * 0.8 : (align + 6 % 10) * 0.8
2021         * 10G: align == 65 ? 0 : (align * 0.1 * 32/33)
2022         * 10G w/FEC: align * 0.1 * 32/33
2023         * 25G: align == 65 ? 0 : (align * 0.4 * 32/33)
2024         * 25G w/FEC: align * 0.4 * 32/33
2025         * 40G: align == 65 ? 0 : (align * 0.1 * 32/33)
2026         * 40G w/FEC: align * 0.1 * 32/33
2027         * 50G: align == 65 ? 0 : (align * 0.4 * 32/33)
2028         * 50G w/FEC: align * 0.8 * 32/33
2029         *
2030         * For RS-FEC, if align is < 17 then we must also add 1.6 * 32/33.
2031         *
2032         * To allow for calculating this value using integer arithmetic, we
2033         * instead start with the number of TUs per second, (inverse of the
2034         * length of a Time Unit in nanoseconds), multiply by a value based
2035         * on the PMD alignment register, and then divide by the right value
2036         * calculated based on the table above. To avoid integer overflow this
2037         * division is broken up into a step of dividing by 125 first.
2038         */
2039        if (link_spd == ICE_PTP_LNK_SPD_1G) {
2040                if (pmd_align == 4)
2041                        mult = 10;
2042                else
2043                        mult = (pmd_align + 6) % 10;
2044        } else if (link_spd == ICE_PTP_LNK_SPD_10G ||
2045                   link_spd == ICE_PTP_LNK_SPD_25G ||
2046                   link_spd == ICE_PTP_LNK_SPD_40G ||
2047                   link_spd == ICE_PTP_LNK_SPD_50G) {
2048                /* If Clause 74 FEC, always calculate PMD adjust */
2049                if (pmd_align != 65 || fec_mode == ICE_PTP_FEC_MODE_CLAUSE74)
2050                        mult = pmd_align;
2051                else
2052                        mult = 0;
2053        } else if (link_spd == ICE_PTP_LNK_SPD_25G_RS ||
2054                   link_spd == ICE_PTP_LNK_SPD_50G_RS ||
2055                   link_spd == ICE_PTP_LNK_SPD_100G_RS) {
2056                if (pmd_align < 17)
2057                        mult = pmd_align + 40;
2058                else
2059                        mult = pmd_align;
2060        } else {
2061                ice_debug(hw, ICE_DBG_PTP, "Unknown link speed %d, skipping PMD adjustment\n",
2062                          link_spd);
2063                mult = 0;
2064        }
2065
2066        /* In some cases, there's no need to adjust for the PMD alignment */
2067        if (!mult) {
2068                *pmd_adj = 0;
2069                return ICE_SUCCESS;
2070        }
2071
2072        /* Calculate the adjustment by multiplying TUs per second by the
2073         * appropriate multiplier and divisor. To avoid overflow, we first
2074         * divide by 125, and then handle remaining divisor based on the link
2075         * speed pmd_adj_divisor value.
2076         */
2077        adj = DIV_64BIT(tu_per_sec, 125);
2078        adj *= mult;
2079        adj = DIV_64BIT(adj, pmd_adj_divisor);
2080
2081        /* Finally, for 25G-RS and 50G-RS, a further adjustment for the Rx
2082         * cycle count is necessary.
2083         */
2084        if (link_spd == ICE_PTP_LNK_SPD_25G_RS) {
2085                u64 cycle_adj;
2086                u8 rx_cycle;
2087
2088                status = ice_read_phy_reg_e822(hw, port, P_REG_RX_40_TO_160_CNT,
2089                                               &val);
2090                if (status) {
2091                        ice_debug(hw, ICE_DBG_PTP, "Failed to read 25G-RS Rx cycle count, status %d\n",
2092                                  status);
2093                        return status;
2094                }
2095
2096                rx_cycle = val & P_REG_RX_40_TO_160_CNT_RXCYC_M;
2097                if (rx_cycle) {
2098                        mult = (4 - rx_cycle) * 40;
2099
2100                        cycle_adj = DIV_64BIT(tu_per_sec, 125);
2101                        cycle_adj *= mult;
2102                        cycle_adj = DIV_64BIT(cycle_adj, pmd_adj_divisor);
2103
2104                        adj += cycle_adj;
2105                }
2106        } else if (link_spd == ICE_PTP_LNK_SPD_50G_RS) {
2107                u64 cycle_adj;
2108                u8 rx_cycle;
2109
2110                status = ice_read_phy_reg_e822(hw, port, P_REG_RX_80_TO_160_CNT,
2111                                               &val);
2112                if (status) {
2113                        ice_debug(hw, ICE_DBG_PTP, "Failed to read 50G-RS Rx cycle count, status %d\n",
2114                                  status);
2115                        return status;
2116                }
2117
2118                rx_cycle = val & P_REG_RX_80_TO_160_CNT_RXCYC_M;
2119                if (rx_cycle) {
2120                        mult = rx_cycle * 40;
2121
2122                        cycle_adj = DIV_64BIT(tu_per_sec, 125);
2123                        cycle_adj *= mult;
2124                        cycle_adj = DIV_64BIT(cycle_adj, pmd_adj_divisor);
2125
2126                        adj += cycle_adj;
2127                }
2128        }
2129
2130        /* Return the calculated adjustment */
2131        *pmd_adj = adj;
2132
2133        return ICE_SUCCESS;
2134}
2135
2136/**
2137 * ice_calc_fixed_rx_offset_e822 - Calculated the fixed Rx offset for a port
2138 * @hw: pointer to HW struct
2139 * @link_spd: The Link speed to calculate for
2140 *
2141 * Determine the fixed Rx latency for a given link speed.
2142 */
2143static u64
2144ice_calc_fixed_rx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd)
2145{
2146        u64 cur_freq, clk_incval, tu_per_sec, fixed_offset;
2147
2148        cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw));
2149        clk_incval = ice_ptp_read_src_incval(hw);
2150
2151        /* Calculate TUs per second */
2152        tu_per_sec = cur_freq * clk_incval;
2153
2154        /* Calculate number of TUs to add for the fixed Rx latency. Since the
2155         * latency measurement is in 1/100th of a nanosecond, we need to
2156         * multiply by tu_per_sec and then divide by 1e11. This calculation
2157         * overflows 64 bit integer arithmetic, so break it up into two
2158         * divisions by 1e4 first then by 1e7.
2159         */
2160        fixed_offset = DIV_64BIT(tu_per_sec, 10000);
2161        fixed_offset *= e822_vernier[link_spd].rx_fixed_delay;
2162        fixed_offset = DIV_64BIT(fixed_offset, 10000000);
2163
2164        return fixed_offset;
2165}
2166
2167/**
2168 * ice_phy_cfg_rx_offset_e822 - Configure total Rx timestamp offset
2169 * @hw: pointer to the HW struct
2170 * @port: the PHY port to configure
2171 *
2172 * Program the P_REG_TOTAL_RX_OFFSET register with the number of Time Units to
2173 * adjust Rx timestamps by. This combines calculations from the Vernier offset
2174 * measurements taken in hardware with some data about known fixed delay as
2175 * well as adjusting for multi-lane alignment delay.
2176 *
2177 * This function must be called only after the offset registers are valid,
2178 * i.e. after the Vernier calibration wait has passed, to ensure that the PHY
2179 * has measured the offset.
2180 *
2181 * To avoid overflow, when calculating the offset based on the known static
2182 * latency values, we use measurements in 1/100th of a nanosecond, and divide
2183 * the TUs per second up front. This avoids overflow while allowing
2184 * calculation of the adjustment using integer arithmetic.
2185 */
2186enum ice_status ice_phy_cfg_rx_offset_e822(struct ice_hw *hw, u8 port)
2187{
2188        enum ice_ptp_link_spd link_spd;
2189        enum ice_ptp_fec_mode fec_mode;
2190        u64 total_offset, pmd, val;
2191        enum ice_status status;
2192
2193        status = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode);
2194        if (status)
2195                return status;
2196
2197        total_offset = ice_calc_fixed_rx_offset_e822(hw, link_spd);
2198
2199        /* Read the first Vernier offset from the PHY register and add it to
2200         * the total offset.
2201         */
2202        status = ice_read_64b_phy_reg_e822(hw, port,
2203                                           P_REG_PAR_PCS_RX_OFFSET_L,
2204                                           &val);
2205        if (status)
2206                return status;
2207
2208        total_offset += val;
2209
2210        /* For Rx, all multi-lane link speeds include a second Vernier
2211         * calibration, because the lanes might not be aligned.
2212         */
2213        if (link_spd == ICE_PTP_LNK_SPD_40G ||
2214            link_spd == ICE_PTP_LNK_SPD_50G ||
2215            link_spd == ICE_PTP_LNK_SPD_50G_RS ||
2216            link_spd == ICE_PTP_LNK_SPD_100G_RS) {
2217                status = ice_read_64b_phy_reg_e822(hw, port,
2218                                                   P_REG_PAR_RX_TIME_L,
2219                                                   &val);
2220                if (status)
2221                        return status;
2222
2223                total_offset += val;
2224        }
2225
2226        /* In addition, Rx must account for the PMD alignment */
2227        status = ice_phy_calc_pmd_adj_e822(hw, port, link_spd, fec_mode, &pmd);
2228        if (status)
2229                return status;
2230
2231        /* For RS-FEC, this adjustment adds delay, but for other modes, it
2232         * subtracts delay.
2233         */
2234        if (fec_mode == ICE_PTP_FEC_MODE_RS_FEC)
2235                total_offset += pmd;
2236        else
2237                total_offset -= pmd;
2238
2239        /* Now that the total offset has been calculated, program it to the
2240         * PHY and indicate that the Rx offset is ready. After this,
2241         * timestamps will be enabled.
2242         */
2243        status = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_RX_OFFSET_L,
2244                                            total_offset);
2245        if (status)
2246                return status;
2247
2248        status = ice_write_phy_reg_e822(hw, port, P_REG_RX_OR, 1);
2249        if (status)
2250                return status;
2251
2252        return ICE_SUCCESS;
2253}
2254
2255/**
2256 * ice_phy_cfg_fixed_rx_offset_e822 - Configure fixed Rx offset for bypass mode
2257 * @hw: pointer to the HW struct
2258 * @port: the PHY port to configure
2259 *
2260 * Calculate and program the fixed Rx offset, and indicate that the offset is
2261 * ready. This can be used when operating in bypass mode.
2262 */
2263static enum ice_status
2264ice_phy_cfg_fixed_rx_offset_e822(struct ice_hw *hw, u8 port)
2265{
2266        enum ice_ptp_link_spd link_spd;
2267        enum ice_ptp_fec_mode fec_mode;
2268        enum ice_status status;
2269        u64 total_offset;
2270
2271        status = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode);
2272        if (status)
2273                return status;
2274
2275        total_offset = ice_calc_fixed_rx_offset_e822(hw, link_spd);
2276
2277        /* Program the fixed Rx offset into the P_REG_TOTAL_RX_OFFSET_L
2278         * register, then indicate that the Rx offset is ready. After this,
2279         * timestamps will be enabled.
2280         *
2281         * Note that this skips including the more precise offsets generated
2282         * by Vernier calibration.
2283         */
2284        status = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_RX_OFFSET_L,
2285                                            total_offset);
2286        if (status)
2287                return status;
2288
2289        status = ice_write_phy_reg_e822(hw, port, P_REG_RX_OR, 1);
2290        if (status)
2291                return status;
2292
2293        return ICE_SUCCESS;
2294}
2295
2296/**
2297 * ice_read_phy_and_phc_time_e822 - Simultaneously capture PHC and PHY time
2298 * @hw: pointer to the HW struct
2299 * @port: the PHY port to read
2300 * @phy_time: on return, the 64bit PHY timer value
2301 * @phc_time: on return, the lower 64bits of PHC time
2302 *
2303 * Issue a READ_TIME timer command to simultaneously capture the PHY and PHC
2304 * timer values.
2305 */
2306static enum ice_status
2307ice_read_phy_and_phc_time_e822(struct ice_hw *hw, u8 port, u64 *phy_time,
2308                               u64 *phc_time)
2309{
2310        enum ice_status status;
2311        u64 tx_time, rx_time;
2312        u32 zo, lo;
2313        u8 tmr_idx;
2314
2315        tmr_idx = ice_get_ptp_src_clock_index(hw);
2316
2317        /* Prepare the PHC timer for a READ_TIME capture command */
2318        ice_ptp_src_cmd(hw, READ_TIME);
2319
2320        /* Prepare the PHY timer for a READ_TIME capture command */
2321        status = ice_ptp_one_port_cmd(hw, port, READ_TIME, true);
2322        if (status)
2323                return status;
2324
2325        /* Issue the sync to start the READ_TIME capture */
2326        ice_ptp_exec_tmr_cmd(hw);
2327
2328        /* Read the captured PHC time from the shadow time registers */
2329        zo = rd32(hw, GLTSYN_SHTIME_0(tmr_idx));
2330        lo = rd32(hw, GLTSYN_SHTIME_L(tmr_idx));
2331        *phc_time = (u64)lo << 32 | zo;
2332
2333        /* Read the captured PHY time from the PHY shadow registers */
2334        status = ice_ptp_read_port_capture(hw, port, &tx_time, &rx_time);
2335        if (status)
2336                return status;
2337
2338        /* If the PHY Tx and Rx timers don't match, log a warning message.
2339         * Note that this should not happen in normal circumstances since the
2340         * driver always programs them together.
2341         */
2342        if (tx_time != rx_time)
2343                ice_warn(hw, "PHY port %u Tx and Rx timers do not match, tx_time 0x%016llX, rx_time 0x%016llX\n",
2344                         port, (unsigned long long)tx_time,
2345                         (unsigned long long)rx_time);
2346
2347        *phy_time = tx_time;
2348
2349        return ICE_SUCCESS;
2350}
2351
2352/**
2353 * ice_sync_phy_timer_e822 - Synchronize the PHY timer with PHC timer
2354 * @hw: pointer to the HW struct
2355 * @port: the PHY port to synchronize
2356 *
2357 * Perform an adjustment to ensure that the PHY and PHC timers are in sync.
2358 * This is done by issuing a READ_TIME command which triggers a simultaneous
2359 * read of the PHY timer and PHC timer. Then we use the difference to
2360 * calculate an appropriate 2s complement addition to add to the PHY timer in
2361 * order to ensure it reads the same value as the primary PHC timer.
2362 */
2363static enum ice_status ice_sync_phy_timer_e822(struct ice_hw *hw, u8 port)
2364{
2365        u64 phc_time, phy_time, difference;
2366        enum ice_status status;
2367
2368        if (!ice_ptp_lock(hw)) {
2369                ice_debug(hw, ICE_DBG_PTP, "Failed to acquire PTP semaphore\n");
2370                return ICE_ERR_NOT_READY;
2371        }
2372
2373        status = ice_read_phy_and_phc_time_e822(hw, port, &phy_time, &phc_time);
2374        if (status)
2375                goto err_unlock;
2376
2377        /* Calculate the amount required to add to the port time in order for
2378         * it to match the PHC time.
2379         *
2380         * Note that the port adjustment is done using 2s complement
2381         * arithmetic. This is convenient since it means that we can simply
2382         * calculate the difference between the PHC time and the port time,
2383         * and it will be interpreted correctly.
2384         */
2385        difference = phc_time - phy_time;
2386
2387        status = ice_ptp_prep_port_adj_e822(hw, port, (s64)difference, true);
2388        if (status)
2389                goto err_unlock;
2390
2391        status = ice_ptp_one_port_cmd(hw, port, ADJ_TIME, true);
2392        if (status)
2393                goto err_unlock;
2394
2395        /* Issue the sync to activate the time adjustment */
2396        ice_ptp_exec_tmr_cmd(hw);
2397
2398        /* Re-capture the timer values to flush the command registers and
2399         * verify that the time was properly adjusted.
2400         */
2401        status = ice_read_phy_and_phc_time_e822(hw, port, &phy_time, &phc_time);
2402        if (status)
2403                goto err_unlock;
2404
2405        ice_info(hw, "Port %u PHY time synced to PHC: 0x%016llX, 0x%016llX\n",
2406                 port, (unsigned long long)phy_time,
2407                 (unsigned long long)phc_time);
2408
2409        ice_ptp_unlock(hw);
2410
2411        return ICE_SUCCESS;
2412
2413err_unlock:
2414        ice_ptp_unlock(hw);
2415        return status;
2416}
2417
2418/**
2419 * ice_stop_phy_timer_e822 - Stop the PHY clock timer
2420 * @hw: pointer to the HW struct
2421 * @port: the PHY port to stop
2422 * @soft_reset: if true, hold the SOFT_RESET bit of P_REG_PS
2423 *
2424 * Stop the clock of a PHY port. This must be done as part of the flow to
2425 * re-calibrate Tx and Rx timestamping offsets whenever the clock time is
2426 * initialized or when link speed changes.
2427 */
2428enum ice_status
2429ice_stop_phy_timer_e822(struct ice_hw *hw, u8 port, bool soft_reset)
2430{
2431        enum ice_status status;
2432        u32 val;
2433
2434        status = ice_write_phy_reg_e822(hw, port, P_REG_TX_OR, 0);
2435        if (status)
2436                return status;
2437
2438        status = ice_write_phy_reg_e822(hw, port, P_REG_RX_OR, 0);
2439        if (status)
2440                return status;
2441
2442        status = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val);
2443        if (status)
2444                return status;
2445
2446        val &= ~P_REG_PS_START_M;
2447        status = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
2448        if (status)
2449                return status;
2450
2451        val &= ~P_REG_PS_ENA_CLK_M;
2452        status = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
2453        if (status)
2454                return status;
2455
2456        if (soft_reset) {
2457                val |= P_REG_PS_SFT_RESET_M;
2458                status = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
2459                if (status)
2460                        return status;
2461        }
2462
2463        ice_debug(hw, ICE_DBG_PTP, "Disabled clock on PHY port %u\n", port);
2464
2465        return ICE_SUCCESS;
2466}
2467
2468/**
2469 * ice_start_phy_timer_e822 - Start the PHY clock timer
2470 * @hw: pointer to the HW struct
2471 * @port: the PHY port to start
2472 * @bypass: if true, start the PHY in bypass mode
2473 *
2474 * Start the clock of a PHY port. This must be done as part of the flow to
2475 * re-calibrate Tx and Rx timestamping offsets whenever the clock time is
2476 * initialized or when link speed changes.
2477 *
2478 * Bypass mode enables timestamps immediately without waiting for Vernier
2479 * calibration to complete. Hardware will still continue taking Vernier
2480 * measurements on Tx or Rx of packets, but they will not be applied to
2481 * timestamps. Use ice_phy_exit_bypass_e822 to exit bypass mode once hardware
2482 * has completed offset calculation.
2483 */
2484enum ice_status
2485ice_start_phy_timer_e822(struct ice_hw *hw, u8 port, bool bypass)
2486{
2487        enum ice_status status;
2488        u32 lo, hi, val;
2489        u64 incval;
2490        u8 tmr_idx;
2491
2492        tmr_idx = ice_get_ptp_src_clock_index(hw);
2493
2494        status = ice_stop_phy_timer_e822(hw, port, false);
2495        if (status)
2496                return status;
2497
2498        ice_phy_cfg_lane_e822(hw, port);
2499
2500        status = ice_phy_cfg_uix_e822(hw, port);
2501        if (status)
2502                return status;
2503
2504        status = ice_phy_cfg_parpcs_e822(hw, port);
2505        if (status)
2506                return status;
2507
2508        lo = rd32(hw, GLTSYN_INCVAL_L(tmr_idx));
2509        hi = rd32(hw, GLTSYN_INCVAL_H(tmr_idx));
2510        incval = (u64)hi << 32 | lo;
2511
2512        status = ice_write_40b_phy_reg_e822(hw, port, P_REG_TIMETUS_L, incval);
2513        if (status)
2514                return status;
2515
2516        status = ice_ptp_one_port_cmd(hw, port, INIT_INCVAL, true);
2517        if (status)
2518                return status;
2519
2520        ice_ptp_exec_tmr_cmd(hw);
2521
2522        status = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val);
2523        if (status)
2524                return status;
2525
2526        val |= P_REG_PS_SFT_RESET_M;
2527        status = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
2528        if (status)
2529                return status;
2530
2531        val |= P_REG_PS_START_M;
2532        status = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
2533        if (status)
2534                return status;
2535
2536        val &= ~P_REG_PS_SFT_RESET_M;
2537        status = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
2538        if (status)
2539                return status;
2540
2541        status = ice_ptp_one_port_cmd(hw, port, INIT_INCVAL, true);
2542        if (status)
2543                return status;
2544
2545        ice_ptp_exec_tmr_cmd(hw);
2546
2547        val |= P_REG_PS_ENA_CLK_M;
2548        status = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
2549        if (status)
2550                return status;
2551
2552        val |= P_REG_PS_LOAD_OFFSET_M;
2553        status = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
2554        if (status)
2555                return status;
2556
2557        ice_ptp_exec_tmr_cmd(hw);
2558
2559        status = ice_sync_phy_timer_e822(hw, port);
2560        if (status)
2561                return status;
2562
2563        if (bypass) {
2564                val |= P_REG_PS_BYPASS_MODE_M;
2565                /* Enter BYPASS mode, enabling timestamps immediately. */
2566                status = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
2567                if (status)
2568                        return status;
2569
2570                /* Program the fixed Tx offset */
2571                status = ice_phy_cfg_fixed_tx_offset_e822(hw, port);
2572                if (status)
2573                        return status;
2574
2575                /* Program the fixed Rx offset */
2576                status = ice_phy_cfg_fixed_rx_offset_e822(hw, port);
2577                if (status)
2578                        return status;
2579        }
2580
2581        ice_debug(hw, ICE_DBG_PTP, "Enabled clock on PHY port %u\n", port);
2582
2583        return ICE_SUCCESS;
2584}
2585
2586/**
2587 * ice_phy_exit_bypass_e822 - Exit bypass mode, after vernier calculations
2588 * @hw: pointer to the HW struct
2589 * @port: the PHY port to configure
2590 *
2591 * After hardware finishes vernier calculations for the Tx and Rx offset, this
2592 * function can be used to exit bypass mode by updating the total Tx and Rx
2593 * offsets, and then disabling bypass. This will enable hardware to include
2594 * the more precise offset calibrations, increasing precision of the generated
2595 * timestamps.
2596 *
2597 * This cannot be done until hardware has measured the offsets, which requires
2598 * waiting until at least one packet has been sent and received by the device.
2599 */
2600enum ice_status ice_phy_exit_bypass_e822(struct ice_hw *hw, u8 port)
2601{
2602        enum ice_status status;
2603        u32 val;
2604
2605        status = ice_read_phy_reg_e822(hw, port, P_REG_TX_OV_STATUS, &val);
2606        if (status) {
2607                ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_OV_STATUS for port %u, status %d\n",
2608                          port, status);
2609                return status;
2610        }
2611
2612        if (!(val & P_REG_TX_OV_STATUS_OV_M)) {
2613                ice_debug(hw, ICE_DBG_PTP, "Tx offset is not yet valid for port %u\n",
2614                          port);
2615                return ICE_ERR_NOT_READY;
2616        }
2617
2618        status = ice_read_phy_reg_e822(hw, port, P_REG_RX_OV_STATUS, &val);
2619        if (status) {
2620                ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_OV_STATUS for port %u, status %d\n",
2621                          port, status);
2622                return status;
2623        }
2624
2625        if (!(val & P_REG_TX_OV_STATUS_OV_M)) {
2626                ice_debug(hw, ICE_DBG_PTP, "Rx offset is not yet valid for port %u\n",
2627                          port);
2628                return ICE_ERR_NOT_READY;
2629        }
2630
2631        status = ice_phy_cfg_tx_offset_e822(hw, port);
2632        if (status) {
2633                ice_debug(hw, ICE_DBG_PTP, "Failed to program total Tx offset for port %u, status %d\n",
2634                          port, status);
2635                return status;
2636        }
2637
2638        status = ice_phy_cfg_rx_offset_e822(hw, port);
2639        if (status) {
2640                ice_debug(hw, ICE_DBG_PTP, "Failed to program total Rx offset for port %u, status %d\n",
2641                          port, status);
2642                return status;
2643        }
2644
2645        /* Exit bypass mode now that the offset has been updated */
2646        status = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val);
2647        if (status) {
2648                ice_debug(hw, ICE_DBG_PTP, "Failed to read P_REG_PS for port %u, status %d\n",
2649                          port, status);
2650                return status;
2651        }
2652
2653        if (!(val & P_REG_PS_BYPASS_MODE_M))
2654                ice_debug(hw, ICE_DBG_PTP, "Port %u not in bypass mode\n",
2655                          port);
2656
2657        val &= ~P_REG_PS_BYPASS_MODE_M;
2658        status = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
2659        if (status) {
2660                ice_debug(hw, ICE_DBG_PTP, "Failed to disable bypass for port %u, status %d\n",
2661                          port, status);
2662                return status;
2663        }
2664
2665        ice_info(hw, "Exiting bypass mode on PHY port %u\n", port);
2666
2667        return ICE_SUCCESS;
2668}
2669
2670/* E810 functions
2671 *
2672 * The following functions operate on the E810 series devices which use
2673 * a separate external PHY.
2674 */
2675
2676/**
2677 * ice_read_phy_reg_e810_lp - Read register from external PHY on E810
2678 * @hw: pointer to the HW struct
2679 * @addr: the address to read from
2680 * @val: On return, the value read from the PHY
2681 * @lock_sbq: true if the sideband queue lock must be acquired
2682 *
2683 * Read a register from the external PHY on the E810 device.
2684 */
2685static enum ice_status
2686ice_read_phy_reg_e810_lp(struct ice_hw *hw, u32 addr, u32 *val, bool lock_sbq)
2687{
2688        struct ice_sbq_msg_input msg = {0};
2689        enum ice_status status;
2690
2691        msg.msg_addr_low = ICE_LO_WORD(addr);
2692        msg.msg_addr_high = ICE_HI_WORD(addr);
2693        msg.opcode = ice_sbq_msg_rd;
2694        msg.dest_dev = rmn_0;
2695
2696        status = ice_sbq_rw_reg_lp(hw, &msg, lock_sbq);
2697        if (status) {
2698                ice_debug(hw, ICE_DBG_PTP, "Failed to send message to phy, status %d\n",
2699                          status);
2700                return status;
2701        }
2702
2703        *val = msg.data;
2704
2705        return ICE_SUCCESS;
2706}
2707
2708static enum ice_status
2709ice_read_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 *val)
2710{
2711        return ice_read_phy_reg_e810_lp(hw, addr, val, true);
2712}
2713
2714/**
2715 * ice_write_phy_reg_e810_lp - Write register on external PHY on E810
2716 * @hw: pointer to the HW struct
2717 * @addr: the address to writem to
2718 * @val: the value to write to the PHY
2719 * @lock_sbq: true if the sideband queue lock must be acquired
2720 *
2721 * Write a value to a register of the external PHY on the E810 device.
2722 */
2723static enum ice_status
2724ice_write_phy_reg_e810_lp(struct ice_hw *hw, u32 addr, u32 val, bool lock_sbq)
2725{
2726        struct ice_sbq_msg_input msg = {0};
2727        enum ice_status status;
2728
2729        msg.msg_addr_low = ICE_LO_WORD(addr);
2730        msg.msg_addr_high = ICE_HI_WORD(addr);
2731        msg.opcode = ice_sbq_msg_wr;
2732        msg.dest_dev = rmn_0;
2733        msg.data = val;
2734
2735        status = ice_sbq_rw_reg_lp(hw, &msg, lock_sbq);
2736        if (status) {
2737                ice_debug(hw, ICE_DBG_PTP, "Failed to send message to phy, status %d\n",
2738                          status);
2739                return status;
2740        }
2741
2742        return ICE_SUCCESS;
2743}
2744
2745static enum ice_status
2746ice_write_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 val)
2747{
2748        return ice_write_phy_reg_e810_lp(hw, addr, val, true);
2749}
2750
2751/**
2752 * ice_read_phy_tstamp_e810 - Read a PHY timestamp out of the external PHY
2753 * @hw: pointer to the HW struct
2754 * @lport: the lport to read from
2755 * @idx: the timestamp index to read
2756 * @tstamp: on return, the 40bit timestamp value
2757 *
2758 * Read a 40bit timestamp value out of the timestamp block of the external PHY
2759 * on the E810 device.
2760 */
2761static enum ice_status
2762ice_read_phy_tstamp_e810(struct ice_hw *hw, u8 lport, u8 idx, u64 *tstamp)
2763{
2764        enum ice_status status;
2765        u32 lo_addr, hi_addr, lo, hi;
2766
2767        lo_addr = TS_EXT(LOW_TX_MEMORY_BANK_START, lport, idx);
2768        hi_addr = TS_EXT(HIGH_TX_MEMORY_BANK_START, lport, idx);
2769
2770        status = ice_read_phy_reg_e810(hw, lo_addr, &lo);
2771        if (status) {
2772                ice_debug(hw, ICE_DBG_PTP, "Failed to read low PTP timestamp register, status %d\n",
2773                          status);
2774                return status;
2775        }
2776
2777        status = ice_read_phy_reg_e810(hw, hi_addr, &hi);
2778        if (status) {
2779                ice_debug(hw, ICE_DBG_PTP, "Failed to read high PTP timestamp register, status %d\n",
2780                          status);
2781                return status;
2782        }
2783
2784        /* For E810 devices, the timestamp is reported with the lower 32 bits
2785         * in the low register, and the upper 8 bits in the high register.
2786         */
2787        *tstamp = ((u64)hi) << TS_HIGH_S | ((u64)lo & TS_LOW_M);
2788
2789        return ICE_SUCCESS;
2790}
2791
2792/**
2793 * ice_clear_phy_tstamp_e810 - Clear a timestamp from the external PHY
2794 * @hw: pointer to the HW struct
2795 * @lport: the lport to read from
2796 * @idx: the timestamp index to reset
2797 *
2798 * Clear a timestamp, resetting its valid bit, from the timestamp block of the
2799 * external PHY on the E810 device.
2800 */
2801static enum ice_status
2802ice_clear_phy_tstamp_e810(struct ice_hw *hw, u8 lport, u8 idx)
2803{
2804        enum ice_status status;
2805        u32 lo_addr, hi_addr;
2806
2807        lo_addr = TS_EXT(LOW_TX_MEMORY_BANK_START, lport, idx);
2808        hi_addr = TS_EXT(HIGH_TX_MEMORY_BANK_START, lport, idx);
2809
2810        status = ice_write_phy_reg_e810(hw, lo_addr, 0);
2811        if (status) {
2812                ice_debug(hw, ICE_DBG_PTP, "Failed to clear low PTP timestamp register, status %d\n",
2813                          status);
2814                return status;
2815        }
2816
2817        status = ice_write_phy_reg_e810(hw, hi_addr, 0);
2818        if (status) {
2819                ice_debug(hw, ICE_DBG_PTP, "Failed to clear high PTP timestamp register, status %d\n",
2820                          status);
2821                return status;
2822        }
2823
2824        return ICE_SUCCESS;
2825}
2826
2827/**
2828 * ice_ptp_init_phy_e810 - Enable PTP function on the external PHY
2829 * @hw: pointer to HW struct
2830 *
2831 * Enable the timesync PTP functionality for the external PHY connected to
2832 * this function.
2833 *
2834 * Note there is no equivalent function needed on E822 based devices.
2835 */
2836enum ice_status ice_ptp_init_phy_e810(struct ice_hw *hw)
2837{
2838        enum ice_status status;
2839        u8 tmr_idx;
2840
2841        tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
2842        status = ice_write_phy_reg_e810(hw, ETH_GLTSYN_ENA(tmr_idx),
2843                                        GLTSYN_ENA_TSYN_ENA_M);
2844        if (status)
2845                ice_debug(hw, ICE_DBG_PTP, "PTP failed in ena_phy_time_syn %d\n",
2846                          status);
2847
2848        return status;
2849}
2850
2851/**
2852 * ice_ptp_init_phc_e810 - Perform E810 specific PHC initialization
2853 * @hw: pointer to HW struct
2854 *
2855 * Perform E810-specific PTP hardware clock initialization steps.
2856 */
2857static enum ice_status ice_ptp_init_phc_e810(struct ice_hw *hw)
2858{
2859        /* Ensure synchronization delay is zero */
2860        wr32(hw, GLTSYN_SYNC_DLAY, 0);
2861
2862        /* Initialize the PHY */
2863        return ice_ptp_init_phy_e810(hw);
2864}
2865
2866/**
2867 * ice_ptp_prep_phy_time_e810 - Prepare PHY port with initial time
2868 * @hw: Board private structure
2869 * @time: Time to initialize the PHY port clock to
2870 *
2871 * Program the PHY port ETH_GLTSYN_SHTIME registers in preparation setting the
2872 * initial clock time. The time will not actually be programmed until the
2873 * driver issues an INIT_TIME command.
2874 *
2875 * The time value is the upper 32 bits of the PHY timer, usually in units of
2876 * nominal nanoseconds.
2877 */
2878static enum ice_status ice_ptp_prep_phy_time_e810(struct ice_hw *hw, u32 time)
2879{
2880        enum ice_status status;
2881        u8 tmr_idx;
2882
2883        tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
2884        status = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_0(tmr_idx), 0);
2885        if (status) {
2886                ice_debug(hw, ICE_DBG_PTP, "Failed to write SHTIME_0, status %d\n",
2887                          status);
2888                return status;
2889        }
2890
2891        status = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_L(tmr_idx), time);
2892        if (status) {
2893                ice_debug(hw, ICE_DBG_PTP, "Failed to write SHTIME_L, status %d\n",
2894                          status);
2895                return status;
2896        }
2897
2898        return ICE_SUCCESS;
2899}
2900
2901/**
2902 * ice_ptp_prep_phy_adj_e810 - Prep PHY port for a time adjustment
2903 * @hw: pointer to HW struct
2904 * @adj: adjustment value to program
2905 * @lock_sbq: true if the sideband queue luck must be acquired
2906 *
2907 * Prepare the PHY port for an atomic adjustment by programming the PHY
2908 * ETH_GLTSYN_SHADJ_L and ETH_GLTSYN_SHADJ_H registers. The actual adjustment
2909 * is completed by issuing an ADJ_TIME sync command.
2910 *
2911 * The adjustment value only contains the portion used for the upper 32bits of
2912 * the PHY timer, usually in units of nominal nanoseconds. Negative
2913 * adjustments are supported using 2s complement arithmetic.
2914 */
2915static enum ice_status
2916ice_ptp_prep_phy_adj_e810(struct ice_hw *hw, s32 adj, bool lock_sbq)
2917{
2918        enum ice_status status;
2919        u8 tmr_idx;
2920
2921        tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
2922
2923        /* Adjustments are represented as signed 2's complement values in
2924         * nanoseconds. Sub-nanosecond adjustment is not supported.
2925         */
2926        status = ice_write_phy_reg_e810_lp(hw, ETH_GLTSYN_SHADJ_L(tmr_idx),
2927                                           0, lock_sbq);
2928        if (status) {
2929                ice_debug(hw, ICE_DBG_PTP, "Failed to write adj to PHY SHADJ_L, status %d\n",
2930                          status);
2931                return status;
2932        }
2933
2934        status = ice_write_phy_reg_e810_lp(hw, ETH_GLTSYN_SHADJ_H(tmr_idx),
2935                                           adj, lock_sbq);
2936        if (status) {
2937                ice_debug(hw, ICE_DBG_PTP, "Failed to write adj to PHY SHADJ_H, status %d\n",
2938                          status);
2939                return status;
2940        }
2941
2942        return ICE_SUCCESS;
2943}
2944
2945/**
2946 * ice_ptp_prep_phy_incval_e810 - Prep PHY port increment value change
2947 * @hw: pointer to HW struct
2948 * @incval: The new 40bit increment value to prepare
2949 *
2950 * Prepare the PHY port for a new increment value by programming the PHY
2951 * ETH_GLTSYN_SHADJ_L and ETH_GLTSYN_SHADJ_H registers. The actual change is
2952 * completed by issuing an INIT_INCVAL command.
2953 */
2954static enum ice_status
2955ice_ptp_prep_phy_incval_e810(struct ice_hw *hw, u64 incval)
2956{
2957        enum ice_status status;
2958        u32 high, low;
2959        u8 tmr_idx;
2960
2961        tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
2962        low = ICE_LO_DWORD(incval);
2963        high = ICE_HI_DWORD(incval);
2964
2965        status = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_L(tmr_idx), low);
2966        if (status) {
2967                ice_debug(hw, ICE_DBG_PTP, "Failed to write incval to PHY SHADJ_L, status %d\n",
2968                          status);
2969                return status;
2970        }
2971
2972        status = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_H(tmr_idx), high);
2973        if (status) {
2974                ice_debug(hw, ICE_DBG_PTP, "Failed to write incval PHY SHADJ_H, status %d\n",
2975                          status);
2976                return status;
2977        }
2978
2979        return ICE_SUCCESS;
2980}
2981
2982/**
2983 * ice_ptp_prep_phy_adj_target_e810 - Prepare PHY port with adjust target
2984 * @hw: Board private structure
2985 * @target_time: Time to trigger the clock adjustment at
2986 *
2987 * Program the PHY port ETH_GLTSYN_SHTIME registers in preparation for
2988 * a target time adjust, which will trigger an adjustment of the clock in the
2989 * future. The actual adjustment will occur the next time the PHY port timer
2990 * crosses over the provided value after the driver issues an ADJ_TIME_AT_TIME
2991 * command.
2992 *
2993 * The time value is the upper 32 bits of the PHY timer, usually in units of
2994 * nominal nanoseconds.
2995 */
2996static enum ice_status
2997ice_ptp_prep_phy_adj_target_e810(struct ice_hw *hw, u32 target_time)
2998{
2999        enum ice_status status;
3000        u8 tmr_idx;
3001
3002        tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
3003        status = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_0(tmr_idx), 0);
3004        if (status) {
3005                ice_debug(hw, ICE_DBG_PTP, "Failed to write target time to SHTIME_0, status %d\n",
3006                          status);
3007                return status;
3008        }
3009
3010        status = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_L(tmr_idx),
3011                                        target_time);
3012        if (status) {
3013                ice_debug(hw, ICE_DBG_PTP, "Failed to write target time to SHTIME_L, status %d\n",
3014                          status);
3015                return status;
3016        }
3017
3018        return ICE_SUCCESS;
3019}
3020
3021/**
3022 * ice_ptp_port_cmd_e810 - Prepare all external PHYs for a timer command
3023 * @hw: pointer to HW struct
3024 * @cmd: Command to be sent to the port
3025 * @lock_sbq: true if the sideband queue lock must be acquired
3026 *
3027 * Prepare the external PHYs connected to this device for a timer sync
3028 * command.
3029 */
3030static enum ice_status
3031ice_ptp_port_cmd_e810(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd,
3032                      bool lock_sbq)
3033{
3034        enum ice_status status;
3035        u32 cmd_val, val;
3036
3037        switch (cmd) {
3038        case INIT_TIME:
3039                cmd_val = GLTSYN_CMD_INIT_TIME;
3040                break;
3041        case INIT_INCVAL:
3042                cmd_val = GLTSYN_CMD_INIT_INCVAL;
3043                break;
3044        case ADJ_TIME:
3045                cmd_val = GLTSYN_CMD_ADJ_TIME;
3046                break;
3047        case ADJ_TIME_AT_TIME:
3048                cmd_val = GLTSYN_CMD_ADJ_INIT_TIME;
3049                break;
3050        case READ_TIME:
3051                cmd_val = GLTSYN_CMD_READ_TIME;
3052                break;
3053        default:
3054                ice_warn(hw, "Unknown timer command %u\n", cmd);
3055                return ICE_ERR_PARAM;
3056        }
3057
3058        /* Read, modify, write */
3059        status = ice_read_phy_reg_e810_lp(hw, ETH_GLTSYN_CMD, &val, lock_sbq);
3060        if (status) {
3061                ice_debug(hw, ICE_DBG_PTP, "Failed to read GLTSYN_CMD, status %d\n",
3062                          status);
3063                return status;
3064        }
3065
3066        /* Modify necessary bits only and perform write */
3067        val &= ~TS_CMD_MASK_E810;
3068        val |= cmd_val;
3069
3070        status = ice_write_phy_reg_e810_lp(hw, ETH_GLTSYN_CMD, val, lock_sbq);
3071        if (status) {
3072                ice_debug(hw, ICE_DBG_PTP, "Failed to write back GLTSYN_CMD, status %d\n",
3073                          status);
3074                return status;
3075        }
3076
3077        return ICE_SUCCESS;
3078}
3079
3080/* E810T SMA functions
3081 *
3082 * The following functions operate specifically on E810T hardware and are used
3083 * to access the extended GPIOs available.
3084 */
3085
3086/**
3087 * ice_get_pca9575_handle
3088 * @hw: pointer to the hw struct
3089 * @pca9575_handle: GPIO controller's handle
3090 *
3091 * Find and return the GPIO controller's handle in the netlist.
3092 * When found - the value will be cached in the hw structure and following calls
3093 * will return cached value
3094 */
3095static enum ice_status
3096ice_get_pca9575_handle(struct ice_hw *hw, __le16 *pca9575_handle)
3097{
3098        struct ice_aqc_get_link_topo *cmd;
3099        struct ice_aq_desc desc;
3100        enum ice_status status;
3101        u8 idx;
3102
3103        if (!hw || !pca9575_handle)
3104                return ICE_ERR_PARAM;
3105
3106        /* If handle was read previously return cached value */
3107        if (hw->io_expander_handle) {
3108                *pca9575_handle = hw->io_expander_handle;
3109                return ICE_SUCCESS;
3110        }
3111
3112        /* If handle was not detected read it from the netlist */
3113        cmd = &desc.params.get_link_topo;
3114        ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_link_topo);
3115
3116        /* Set node type to GPIO controller */
3117        cmd->addr.topo_params.node_type_ctx =
3118                (ICE_AQC_LINK_TOPO_NODE_TYPE_M &
3119                 ICE_AQC_LINK_TOPO_NODE_TYPE_GPIO_CTRL);
3120
3121#define SW_PCA9575_SFP_TOPO_IDX         2
3122#define SW_PCA9575_QSFP_TOPO_IDX        1
3123
3124        /* Check if the SW IO expander controlling SMA exists in the netlist. */
3125        if (hw->device_id == ICE_DEV_ID_E810C_SFP)
3126                idx = SW_PCA9575_SFP_TOPO_IDX;
3127        else if (hw->device_id == ICE_DEV_ID_E810C_QSFP)
3128                idx = SW_PCA9575_QSFP_TOPO_IDX;
3129        else
3130                return ICE_ERR_NOT_SUPPORTED;
3131
3132        cmd->addr.topo_params.index = idx;
3133
3134        status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
3135        if (status)
3136                return ICE_ERR_NOT_SUPPORTED;
3137
3138        /* Verify if we found the right IO expander type */
3139        if (desc.params.get_link_topo.node_part_num !=
3140                ICE_ACQ_GET_LINK_TOPO_NODE_NR_PCA9575)
3141                return ICE_ERR_NOT_SUPPORTED;
3142
3143        /* If present save the handle and return it */
3144        hw->io_expander_handle = desc.params.get_link_topo.addr.handle;
3145        *pca9575_handle = hw->io_expander_handle;
3146
3147        return ICE_SUCCESS;
3148}
3149
3150/**
3151 * ice_read_e810t_pca9575_reg
3152 * @hw: pointer to the hw struct
3153 * @offset: GPIO controller register offset
3154 * @data: pointer to data to be read from the GPIO controller
3155 *
3156 * Read the register from the GPIO controller
3157 */
3158enum ice_status
3159ice_read_e810t_pca9575_reg(struct ice_hw *hw, u8 offset, u8 *data)
3160{
3161        struct ice_aqc_link_topo_addr link_topo;
3162        enum ice_status status;
3163        __le16 addr;
3164
3165        memset(&link_topo, 0, sizeof(link_topo));
3166
3167        status = ice_get_pca9575_handle(hw, &link_topo.handle);
3168        if (status)
3169                return status;
3170
3171        link_topo.topo_params.node_type_ctx =
3172                (ICE_AQC_LINK_TOPO_NODE_CTX_PROVIDED <<
3173                 ICE_AQC_LINK_TOPO_NODE_CTX_S);
3174
3175        addr = CPU_TO_LE16((u16)offset);
3176
3177        return ice_aq_read_i2c(hw, link_topo, 0, addr, 1, data, NULL);
3178}
3179
3180/**
3181 * ice_write_e810t_pca9575_reg
3182 * @hw: pointer to the hw struct
3183 * @offset: GPIO controller register offset
3184 * @data: data to be written to the GPIO controller
3185 *
3186 * Write the data to the GPIO controller register
3187 */
3188enum ice_status
3189ice_write_e810t_pca9575_reg(struct ice_hw *hw, u8 offset, u8 data)
3190{
3191        struct ice_aqc_link_topo_addr link_topo;
3192        enum ice_status status;
3193        __le16 addr;
3194
3195        memset(&link_topo, 0, sizeof(link_topo));
3196
3197        status = ice_get_pca9575_handle(hw, &link_topo.handle);
3198        if (status)
3199                return status;
3200
3201        link_topo.topo_params.node_type_ctx =
3202                (ICE_AQC_LINK_TOPO_NODE_CTX_PROVIDED <<
3203                 ICE_AQC_LINK_TOPO_NODE_CTX_S);
3204
3205        addr = CPU_TO_LE16((u16)offset);
3206
3207        return ice_aq_write_i2c(hw, link_topo, 0, addr, 1, &data, NULL);
3208}
3209
3210/**
3211 * ice_read_sma_ctrl_e810t
3212 * @hw: pointer to the hw struct
3213 * @data: pointer to data to be read from the GPIO controller
3214 *
3215 * Read the SMA controller state. Only bits 3-7 in data are valid.
3216 */
3217enum ice_status ice_read_sma_ctrl_e810t(struct ice_hw *hw, u8 *data)
3218{
3219        enum ice_status status;
3220        u16 handle;
3221        u8 i;
3222
3223        status = ice_get_pca9575_handle(hw, &handle);
3224        if (status)
3225                return status;
3226
3227        *data = 0;
3228
3229        for (i = ICE_E810T_SMA_MIN_BIT; i <= ICE_E810T_SMA_MAX_BIT; i++) {
3230                bool pin;
3231
3232                status = ice_aq_get_gpio(hw, handle, i + ICE_E810T_P1_OFFSET,
3233                                         &pin, NULL);
3234                if (status)
3235                        break;
3236                *data |= (u8)(!pin) << i;
3237        }
3238
3239        return status;
3240}
3241
3242/**
3243 * ice_write_sma_ctrl_e810t
3244 * @hw: pointer to the hw struct
3245 * @data: data to be written to the GPIO controller
3246 *
3247 * Write the data to the SMA controller. Only bits 3-7 in data are valid.
3248 */
3249enum ice_status ice_write_sma_ctrl_e810t(struct ice_hw *hw, u8 data)
3250{
3251        enum ice_status status;
3252        u16 handle;
3253        u8 i;
3254
3255        status = ice_get_pca9575_handle(hw, &handle);
3256        if (status)
3257                return status;
3258
3259        for (i = ICE_E810T_SMA_MIN_BIT; i <= ICE_E810T_SMA_MAX_BIT; i++) {
3260                bool pin;
3261
3262                pin = !(data & (1 << i));
3263                status = ice_aq_set_gpio(hw, handle, i + ICE_E810T_P1_OFFSET,
3264                                         pin, NULL);
3265                if (status)
3266                        break;
3267        }
3268
3269        return status;
3270}
3271
3272/**
3273 * ice_e810t_is_pca9575_present
3274 * @hw: pointer to the hw struct
3275 *
3276 * Check if the SW IO expander is present in the netlist
3277 */
3278bool ice_e810t_is_pca9575_present(struct ice_hw *hw)
3279{
3280        enum ice_status status;
3281        __le16 handle = 0;
3282
3283        if (!ice_is_e810t(hw))
3284                return false;
3285
3286        status = ice_get_pca9575_handle(hw, &handle);
3287        if (!status && handle)
3288                return true;
3289
3290        return false;
3291}
3292
3293/* Device agnostic functions
3294 *
3295 * The following functions implement shared behavior common to both E822 and
3296 * E810 devices, possibly calling a device specific implementation where
3297 * necessary.
3298 */
3299
3300/**
3301 * ice_ptp_lock - Acquire PTP global semaphore register lock
3302 * @hw: pointer to the HW struct
3303 *
3304 * Acquire the global PTP hardware semaphore lock. Returns true if the lock
3305 * was acquired, false otherwise.
3306 *
3307 * The PFTSYN_SEM register sets the busy bit on read, returning the previous
3308 * value. If software sees the busy bit cleared, this means that this function
3309 * acquired the lock (and the busy bit is now set). If software sees the busy
3310 * bit set, it means that another function acquired the lock.
3311 *
3312 * Software must clear the busy bit with a write to release the lock for other
3313 * functions when done.
3314 */
3315bool ice_ptp_lock(struct ice_hw *hw)
3316{
3317        u32 hw_lock;
3318        int i;
3319
3320#define MAX_TRIES 5
3321
3322        for (i = 0; i < MAX_TRIES; i++) {
3323                hw_lock = rd32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id));
3324                hw_lock = hw_lock & PFTSYN_SEM_BUSY_M;
3325                if (hw_lock) {
3326                        /* Somebody is holding the lock */
3327                        ice_msec_delay(10, true);
3328                        continue;
3329                } else {
3330                        break;
3331                }
3332        }
3333
3334        return !hw_lock;
3335}
3336
3337/**
3338 * ice_ptp_unlock - Release PTP global semaphore register lock
3339 * @hw: pointer to the HW struct
3340 *
3341 * Release the global PTP hardware semaphore lock. This is done by writing to
3342 * the PFTSYN_SEM register.
3343 */
3344void ice_ptp_unlock(struct ice_hw *hw)
3345{
3346        wr32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id), 0);
3347}
3348
3349/**
3350 * ice_ptp_src_cmd - Prepare source timer for a timer command
3351 * @hw: pointer to HW structure
3352 * @cmd: Timer command
3353 *
3354 * Prepare the source timer for an upcoming timer sync command.
3355 */
3356void ice_ptp_src_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
3357{
3358        u32 cmd_val;
3359        u8 tmr_idx;
3360
3361        tmr_idx = ice_get_ptp_src_clock_index(hw);
3362        cmd_val = tmr_idx << SEL_CPK_SRC;
3363
3364        switch (cmd) {
3365        case INIT_TIME:
3366                cmd_val |= GLTSYN_CMD_INIT_TIME;
3367                break;
3368        case INIT_INCVAL:
3369                cmd_val |= GLTSYN_CMD_INIT_INCVAL;
3370                break;
3371        case ADJ_TIME:
3372                cmd_val |= GLTSYN_CMD_ADJ_TIME;
3373                break;
3374        case ADJ_TIME_AT_TIME:
3375                cmd_val |= GLTSYN_CMD_ADJ_INIT_TIME;
3376                break;
3377        case READ_TIME:
3378                cmd_val |= GLTSYN_CMD_READ_TIME;
3379                break;
3380        default:
3381                ice_warn(hw, "Unknown timer command %u\n", cmd);
3382                return;
3383        }
3384
3385        wr32(hw, GLTSYN_CMD, cmd_val);
3386}
3387
3388/**
3389 * ice_ptp_tmr_cmd - Prepare and trigger a timer sync command
3390 * @hw: pointer to HW struct
3391 * @cmd: the command to issue
3392 * @lock_sbq: true if the sideband queue lock must be acquired
3393 *
3394 * Prepare the source timer and PHY timers and then trigger the requested
3395 * command. This causes the shadow registers previously written in preparation
3396 * for the command to be synchronously applied to both the source and PHY
3397 * timers.
3398 */
3399static enum ice_status
3400ice_ptp_tmr_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd, bool lock_sbq)
3401{
3402        enum ice_status status;
3403
3404        /* First, prepare the source timer */
3405        ice_ptp_src_cmd(hw, cmd);
3406
3407        /* Next, prepare the ports */
3408        if (ice_is_e810(hw))
3409                status = ice_ptp_port_cmd_e810(hw, cmd, lock_sbq);
3410        else
3411                status = ice_ptp_port_cmd_e822(hw, cmd, lock_sbq);
3412        if (status) {
3413                ice_debug(hw, ICE_DBG_PTP, "Failed to prepare PHY ports for timer command %u, status %d\n",
3414                          cmd, status);
3415                return status;
3416        }
3417
3418        /* Write the sync command register to drive both source and PHY timer
3419         * commands synchronously
3420         */
3421        ice_ptp_exec_tmr_cmd(hw);
3422
3423        return ICE_SUCCESS;
3424}
3425
3426/**
3427 * ice_ptp_init_time - Initialize device time to provided value
3428 * @hw: pointer to HW struct
3429 * @time: 64bits of time (GLTSYN_TIME_L and GLTSYN_TIME_H)
3430 *
3431 * Initialize the device to the specified time provided. This requires a three
3432 * step process:
3433 *
3434 * 1) write the new init time to the source timer shadow registers
3435 * 2) write the new init time to the phy timer shadow registers
3436 * 3) issue an init_time timer command to synchronously switch both the source
3437 *    and port timers to the new init time value at the next clock cycle.
3438 */
3439enum ice_status ice_ptp_init_time(struct ice_hw *hw, u64 time)
3440{
3441        enum ice_status status;
3442        u8 tmr_idx;
3443
3444        tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
3445
3446        /* Source timers */
3447        wr32(hw, GLTSYN_SHTIME_L(tmr_idx), ICE_LO_DWORD(time));
3448        wr32(hw, GLTSYN_SHTIME_H(tmr_idx), ICE_HI_DWORD(time));
3449        wr32(hw, GLTSYN_SHTIME_0(tmr_idx), 0);
3450
3451        /* PHY Clks */
3452        /* Fill Rx and Tx ports and send msg to PHY */
3453        if (ice_is_e810(hw))
3454                status = ice_ptp_prep_phy_time_e810(hw, time & 0xFFFFFFFF);
3455        else
3456                status = ice_ptp_prep_phy_time_e822(hw, time & 0xFFFFFFFF);
3457        if (status)
3458                return status;
3459
3460        return ice_ptp_tmr_cmd(hw, INIT_TIME, true);
3461}
3462
3463/**
3464 * ice_ptp_write_incval - Program PHC with new increment value
3465 * @hw: pointer to HW struct
3466 * @incval: Source timer increment value per clock cycle
3467 *
3468 * Program the PHC with a new increment value. This requires a three-step
3469 * process:
3470 *
3471 * 1) Write the increment value to the source timer shadow registers
3472 * 2) Write the increment value to the PHY timer shadow registers
3473 * 3) Issue an INIT_INCVAL timer command to synchronously switch both the
3474 *    source and port timers to the new increment value at the next clock
3475 *    cycle.
3476 */
3477enum ice_status ice_ptp_write_incval(struct ice_hw *hw, u64 incval)
3478{
3479        enum ice_status status;
3480        u8 tmr_idx;
3481
3482        tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
3483
3484        /* Shadow Adjust */
3485        wr32(hw, GLTSYN_SHADJ_L(tmr_idx), ICE_LO_DWORD(incval));
3486        wr32(hw, GLTSYN_SHADJ_H(tmr_idx), ICE_HI_DWORD(incval));
3487
3488        if (ice_is_e810(hw))
3489                status = ice_ptp_prep_phy_incval_e810(hw, incval);
3490        else
3491                status = ice_ptp_prep_phy_incval_e822(hw, incval);
3492        if (status)
3493                return status;
3494
3495        return ice_ptp_tmr_cmd(hw, INIT_INCVAL, true);
3496}
3497
3498/**
3499 * ice_ptp_write_incval_locked - Program new incval while holding semaphore
3500 * @hw: pointer to HW struct
3501 * @incval: Source timer increment value per clock cycle
3502 *
3503 * Program a new PHC incval while holding the PTP semaphore.
3504 */
3505enum ice_status ice_ptp_write_incval_locked(struct ice_hw *hw, u64 incval)
3506{
3507        enum ice_status status;
3508
3509        if (!ice_ptp_lock(hw))
3510                return ICE_ERR_NOT_READY;
3511
3512        status = ice_ptp_write_incval(hw, incval);
3513
3514        ice_ptp_unlock(hw);
3515
3516        return status;
3517}
3518
3519/**
3520 * ice_ptp_adj_clock - Adjust PHC clock time atomically
3521 * @hw: pointer to HW struct
3522 * @adj: Adjustment in nanoseconds
3523 * @lock_sbq: true to lock the sbq sq_lock (the usual case); false if the
3524 *            sq_lock has already been locked at a higher level
3525 *
3526 * Perform an atomic adjustment of the PHC time by the specified number of
3527 * nanoseconds. This requires a three-step process:
3528 *
3529 * 1) Write the adjustment to the source timer shadow registers
3530 * 2) Write the adjustment to the PHY timer shadow registers
3531 * 3) Issue an ADJ_TIME timer command to synchronously apply the adjustment to
3532 *    both the source and port timers at the next clock cycle.
3533 */
3534enum ice_status ice_ptp_adj_clock(struct ice_hw *hw, s32 adj, bool lock_sbq)
3535{
3536        enum ice_status status;
3537        u8 tmr_idx;
3538
3539        tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
3540
3541        /* Write the desired clock adjustment into the GLTSYN_SHADJ register.
3542         * For an ADJ_TIME command, this set of registers represents the value
3543         * to add to the clock time. It supports subtraction by interpreting
3544         * the value as a 2's complement integer.
3545         */
3546        wr32(hw, GLTSYN_SHADJ_L(tmr_idx), 0);
3547        wr32(hw, GLTSYN_SHADJ_H(tmr_idx), adj);
3548
3549        if (ice_is_e810(hw))
3550                status = ice_ptp_prep_phy_adj_e810(hw, adj, lock_sbq);
3551        else
3552                status = ice_ptp_prep_phy_adj_e822(hw, adj, lock_sbq);
3553        if (status)
3554                return status;
3555
3556        return ice_ptp_tmr_cmd(hw, ADJ_TIME, lock_sbq);
3557}
3558
3559/**
3560 * ice_ptp_adj_clock_at_time - Adjust PHC atomically at specified time
3561 * @hw: pointer to HW struct
3562 * @at_time: Time in nanoseconds at which to perform the adjustment
3563 * @adj: Adjustment in nanoseconds
3564 *
3565 * Perform an atomic adjustment to the PHC clock at the specified time. This
3566 * requires a five-step process:
3567 *
3568 * 1) Write the adjustment to the source timer shadow adjust registers
3569 * 2) Write the target time to the source timer shadow time registers
3570 * 3) Write the adjustment to the PHY timers shadow adjust registers
3571 * 4) Write the target time to the PHY timers shadow adjust registers
3572 * 5) Issue an ADJ_TIME_AT_TIME command to initiate the atomic adjustment.
3573 */
3574enum ice_status
3575ice_ptp_adj_clock_at_time(struct ice_hw *hw, u64 at_time, s32 adj)
3576{
3577        enum ice_status status;
3578        u32 time_lo, time_hi;
3579        u8 tmr_idx;
3580
3581        tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
3582        time_lo = ICE_LO_DWORD(at_time);
3583        time_hi = ICE_HI_DWORD(at_time);
3584
3585        /* Write the desired clock adjustment into the GLTSYN_SHADJ register.
3586         * For an ADJ_TIME_AT_TIME command, this set of registers represents
3587         * the value to add to the clock time. It supports subtraction by
3588         * interpreting the value as a 2's complement integer.
3589         */
3590        wr32(hw, GLTSYN_SHADJ_L(tmr_idx), 0);
3591        wr32(hw, GLTSYN_SHADJ_H(tmr_idx), adj);
3592
3593        /* Write the target time to trigger the adjustment for source clock */
3594        wr32(hw, GLTSYN_SHTIME_0(tmr_idx), 0);
3595        wr32(hw, GLTSYN_SHTIME_L(tmr_idx), time_lo);
3596        wr32(hw, GLTSYN_SHTIME_H(tmr_idx), time_hi);
3597
3598        /* Prepare PHY port adjustments */
3599        if (ice_is_e810(hw))
3600                status = ice_ptp_prep_phy_adj_e810(hw, adj, true);
3601        else
3602                status = ice_ptp_prep_phy_adj_e822(hw, adj, true);
3603        if (status)
3604                return status;
3605
3606        /* Set target time for each PHY port */
3607        if (ice_is_e810(hw))
3608                status = ice_ptp_prep_phy_adj_target_e810(hw, time_lo);
3609        else
3610                status = ice_ptp_prep_phy_adj_target_e822(hw, time_lo);
3611        if (status)
3612                return status;
3613
3614        return ice_ptp_tmr_cmd(hw, ADJ_TIME_AT_TIME, true);
3615}
3616
3617/**
3618 * ice_read_phy_tstamp - Read a PHY timestamp from the timestamo block
3619 * @hw: pointer to the HW struct
3620 * @block: the block to read from
3621 * @idx: the timestamp index to read
3622 * @tstamp: on return, the 40bit timestamp value
3623 *
3624 * Read a 40bit timestamp value out of the timestamp block. For E822 devices,
3625 * the block is the quad to read from. For E810 devices, the block is the
3626 * logical port to read from.
3627 */
3628enum ice_status
3629ice_read_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx, u64 *tstamp)
3630{
3631        if (ice_is_e810(hw))
3632                return ice_read_phy_tstamp_e810(hw, block, idx, tstamp);
3633        else
3634                return ice_read_phy_tstamp_e822(hw, block, idx, tstamp);
3635}
3636
3637/**
3638 * ice_clear_phy_tstamp - Clear a timestamp from the timestamp block
3639 * @hw: pointer to the HW struct
3640 * @block: the block to read from
3641 * @idx: the timestamp index to reset
3642 *
3643 * Clear a timestamp, resetting its valid bit, from the timestamp block. For
3644 * E822 devices, the block is the quad to clear from. For E810 devices, the
3645 * block is the logical port to clear from.
3646 */
3647enum ice_status
3648ice_clear_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx)
3649{
3650        if (ice_is_e810(hw))
3651                return ice_clear_phy_tstamp_e810(hw, block, idx);
3652        else
3653                return ice_clear_phy_tstamp_e822(hw, block, idx);
3654}
3655
3656/**
3657 * ice_ptp_init_phc - Initialize PTP hardware clock
3658 * @hw: pointer to the HW struct
3659 *
3660 * Perform the steps required to initialize the PTP hardware clock.
3661 */
3662enum ice_status ice_ptp_init_phc(struct ice_hw *hw)
3663{
3664        u8 src_idx = hw->func_caps.ts_func_info.tmr_index_owned;
3665
3666        /* Enable source clocks */
3667        wr32(hw, GLTSYN_ENA(src_idx), GLTSYN_ENA_TSYN_ENA_M);
3668
3669        /* Clear event status indications for auxiliary pins */
3670        (void)rd32(hw, GLTSYN_STAT(src_idx));
3671
3672        if (ice_is_e810(hw))
3673                return ice_ptp_init_phc_e810(hw);
3674        else
3675                return ice_ptp_init_phc_e822(hw);
3676}
3677