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