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

viper_sim.c (15307B)


      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  * Viper 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 #include <phymod/chip/bcmi_viper_xgxs_resetval.h>
     42 
     43 /* Convenience macro */
     44 #define DBG_VERB PHYMOD_DEBUG_VERBOSE
     45 
     46 /* Bit field get/set macros */
     47 #define VIPER_BF_SET(_val, _mask, _shift) _val |= ((_mask) << (_shift))
     48 #define VIPER_BF_GET(_val, _mask, _shift) (((_val) >> (_shift)) & (_mask))
     49 
     50 /*
     51  * Raw 32-bit address consists of AER value in upper 16 bits and
     52  * clause 45 address in lower 16 bits.
     53  */
     54 #define VIPER_DEVAD_SHIFT       27
     55 #define VIPER_DEVAD_MASK        0x1f
     56 #define VIPER_DEVAD_GET(_addr) \
     57     VIPER_BF_GET(_addr, VIPER_DEVAD_MASK, VIPER_DEVAD_SHIFT)
     58 #define VIPER_LANE_SHIFT        16
     59 #define VIPER_LANE_MASK         0x7
     60 #define VIPER_LANE_GET(_addr) \
     61     VIPER_BF_GET(_addr, VIPER_LANE_MASK, VIPER_LANE_SHIFT)
     62 #define VIPER_REG_SHIFT         0
     63 #define VIPER_REG_MASK          0xffff
     64 #define VIPER_REG_GET(_addr) \
     65     VIPER_BF_GET(_addr, VIPER_REG_MASK, VIPER_REG_SHIFT)
     66 
     67 #define VIPER_ADDR(_devad, _lane, _reg) \
     68     (((_devad) << VIPER_DEVAD_SHIFT) +  \
     69      ((_lane) << VIPER_LANE_SHIFT) +    \
     70      ((_reg) << VIPER_REG_SHIFT))
     71 
     72 #define VIPER_AER               VIPER_ADDR(0, 0, 0xffde)
     73 #define VIPER_BLK               VIPER_ADDR(0, 0, 0x001f)
     74 
     75 
     76 /*
     77  * The CL45 indicator is used to determine whether the upper 16 bits
     78  * of the address is an AER value or a clause 45 DEVAD.
     79  */
     80 #define VIPER_CL45              (0x20 << 16)
     81 #define VIPER_CL45_MASK         (0xe0 << 16)
     82 
     83 #define VMOD_ID0       0x0143
     84 #define VMOD_ID1       0xbff0
     85 
     86 #define VXMOD_MODEL    0x02c8
     87 #define VGMOD_MODEL    0x02cf
     88 
     89 /* Forward declarations */
     90 STATIC int
     91 _viper_sim_read(phymod_sim_data_t *pms_data, uint32_t core_type, uint32_t addr, uint32_t *data);
     92 STATIC int
     93 _viper_sim_write(phymod_sim_data_t *pms_data, uint32_t core_type, uint32_t addr, uint32_t data);
     94 
     95 
     96 STATIC uint32_t
     97 viper_sim_default_data_get(uint32_t core_type, uint32_t addr)
     98 {
     99     uint32_t devad, reg;
    100 
    101     devad = VIPER_DEVAD_GET(addr);
    102     reg = VIPER_REG_GET(addr);
    103 
    104     if (devad == 0) {
    105         switch (reg) {
    106             case 0x0002:
    107             case 0xffe2:
    108                 return VMOD_ID0;
    109             case 0x0003:
    110             case 0xffe3:
    111                 return VMOD_ID1;
    112             case 0x8310:
    113                 return (core_type == VXMOD_MODEL ? VXMOD_MODEL : VGMOD_MODEL);
    114             case 0x00000001:
    115                 return 0x109;
    116             default:
    117                 break;
    118         }
    119     }
    120 
    121     
    122     return 0;
    123 }
    124 
    125 STATIC uint32_t
    126 viper_sim_reg_copies_get(uint32_t addr)
    127 {
    128     uint32_t devad, reg;
    129 
    130     devad = VIPER_DEVAD_GET(addr);
    131     reg = VIPER_REG_GET(addr);
    132 
    133     if (reg == VIPER_AER || reg == VIPER_BLK) {
    134         return 1;
    135     }
    136 
    137     if (devad == 0) {
    138         if ((reg & 0xf000) == 0x9000) {
    139             return 1;
    140         }
    141         if ((reg & 0xf000) == 0xa000) {
    142             return 2;
    143         }
    144         return 4;
    145     } else if (devad == 1) {
    146         return 4;
    147     }
    148     return 0;
    149 }
    150 
    151 STATIC uint32_t
    152 viper_sim_write_adjust(phymod_sim_data_t *pms_data, uint32_t core_type, uint32_t addr, uint32_t data)
    153 {
    154     uint32_t devad, reg, val;
    155     uint32_t sgmii_mode = 0, speed_id = 0, duplex_status = 0;
    156 
    157     devad = VIPER_DEVAD_GET(addr);
    158     reg = VIPER_REG_GET(addr);
    159 
    160     if (devad == 0) {
    161         switch (reg) {
    162         case 0xc050:
    163             /* Set SW_SPEED_CHANGE_DONE and SW_SPEED_CONFIG_VLD in status reg */
    164             _viper_sim_write(pms_data, core_type, addr + 1, 0x3);
    165             break;
    166         case 0x0000:
    167             /* Set SPEED_STATUS and DUPLEX_STATUS  in status reg 0x8304  */
    168             _viper_sim_read(pms_data, core_type, addr + 0x8304, &val);
    169             speed_id = (((data >> 6) & 0x1) << 1) | ((data >> 13) & 0x1);
    170             duplex_status = ((data >> 8) & 0x1);
    171             val = (val & 0xfffffffd) | ((duplex_status & 0x1) << 2) | (0x1 << 1);
    172             val = (val & 0xffffffc7) | ((speed_id & 0x3) << 3);
    173             _viper_sim_write(pms_data, core_type, addr + 0x8304, val);
    174             break;
    175         case 0x8300:
    176             /* Set SGMII_MODE in status reg 0x8304 */
    177             _viper_sim_read(pms_data, core_type, addr + 0x4, &val);
    178             sgmii_mode = ((data & 0x1)==1)?0:1;
    179             val = (val & 0xfffffffe) | (sgmii_mode & 0x1) | (0x1 << 1);
    180             _viper_sim_write(pms_data, core_type, addr + 0x4, val);
    181             break;
    182         case 0x8308:
    183             if ((data & 0x1f)==0x10) {   /* 2.5G, set SPEED_STATUS in status reg 0x8304 */
    184                 speed_id = 0x3;
    185                 _viper_sim_read(pms_data, core_type, addr - 0x4, &val);
    186                 val = (val & 0xffffffc7) | ((speed_id & 0x3) << 3) | (0x1 << 1);
    187                 _viper_sim_write(pms_data, core_type, addr - 0x4, val);
    188             } else if ((data & 0x1f)==0x14) { /* 10G, set SPEED_STATUS in status reg 0x8122 */
    189                 speed_id = 0x7;
    190                 _viper_sim_read(pms_data, core_type, addr - 0x1E6, &val);
    191                 val = (val & 0xffffffF0) | (speed_id & 0xF) | (0x1 << 9);
    192                 _viper_sim_write(pms_data, core_type,  addr - 0x1E6, val);
    193             }
    194             break;
    195         default:
    196             break;
    197         }
    198     } else if (devad == 1) {
    199         switch (reg) {
    200         default:
    201             break;
    202         }
    203     }
    204 
    205     return data;
    206 }
    207 
    208 STATIC int
    209 viper_sim_init(phymod_sim_data_t *pms_data,
    210                int num_entries, phymod_sim_entry_t *entries)
    211 {
    212     if (pms_data != NULL) {
    213         PHYMOD_MEMSET(pms_data, 0, sizeof(*pms_data));
    214         pms_data->num_entries = num_entries;
    215         pms_data->entries = entries;
    216     }
    217     return PHYMOD_E_NONE;
    218 }
    219 
    220 STATIC int
    221 viper_sim_reset(phymod_sim_data_t *pms_data)
    222 {
    223     uint32_t sim_size;
    224 
    225     if (pms_data == NULL || pms_data->entries == NULL) {
    226         return PHYMOD_E_INIT;
    227     }
    228 
    229     pms_data->entries_used = 0;
    230     sim_size = pms_data->num_entries * sizeof(phymod_sim_entry_t);
    231     PHYMOD_MEMSET(pms_data->entries, 0, sim_size);
    232 
    233     return PHYMOD_E_NONE;
    234 }
    235 
    236 STATIC int
    237 _viper_sim_read(phymod_sim_data_t *pms_data, uint32_t core_type, uint32_t addr, uint32_t *data)
    238 {
    239     int idx;
    240     uint32_t aer, blk, devad, reg, copies;
    241     uint32_t lane = 0;
    242     phymod_sim_entry_t *pse;
    243 
    244     if (pms_data == NULL || pms_data->entries == NULL) {
    245         return PHYMOD_E_INIT;
    246     }
    247 
    248     devad = 0;
    249 
    250     if (addr < VIPER_BLK) {
    251         /* Assume clause 22 access */
    252         (void)_viper_sim_read(pms_data, core_type, VIPER_BLK, &blk);
    253         /* IEEE bit */
    254         if (addr & 0x10) {
    255             blk |= 0x8000;
    256         } else {
    257             blk &= ~0x8000;
    258         }
    259         addr = (addr & 0xf) | (blk & 0xfff0);
    260         if (addr != VIPER_AER && addr != VIPER_BLK) {
    261             (void)_viper_sim_read(pms_data, core_type, VIPER_AER, &aer);
    262             addr |= (aer << 16);
    263         }
    264     } else {
    265         /* Extract devad if clause 45 address format */
    266         if ((addr & VIPER_CL45_MASK) == VIPER_CL45) {
    267             devad = (addr >> 16) & 0x1f;
    268             addr &= 0xffff;
    269         }
    270     }
    271 
    272     if (addr != VIPER_AER && addr != VIPER_BLK) {
    273         /* Assume AER is in upper 16 bits */
    274         aer = (addr >> 16);
    275         if (aer == 0) {
    276             /* Try reading real AER instead */
    277             (void)_viper_sim_read(pms_data, core_type, VIPER_AER, &aer);
    278         }
    279         /* Add clause 45 devad (if used) */
    280         if (devad) {
    281             aer |= (devad << 11);
    282             addr = (addr & 0xffff) | (aer << 16);
    283         }
    284         lane = (aer & 0x7);
    285         if (lane > 3) {
    286             /* Force lane 0 if lane is invalid */
    287             addr = VIPER_ADDR(VIPER_DEVAD_GET(addr), 0, VIPER_REG_GET(addr));
    288         }
    289     }
    290 
    291     /* Adjust lane according to number of copies */
    292     devad = VIPER_DEVAD_GET(addr);
    293     reg = VIPER_REG_GET(addr);
    294     copies = viper_sim_reg_copies_get(addr);
    295     if (copies == 1) {
    296         lane = 0;
    297     } else if (copies == 2) {
    298         lane &= ~0x1;
    299     }
    300     addr = VIPER_ADDR(devad, lane, reg);
    301 
    302     /* Check if this register has been written already */
    303     for (idx = 0; idx < pms_data->entries_used; idx++) {
    304         pse = &pms_data->entries[idx];
    305         if (pse->addr == addr) {
    306             *data = pse->data;
    307             DBG_VERB(("_viper_sim_read 0x%08"PRIx32" = 0x%04"PRIx32"\n",
    308                       addr, *data));
    309             return PHYMOD_E_NONE;
    310         }
    311     }
    312 
    313     /* Return default value if register was never written */
    314     *data = viper_sim_default_data_get(core_type, addr);
    315 
    316     DBG_VERB(("_viper_sim_read 0x%08"PRIx32" = [0x%04"PRIx32"]\n",
    317               addr, *data));
    318 
    319     return PHYMOD_E_NONE;
    320 }
    321 
    322 STATIC int
    323 _viper_sim_write(phymod_sim_data_t *pms_data, uint32_t core_type, uint32_t addr, uint32_t data)
    324 {
    325     int idx;
    326     uint32_t aer, blk, devad, reg, copies, mask;
    327     uint32_t lane = 0;
    328     phymod_sim_entry_t *pse;
    329 
    330     if (pms_data == NULL || pms_data->entries == NULL) {
    331         return PHYMOD_E_INIT;
    332     }
    333 
    334     devad = 0;
    335 
    336     if (addr < VIPER_BLK) {
    337         /* Assume clause 22 access */
    338         (void)_viper_sim_read(pms_data, core_type, VIPER_BLK, &blk);
    339         /* IEEE bit */
    340         if (addr & 0x10) {
    341             blk |= 0x8000;
    342         } else {
    343             blk &= ~0x8000;
    344         }
    345         addr = (addr & 0xf) | (blk & 0xfff0);
    346         if (addr != VIPER_AER && addr != VIPER_BLK) {
    347             (void)_viper_sim_read(pms_data, core_type, VIPER_AER, &aer);
    348             addr |= (aer << 16);
    349         }
    350     } else {
    351         /* Extract devad if clause 45 address format */
    352         if ((addr & VIPER_CL45_MASK) == VIPER_CL45) {
    353             devad = (addr >> 16) & 0x1f;
    354             addr &= 0xffff;
    355         }
    356     }
    357 
    358     if (addr != VIPER_AER && addr != VIPER_BLK) {
    359         /* Assume AER is in upper 16 bits */
    360         aer = (addr >> 16);
    361         if (aer == 0) {
    362             /* Try reading real AER instead */
    363             (void)_viper_sim_read(pms_data, core_type, VIPER_AER, &aer);
    364         }
    365         /* Add clause 45 devad (if used) */
    366         if (devad) {
    367             aer |= (devad << 11);
    368             addr = (addr & 0xffff) | (aer << 16);
    369         }
    370         lane = (aer & 0x7);
    371         if (lane > 6) {
    372             return PHYMOD_E_PARAM;
    373         }
    374         if (lane > 3) {
    375             /*
    376              * Handle lane broadcast
    377              *
    378              * Note that we use lane 8 instead of lane 0 to prevent a
    379              * broadcast loop. The value 8 will become 0 when masked
    380              * with 0x7, but it prevents the AER in the upper 16 bits
    381              * from being zero, which will cause the code above to
    382              * obtain the AER value from register 0xffde.
    383              */
    384             reg = VIPER_REG_GET(addr);
    385             devad = VIPER_DEVAD_GET(addr);
    386             if (lane == 4 || lane == 6) {
    387                 /* Write lanes 0 and 1 */
    388                 addr = VIPER_ADDR(devad, 8, reg);
    389                 (void)_viper_sim_write(pms_data, core_type, addr, data);
    390                 addr = VIPER_ADDR(devad, 1, reg);
    391                 (void)_viper_sim_write(pms_data, core_type, addr, data);
    392             }
    393             if (lane == 5 || lane == 6) {
    394                 /* Write lanes 2 and 3 */
    395                 addr = VIPER_ADDR(devad, 2, reg);
    396                 (void)_viper_sim_write(pms_data, core_type, addr, data);
    397                 addr = VIPER_ADDR(devad, 3, reg);
    398                 (void)_viper_sim_write(pms_data, core_type, addr, data);
    399             }
    400             return PHYMOD_E_NONE;
    401         }
    402     }
    403 
    404     /* Adjust data and/or related registers */
    405     data = viper_sim_write_adjust(pms_data, core_type, addr, data);
    406 
    407     /* Adjust lane according to number of copies */
    408     devad = VIPER_DEVAD_GET(addr);
    409     reg = VIPER_REG_GET(addr);
    410     copies = viper_sim_reg_copies_get(addr);
    411     if (copies == 1) {
    412         lane = 0;
    413     } else if (copies == 2) {
    414         lane &= ~0x1;
    415     }
    416     addr = VIPER_ADDR(devad, lane, reg);
    417 
    418     /* Support optional write mask in upper 16 bits */
    419     mask = (data >> 16);
    420     if (mask == 0) {
    421         mask = 0xffff;
    422     }
    423     data &= mask;
    424 
    425     /* Check if this register has been written already */
    426     for (idx = 0; idx < pms_data->entries_used; idx++) {
    427         pse = &pms_data->entries[idx];
    428         if (pse->addr == addr) {
    429             pse->data &= ~mask;
    430             pse->data |= data;
    431             DBG_VERB(("_viper_sim_write 0x%08"PRIx32" = 0x%04"PRIx32"\n",
    432                       addr, pse->data));
    433             return PHYMOD_E_NONE;
    434         }
    435     }
    436 
    437     /* Check if database is full */
    438     if (pms_data->entries_used >= pms_data->num_entries) {
    439         return PHYMOD_E_RESOURCE;
    440     }
    441 
    442     /* Check if new data matches default value */
    443     if (data == viper_sim_default_data_get(core_type, addr)) {
    444         return PHYMOD_E_NONE;
    445     }
    446 
    447     /* Add new register value */
    448     pse = &pms_data->entries[pms_data->entries_used++];
    449     pse->addr = addr;
    450     pse->data = data;
    451 
    452     DBG_VERB(("_viper_sim_write 0x%08"PRIx32" = 0x%04"PRIx32" (new)\n",
    453               addr, pse->data));
    454 
    455     return PHYMOD_E_NONE;
    456 }
    457 STATIC int
    458 viper_sim_read(phymod_sim_data_t *pms_data, uint32_t addr, uint32_t *data)
    459 {
    460     return _viper_sim_read(pms_data, VXMOD_MODEL, addr, data);
    461 }
    462 
    463 STATIC int
    464 viper_sim_write(phymod_sim_data_t *pms_data, uint32_t addr, uint32_t data)
    465 {
    466     return _viper_sim_write(pms_data, VXMOD_MODEL, addr, data);
    467 }
    468 
    469 STATIC int
    470 viper_sp2_sim_read(phymod_sim_data_t *pms_data, uint32_t addr, uint32_t *data)
    471 {
    472     return _viper_sim_read(pms_data, VGMOD_MODEL, addr, data);
    473 }
    474 
    475 STATIC int
    476 viper_sp2_sim_write(phymod_sim_data_t *pms_data, uint32_t addr, uint32_t data)
    477 {
    478     return _viper_sim_write(pms_data, VGMOD_MODEL, addr, data);
    479 }
    480 
    481 STATIC int
    482 viper_sim_event(phymod_sim_data_t *pms_data, phymod_sim_event_t event)
    483 {
    484     if (pms_data == NULL || pms_data->entries == NULL) {
    485         return PHYMOD_E_INIT;
    486     }
    487 
    488     return PHYMOD_E_NONE;
    489 }
    490 
    491 phymod_sim_drv_t viper_sim_drv = {
    492     viper_sim_init,
    493     viper_sim_reset,
    494     viper_sim_read,
    495     viper_sim_write,
    496     viper_sim_event
    497 };
    498 
    499 
    500 /* for SGMIIPLUS2 core sim driver */
    501 phymod_sim_drv_t viper_sp2_sim_drv = {
    502     viper_sim_init,
    503     viper_sim_reset,
    504     viper_sp2_sim_read,
    505     viper_sp2_sim_write,
    506     viper_sim_event
    507 };