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 };