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

qtce16_sim.c (23974B)


      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 
     42 /* Convenience macro */
     43 #define DBG_VERB PHYMOD_DEBUG_VERBOSE
     44 
     45 /* Bit field get/set macros */
     46 #define QTCE16_BF_SET(_val, _mask, _shift) _val |= ((_mask) << (_shift))
     47 #define QTCE16_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 QTCE16_DEVAD_SHIFT       27
     54 #define QTCE16_DEVAD_MASK        0x1f
     55 #define QTCE16_DEVAD_GET(_addr) \
     56     QTCE16_BF_GET(_addr, QTCE16_DEVAD_MASK, QTCE16_DEVAD_SHIFT)
     57 #define QTCE16_LANE_SHIFT        16
     58 #define QTCE16_LANE_MASK         0x7
     59 #define QTCE16_LANE_GET(_addr) \
     60     QTCE16_BF_GET(_addr, QTCE16_LANE_MASK, QTCE16_LANE_SHIFT)
     61 #define QTCE16_REG_SHIFT         0
     62 #define QTCE16_REG_MASK          0xffff
     63 #define QTCE16_REG_GET(_addr) \
     64     QTCE16_BF_GET(_addr, QTCE16_REG_MASK, QTCE16_REG_SHIFT)
     65 
     66 #define QTCE16_ADDR(_devad, _lane, _reg) \
     67     (((_devad) << QTCE16_DEVAD_SHIFT) +  \
     68      ((_lane) << QTCE16_LANE_SHIFT) +    \
     69      ((_reg) << QTCE16_REG_SHIFT))
     70 
     71 #define QTCE16_AER               QTCE16_ADDR(0, 0, 0xffde)
     72 #define QTCE16_BLK               QTCE16_ADDR(0, 0, 0x001f)
     73 
     74 /*
     75  * The CL45 indicator is used to determine whether the upper 16 bits
     76  * of the address is an AER value or a clause 45 DEVAD.
     77  */
     78 #define QTCE16_CL45              (0x20 << 16)
     79 #define QTCE16_CL45_MASK         (0xe0 << 16)
     80 
     81 #define QTCE16_SIM_FW_LOAD_DONE_REG_ADDR (0x0800d205)
     82 #define QTCE16_SIM_DSC_UC_CTRL_REG_ADDR (0x0800d00d)
     83 
     84 /*RAM sim*/
     85 #define QTCE16_RAM_AHB_CTRL         (0xd202)
     86 #define QTCE16_RAM_WR_ADDR_REG_MS   (0xd205)
     87 #define QTCE16_RAM_WR_ADDR_REG_LS   (0xd204)
     88 #define QTCE16_RAM_WR_DATA_REG_MS   (0xd207)
     89 #define QTCE16_RAM_WR_DATA_REG_LS   (0xd206)
     90 #define QTCE16_RAM_RD_ADDR_REG_MS   (0xd209)
     91 #define QTCE16_RAM_RD_ADDR_REG_LS   (0xd208)
     92 #define QTCE16_RAM_RD_DATA_REG_MS   (0xd20b)
     93 #define QTCE16_RAM_RD_DATA_REG_LS   (0xd20a)
     94 #define QTCE16_IS_RAM_ADDR_REG(reg) (reg == QTCE16_RAM_WR_ADDR_REG_MS || reg == QTCE16_RAM_WR_ADDR_REG_LS || reg == QTCE16_RAM_RD_ADDR_REG_MS || reg == QTCE16_RAM_RD_ADDR_REG_LS)
     95 #define QTCE16_IS_RAM_DATA_REG(reg) (reg == QTCE16_RAM_WR_DATA_REG_MS || reg == QTCE16_RAM_WR_DATA_REG_LS || reg == QTCE16_RAM_RD_DATA_REG_MS || reg == QTCE16_RAM_RD_DATA_REG_LS)
     96 
     97 #define QTCE16_SIM_ENTRY_F_RAM_LS_DATA_ENTRY (0x1)
     98 #define QTCE16_SIM_ENTRY_F_RAM_MS_DATA_ENTRY (0x2)
     99 #define QTCE16_SIM_ENTRY_F_RAM_LS_ADDR_ENTRY (0x4)
    100 #define QTCE16_SIM_ENTRY_F_RAM_MS_ADDR_ENTRY (0x8)
    101 
    102 #define QTCE16_UC_TABLE_RAM_BASE  (0x100)
    103 #define QTCE16_UC_TABLE_RAM_SIZE  (56)
    104 static uint16_t qtce16_uc_mem_table[QTCE16_UC_TABLE_RAM_SIZE] =
    105 {
    106     0x6e49, 0x3566, 0x010c, 0x00d1, 0x0300, 0x0100, 0x2404, 0x0100, 0x0100, 0x2000, 0x0400, 0x2000,
    107     0x0,    0x0,    0x0500, 0x2000, 0x0008, 0x0,    0x0080, 0x0040, 0x0424, 0x2000, 0x0e00, 0x2000,
    108     0x0a00, 0x2000, 0x0010, 0x0,    0x0900, 0x2000, 0x0444, 0x2000, 0x0,    0x0,    0x0,    0x0,
    109     0x0,    0x0,    0x0,    0x0,    0x0,    0x0,    0x0,    0x0,    0x0,    0x0,    0x0,    0x0,
    110     0x1,    0x0,    0x0,    0x0,    0x0,    0x0,    0x0,    0x0
    111 };
    112 static int qtce16_ram_addr;
    113 
    114 /* Forward declarations */
    115 STATIC int
    116 qtce16_sim_write(phymod_sim_data_t *pms_data, uint32_t addr, uint32_t data);
    117 STATIC int
    118 qtce16_sim_read(phymod_sim_data_t *pms_data, uint32_t addr, uint32_t *data);
    119 
    120 STATIC uint32_t
    121 qtce16_sim_default_data_get(uint32_t addr)
    122 {
    123     uint32_t devad, reg;
    124 
    125     /*force FW load success */
    126     if(addr == QTCE16_SIM_FW_LOAD_DONE_REG_ADDR) {
    127         return (1 << 15);
    128     }
    129 
    130     devad = QTCE16_DEVAD_GET(addr);
    131     reg = QTCE16_REG_GET(addr);
    132 
    133     if (devad == 0) {
    134         switch (reg) {
    135         case 0x0002:
    136             return 0x600d;
    137         case 0x0003:
    138             return 0x8770;
    139         case 0x9007: /* MAIN_SERDESID */
    140             return 0x0316;
    141         case 0xc041: /* sc_x4_final_config_status_sp(0)_A */
    142         case 0xc051: /* sc_x4_final_config_status_sp(1)_A */
    143         case 0xc061: /* sc_x4_final_config_status_sp(2)_A */
    144         case 0xc071: /* sc_x4_final_config_status_sp(3)_A */
    145             return 0x20;
    146             /*
    147         case 0xc020:  sc_x4_control_control 
    148             return 0x1ff;
    149             */
    150         case 0xc179: 
    151             return 0xff;
    152         default:
    153             break;
    154         }
    155     } else if (devad == 1) {
    156         switch (reg) {
    157         case 0xd205: /* UC_DOWNLOAD_STS */
    158             return 0x0080;
    159         case 0xd089:
    160             return 0x0007;
    161         case 0xd0f8:
    162             return 0x0007;
    163         case 0xd0fa:
    164             return 0x403c;
    165         case 0xd0a2:
    166             return 0x5250;
    167         case 0xd0b1:
    168             return 0x0007;
    169         case 0xd0b4:
    170             return 0x0500;
    171         case 0xd0b8:
    172             return 0x4042;
    173         case 0xd0c1:
    174             return 0x0008;
    175         case 0xd0d2:
    176             return 0x000e;
    177         case 0xd0e2:
    178             return 0x0002;
    179         case 0xd0f4:
    180             /* this is not the default value. value is changed to pass through
    181              * core int.
    182              */
    183             return 0x0271;
    184         case 0xd111:
    185             return 0x0020;
    186         case 0xd189:
    187             return 0x0007;
    188         case 0xd203:
    189             /* this is not the default value. value is changed to pass through
    190              * core init.
    191              */
    192             return 0x1;
    193         default:
    194             break;
    195         }
    196     }
    197 
    198     return 0;
    199 }
    200 
    201 STATIC uint32_t
    202 qtce16_sim_reg_copies_get(uint32_t addr)
    203 {
    204     uint32_t devad, reg;
    205 
    206     devad = QTCE16_DEVAD_GET(addr);
    207     reg = QTCE16_REG_GET(addr);
    208 
    209     if (reg == QTCE16_AER || reg == QTCE16_BLK) {
    210         return 1;
    211     }
    212 
    213     if (devad == 0) {
    214         if ((reg & 0xf000) == 0x9000) {
    215             return 1;
    216         }
    217         if ((reg & 0xf000) == 0xa000) {
    218             return 2;
    219         }
    220         return 4;
    221     } else if (devad == 1) {
    222         if ((reg & 0xffff) == 0xd0b8) {
    223             return 1;
    224         }
    225         return 4;
    226     }
    227     return 0;
    228 }
    229 
    230 STATIC int
    231 _qtce16_sim_write(phymod_sim_data_t *pms_data, uint32_t addr, uint32_t data)
    232 {
    233     int idx;
    234     uint32_t mask;
    235 
    236     phymod_sim_entry_t *pse;
    237 
    238     if (pms_data == NULL || pms_data->entries == NULL) {
    239         return PHYMOD_E_INIT;
    240     }
    241 
    242     /* Support optional write mask in upper 16 bits */
    243     mask = (data >> 16);
    244     if (mask == 0) {
    245         mask = 0xffff;
    246     }
    247     data &= mask;
    248 
    249     /* Check if this register has been written already */
    250     for (idx = 0; idx < pms_data->entries_used; idx++) {
    251         pse = &pms_data->entries[idx];
    252         if (pse->addr == addr) {
    253             pse->data &= ~mask;
    254             pse->data |= data;
    255             DBG_VERB(("_qtce16_sim_write 0x%08"PRIx32" = 0x%04"PRIx32"\n",
    256                       addr, pse->data));
    257             return PHYMOD_E_NONE;
    258         }
    259     }
    260 
    261     /* Check if database is full */
    262     if (pms_data->entries_used >= pms_data->num_entries) {
    263         return PHYMOD_E_RESOURCE;
    264     }
    265 
    266     /* Check if new data matches default value */
    267     if (data == qtce16_sim_default_data_get(addr)) {
    268         return PHYMOD_E_NONE;
    269     }
    270 
    271     /* Add new register value */
    272     pse = &pms_data->entries[pms_data->entries_used++];
    273     pse->addr = addr;
    274     pse->data = data;
    275 
    276     DBG_VERB(("_qtce16_sim_write 0x%08"PRIx32" = 0x%04"PRIx32" (new)\n",
    277               addr, pse->data));
    278 
    279     return PHYMOD_E_NONE;
    280 }
    281 
    282 STATIC uint32_t
    283 qtce16_sim_write_adjust(phymod_sim_data_t *pms_data, uint32_t addr, uint32_t data)
    284 {
    285     uint32_t devad, reg;
    286     uint32_t addr_tmp, data_tmp, data_r;
    287     uint32_t i, mask;
    288 
    289     devad = QTCE16_DEVAD_GET(addr);
    290     reg = QTCE16_REG_GET(addr);
    291 
    292     if (devad == 0) {
    293         switch (reg) {
    294         case 0xc020:
    295             
    296             /* Set SW_SPEED_CHANGE_DONE and SW_SPEED_CONFIG_VLD in status reg */
    297             qtce16_sim_write(pms_data, addr + 2, 0x3);
    298             /* Sync speed to  0xc040 sc_x4_final_config_status_sp0_resolved_speed */
    299             qtce16_sim_write(pms_data, addr + 0x20, data & 0xff);
    300             /* Set 0xc179 RX_X4_Status0_pcs_live_status and 0xc178 RX_X4_Status0_pcs_latched_status. force all ports link up */
    301             qtce16_sim_write(pms_data, addr + 0x158, 0x0);
    302             qtce16_sim_write(pms_data, addr + 0x159, 0xff);
    303             break;
    304         case 0xc021:
    305             mask = (data >> 16);
    306             if (mask == 0) {
    307                 mask = 0xffff;
    308             }
    309 
    310             qtce16_sim_read(pms_data, addr, &data_r);
    311             data_r &= ~mask;
    312             data |= data_r;
    313 
    314             for (i = 0; i < 4; i++) {
    315                 /* for QSGMII resolved speed. register 0xc041 */
    316                 addr_tmp = addr + 0x20 + i*0x10;
    317                 data_tmp = (data >> i*2) & 0x3; /* 0: 1G, 1: 100M, 2: 10M  for 0xc021*/
    318                 data_tmp =  data_tmp == 0 ? 2 : data_tmp == 1 ? 0 : 1;  /* 0: 100M, 1: 10M, 2: 1G for 0xc041  */
    319                 qtce16_sim_read(pms_data, addr_tmp, &data_r);
    320                 qtce16_sim_write(pms_data, addr_tmp, ((data_r & 0xffcf) |  (data_tmp << 4)));
    321 
    322                 /* for USXGMII resolved speed, register 0xc040 */
    323                 addr_tmp = addr + 0x1f + i*0x10;
    324                 data_tmp = (data >> i*2) & 0x3; /* 0: 1G, 1: 100M, 2: 10M, 3: USXGMII 2.5G  for 0xc021*/
    325                 data_tmp =  data_tmp == 0 ? 3 : data_tmp == 1 ? 2 : data_tmp == 2 ? 1 : 0x48;  /* 1: 10M, 2: 100M, 3: 1G, 0x48: 2.5G for 0xc040  */
    326                 qtce16_sim_read(pms_data, addr_tmp, &data_r);
    327                 qtce16_sim_write(pms_data, addr_tmp, ((data_r & 0xff00) |  (data_tmp)));
    328              }
    329             break;
    330         default:
    331             break;
    332         }
    333     } else if (devad == 1) {
    334         switch (reg) {
    335         case 0xd127:
    336             /* Sync configured all lanes' PLL_CAL_CTL7 register. Only one PLL/VCO per core */
    337             /* Write lanes 0, 1, 2 and 3 */
    338             addr = QTCE16_ADDR(devad, 0, reg);
    339             (void)_qtce16_sim_write(pms_data, addr, data);
    340 
    341             addr = QTCE16_ADDR(devad, 1, reg);
    342             (void)_qtce16_sim_write(pms_data, addr, data);
    343 
    344             addr = QTCE16_ADDR(devad, 2, reg);
    345             (void)_qtce16_sim_write(pms_data, addr, data);
    346 
    347             addr = QTCE16_ADDR(devad, 3, reg);
    348             (void)_qtce16_sim_write(pms_data, addr, data);
    349             break;
    350          case 0xd201:
    351             /* Active uC (0xd0f4) when reset uC (0xd201) */
    352             if (data & 0x2) {
    353                 qtce16_sim_read(pms_data, (addr - 0x10d), &data_tmp);
    354                 _qtce16_sim_write(pms_data, (addr - 0x10d), (data_tmp | 0x8000));
    355 
    356                 /* reset ram memory address */
    357                 qtce16_ram_addr = 0;
    358             }
    359             break;
    360         case 0xd203:
    361             /* write data register to UC_RAM_WRDATA(0xd203)
    362              * read data register from UC_RAM_RDDATA(0xd204)
    363              */
    364             _qtce16_sim_write(pms_data, addr + 1, data);
    365             break;
    366         case 0xd0c1:
    367             /* Sync configured SIGDET_CTL1 register. When a port is set disable,
    368              * the port's RX_X4_PCS_LIVE_STS register deletes link status.
    369              * RX_X4_PCS_LIVE_STS register is PCS register, so need set devad to 0.
    370              * 0xF48 = 0xd0c1 - 0xc179*/
    371             qtce16_sim_read(pms_data, (addr - 0xF48) & 0x7ffff, &data_r);
    372             data_r = (data_r & 0xff00) | (((data & 0x80) == 0x80) ? 0 : 0xff);
    373             qtce16_sim_write(pms_data, (addr - 0xF48) & 0x7ffff, data_r);
    374             break;
    375         default:
    376             break;
    377         }
    378     }
    379 
    380     return data;
    381 }
    382 
    383 STATIC int
    384 qtce16_sim_init(phymod_sim_data_t *pms_data,
    385                int num_entries, phymod_sim_entry_t *entries)
    386 {
    387     if (pms_data != NULL) {
    388         PHYMOD_MEMSET(pms_data, 0, sizeof(*pms_data));
    389         pms_data->num_entries = num_entries;
    390         pms_data->entries = entries;
    391     }
    392 
    393     return PHYMOD_E_NONE;
    394 }
    395 
    396 STATIC int
    397 qtce16_sim_reset(phymod_sim_data_t *pms_data)
    398 {
    399     uint32_t sim_size;
    400 
    401     if (pms_data == NULL || pms_data->entries == NULL) {
    402         return PHYMOD_E_INIT;
    403     }
    404 
    405     pms_data->entries_used = 0;
    406     sim_size = pms_data->num_entries * sizeof(phymod_sim_entry_t);
    407     PHYMOD_MEMSET(pms_data->entries, 0, sim_size);
    408 
    409     return PHYMOD_E_NONE;
    410 }
    411 
    412 STATIC int
    413 qtce16_sim_read(phymod_sim_data_t *pms_data, uint32_t addr, uint32_t *data)
    414 {
    415     int idx;
    416     uint32_t aer, blk, devad, reg, copies;
    417     uint32_t lane = 0;
    418     phymod_sim_entry_t *pse;
    419     uint32_t addr_ms = 0, addr_ls = 0, abh_ctrl = 0;
    420     uint32_t pse_flag = 0;
    421     int increase_addr_auto = 0;
    422 
    423     if (pms_data == NULL || pms_data->entries == NULL) {
    424         return PHYMOD_E_INIT;
    425     }
    426 
    427     devad = 0;
    428 
    429     if (addr < QTCE16_BLK) {
    430         /* Assume clause 22 access */
    431         (void)qtce16_sim_read(pms_data, QTCE16_BLK, &blk);
    432         /* IEEE bit */
    433         if (addr & 0x10) {
    434             blk |= 0x8000;
    435         } else {
    436             blk &= ~0x8000;
    437         }
    438         addr = (addr & 0xf) | (blk & 0xfff0);
    439         if (addr != QTCE16_AER && addr != QTCE16_BLK) {
    440             (void)qtce16_sim_read(pms_data, QTCE16_AER, &aer);
    441             addr |= (aer << 16);
    442         }
    443     } else {
    444         /* Extract devad if clause 45 address format */
    445         if ((addr & QTCE16_CL45_MASK) == QTCE16_CL45) {
    446             devad = (addr >> 16) & 0x1f;
    447             addr &= 0xffff;
    448         }
    449     }
    450 
    451     if (addr != QTCE16_AER && addr != QTCE16_BLK) {
    452         /* Assume AER is in upper 16 bits */
    453         aer = (addr >> 16);
    454         if (aer == 0) {
    455             /* Try reading real AER instead */
    456             (void)qtce16_sim_read(pms_data, QTCE16_AER, &aer);
    457         }
    458         /* Add clause 45 devad (if used) */
    459         if (devad) {
    460             aer |= (devad << 11);
    461             addr = (addr & 0xffff) | (aer << 16);
    462         }
    463         lane = (aer & 0x7);
    464         if (lane > 3) {
    465             /* Force lane 0 if lane is invalid */
    466             addr = QTCE16_ADDR(QTCE16_DEVAD_GET(addr), 0, QTCE16_REG_GET(addr));
    467         }
    468     }
    469 
    470     /* Adjust lane according to number of copies */
    471     devad = QTCE16_DEVAD_GET(addr);
    472     reg = QTCE16_REG_GET(addr);
    473     copies = qtce16_sim_reg_copies_get(addr);
    474     if (copies == 1) {
    475         lane = 0;
    476     } else if (copies == 2) {
    477         lane &= ~0x1;
    478     }
    479 
    480     /*handle ram read/write*/
    481     if (QTCE16_IS_RAM_DATA_REG(reg) || QTCE16_IS_RAM_ADDR_REG(reg)) {
    482 
    483         if (QTCE16_IS_RAM_DATA_REG(reg)) {
    484             (void)qtce16_sim_read(pms_data, QTCE16_ADDR(devad, lane, QTCE16_RAM_AHB_CTRL), &abh_ctrl);
    485             increase_addr_auto = ((abh_ctrl >> 13) & 0x1);
    486 
    487             (void)qtce16_sim_read(pms_data, QTCE16_ADDR(devad, lane, QTCE16_RAM_RD_ADDR_REG_LS), &addr_ls);
    488             (void)qtce16_sim_read(pms_data, QTCE16_ADDR(devad, lane, QTCE16_RAM_RD_ADDR_REG_MS), &addr_ms);
    489             addr = addr_ls | (addr_ms << 16);
    490 
    491             if (qtce16_ram_addr == 0 ) {
    492                 qtce16_ram_addr = addr;
    493             } else {
    494                 if (increase_addr_auto) {
    495                     qtce16_ram_addr += 1;
    496                 } else {
    497                     qtce16_ram_addr = 0;
    498                 }
    499             }
    500 
    501             if (reg == QTCE16_RAM_RD_DATA_REG_LS || reg == QTCE16_RAM_WR_DATA_REG_LS) {
    502                 pse_flag |= QTCE16_SIM_ENTRY_F_RAM_LS_DATA_ENTRY;
    503             } else {
    504                 pse_flag |= QTCE16_SIM_ENTRY_F_RAM_MS_DATA_ENTRY;
    505             }
    506         } else { /*QTCE16_IS_RAM_ADDR_REG*/
    507             addr = QTCE16_ADDR(devad, lane, 0 /*dummy*/);
    508             if (reg == QTCE16_RAM_RD_ADDR_REG_LS || reg == QTCE16_RAM_WR_ADDR_REG_LS) {
    509                 pse_flag |= QTCE16_SIM_ENTRY_F_RAM_LS_ADDR_ENTRY;
    510             } else {
    511                 pse_flag |= QTCE16_SIM_ENTRY_F_RAM_MS_ADDR_ENTRY;
    512             }
    513         }
    514 
    515         /* Check if this register has been written already */
    516         for (idx = 0; idx < pms_data->entries_used; idx++) {
    517             pse = &pms_data->entries[idx];
    518             if ((pse->addr == addr) && (pse->flags == pse_flag)) {
    519                 *data = pse->data;
    520                 DBG_VERB(("qtce16_sim_read 0x%08"PRIx32" = 0x%04"PRIx32"\n",
    521                           addr, *data));
    522                 return PHYMOD_E_NONE;
    523             }
    524         }
    525 
    526         if((qtce16_ram_addr >= QTCE16_UC_TABLE_RAM_BASE) && (qtce16_ram_addr < (QTCE16_UC_TABLE_RAM_BASE + QTCE16_UC_TABLE_RAM_SIZE))) {
    527             *data = qtce16_uc_mem_table[qtce16_ram_addr - QTCE16_UC_TABLE_RAM_BASE];
    528         }else {
    529             *data = 0;
    530         }
    531 
    532         return PHYMOD_E_NONE;
    533     }
    534 
    535     addr = QTCE16_ADDR(devad, lane, reg);
    536 
    537     if (addr == 0x800d00d) { /* DSC_UC_CTL:UC_DSC_READY_FOR_CMD */
    538         *data = 0x80;
    539         return PHYMOD_E_NONE;
    540     } else if (addr == 0x800d00e) { /* DSC_SCRATCH */
    541         *data = 0xf6c0; /* expected CRC */
    542         return PHYMOD_E_NONE;
    543     }
    544 
    545     /* Check if this register has been written already */
    546     for (idx = 0; idx < pms_data->entries_used; idx++) {
    547         pse = &pms_data->entries[idx];
    548         if (pse->addr == addr) {
    549             *data = pse->data;
    550             DBG_VERB(("qtce16_sim_read 0x%08"PRIx32" = 0x%04"PRIx32"\n",
    551                       addr, *data));
    552             return PHYMOD_E_NONE;
    553         }
    554     }
    555 
    556     /* Return default value if register was never written */
    557     *data = qtce16_sim_default_data_get(addr);
    558 
    559     DBG_VERB(("qtce16_sim_read 0x%08"PRIx32" = [0x%04"PRIx32"]\n",
    560               addr, *data));
    561 
    562     return PHYMOD_E_NONE;
    563 }
    564 
    565 STATIC int
    566 qtce16_sim_write(phymod_sim_data_t *pms_data, uint32_t addr, uint32_t data)
    567 {
    568     int idx;
    569     uint32_t aer, blk, devad, reg, copies;
    570     uint32_t lane = 0;
    571     phymod_sim_entry_t *pse;
    572     uint32_t pse_flag = 0;
    573     uint32_t addr_ms = 0, addr_ls = 0;
    574 
    575     if (pms_data == NULL || pms_data->entries == NULL) {
    576         return PHYMOD_E_INIT;
    577     }
    578 
    579     devad = 0;
    580 
    581     if (addr < QTCE16_BLK) {
    582         /* Assume clause 22 access */
    583         (void)qtce16_sim_read(pms_data, QTCE16_BLK, &blk);
    584         /* IEEE bit */
    585         if (addr & 0x10) {
    586             blk |= 0x8000;
    587         } else {
    588             blk &= ~0x8000;
    589         }
    590         addr = (addr & 0xf) | (blk & 0xfff0);
    591         if (addr != QTCE16_AER && addr != QTCE16_BLK) {
    592             (void)qtce16_sim_read(pms_data, QTCE16_AER, &aer);
    593             addr |= (aer << 16);
    594         }
    595     } else {
    596         /* Extract devad if clause 45 address format */
    597         if ((addr & QTCE16_CL45_MASK) == QTCE16_CL45) {
    598             devad = (addr >> 16) & 0x1f;
    599             addr &= 0xffff;
    600         }
    601     }
    602 
    603     if (addr != QTCE16_AER && addr != QTCE16_BLK) {
    604         /* Assume AER is in upper 16 bits */
    605         aer = (addr >> 16);
    606         if (aer == 0) {
    607             /* Try reading real AER instead */
    608             (void)qtce16_sim_read(pms_data, QTCE16_AER, &aer);
    609         }
    610         /* Add clause 45 devad (if used) */
    611         if (devad) {
    612             aer |= (devad << 11);
    613             addr = (addr & 0xffff) | (aer << 16);
    614         }
    615         lane = (aer & 0x7);
    616         if (lane > 6) {
    617             return PHYMOD_E_PARAM;
    618         }
    619         if (lane > 3) {
    620             /*
    621              * Handle lane broadcast
    622              *
    623              * Note that we use lane 8 instead of lane 0 to prevent a
    624              * broadcast loop. The value 8 will become 0 when masked
    625              * with 0x7, but it prevents the AER in the upper 16 bits
    626              * from being zero, which will cause the code above to
    627              * obtain the AER value from register 0xffde.
    628              */
    629             reg = QTCE16_REG_GET(addr);
    630             devad = QTCE16_DEVAD_GET(addr);
    631             if (lane == 4 || lane == 6) {
    632                 /* Write lanes 0 and 1 */
    633                 addr = QTCE16_ADDR(devad, 8, reg);
    634                 (void)qtce16_sim_write(pms_data, addr, data);
    635                 addr = QTCE16_ADDR(devad, 1, reg);
    636                 (void)qtce16_sim_write(pms_data, addr, data);
    637             }
    638             if (lane == 5 || lane == 6) {
    639                 /* Write lanes 2 and 3 */
    640                 addr = QTCE16_ADDR(devad, 2, reg);
    641                 (void)qtce16_sim_write(pms_data, addr, data);
    642                 addr = QTCE16_ADDR(devad, 3, reg);
    643                 (void)qtce16_sim_write(pms_data, addr, data);
    644             }
    645             return PHYMOD_E_NONE;
    646         }
    647     }
    648 
    649     /* Adjust data and/or related registers */
    650     data = qtce16_sim_write_adjust(pms_data, addr, data);
    651 
    652     /* Adjust lane according to number of copies */
    653     devad = QTCE16_DEVAD_GET(addr);
    654     reg = QTCE16_REG_GET(addr);
    655     copies = qtce16_sim_reg_copies_get(addr);
    656     if (copies == 1) {
    657         lane = 0;
    658     } else if (copies == 2) {
    659         lane &= ~0x1;
    660     }
    661 
    662     if (QTCE16_IS_RAM_DATA_REG(reg) || QTCE16_IS_RAM_ADDR_REG(reg)) {
    663 
    664         if (QTCE16_IS_RAM_DATA_REG(reg)) {
    665             (void)qtce16_sim_read(pms_data, QTCE16_ADDR(devad, lane, QTCE16_RAM_RD_ADDR_REG_LS), &addr_ls);
    666             (void)qtce16_sim_read(pms_data, QTCE16_ADDR(devad, lane, QTCE16_RAM_RD_ADDR_REG_MS), &addr_ms);
    667             addr = addr_ls | (addr_ms << 16);
    668             if (reg == QTCE16_RAM_RD_DATA_REG_LS || reg == QTCE16_RAM_WR_DATA_REG_LS) {
    669                 pse_flag |= QTCE16_SIM_ENTRY_F_RAM_LS_DATA_ENTRY;
    670             } else {
    671                 pse_flag |= QTCE16_SIM_ENTRY_F_RAM_MS_DATA_ENTRY;
    672             }
    673         } else { /*QTCE16_IS_RAM_ADDR_REG*/
    674             addr = QTCE16_ADDR(devad, lane, 0/*dummy*/);
    675             if (reg == QTCE16_RAM_RD_ADDR_REG_LS || reg == QTCE16_RAM_WR_ADDR_REG_LS) {
    676                 pse_flag |= QTCE16_SIM_ENTRY_F_RAM_LS_ADDR_ENTRY;
    677             } else {
    678                 pse_flag |= QTCE16_SIM_ENTRY_F_RAM_MS_ADDR_ENTRY;
    679             }
    680         }
    681 
    682         /* Check if this register has been written already */
    683         for (idx = 0; idx < pms_data->entries_used; idx++) {
    684             pse = &pms_data->entries[idx];
    685             if ((pse->addr == addr) && (pse->flags == pse_flag)) {
    686                 pse->data = data;
    687                 DBG_VERB(("qtce16_sim_write 0x%08"PRIx32" = 0x%04"PRIx32" - flag = %u \n",
    688                           addr, pse->data, pse_flag));
    689                 return PHYMOD_E_NONE;
    690             }
    691         }
    692 
    693         pse = &pms_data->entries[pms_data->entries_used++];
    694         pse->addr = addr;
    695         pse->data = data;
    696         pse->flags = pse_flag;
    697 
    698         DBG_VERB(("qtce16_sim_write 0x%08"PRIx32" = 0x%04"PRIx32"  - flag = %u (new)\n",
    699               addr, pse->data, pse->flags));
    700 
    701         return PHYMOD_E_NONE;
    702     }
    703 
    704     addr = QTCE16_ADDR(devad, lane, reg);
    705 
    706     return _qtce16_sim_write(pms_data, addr, data);;
    707 }
    708 
    709 STATIC int
    710 qtce16_sim_event(phymod_sim_data_t *pms_data, phymod_sim_event_t event)
    711 {
    712     if (pms_data == NULL || pms_data->entries == NULL) {
    713         return PHYMOD_E_INIT;
    714     }
    715 
    716     return PHYMOD_E_NONE;
    717 }
    718 
    719 phymod_sim_drv_t qtce16_sim_drv = {
    720     qtce16_sim_init,
    721     qtce16_sim_reset,
    722     qtce16_sim_read,
    723     qtce16_sim_write,
    724     qtce16_sim_event
    725 };
    726