w229b.c (23816B)
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 * BCM56xx I2C Device Driver for Cypress W229B/W311 Clock generator (PLL) chip. 8 * The W229b is a highly integrated frequency timing generator, 9 * supplying a variety of common clock sources. 10 * 11 * The W311 is a more robust version of the W229b which allows for 12 * read capability and arbitrary SMB byte, word, or block operations. 13 * 14 * This driver supports both the W229b (for downward compatibility 15 * with older 5605 baseboards) as well as the W311 chip. In order to 16 * determine if we are running in W311 mode, we attempt to read the 17 * W311 device and vendor Id from register offset 8; if this succeeds, 18 * then we assume that we are communicating with a W311. 19 * 20 * The W229b clock frequency configuration is table driven, the W311 21 * uses M and N values to set the clock frequency. In addition, the 22 * W311 allows setting of the clock frequency and then later reading 23 * it back. 24 * 25 * On Broadcom BCM95605 baseboards, the W229b clock chip is used to 26 * supply the 5605/5606 baseboard with a core clock. On new Broadcom 27 * BCM5605 baseboards and 48port (p48) boards, the W311 chip is used 28 * instead. 29 * 30 * In W229b data sheet, the CPU clock is the switch core clock in 31 * Table 4. The same holds true for the W311. 32 * 33 * For W229b, in the ioctl interface to this driver, if the clock 34 * value supplied is in between the higher and lower value, we pick 35 * the lower value. 36 * 37 * See the Cypress W229B/W311 Clock chip data sheet(s) for more details. 38 */ 39 #include <sal/types.h> 40 #include <soc/debug.h> 41 #include <soc/drv.h> 42 #include <soc/error.h> 43 #include <soc/i2c.h> 44 #include <shared/bsl.h> 45 /* W229B Command code : Always Zero */ 46 #define W229B_COMM_CODE 0x00000000 47 #define W229B_N_REGS 7 /* Bytes 0 - 6 */ 48 49 /* 50 * Definitions for Control Byte 4: SEL bits for freq select 51 * Return byte represent SEL values with FS override set (SEL selects 52 * the operating frequency). Used for both W229/W311 clock chips. 53 */ 54 #define W229_SPEED(s4, s3, s2, s1, s0)\ 55 ( (s3 << 7) | (s2 << 6) | (s1 << 5)|(s0 << 4)|(1 << 3)|(s4 << 2) ) 56 57 #define W311_SPEED(s4, s3, s2, s1, s0)\ 58 ( (s4 << 5) | (s3 << 4) | (s2 << 3)|(s1 << 2)|(s0 << 1)|s0) 59 60 61 /* W229b: Min Freq = 66Mhz, Max = 166Mhz */ 62 #define W229B_MIN_SPEED 66000000 63 #define W229B_MAX_SPEED 166000000 64 65 /* W229b: Default Control/Reserved registers: Bytes0-3 */ 66 #define W229B_R0 0x06 67 #define W229B_R1 0xff 68 #define W229B_R2 0xff 69 #define W229B_R3 0x08 70 #define W229B_CNT 5 /* 5 byte SMB block write */ 71 72 /* Constants for conversions */ 73 #define MHZ 1000*1000 74 #define Megahertz(x) ((x)*MHZ) 75 76 /* W311 Definitions */ 77 #define W311_ID_REG 0x08 78 #define W311_CTRL_REG1 0x01 79 #define W311_N_REG 0X0d /* N Register */ 80 #define W311_M_REG 0x0e /* M Register (and programmable freq enable)*/ 81 #ifdef COMPILER_HAS_DOUBLE 82 #define W311_GEAR_CONSTANT 48.00741 83 #else 84 #define W311_GEAR_CONSTANT 48007410 85 #endif 86 #define W311_M_LOWSPEED 93 /* 50-129 Mhz */ 87 #define W311_M_HIGHSPEED 45 /* 130-248 Mhz */ 88 #define W311_FS_REG 0x0f /* Reserved reg for latched FS_Sel bits */ 89 90 /* Byte or Word Command Operationse */ 91 #define W311_COMM_CODE(addr) (0x80|(addr)) 92 93 /* Min and Max clock output values */ 94 #define W311_MIN_CLOCK 50 95 #define W311_MAX_CLOCK 258 96 97 /* Low scale Mhz range for LOWSPEED M value, in this range of 98 * frequencies, clock output is tunable to 0.5Mhz resolution! 99 * So, 126.5 is possible, however 132.5 is not. 100 */ 101 #define W311_LOW_MIN 50 102 #define W311_LOW_MAX 129 103 104 /* Spread spectrum defines for W311 clock chip. 105 * Bit definitions for Byte 1 (Control register 1) 106 */ 107 #define W311_SS_CLEAR 0x0f 108 #define W311_SS_TRISTATE (0x30) 109 #define W311_SS_ENABLE_NEG5 (0x40) 110 #define W311_SS_ENABLE_5_5 (0x50) 111 #define W311_SS_ENABLE_2_5 (0x60) 112 #define W311_SS_ENABLE_3_8 (0x70) 113 114 /* Useful macros */ 115 #define W311_SS_SET_DISABLE(x) ((x) & W311_SS_CLEAR) 116 #define W311_SS_SET_ENABLE_NEG5(x) ((x) | W311_SS_ENABLE_NEG5) /* -0.50% */ 117 #define W311_SS_SET_ENABLE_5_5(x) ((x) | W311_SS_ENABLE_5_5) /* +/- 0.50% */ 118 #define W311_SS_SET_ENABLE_2_5(x) ((x) | W311_SS_ENABLE_2_5) /* +/- 0.25% */ 119 #define W311_SS_SET_ENABLE_3_8(x) ((x) | W311_SS_ENABLE_3_8) /* +/- 0.38% */ 120 121 /* Decimal point formatting */ 122 #define INT_FRAC_2PT_4(x) (x) / 1000000, ((x) / 10000) % 100 123 124 /* Whether we are in W311 mode or W229b mode */ 125 static int is311 = FALSE; 126 127 /* 128 * Data: w311_freq_tab 129 * Purpose: Table 5 in W311 DataSheet. 130 * This table encodes the FS_Sel bits of the W311 clock speeds 131 * found in the pin strapping option which is read-only 132 * via reserved register 15 (0xf) 133 * NOTE: This table is used for retrieving hardwired speeds, it does 134 * not need to be sorted by frequency. 135 */ 136 #ifdef COMPILER_HAS_DOUBLE 137 static struct 138 w311_freq_tab_s{ 139 uint8 control; 140 double speed; /* In Mhz */ 141 } w311_freq_tab[] = { 142 { W311_SPEED(0,0,0,0,0), 200.0}, 143 { W311_SPEED(0,0,0,0,1), 190.0}, 144 { W311_SPEED(0,0,0,1,0), 180.0}, 145 { W311_SPEED(0,0,0,1,1), 170.0}, 146 { W311_SPEED(0,0,1,0,0), 166.0}, 147 { W311_SPEED(0,0,1,0,1), 160.0}, 148 { W311_SPEED(0,0,1,1,0), 150.0}, 149 { W311_SPEED(0,0,1,1,1), 145.0}, 150 { W311_SPEED(0,1,0,0,0), 140.0}, 151 { W311_SPEED(0,1,0,0,1), 136.0}, 152 { W311_SPEED(0,1,0,1,0), 130.0}, 153 { W311_SPEED(0,1,0,1,1), 124.0}, 154 { W311_SPEED(0,1,1,0,0), 66.6}, 155 { W311_SPEED(0,1,1,0,1), 100.0}, 156 { W311_SPEED(0,1,1,1,0), 118.0}, 157 { W311_SPEED(0,1,1,1,1), 133.3}, 158 { W311_SPEED(1,0,0,0,0), 66.8}, 159 { W311_SPEED(1,0,0,0,1), 100.2}, 160 { W311_SPEED(1,0,0,1,0), 115.0}, 161 { W311_SPEED(1,0,0,1,1), 133.6}, 162 { W311_SPEED(1,0,1,0,0), 66.8}, 163 { W311_SPEED(1,0,1,0,1), 100.2}, 164 { W311_SPEED(1,0,1,1,0), 110.0}, 165 { W311_SPEED(1,0,1,1,1), 133.6}, 166 { W311_SPEED(1,1,0,0,0), 105.0}, 167 { W311_SPEED(1,1,0,0,1), 90.0}, 168 { W311_SPEED(1,1,0,1,0), 85.0}, 169 { W311_SPEED(1,1,0,1,1), 78.0}, 170 { W311_SPEED(1,1,1,0,0), 66.6}, 171 { W311_SPEED(1,1,1,0,1), 100.0}, 172 { W311_SPEED(1,1,1,1,0), 75.0}, 173 { W311_SPEED(1,1,1,1,1), 133.33}, 174 }; 175 #else 176 static struct 177 w311_freq_tab_s{ 178 uint8 control; 179 int speed; /* In Hz */ 180 } w311_freq_tab[] = { 181 { W311_SPEED(0,0,0,0,0), 200000000}, /* 200.00 MHz */ 182 { W311_SPEED(0,0,0,0,1), 190000000}, /* 190.00 MHz */ 183 { W311_SPEED(0,0,0,1,0), 180000000}, /* 180.00 MHz */ 184 { W311_SPEED(0,0,0,1,1), 170000000}, /* 170.00 MHz */ 185 { W311_SPEED(0,0,1,0,0), 166000000}, /* 166.00 MHz */ 186 { W311_SPEED(0,0,1,0,1), 160000000}, /* 160.00 MHz */ 187 { W311_SPEED(0,0,1,1,0), 150000000}, /* 150.00 MHz */ 188 { W311_SPEED(0,0,1,1,1), 145000000}, /* 145.00 MHz */ 189 { W311_SPEED(0,1,0,0,0), 140000000}, /* 140.00 MHz */ 190 { W311_SPEED(0,1,0,0,1), 136000000}, /* 136.00 MHz */ 191 { W311_SPEED(0,1,0,1,0), 130000000}, /* 130.00 MHz */ 192 { W311_SPEED(0,1,0,1,1), 124000000}, /* 124.00 MHz */ 193 { W311_SPEED(0,1,1,0,0), 66600000}, /* 66.60 MHz */ 194 { W311_SPEED(0,1,1,0,1), 100000000}, /* 100.00 MHz */ 195 { W311_SPEED(0,1,1,1,0), 118000000}, /* 118.00 MHz */ 196 { W311_SPEED(0,1,1,1,1), 133300000}, /* 133.30 MHz */ 197 { W311_SPEED(1,0,0,0,0), 66800000}, /* 66.80 MHz */ 198 { W311_SPEED(1,0,0,0,1), 100200000}, /* 100.20 MHz */ 199 { W311_SPEED(1,0,0,1,0), 115000000}, /* 115.00 MHz */ 200 { W311_SPEED(1,0,0,1,1), 133600000}, /* 133.60 MHz */ 201 { W311_SPEED(1,0,1,0,0), 66800000}, /* 66.80 MHz */ 202 { W311_SPEED(1,0,1,0,1), 100200000}, /* 100.20 MHz */ 203 { W311_SPEED(1,0,1,1,0), 110000000}, /* 110.00 MHz */ 204 { W311_SPEED(1,0,1,1,1), 133600000}, /* 133.60 MHz */ 205 { W311_SPEED(1,1,0,0,0), 105000000}, /* 105.00 MHz */ 206 { W311_SPEED(1,1,0,0,1), 90000000}, /* 90.00 MHz */ 207 { W311_SPEED(1,1,0,1,0), 85000000}, /* 85.00 MHz */ 208 { W311_SPEED(1,1,0,1,1), 78000000}, /* 78.00 MHz */ 209 { W311_SPEED(1,1,1,0,0), 66600000}, /* 66.60 MHz */ 210 { W311_SPEED(1,1,1,0,1), 100000000}, /* 100.00 MHz */ 211 { W311_SPEED(1,1,1,1,0), 75000000}, /* 75.00 MHz */ 212 { W311_SPEED(1,1,1,1,1), 133330000}, /* 133.33 MHz */ 213 }; 214 #endif 215 #define N_W311_FREQS COUNTOF(w311_freq_tab) 216 217 /* 218 * Data: w229b_freq_tab 219 * Purpose: Table 4: Reserved Register Settings (CPU output frequencies and 220 * their SEL bits, sorted by frequency): Byte 4 221 */ 222 static struct 223 w229b_freq_tab_s{ 224 uint8 control; 225 uint32 speed; 226 } w229b_freq_tab[] = { 227 { W229_SPEED(0,1,0,0,0), 66300000}, /* 66.3Mhz */ 228 { W229_SPEED(1,1,1,0,0), 66600000}, /* 66.6Mhz */ 229 { W229_SPEED(0,1,1,0,0), 66800000}, /* 66.8Mhz */ 230 { W229_SPEED(0,0,0,0,0), 75300000}, /* 75.3Mhz */ 231 { W229_SPEED(1,1,0,0,1), 78000000}, /* 78Mhz */ 232 { W229_SPEED(1,1,0,0,0), 80000000}, /* 80Mhz */ 233 { W229_SPEED(0,0,0,0,1), 95000000}, /* 95Mhz */ 234 { W229_SPEED(1,1,1,0,1), 100000000}, /* 100Mhz */ 235 { W229_SPEED(0,1,1,0,1), 100200000}, /* 100.2Mhz */ 236 { W229_SPEED(0,1,0,0,1), 105000000}, /* 105Mhz */ 237 { W229_SPEED(0,0,1,0,1), 110000000}, /* 110Mhz */ 238 { W229_SPEED(1,0,1,1,1), 114000000}, /* 114Mhz */ 239 { W229_SPEED(1,0,1,1,0), 117000000}, /* 117Mhz */ 240 { W229_SPEED(1,0,0,1,1), 122000000}, /* 122Mhz */ 241 { W229_SPEED(1,0,1,0,1), 122000000}, /* 122Mhz */ 242 { W229_SPEED(1,0,1,0,0), 127000000}, /* 127Mhz */ 243 { W229_SPEED(0,0,0,1,0), 129000000}, /* 129Mhz */ 244 { W229_SPEED(1,1,1,1,0), 133300000}, /* 133.3Mhz */ 245 { W229_SPEED(1,1,1,1,1), 133300000}, /* 133.3Mhz */ 246 { W229_SPEED(1,1,0,1,1), 133600000}, /* 133.6Mhz */ 247 { W229_SPEED(0,1,1,1,0), 133600000}, /* 133.6Mhz */ 248 { W229_SPEED(0,1,1,1,1), 133600000}, /* 133.6Mhz */ 249 { W229_SPEED(0,1,0,1,0), 138000000}, /* 138Mhz */ 250 { W229_SPEED(0,0,1,1,0), 140000000}, /* 140Mhz */ 251 { W229_SPEED(0,1,0,1,1), 140000000}, /* 140Mhz */ 252 { W229_SPEED(0,0,1,1,1), 144000000}, /* 144Mhz */ 253 { W229_SPEED(0,0,0,1,1), 150000000}, /* 150Mhz */ 254 { W229_SPEED(0,0,1,0,0), 150000000}, /* 150Mhz */ 255 { W229_SPEED(1,0,0,0,0), 157300000}, /* 157.3Mhz */ 256 { W229_SPEED(1,0,0,0,1), 160000000}, /* 160Mhz */ 257 { W229_SPEED(1,1,0,1,0), 166000000}, /* 166Mhz */ 258 }; 259 #define N_W229B_FREQS COUNTOF(w229b_freq_tab) 260 261 static uint8 w229_regvals[W229B_N_REGS]; 262 263 /* 264 * Create control word for SMB word write operation updating N and M. 265 */ 266 STATIC uint16 267 w311_control_word(uint8 n, uint8 m) 268 { 269 uint16 tmp; 270 m |= 0x80; /* Programmable frequency enable */ 271 tmp = m; 272 tmp <<= 8; 273 tmp |= n; 274 return tmp; 275 } 276 277 STATIC void 278 w311_ss_print(char* pfx, uint8 cb) 279 { 280 char* modeStr = NULL; 281 if( cb == W311_SS_CLEAR) 282 modeStr = "(off)"; 283 else if( cb == (W311_SS_ENABLE_NEG5 | W311_SS_CLEAR)) 284 modeStr = "enabled (-0.5%)"; 285 else if( cb == (W311_SS_ENABLE_5_5 | W311_SS_CLEAR)) 286 modeStr = "enabled (+/-0.5%)"; 287 else if( cb == (W311_SS_ENABLE_2_5 | W311_SS_CLEAR)) 288 modeStr = "enabled (+/- 0.25%)"; 289 else if( cb == (W311_SS_ENABLE_3_8 | W311_SS_CLEAR)) 290 modeStr = "enabled (+/- 0.38%)"; 291 else 292 modeStr = "unknown"; 293 LOG_CLI((BSL_META("w311: %s spread spectrum %s (0x%x)\n"), pfx, modeStr, cb)); 294 } 295 296 /* 297 * Function: w311_ioctl 298 * 299 * Purpose: Given an input speed (clock frequency), tell W311 to 300 * output that frequency for core switch clocks. 301 * 302 * If the user provides a data pointer, we simply query the chip for 303 * the clock speed and return the data in an integer format. 304 * 305 * The user provides speed value in opcode, we check that the value 306 * is in range, and if so, we compute M/N and program the 307 * chip. If data is non-null, we simply return the current speed. 308 * 309 * Parameters: 310 * unit - StrataSwitch device number or I2C bus number 311 * devno - chip device id 312 * opcode - clock speed value, if less than 1Mhz, multiplied by 1Mhz 313 * data - if not-null, we return the clock speed read from the device. 314 * len - unused 315 * 316 * Returns: 317 * SOC_E_NONE - no error 318 * SOC_E_TIMEOUT - chip temperature reading unavailable or IO error. 319 */ 320 STATIC int 321 w311_ioctl(int unit, int devno, 322 int opcode, void* data, int len) 323 { 324 int i, rv = SOC_E_NONE; 325 uint8 m,n,saddr = soc_i2c_addr(unit, devno); 326 #ifdef COMPILER_HAS_DOUBLE 327 double val = 0, speed = 0; 328 #else 329 int val = 0, speed = 0; 330 #endif 331 uint16 nm; 332 333 if(!data) 334 return SOC_E_PARAM; 335 336 if( opcode == I2C_PLL_W311_SETSPEED ){ 337 338 /* Grab requested value */ 339 #ifdef COMPILER_HAS_DOUBLE 340 speed = *((double*)data); 341 342 /* Convert to MHZ if short form given */ 343 if ( speed < MHZ ) 344 speed *= MHZ; 345 LOG_VERBOSE(BSL_LS_SOC_COMMON, 346 (BSL_META_U(unit, 347 "Speed requested = %2.2f\n"), speed)); 348 #else 349 speed = *((int*)data); 350 LOG_VERBOSE(BSL_LS_SOC_COMMON, 351 (BSL_META_U(unit, 352 "Speed requested = %d.%02d\n"), 353 INT_FRAC_2PT_4(speed))); 354 #endif 355 356 if((int)speed < Megahertz(W311_MIN_CLOCK) || 357 (int)speed > Megahertz(W311_MAX_CLOCK)){ 358 LOG_ERROR(BSL_LS_SOC_I2C, 359 (BSL_META_U(unit, 360 "unit %d i2c %s: invalid clock speed %dMhz," 361 " valid range %d:%dMHz\n"), 362 unit, soc_i2c_devname(unit,devno), 363 (int)speed / MHZ, W311_MIN_CLOCK, W311_MAX_CLOCK)); 364 return SOC_E_PARAM; 365 } 366 367 if( (int)speed >= Megahertz(W311_LOW_MIN) && 368 (int)speed <= Megahertz(W311_LOW_MAX)) 369 m = W311_M_LOWSPEED ; 370 else 371 m = W311_M_HIGHSPEED ; 372 /* 373 * The new frequency will start to load whenever there is an 374 * update to either CPU_FSEL_N[7:0] or CPU_FSEL_M[6:0], therefore, 375 * it is recommended by Cypress that Word or Block write be used 376 * to update both registers in one SMBus transaction. 377 */ 378 /* FCpu = G * (N+3)/(M+3) 379 * n = ((FCpu * (M+3)) / G) - 3 380 */ 381 #ifdef COMPILER_HAS_DOUBLE 382 speed /= MHZ; 383 val = ( ( (speed * (m + 3) ) / W311_GEAR_CONSTANT) - 3.0) + 0.5; 384 #else 385 val = ( ( (speed * (m + 3) ) / W311_GEAR_CONSTANT) - 3); 386 #endif 387 n = (uint8) val; 388 nm = w311_control_word(n, m); 389 #ifdef COMPILER_HAS_DOUBLE 390 LOG_VERBOSE(BSL_LS_SOC_COMMON, 391 (BSL_META_U(unit, 392 "w311: set speed=%2.2f n(fp)=%f (m=%d n=%d) hwval=0x%x\n"), 393 speed, val, m, n, nm)); 394 #else 395 LOG_VERBOSE(BSL_LS_SOC_COMMON, 396 (BSL_META_U(unit, 397 "w311: set speed=%d.%02d n(fp)=%d (m=%d n=%d) hwval=0x%x\n"), 398 INT_FRAC_2PT_4(speed), val, m, n, nm)); 399 #endif 400 rv = soc_i2c_write_word_data(unit, saddr, 401 W311_COMM_CODE(W311_N_REG), nm); 402 return rv; 403 } 404 405 406 if( opcode == I2C_PLL_W311_GETSPEED ){ 407 408 /* Read M/N values and compute frequency .. */ 409 rv = soc_i2c_read_word_data(unit, saddr, 410 W311_COMM_CODE(W311_N_REG), &nm); 411 412 m = (uint8)(nm >> 8 & 0x00ff); 413 m &= ~0x80; 414 n = (uint8)nm; 415 416 417 /* 418 * User did not program clock via M/N method, read hardwired 419 * freq from latched FS-Sel pins and do table-lookup for 420 * frequency. 421 */ 422 if( nm == 0){ 423 rv = soc_i2c_read_byte_data(unit, saddr, 424 W311_COMM_CODE(W311_FS_REG), &n); 425 n &= ~(0x07); 426 n >>= 3; 427 428 /* FS0,1,2 */ 429 #ifdef COMPILER_HAS_DOUBLE 430 #ifdef CLOCK_DEBUG 431 LOG_VERBOSE(BSL_LS_SOC_COMMON, 432 (BSL_META_U(unit, 433 "w311: FS_Sel[0:4]=0x%x f=%2.2f\n"), 434 n,0.0)); 435 #endif 436 *((double*)data) = 0.0; 437 #else 438 *((int*)data) = 0; 439 #endif 440 441 /* Look for table match */ 442 for ( i = 0; i < N_W311_FREQS; i++) { 443 #ifdef CLOCK_DEBUG 444 LOG_VERBOSE(BSL_LS_SOC_COMMON, 445 (BSL_META_U(unit, 446 "n=0x%x tab=0x%x\n"), 447 n, w311_freq_tab[i].control)); 448 #endif 449 if(n == w311_freq_tab[i].control){ 450 #ifdef COMPILER_HAS_DOUBLE 451 *((double*)data) = w311_freq_tab[i].speed; 452 #else 453 *((int*)data) = w311_freq_tab[i].speed; 454 #endif 455 } 456 457 } 458 } 459 else { 460 #ifdef COMPILER_HAS_DOUBLE 461 #ifdef CLOCK_DEBUG 462 LOG_VERBOSE(BSL_LS_SOC_COMMON, 463 (BSL_META_U(unit, 464 "w311: m/n=0x%x m=0x%x n=0x%x, f=%2.2f\n"), 465 nm, m, n, 466 (W311_GEAR_CONSTANT * (( n + 3.0)/(m + 3.0))))); 467 #endif 468 /* Compute freq from data-sheet */ 469 *((double*)data) = (W311_GEAR_CONSTANT * (( n + 3.0)/(m + 3.0))); 470 #else 471 *((int*)data) = (W311_GEAR_CONSTANT * (( n + 3)/(m + 3))); 472 #endif 473 } 474 } 475 476 if(opcode == I2C_PLL_W311_GETSPREAD){ 477 uint8 cb = 0; 478 rv =soc_i2c_read_byte_data(unit, saddr, 479 W311_COMM_CODE(W311_CTRL_REG1),&cb); 480 481 if (cb == W311_SS_CLEAR) 482 *((int*)data)=0; 483 else 484 *((int*)data)=1; 485 } 486 487 if(opcode == I2C_PLL_W311_SPREAD){ 488 489 uint8 cb = 0; 490 int mode = *((int*)data); 491 /* 492 * W311 Byte1: Control Register 1 493 */ 494 if((rv =soc_i2c_read_byte_data(unit, saddr, 495 W311_COMM_CODE(W311_CTRL_REG1),&cb))<0){ 496 LOG_ERROR(BSL_LS_SOC_I2C, 497 (BSL_META_U(unit, 498 "w311: could not read W311 byte1, control reg1!\n"))); 499 } 500 501 /* Show current mode decoding */ 502 w311_ss_print("current",cb); 503 504 /* If user didn't input mode, just quit */ 505 if((mode < I2C_PLL_SPREAD_NONE) || (mode > I2C_PLL_SPREAD_3_8)) { 506 return rv; 507 } 508 509 switch(mode){ 510 511 case I2C_PLL_SPREAD_NONE: 512 cb = W311_SS_SET_DISABLE(cb); 513 break; 514 case I2C_PLL_SPREAD_NEG5: 515 cb = W311_SS_SET_ENABLE_NEG5(cb); 516 break; 517 case I2C_PLL_SPREAD_5_5: 518 cb = W311_SS_SET_ENABLE_5_5(cb); 519 break; 520 case I2C_PLL_SPREAD_2_5: 521 cb = W311_SS_SET_ENABLE_2_5(cb); 522 break; 523 case I2C_PLL_SPREAD_3_8: 524 cb = W311_SS_SET_ENABLE_3_8(cb); 525 break; 526 /* 527 mode is validated above. So the default case is never used. 528 default: 529 LOG_ERROR(BSL_LS_SOC_I2C, 530 (BSL_META_U(unit, 531 "w311: spread spectrum error: no mode %d\n"), mode)); 532 break; 533 */ 534 } 535 536 if((rv =soc_i2c_write_byte_data(unit, saddr, 537 W311_COMM_CODE(W311_CTRL_REG1),cb))<0){ 538 LOG_ERROR(BSL_LS_SOC_I2C, 539 (BSL_META_U(unit, 540 "w311: could not write W311 byte1, control reg1!\n"))); 541 } 542 543 w311_ss_print("new", cb); 544 return rv; 545 } 546 547 return rv; 548 } 549 550 551 552 /* 553 * Function: w229b_ioctl 554 * 555 * Purpose: Given an input speed (clock frequency), tell W229b to 556 * output that frequency for core switch clocks. 557 * 558 * The user provides speed value in opcode, we check that the value 559 * is in range, and if so, we find the desired speed, and program the 560 * clock chip. 561 * 562 * Parameters: 563 * unit - StrataSwitch device number or I2C bus number 564 * devno - chip device id 565 * opcode - clock speed value, if less than 1Mhz, multiplied by 1Mhz 566 * data - unused 567 * len - unused 568 * 569 * Returns: 570 * SOC_E_NONE - no error 571 * SOC_E_TIMEOUT - chip temperature reading unavailable or IO error. 572 */ 573 STATIC int 574 w229b_ioctl(int unit, int devno, 575 int opcode, void* data, int len) 576 { 577 int i, rv = SOC_E_NONE; 578 uint8 saddr = soc_i2c_addr(unit, devno); 579 uint32 speed = opcode; 580 #ifdef COMPILER_HAS_DOUBLE 581 double val = 0; 582 #else 583 int val = 0; 584 #endif 585 586 /* Set Chip driver access mode first (W311 or W229b mode) */ 587 if ( data ) { 588 if( opcode == I2C_PLL_SETW311 ){ 589 is311 = * ((int*)data); 590 return SOC_E_NONE; 591 } 592 } 593 /* Handle W311 differently : it does .5Mhz increments */ 594 if( is311) 595 return w311_ioctl(unit, devno, opcode, data, len); 596 597 /* Convert to MHZ if short form given */ 598 if ( speed < MHZ ) 599 speed *= MHZ; 600 601 if((speed > W229B_MAX_SPEED) || (speed < W229B_MIN_SPEED)){ 602 LOG_CLI((BSL_META_U(unit, 603 "The following speeds are available on W229b:\n"))); 604 605 for(i = 0; i < N_W229B_FREQS; i++){ 606 #ifdef COMPILER_HAS_DOUBLE 607 val = (double)w229b_freq_tab[i].speed / (1000.0 * 1000.0) ; 608 LOG_CLI((BSL_META_U(unit, 609 "\t%2.2fMhz\n"), val)); 610 #else 611 val = w229b_freq_tab[i].speed; 612 LOG_CLI((BSL_META_U(unit, 613 "\t%d.%02dMhz\n"), INT_FRAC_2PT_4(val))); 614 #endif 615 } 616 617 return SOC_E_NONE; 618 } 619 620 /* Go through table, find speed match ... */ 621 for(i = 0; i < N_W229B_FREQS; i++) { 622 623 /* Load configuration defaults */ 624 w229_regvals[0] = W229B_R0; 625 w229_regvals[1] = W229B_R1; 626 w229_regvals[2] = W229B_R2; 627 w229_regvals[3] = W229B_R3; 628 629 /* Load clock speed bytes : write to H/W */ 630 w229_regvals[4] = w229b_freq_tab[i].control; 631 632 if ( speed <= w229b_freq_tab[i].speed ) { 633 634 if ( (rv = soc_i2c_block_write(unit, saddr, 635 W229B_COMM_CODE, 636 W229B_CNT, w229_regvals ) ) < 0 ) { 637 638 LOG_ERROR(BSL_LS_SOC_I2C, 639 (BSL_META_U(unit, 640 "unit %d i2c %s: error on SMB block write: %s\n"), 641 unit, soc_i2c_devname(unit,devno), 642 soc_errmsg(rv))); 643 644 return rv; 645 } 646 soc_i2c_device(unit, devno)->tbyte += 5; 647 #ifdef COMPILER_HAS_DOUBLE 648 val = (double)w229b_freq_tab[i].speed / (1000.0 * 1000.0) ; 649 LOG_VERBOSE(BSL_LS_SOC_COMMON, 650 (BSL_META_U(unit, 651 "unit %d i2c %s: set W229B Clock Speed=%.2fMhz" 652 " (CB=0x%x)\n"), 653 unit, soc_i2c_devname(unit,devno), 654 val, w229_regvals[4])); 655 #else 656 val = w229b_freq_tab[i].speed; 657 LOG_VERBOSE(BSL_LS_SOC_COMMON, 658 (BSL_META_U(unit, 659 "unit %d i2c %s: set W229B Clock Speed=%d.%02dMHz" 660 " (CB=0x%x)\n"), 661 unit, soc_i2c_devname(unit,devno), 662 INT_FRAC_2PT_4(val), w229_regvals[4])); 663 #endif 664 break; 665 } 666 } 667 return rv; 668 } 669 670 /* 671 * Function: w229b_init 672 * Purpose: Initialize the W229b clock chip 673 * 674 * Parameters: 675 * unit - StrataSwitch device number or I2C bus number 676 * devno - chip device id 677 * data - not used 678 * len - not used 679 * 680 * Returns: 681 * SOC_E_NONE - no failure 682 */ 683 STATIC int 684 w229b_init(int unit, int devno, 685 void* data, int len) 686 { 687 uint8 saddr = soc_i2c_addr(unit, devno); 688 uint8 rev; 689 690 if(is311){ 691 /* 5615 and higher boards should have it ... */ 692 if((soc_i2c_read_byte_data(unit, saddr, W311_ID_REG, &rev)) < 0){ 693 is311 = FALSE; 694 soc_i2c_devdesc_set(unit, devno, "Cypress W229B Clock Chip"); 695 } else { 696 is311 = TRUE; 697 soc_i2c_devdesc_set(unit, devno, "Cypress W311 Clock Chip"); 698 LOG_VERBOSE(BSL_LS_SOC_COMMON, 699 (BSL_META_U(unit, 700 "%s: vendor 0x%x revision 0x%x\n"), 701 soc_i2c_devname(unit,devno), 702 rev & 0xf0, /* Bits 0-3 */ 703 rev & 0x0f)); /* Bits 4-7 */ 704 } 705 } else { 706 /* In a perfect world, the above detection algorithm would work, 707 * but, however the w229 does not like being read from in a byte 708 * read operation and hangs the I2c bus. 709 */ 710 soc_i2c_devdesc_set(unit, devno, "Cypress W229B/W311 Clock Chip"); 711 } 712 return SOC_E_NONE; 713 } 714 715 /* NOT USED */ 716 STATIC int 717 w229b_read(int unit, int devno, 718 uint16 addr, uint8* data, uint32* len) 719 { 720 return SOC_E_NONE; 721 } 722 723 /* NOT USED */ 724 STATIC int 725 w229b_write(int unit, int devno, 726 uint16 addr, uint8* data, uint32 len) 727 { 728 return SOC_E_NONE; 729 } 730 731 /* W229B/W311 Clock Chip Driver callout */ 732 i2c_driver_t _soc_i2c_w229b_driver = { 733 0x0, 0x0, /* System assigned bytes */ 734 W229B_DEVICE_TYPE, 735 w229b_read, 736 w229b_write, 737 w229b_ioctl, 738 w229b_init, 739 NULL, 740 };