openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

tscbh_sim.c (23695B)


      1 /*
      2  * 
      3  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      4  * 
      5  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      6  *
      7  *
      8  * This software simulator can emulate basic register access for the
      9  * TSC/Eagle SerDes PHY.
     10  *
     11  * The simulator suppor both IEEE clause 22/45 access and Broadcom
     12  * proprietary SBUS access.
     13  *
     14  * Clause 22 address format:
     15  *   Bits [4:0]   : Clause 22 register address
     16  *   Bits [31:5]  : Unused
     17  *
     18  * Clause 45 address format:
     19  *   Bits [15:0]  : Clause 45 register address
     20  *   Bits [20:16] : Clause 45 DEVAD
     21  *   Bits [23:21] : Clause 45 indicator (001b)
     22  *   Bits [31:24] : Unused
     23  *
     24  * SBUS address format:
     25  *   Bits [15:0]  : Clause 45 register address
     26  *   Bits [18:16] : Lane control
     27  *   Bits [26:19] : Lane multicast (old format)
     28  *   Bits [31:27] : Clause 45 DEVAD
     29  *
     30  * The upper 16 bits if the SBUS address format is identical to the
     31  * Broadcom Address Extension Register (AER) format.
     32  *
     33  * The clause 45 indicator serves two purposes which is to ensure that
     34  * the upper 16 bits are never zero for a clause 45 address, but it
     35  * also makes it possible for the PHY bus driver to distinguish
     36  * between a clause 45 DEVAD and the old AER multicast format.
     37  */
     38 
     39 #include <phymod/phymod_system.h>
     40 #include <phymod/phymod_sim.h>
     41 
     42 /* Convenience macro */
     43 #define DBG_VERB PHYMOD_DEBUG_VERBOSE
     44 
     45 /* Bit field get/set macros */
     46 #define TSCBH_BF_SET(_val, _mask, _shift) _val |= ((_mask) << (_shift))
     47 #define TSCBH_BF_GET(_val, _mask, _shift) (((_val) >> (_shift)) & (_mask))
     48 
     49 /*
     50  * Raw 32-bit address consists of AER value in upper 16 bits and
     51  * clause 45 address in lower 16 bits.
     52  */
     53 #define TSCBH_DEVAD_SHIFT       27
     54 #define TSCBH_DEVAD_MASK        0x1f
     55 #define TSCBH_DEVAD_GET(_addr) \
     56     TSCBH_BF_GET(_addr, TSCBH_DEVAD_MASK, TSCBH_DEVAD_SHIFT)
     57 #define TSCBH_LANE_SHIFT        16
     58 #define TSCBH_LANE_MASK         0xff
     59 #define TSCBH_LANE_GET(_addr) \
     60     TSCBH_BF_GET(_addr, TSCBH_LANE_MASK, TSCBH_LANE_SHIFT)
     61 #define TSCBH_PLL_ID_SHIFT      24
     62 #define TSCBH_PLL_ID_MASK       0x3
     63 #define TSCBH_PLL_ID_GET(_addr) \
     64     TSCBH_BF_GET(_addr, TSCBH_PLL_ID_MASK, TSCBH_PLL_ID_SHIFT)
     65 #define TSCBH_REG_SHIFT         0
     66 #define TSCBH_REG_MASK          0xffff
     67 #define TSCBH_REG_GET(_addr) \
     68     TSCBH_BF_GET(_addr, TSCBH_REG_MASK, TSCBH_REG_SHIFT)
     69 #define TSCBH_MPP_ID_SHIFT      24
     70 #define TSCBH_MPP_ID_MASK       0x3
     71 #define TSCBH_MPP_ID_GET(_addr) \
     72     TSCBH_BF_GET(_addr, TSCBH_MPP_ID_MASK, TSCBH_MPP_ID_SHIFT)
     73 
     74 #define TSCBH_ADDR(_devad, _pll_id, _lane, _reg) \
     75     (((_devad) << TSCBH_DEVAD_SHIFT) +  \
     76      ((_pll_id) << TSCBH_PLL_ID_SHIFT) +  \
     77      ((_lane) << TSCBH_LANE_SHIFT) +    \
     78      ((_reg) << TSCBH_REG_SHIFT))
     79 
     80 #define TSCBH_ADDR_PCS(_devad, _mpp_id, _lane, _reg) \
     81    (((_devad) << TSCBH_DEVAD_SHIFT) + \
     82     ((_mpp_id) << TSCBH_MPP_ID_SHIFT) + \
     83     ((_lane) << TSCBH_LANE_SHIFT) + \
     84     ((_reg) << TSCBH_REG_SHIFT))
     85 
     86 #define TSCBH_AER               TSCBH_ADDR(0, 0, 0, 0xffde)
     87 #define TSCBH_BLK               TSCBH_ADDR(0, 0, 0, 0x001f)
     88 
     89 /*
     90  * The CL45 indicator is used to determine whether the upper 16 bits
     91  * of the address is an AER value or a clause 45 DEVAD.
     92  */
     93 #define TSCBH_CL45              (0x20 << 16)
     94 #define TSCBH_CL45_MASK         (0xe0 << 16)
     95 
     96 #define TSCBH_ID0                 0x600d
     97 #define TSCBH_ID1                 0x8770
     98 #define TSCBH_MODEL               0x26
     99 #define TSCBH_SERDES_ID           0x0325 /* 0x9008 Main0_serdesID - Serdes ID Register */
    100 
    101 #define TSCBH_MPP_0               0x1
    102 #define TSCBH_MPP_1               0x2
    103 #define TSCBH_MPP_0_1             0x3
    104 
    105 #define TSCBH_SIM_FW_LOAD_DONE_REG_ADDR (0x800d203)
    106 
    107 /*RAM sim*/
    108 #define TSCBH_RAM_WR_ADDR_REG_MS   (0xd205)
    109 #define TSCBH_RAM_WR_ADDR_REG_LS   (0xd204)
    110 #define TSCBH_RAM_WR_DATA_REG_MS   (0xd207)
    111 #define TSCBH_RAM_WR_DATA_REG_LS   (0xd206)
    112 #define TSCBH_RAM_RD_ADDR_REG_MS   (0xd209)
    113 #define TSCBH_RAM_RD_ADDR_REG_LS   (0xd208)
    114 #define TSCBH_RAM_RD_DATA_REG_MS   (0xd20b)
    115 #define TSCBH_RAM_RD_DATA_REG_LS   (0xd20a)
    116 #define TSCBH_IS_RAM_ADDR_REG(reg) (reg == TSCBH_RAM_WR_ADDR_REG_MS || reg == TSCBH_RAM_WR_ADDR_REG_LS || reg == TSCBH_RAM_RD_ADDR_REG_MS || reg == TSCBH_RAM_RD_ADDR_REG_LS)
    117 #define TSCBH_IS_RAM_DATA_REG(reg) (reg == TSCBH_RAM_WR_DATA_REG_MS || reg == TSCBH_RAM_WR_DATA_REG_LS || reg == TSCBH_RAM_RD_DATA_REG_MS || reg == TSCBH_RAM_RD_DATA_REG_LS)
    118 
    119 #define TSCBH_SIM_ENTRY_F_RAM_LS_DATA_ENTRY (0x1)
    120 #define TSCBH_SIM_ENTRY_F_RAM_MS_DATA_ENTRY (0x2)
    121 #define TSCBH_SIM_ENTRY_F_RAM_LS_ADDR_ENTRY (0x4)
    122 #define TSCBH_SIM_ENTRY_F_RAM_MS_ADDR_ENTRY (0x8)
    123 
    124 
    125 /* Forward declarations */
    126 STATIC int
    127 tscbh_sim_write(phymod_sim_data_t *pms_data, uint32_t addr, uint32_t data);
    128 STATIC int
    129 tscbh_sim_read(phymod_sim_data_t *pms_data, uint32_t addr, uint32_t *data);
    130 
    131 
    132 STATIC uint32_t
    133 tscbh_sim_default_data_get(uint32_t addr)
    134 {
    135     uint32_t reg;
    136 
    137     reg = TSCBH_REG_GET(addr);
    138 
    139     /*force FW load success */
    140     if(addr == TSCBH_SIM_FW_LOAD_DONE_REG_ADDR) {
    141         return 1;
    142     }
    143     switch (reg) {
    144         case 0x0002:
    145             return TSCBH_ID0;
    146         case 0x0003:
    147             return TSCBH_ID1;
    148         case 0x9000:
    149             return 0x80;
    150         case 0x9008: /* Main0_serdesID - Serdes ID Register */
    151             return TSCBH_SERDES_ID;
    152         case 0xd03d:
    153             /*
    154              * This is DSC_A_DSC_UC_CTRL for Falcon. Make sure
    155              * The 'ready' bit is set.
    156              */
    157             return 0x0080;
    158         case 0xd0b9: /* RXTXCOM_CKRST_CTRL_sinai_LANE_DP_RESET_STATE_STATUS */
    159             return 0x7;
    160         case 0xd100:
    161             return TSCBH_MODEL;
    162         case 0xd10a: /* DIG_COM_REVID1 - REVID1 */
    163             return 0x803c;
    164         case 0xd147:
    165             return 0x7;
    166         case 0xd188:
    167             /*
    168              * Reset check
    169              */
    170             return 0x7;
    171         case 0xd170: /* TLB_TX_patt_gen_config - Pattern Generator Control */
    172             return 0xb000;
    173         case 0xd1c9: /* LANE_DP_RESET_STATUS */
    174             return 0x7;
    175         default:
    176             break;
    177     }
    178 
    179     return 0;
    180 }
    181 
    182 STATIC uint32_t
    183 tscbh_sim_write_adjust(phymod_sim_data_t *pms_data, uint32_t addr, uint32_t data)
    184 {
    185     uint32_t devad, reg, val;
    186 
    187     devad = TSCBH_DEVAD_GET(addr);
    188     reg = TSCBH_REG_GET(addr);
    189 
    190     if (devad == 0) {
    191         switch (reg) {
    192         case 0xc050:
    193             /* Sync configured speed into final speed status register
    194              * 0x20 = 0xc070 - 0xc050 */
    195             tscbh_sim_read(pms_data, addr + 0x20, &val);
    196             val = (val & 0xffff03ff) | ((data & 0x3f) << 10);
    197             tscbh_sim_write(pms_data, addr + 0x20, val);
    198             break;
    199         default:
    200             break;
    201         }
    202     }
    203 
    204     return data;
    205 }
    206 
    207 STATIC int
    208 _tscbh_sim_write(phymod_sim_data_t *pms_data, uint32_t addr, uint32_t data)
    209 {
    210     int idx;
    211     uint32_t mask;
    212 
    213     phymod_sim_entry_t *pse;
    214 
    215     if (pms_data == NULL || pms_data->entries == NULL) {
    216         return PHYMOD_E_INIT;
    217     }
    218 
    219     /* Support optional write mask in upper 16 bits */
    220     mask = (data >> 16);
    221     if (mask == 0) {
    222         mask = 0xffff;
    223     }
    224     data &= mask;
    225 
    226     /* Check if this register has been written already */
    227     for (idx = 0; idx < pms_data->entries_used; idx++) {
    228         pse = &pms_data->entries[idx];
    229         if (pse->addr == addr) {
    230             pse->data &= ~mask;
    231             pse->data |= data;
    232             DBG_VERB(("_tscbh_sim_write 0x%08"PRIx32" = 0x%04"PRIx32"\n",
    233                       addr, pse->data));
    234             return PHYMOD_E_NONE;
    235         }
    236     }
    237 
    238     /* Check if database is full */
    239     if (pms_data->entries_used >= pms_data->num_entries) {
    240         PHYMOD_DEBUG_ERROR(("phy sim ERROR: Nof modified registers is larger than phy sim database. Please increase PHY_NUM_SIM_ENTRIES.\n"));
    241         return PHYMOD_E_RESOURCE;
    242     }
    243 
    244     /* Check if new data matches default value */
    245     if (data == tscbh_sim_default_data_get(addr)) {
    246         return PHYMOD_E_NONE;
    247     }
    248 
    249     /* Add new register value */
    250     pse = &pms_data->entries[pms_data->entries_used++];
    251     pse->addr = addr;
    252     pse->data = data;
    253 
    254     DBG_VERB(("_tscbh_sim_write 0x%08"PRIx32" = 0x%04"PRIx32" (new)\n",
    255               addr, pse->data));
    256 
    257     return PHYMOD_E_NONE;
    258 }
    259 
    260 
    261 
    262 STATIC uint32_t
    263 tscbh_sim_reg_copies_get(uint32_t addr)
    264 {
    265     uint32_t devad, reg;
    266 
    267     devad = TSCBH_DEVAD_GET(addr);
    268     reg = TSCBH_REG_GET(addr);
    269 
    270     if (reg == TSCBH_AER || reg == TSCBH_BLK) {
    271         return 1;
    272     }
    273 
    274     if (devad == 0) {
    275         if ((reg & 0xf000) == 0x9000) {
    276             return 2;
    277         }
    278         if ((reg & 0xf000) == 0xc000) {
    279             return 4;
    280         }
    281     }
    282     else if (devad == 1) {
    283         if ((reg & 0xfff0) == 0xd100) {
    284             return 1;
    285         }
    286         if ((reg & 0xfff0) == 0xd190) {
    287             return 1;
    288         }
    289         if ((reg & 0xfff0) == 0xd180) {
    290             return 2;
    291         }
    292         if ((reg & 0xfff0) == 0xd140) {
    293             return 2;
    294         }
    295         if ((reg & 0xfff0) == 0xd110) {
    296             return 2;
    297         }
    298         return 8;
    299     }
    300     return 0;
    301 }
    302 
    303 STATIC int
    304 tscbh_sim_init(phymod_sim_data_t *pms_data,
    305                int num_entries, phymod_sim_entry_t *entries)
    306 {
    307     if (pms_data != NULL) {
    308         PHYMOD_MEMSET(pms_data, 0, sizeof(*pms_data));
    309         pms_data->num_entries = num_entries;
    310         pms_data->entries = entries;
    311     }
    312     return PHYMOD_E_NONE;
    313 }
    314 
    315 STATIC int
    316 tscbh_sim_reset(phymod_sim_data_t *pms_data)
    317 {
    318     uint32_t sim_size;
    319 
    320     if (pms_data == NULL || pms_data->entries == NULL) {
    321         return PHYMOD_E_INIT;
    322     }
    323 
    324     pms_data->entries_used = 0;
    325     sim_size = pms_data->num_entries * sizeof(phymod_sim_entry_t);
    326     PHYMOD_MEMSET(pms_data->entries, 0, sim_size);
    327 
    328     return PHYMOD_E_NONE;
    329 }
    330 
    331 STATIC int
    332 tscbh_sim_read(phymod_sim_data_t *pms_data, uint32_t addr, uint32_t *data)
    333 {
    334     int idx;
    335     uint32_t aer, blk, devad, reg, copies, pll_id=0;
    336     uint32_t lane = 0;
    337     uint32_t mpp_id=0;
    338     phymod_sim_entry_t *pse;
    339     uint32_t pse_flag = 0;
    340     uint32_t addr_ms, addr_ls;
    341 
    342     if (pms_data == NULL || pms_data->entries == NULL) {
    343         return PHYMOD_E_INIT;
    344     }
    345 
    346     devad = 0;
    347 
    348 
    349     if (addr < TSCBH_BLK) {
    350         /* Assume clause 22 access */
    351         (void)tscbh_sim_read(pms_data, TSCBH_BLK, &blk);
    352         if (addr & 0x10) {
    353             /* IEEE bit */
    354             blk |= 0x8000;
    355         }
    356         addr = (addr & 0xf) | (blk & 0xfff0);
    357         if (addr != TSCBH_AER && addr != TSCBH_BLK) {
    358             (void)tscbh_sim_read(pms_data, TSCBH_AER, &aer);
    359             addr |= (aer << 16);
    360         }
    361     } else {
    362         /* Extract devad if clause 45 address format */
    363         if ((addr & TSCBH_CL45_MASK) == TSCBH_CL45) {
    364             devad = (addr >> 16) & 0x1f;
    365             addr &= 0xffff;
    366         }
    367     }
    368 
    369     if (addr != TSCBH_AER && addr != TSCBH_BLK) {
    370         /* Assume AER is in upper 16 bits */
    371         aer = (addr >> 16);
    372         if (aer == 0) {
    373             /* Try reading real AER instead */
    374             (void)tscbh_sim_read(pms_data, TSCBH_AER, &aer);
    375         }
    376         /* Add clause 45 devad (if used) */
    377         aer |= (devad << 11);
    378         addr = (addr & 0xffff) | (aer << 16);
    379 
    380         lane = (aer & 0x7);
    381 
    382         if (devad != 1) { /* PCS registers */
    383             mpp_id = TSCBH_MPP_ID_GET(addr);
    384             if (mpp_id == TSCBH_MPP_0_1) {
    385                 /* Force mpp0 if mpp is invalid */
    386                 addr = TSCBH_ADDR_PCS(TSCBH_DEVAD_GET(addr), TSCBH_MPP_0, lane, TSCBH_REG_GET(addr));
    387             }
    388             if (lane > 3) {
    389                 /* Force lane 0 if lane is invalid */
    390                 lane = 0;
    391                 addr = TSCBH_ADDR_PCS(TSCBH_DEVAD_GET(addr), TSCBH_MPP_ID_GET(addr), lane, TSCBH_REG_GET(addr));
    392             }
    393         }
    394     }
    395 
    396     /* Adjust lane according to number of copies */
    397     devad = TSCBH_DEVAD_GET(addr);
    398     reg = TSCBH_REG_GET(addr);
    399     copies = tscbh_sim_reg_copies_get(addr);
    400     if (devad == 1) { /* PMD register */
    401         if (copies == 1) {
    402             lane = 0;
    403         } else if (copies == 2) {
    404             pll_id = TSCBH_PLL_ID_GET(addr);
    405             lane = (pll_id == 0) ? 0 : 1;
    406         }
    407     } else { /* PCS register */
    408         mpp_id = TSCBH_MPP_ID_GET(addr);
    409         if (copies == 2) {
    410            lane = 0;
    411         }
    412     }
    413 
    414     /*handle ram read/write*/
    415     if (TSCBH_IS_RAM_DATA_REG(reg) || TSCBH_IS_RAM_ADDR_REG(reg)) {
    416 
    417         if (TSCBH_IS_RAM_DATA_REG(reg)) {
    418             (void)tscbh_sim_read(pms_data, TSCBH_ADDR(devad, pll_id, lane, TSCBH_RAM_RD_ADDR_REG_LS), &addr_ls);
    419             (void)tscbh_sim_read(pms_data, TSCBH_ADDR(devad, pll_id, lane, TSCBH_RAM_RD_ADDR_REG_MS), &addr_ms);
    420             addr = addr_ls | (addr_ms << 16);
    421             if (reg == TSCBH_RAM_RD_DATA_REG_LS || reg == TSCBH_RAM_WR_DATA_REG_LS) {
    422                 pse_flag |= TSCBH_SIM_ENTRY_F_RAM_LS_DATA_ENTRY;
    423             } else {
    424                 pse_flag |= TSCBH_SIM_ENTRY_F_RAM_MS_DATA_ENTRY;
    425             }
    426         } else { /*TSCBH_IS_RAM_ADDR_REG*/
    427             addr = TSCBH_ADDR(devad, 0, lane, 0 /*dummy*/);
    428             if (reg == TSCBH_RAM_RD_ADDR_REG_LS || reg == TSCBH_RAM_WR_ADDR_REG_LS) {
    429                 pse_flag |= TSCBH_SIM_ENTRY_F_RAM_LS_DATA_ENTRY;
    430             } else {
    431                 pse_flag |= TSCBH_SIM_ENTRY_F_RAM_MS_DATA_ENTRY;
    432             }
    433         }
    434 
    435         /* Check if this register has been written already */
    436         for (idx = 0; idx < pms_data->entries_used; idx++) {
    437             pse = &pms_data->entries[idx];
    438             if ((pse->addr == addr) && (pse->flags == pse_flag)) {
    439                 *data = pse->data;
    440                 DBG_VERB(("tscbh_sim_read 0x%08"PRIx32" = 0x%04"PRIx32"\n",
    441                           addr, *data));
    442                 return PHYMOD_E_NONE;
    443             }
    444         }
    445 
    446         *data = 0;
    447         return PHYMOD_E_NONE;
    448     }
    449 
    450 
    451     if (devad == 1) {
    452         addr = TSCBH_ADDR(devad, pll_id, lane, reg);
    453     } else {
    454         addr = TSCBH_ADDR_PCS(devad, mpp_id, lane, reg);
    455     }
    456 
    457     /* Check if this register has been written already */
    458     for (idx = 0; idx < pms_data->entries_used; idx++) {
    459         pse = &pms_data->entries[idx];
    460         if ((pse->addr == addr) && (pse->flags == pse_flag)) {
    461             *data = pse->data;
    462             DBG_VERB(("tscbh_sim_read 0x%08"PRIx32" = 0x%04"PRIx32"\n",
    463                       addr, *data));
    464             return PHYMOD_E_NONE;
    465         }
    466     }
    467 
    468     /* Return default value if register was never written */
    469     *data = tscbh_sim_default_data_get(addr);
    470 
    471     DBG_VERB(("tscbh_sim_read 0x%08"PRIx32" = [0x%04"PRIx32"]\n",
    472               addr, *data));
    473 
    474     return PHYMOD_E_NONE;
    475 }
    476 
    477 STATIC int
    478 tscbh_sim_write(phymod_sim_data_t *pms_data, uint32_t addr, uint32_t data)
    479 {
    480     uint32_t aer, blk, devad, reg, copies, pll_id=0;
    481     uint32_t lane = 0;
    482     uint32_t mpp_id;
    483 
    484     if (pms_data == NULL || pms_data->entries == NULL) {
    485         return PHYMOD_E_INIT;
    486     }
    487 
    488     devad = 0;
    489 
    490     if (addr < TSCBH_BLK) {
    491         /* Assume clause 22 access */
    492         (void)tscbh_sim_read(pms_data, TSCBH_BLK, &blk);
    493         /* IEEE bit */
    494         if (addr & 0x10) {
    495             blk |= 0x8000;
    496         } else {
    497             blk &= ~0x8000;
    498         }
    499         addr = (addr & 0xf) | (blk & 0xfff0);
    500         if (addr != TSCBH_AER && addr != TSCBH_BLK) {
    501             (void)tscbh_sim_read(pms_data, TSCBH_AER, &aer);
    502             addr |= (aer << 16);
    503         }
    504     } else {
    505         /* Extract devad if clause 45 address format */
    506         if ((addr & TSCBH_CL45_MASK) == TSCBH_CL45) {
    507             devad = (addr >> 16) & 0x1f;
    508             addr &= 0xffff;
    509         }
    510     }
    511 
    512     if (addr != TSCBH_AER && addr != TSCBH_BLK) {
    513         /* Assume AER is in upper 16 bits */
    514         aer = (addr >> 16);
    515         if (aer == 0) {
    516             /* Try reading real AER instead */
    517             (void)tscbh_sim_read(pms_data, TSCBH_AER, &aer);
    518         }
    519 
    520         /* Add clause 45 devad (if used) */
    521         aer |= (devad << 11);
    522         addr = (addr & 0xffff) | (aer << 16);
    523         devad = TSCBH_DEVAD_GET(addr);
    524         reg = TSCBH_REG_GET(addr);
    525 
    526         if (devad == 1) { /* Access PMD registers */
    527             lane = (aer & 0xff);
    528             if (lane > 7) {
    529                 /*
    530                  * Handle lane broadcast
    531                  *
    532                  * Note that we use lane 8 instead of lane 0 to prevent a
    533                  * broadcast loop. The value 8 will become 0 when masked
    534                  * with 0x7, but it prevents the AER in the upper 16 bits
    535                  * from being zero, which will cause the code above to
    536                  * obtain the AER value from register 0xffde.
    537                  */
    538 
    539                 pll_id = TSCBH_PLL_ID_GET(addr);
    540                 if (lane == 0x20) {
    541                     /* Write lanes 0 and 1 */
    542                     addr = TSCBH_ADDR(devad, pll_id, 0, reg);
    543                     (void)tscbh_sim_write(pms_data, addr, data);
    544                     addr = TSCBH_ADDR(devad, pll_id, 1, reg);
    545                     (void)tscbh_sim_write(pms_data, addr, data);
    546                 }
    547                 if (lane == 0x21) {
    548                     /* Write lanes 2 and 3 */
    549                     addr = TSCBH_ADDR(devad, pll_id, 2, reg);
    550                     (void)tscbh_sim_write(pms_data, addr, data);
    551                     addr = TSCBH_ADDR(devad, pll_id, 3, reg);
    552                     (void)tscbh_sim_write(pms_data, addr, data);
    553                 }
    554                 if (lane == 0x22) {
    555                     /* Write lanes 4 and 5 */
    556                     addr = TSCBH_ADDR(devad, pll_id, 4, reg);
    557                     (void)tscbh_sim_write(pms_data, addr, data);
    558                     addr = TSCBH_ADDR(devad, pll_id, 5, reg);
    559                     (void)tscbh_sim_write(pms_data, addr, data);
    560                 }
    561                 if (lane == 0x23) {
    562                     /* Write lanes 6 and 7 */
    563                     addr = TSCBH_ADDR(devad, pll_id, 6, reg);
    564                     (void)tscbh_sim_write(pms_data, addr, data);
    565                     addr = TSCBH_ADDR(devad, pll_id, 7, reg);
    566                     (void)tscbh_sim_write(pms_data, addr, data);
    567                 }
    568                 if (lane == 0x40) {
    569                     /* Write lanes 0,1,2,and 3 */
    570                     addr = TSCBH_ADDR(devad, pll_id, 0, reg);
    571                     (void)tscbh_sim_write(pms_data, addr, data);
    572                     addr = TSCBH_ADDR(devad, pll_id, 1, reg);
    573                     (void)tscbh_sim_write(pms_data, addr, data);
    574                     addr = TSCBH_ADDR(devad, pll_id, 2, reg);
    575                     (void)tscbh_sim_write(pms_data, addr, data);
    576                     addr = TSCBH_ADDR(devad, pll_id, 3, reg);
    577                     (void)tscbh_sim_write(pms_data, addr, data);
    578                 }
    579                 if (lane == 0x41) {
    580                     /* Write lanes 4,5,6 and 7 */
    581                     addr = TSCBH_ADDR(devad, pll_id, 4, reg);
    582                     (void)tscbh_sim_write(pms_data, addr, data);
    583                     addr = TSCBH_ADDR(devad, pll_id, 5, reg);
    584                     (void)tscbh_sim_write(pms_data, addr, data);
    585                     addr = TSCBH_ADDR(devad, pll_id, 6, reg);
    586                     (void)tscbh_sim_write(pms_data, addr, data);
    587                     addr = TSCBH_ADDR(devad, pll_id, 7, reg);
    588                     (void)tscbh_sim_write(pms_data, addr, data);
    589                 }
    590                 if (lane == 0xff) {
    591                     /* Write lanes 2 and 3 */
    592                     addr = TSCBH_ADDR(devad, pll_id, 0, reg);
    593                     (void)tscbh_sim_write(pms_data, addr, data);
    594                     addr = TSCBH_ADDR(devad, pll_id, 1, reg);
    595                     (void)tscbh_sim_write(pms_data, addr, data);
    596                     addr = TSCBH_ADDR(devad, pll_id, 2, reg);
    597                     (void)tscbh_sim_write(pms_data, addr, data);
    598                     addr = TSCBH_ADDR(devad, pll_id, 3, reg);
    599                     (void)tscbh_sim_write(pms_data, addr, data);
    600                     addr = TSCBH_ADDR(devad, pll_id, 4, reg);
    601                     (void)tscbh_sim_write(pms_data, addr, data);
    602                     addr = TSCBH_ADDR(devad, pll_id, 5, reg);
    603                     (void)tscbh_sim_write(pms_data, addr, data);
    604                     addr = TSCBH_ADDR(devad, pll_id, 6, reg);
    605                     (void)tscbh_sim_write(pms_data, addr, data);
    606                     addr = TSCBH_ADDR(devad, pll_id, 7, reg);
    607                     (void)tscbh_sim_write(pms_data, addr, data);
    608                 }
    609                 return PHYMOD_E_NONE;
    610             }
    611         } else { /* Access PCS registers */
    612             mpp_id = TSCBH_MPP_ID_GET(addr);
    613             lane = aer & 0x7;
    614             if (lane > 0x6) {
    615                 return PHYMOD_E_PARAM;
    616             }
    617             if (mpp_id == TSCBH_MPP_0_1) {
    618                 addr = TSCBH_ADDR_PCS(devad, TSCBH_MPP_0, lane, reg);
    619                 (void)tscbh_sim_write(pms_data, addr, data);
    620                 addr = TSCBH_ADDR_PCS(devad, TSCBH_MPP_1, lane, reg);
    621                 (void)tscbh_sim_write(pms_data, addr, data);
    622                 return PHYMOD_E_NONE;
    623             } else {
    624                 if (lane > 3) {
    625                     if (lane == 0x4) {
    626                         /* Write lanes 0 and 1 */
    627                         addr = TSCBH_ADDR_PCS(devad, mpp_id, 0, reg);
    628                         (void)tscbh_sim_write(pms_data, addr, data);
    629                         addr = TSCBH_ADDR_PCS(devad, mpp_id, 1, reg);
    630                         (void)tscbh_sim_write(pms_data, addr, data);
    631                     }
    632                     if (lane == 0x5) {
    633                         /* Write lanes 2 and 3 */
    634                         addr = TSCBH_ADDR_PCS(devad, mpp_id, 2, reg);
    635                         (void)tscbh_sim_write(pms_data, addr, data);
    636                         addr = TSCBH_ADDR_PCS(devad, mpp_id, 3, reg);
    637                         (void)tscbh_sim_write(pms_data, addr, data);
    638                     }
    639                     if (lane == 0x6) {
    640                         /* Write lanes 0, 1, 2 and 3 */
    641                         addr = TSCBH_ADDR_PCS(devad, mpp_id, 0, reg);
    642                         (void)tscbh_sim_write(pms_data, addr, data);
    643                         addr = TSCBH_ADDR_PCS(devad, mpp_id, 1, reg);
    644                         (void)tscbh_sim_write(pms_data, addr, data);
    645                         addr = TSCBH_ADDR_PCS(devad, mpp_id, 2, reg);
    646                         (void)tscbh_sim_write(pms_data, addr, data);
    647                         addr = TSCBH_ADDR_PCS(devad, mpp_id, 3, reg);
    648                         (void)tscbh_sim_write(pms_data, addr, data);
    649                     }
    650                     return PHYMOD_E_NONE;
    651                 }
    652             }
    653         }
    654     }
    655 
    656     /* Adjust data and/or related registers */
    657     data = tscbh_sim_write_adjust(pms_data, addr, data);
    658 
    659     /* Adjust lane according to number of copies */
    660     devad = TSCBH_DEVAD_GET(addr);
    661     reg = TSCBH_REG_GET(addr);
    662     copies = tscbh_sim_reg_copies_get(addr);
    663 
    664     if (devad == 1) { /* PMD registers */
    665         if (copies == 1) {
    666             lane = 0;
    667         } else if (copies == 2) {
    668             pll_id = TSCBH_PLL_ID_GET(addr);
    669             lane = (pll_id == 0) ? 0 : 1;
    670         }
    671         addr = TSCBH_ADDR(devad, pll_id, lane, reg);
    672     } else { /* PCS registers */
    673         mpp_id = TSCBH_MPP_ID_GET(addr);
    674         if (copies == 2) {
    675             lane = 0;
    676         }
    677         addr = TSCBH_ADDR_PCS(devad, mpp_id, lane, reg);
    678     }
    679 
    680     return _tscbh_sim_write(pms_data, addr, data);
    681 }
    682 
    683 STATIC int
    684 tscbh_sim_event(phymod_sim_data_t *pms_data, phymod_sim_event_t event)
    685 {
    686     if (pms_data == NULL || pms_data->entries == NULL) {
    687         return PHYMOD_E_INIT;
    688     }
    689 
    690     return PHYMOD_E_NONE;
    691 }
    692 
    693 phymod_sim_drv_t tscbh_sim_drv = {
    694     tscbh_sim_init,
    695     tscbh_sim_reset,
    696     tscbh_sim_read,
    697     tscbh_sim_write,
    698     tscbh_sim_event
    699 };