cy2239x.c (12874B)
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 W229393 Clock generator (PLL) chip. 8 * The W229393 is a highly integrated frequency timing generator, 9 * supplying a variety of common clock sources. 10 * 11 * This driver is meant to replace the W229/W311 clock chips found on 12 * most StrataSwitch reference designs. 13 * 14 * The following output below is from the correct programming of the 15 * CY22393x device using Cyclocks RT. 16 * 17 * _____ _____________________ 18 * / __\ \ / / _ \ _ \ __/ __/ __| 19 * | (__ \ ^ /| _/ / _|\__ \__ \ 20 * \___| |_| |_| |_|_\___|___/___/ TIMING TECHNOLOGY 21 * ================================================== 22 * ______________ 23 * _| \__/ |_ ________ 24 * CLKC |_| 1 16 |_| SHUTDOWN/OE 25 * _| |_ _______ 26 * VDD |_| 2 15 |_| S2/SUSPEND 27 * _| |_ 28 * AGND |_| 3 14 |_| AVDD 29 * _| |_ 30 * XTALIN |_| 4 13 |_| SCLK 31 * _| CY22393 |_ 32 * XTALOUT |_| 5 12 |_| SDAT 33 * _| |_ 34 * XBUF |_| 6 11 |_| GND 35 * _| |_ 36 * CLKD |_| 7 10 |_| CLKA 37 * _| |_ 38 * CLKE |_| 8 9 |_| CLKB 39 * |______________| 40 * 41 * Generated by CyClocksRT R1.05.00 42 * 43 * Modification Date: 2/14/02 44 * Comments: Slave Address is 0x6A which translated to 0xd4 (bit zero 45 * not used by CyClocksRT program). 46 * Customer: Broadcom 47 * FAE: n/a 48 * License #:n/a 49 * Reference Input: 25.000000 MHz External 50 * ============================================================= 51 * | Pll | S2 | Source| Desired | Actual | PPM | 52 * ============================================================= 53 * | Pll3 | - | Ref | 266.000000 | 266.000000 | 0.0 | 54 * | Pll2 | - | Ref | 375.000000 | 375.000000 | 0.0 | 55 * | Pll1 | 0 | Ref | 200.000000 | 200.000000 | 0.0 | 56 * | Pll1 | 1 | Ref | 134.000000 | 134.000000 | 0.0 | 57 * ============================================================= 58 * 59 * Clock Output 60 * ========================================================================= 61 * |Output| S2 | Source | Desired | Actual | PPM | Voltage| 62 * ========================================================================= 63 * | XBUF | - | Ref | 25.000000 | 25.000000 | +0.0 | 3.3V | 64 * | CLKE | - | Pll1/4 | 50.000000 | 50.000000 | +0.0 | 3.3V | 65 * | CLKD | - | Pll2/3 | 125.000000 | 125.000000 | +0.0 | 3.3V | 66 * | CLKC | - | Pll2/3 | 125.000000 | 125.000000 | +0.0 | 3.3V | 67 * | CLKB | - | Pll3/2 | 133.000000 | 133.000000 | +0.0 | 3.3V | 68 * | CLKA | - | Pll3/2 | 133.000000 | 133.000000 | +0.0 | 3.3V | 69 * ========================================================================= 70 * 71 * 72 * Programming Algorithm 73 * 74 * For Core (Outputs AB, PLL3): NOTE: Q defaults to 25 so no adjustmnt 75 * is necessary. 76 * 77 * 1. Adjust Q to desired value (25). Default so no action necessary!!! 78 * 2. Adjust P to desired value 3. Adjust output divider to desired value 79 * (2) - default is 3 for core and SDRAM 4. Adjust LF 80 * 81 * For SDRAM (Outputs CD, PLL2): 82 * 83 * 1. Adjust Q to desired value (25) 84 * 2. Adjust P to desired value 85 * 3. Adjust output divider to desired value (2) - default is 3 for core and 86 * SDRAM 87 * 4. Adjust LF 88 * 89 * For PCI/CPU clock (OUTPUT E, PLL1) 90 * 91 * 1. Adjust Q to desired value (25). Default so no action necessary!!! 92 * 2. Adjust P to desired value 93 * 3. Adjust output divider to desired value (4) - Default so no action 94 * necessary!!! 95 * 4. Adjust LF. 96 * 5. Compensate as necessary for baud rate or other parameters affected by 97 * changing the PCI or CPU frequency!!!!!! 98 * 99 * 100 * See the Cypress W22393 Clock chip data sheet(s) for more details. 101 * See also: http://www.cypress.com/clock/datasheets.html 102 */ 103 104 #include <sal/types.h> 105 #include <soc/drv.h> 106 #include <soc/error.h> 107 #include <soc/i2c.h> 108 #include <shared/bsl.h> 109 #define MHZ(x) ((x)*1000000) 110 111 /* FRef = 25MHz */ 112 #define CY2239x_REF_CLK MHZ(25) 113 #define CY2239x_DIV_CORE 2 114 #define CY2239x_DIV_SDRAM 2 115 #define CY2239x_DIV_PCI 4 116 #define CY_DEBUG(x) { \ 117 LOG_CLI((BSL_META(x))); sal_usleep(1000)));} 118 119 /* 120 * Loop filter : Computed based on PT 121 * See datasheet for more info. 122 */ 123 STATIC uint8 124 cy2239x_loop_filter(int val) 125 { 126 uint8 tmp; 127 128 /* Convert from MHz if required */ 129 if (val > MHZ(1)) { 130 val /= MHZ(1); 131 } 132 if (val >= 16 && val <= 231) { 133 tmp = 0; 134 } else if (val >= 232 && val <= 626) { 135 tmp = 1; 136 } else if (val >= 627 && val <= 834) { 137 tmp = 2; 138 } else if (val >= 835 && val <= 1043) { 139 tmp = 3; 140 } else if (val >= 1044 && val <= 1600) { 141 tmp = 4; 142 } else { 143 tmp = 0; 144 } 145 return tmp; 146 } 147 148 STATIC int 149 cy2239x_ioctl(int unit, int devno, 150 int opcode, void* data, int len) 151 { 152 #ifdef COMPILER_HAS_DOUBLE 153 double clk, qt; 154 #else 155 int qt; 156 #endif 157 int iclk, P0, ip, iq; 158 uint8 tmp, lf, saddr = soc_i2c_addr(unit, devno); 159 160 if ( I2C_XPLL_SET_PCI == opcode ) { 161 #ifdef COMPILER_HAS_DOUBLE 162 clk = *((double *)data); 163 /* Convert from MHz if required */ 164 if (clk < MHZ(1)) 165 clk *= MHZ(1); 166 167 /* Setup new core clock */ 168 iclk = (int) clk; 169 #else 170 iclk = *((int *)data); 171 #endif 172 /* Compute actual frequency in MHz */ 173 iclk = (CY2239x_DIV_PCI * iclk) / MHZ(1); 174 175 /* This is set only on an odd clock freq */ 176 P0 = iclk % 2; 177 178 /* Compute Qt and convert to byte value (in MHz)*/ 179 qt = CY2239x_REF_CLK - MHZ(2); 180 qt = qt / MHZ(1); 181 182 /* Compute P/Q (integer format) */ 183 ip = ((iclk - P0) / 2) - 3; 184 iq = (int) qt; 185 186 /* Compute loop filter */ 187 lf = cy2239x_loop_filter(iclk); 188 189 /* Read DivSel/PLL_Enable register */ 190 soc_i2c_read_byte_data(unit, saddr, 0x57, &tmp); 191 192 /* Mask fields to be updated */ 193 tmp &= ~(0x03); 194 195 /* Add upper P bits */ 196 tmp |= (ip >> 8) & 3; 197 198 /* Add PO bit */ 199 tmp |= (P0 << 2); 200 201 /* Add Loop Filter bits */ 202 tmp |= (lf << 3); 203 204 /* Configure new clock setting */ 205 soc_i2c_write_byte_data(unit, saddr, 0x55, (uint8)iq); 206 soc_i2c_write_byte_data(unit, saddr, 0x56, (uint8)ip); 207 soc_i2c_write_byte_data(unit, saddr, 0x57, tmp); 208 209 } else if ( I2C_XPLL_GET_PCI == opcode ) { 210 uint8 p_l, p_h, q, pNot; 211 uint16 p; 212 213 soc_i2c_read_byte_data(unit, saddr, 0x55, &q); 214 soc_i2c_read_byte_data(unit, saddr, 0x56, &p_l); 215 soc_i2c_read_byte_data(unit, saddr, 0x57, &p_h); 216 217 pNot = ((p_h & 0x04) >> 2); /* Bit 2 of 0x57 */ 218 p_h &= 0x03; /* Clear all bits except bits 0-1 */ 219 p = (p_h << 8) | p_l; /* 10 bits of p value */ 220 #ifdef COMPILER_HAS_DOUBLE 221 clk = 2 * ( p + 3 ) + pNot ; 222 clk *= CY2239x_REF_CLK; 223 clk /= (q+2); 224 clk /= CY2239x_DIV_PCI; 225 clk /= MHZ(1); 226 *((double *)data) = clk; 227 #else 228 iclk = 2 * (p + 3) + pNot ; 229 iclk *= CY2239x_REF_CLK / (q + 2); 230 iclk /= CY2239x_DIV_PCI; 231 *((int *)data) = iclk; 232 #endif 233 } else if ( I2C_XPLL_SET_CORE == opcode ) { 234 #ifdef COMPILER_HAS_DOUBLE 235 clk = *((double *)data); 236 237 /* Convert from MHz if required */ 238 if (clk < MHZ(1)) 239 clk *= MHZ(1); 240 241 /* Setup new core clock */ 242 iclk = (int) clk; 243 #else 244 iclk = *((int *)data); 245 #endif 246 /* Compute actual frequency in MHz */ 247 iclk = (CY2239x_DIV_CORE * iclk) / MHZ(1); 248 249 /* This is set only on an odd clock freq */ 250 P0 = iclk % 2; 251 252 /* Compute Qt and convert to byte value (in MHz)*/ 253 qt = CY2239x_REF_CLK - MHZ(2); 254 qt = qt / MHZ(1); 255 256 /* Compute P/Q (integer format) */ 257 ip = ((iclk - P0) / 2) - 3; 258 iq = (int) qt; 259 260 /* Compute loop filter */ 261 lf = cy2239x_loop_filter(iclk); 262 263 /* Read DivSel/PLL_Enable register */ 264 soc_i2c_read_byte_data(unit, saddr, 0x16, &tmp); 265 266 /* Mask fields to be updated */ 267 tmp &= ~(0x03); 268 269 /* Add upper P bits */ 270 tmp |= (ip >> 8) & 3; 271 272 /* Add PO bit */ 273 tmp |= (P0 << 2); 274 275 /* Add Loop Filter bits */ 276 tmp |= (lf << 3); 277 278 /* Configure new clock setting */ 279 soc_i2c_write_byte_data(unit, saddr, 0x15, (uint8)ip); 280 soc_i2c_write_byte_data(unit, saddr, 0x14, (uint8)iq); 281 soc_i2c_write_byte_data(unit, saddr, 0x08, 2); 282 soc_i2c_write_byte_data(unit, saddr, 0x0a, 2); 283 soc_i2c_write_byte_data(unit, saddr, 0x16, tmp); 284 285 } else if ( I2C_XPLL_GET_CORE == opcode) { 286 uint8 p_l, p_h, q, pNot, div; 287 uint16 p; 288 289 soc_i2c_read_byte_data(unit, saddr, 0x15, &p_l); 290 soc_i2c_read_byte_data(unit, saddr, 0x16, &p_h); 291 soc_i2c_read_byte_data(unit, saddr, 0x14, &q); 292 soc_i2c_read_byte_data(unit, saddr, 0x08, &div); 293 div &= 0x7f; 294 pNot = ((p_h & 0x04) >> 2); /* Bit 2 of 0x57 */ 295 p_h &= 0x03; /* Clear all bits except bits 0-1 */ 296 p = (p_h << 8) | p_l; /* 10 bits of p value */ 297 #ifdef COMPILER_HAS_DOUBLE 298 clk = 2 * ( p + 3 ) + pNot ; 299 clk *= CY2239x_REF_CLK; 300 clk /= (q+2); 301 clk /= div; 302 clk /= MHZ(1); 303 *((double *)data) = clk; 304 #else 305 iclk = 2 * (p + 3) + pNot ; 306 iclk *= CY2239x_REF_CLK / (q + 2); 307 iclk /= div; 308 *((int *)data) = iclk; 309 #endif 310 } else if ( I2C_XPLL_SET_SDRAM == opcode) { 311 312 #ifdef COMPILER_HAS_DOUBLE 313 clk = *((double *)data); 314 315 /* Convert to MHz if required */ 316 if (clk < MHZ(1)) 317 clk *= MHZ(1); 318 319 /* Setup new core clock */ 320 iclk = (int) clk; 321 #else 322 iclk = *((int *)data); 323 #endif 324 /* Compute actual frequency in MHz */ 325 iclk = (CY2239x_DIV_SDRAM * iclk) / MHZ(1); 326 327 /* This is set only on an odd clock freq */ 328 P0 = iclk % 2; 329 330 /* Compute Qt and convert to byte value (in MHz)*/ 331 qt = CY2239x_REF_CLK - MHZ(2); 332 qt = qt / MHZ(1); 333 334 /* Compute P/Q (integer format) */ 335 ip = ((iclk - P0) / 2) - 3; 336 iq = (int) qt; 337 338 /* Compute loop filter */ 339 lf = cy2239x_loop_filter(iclk); 340 341 /* Read DivSel/PLL_Enable register */ 342 soc_i2c_read_byte_data(unit, saddr, 0x13, &tmp); 343 344 /* Mask fields to be updated */ 345 tmp &= ~(0x03); 346 347 /* Add upper P bits */ 348 tmp |= (ip >> 8) & 3; 349 350 /* Add PO bit */ 351 tmp |= (P0 << 2); 352 353 /* Add Loop Filter bits */ 354 tmp |= (lf << 3); 355 356 /* Configure new clock setting */ 357 soc_i2c_write_byte_data(unit, saddr, 0x12, (uint8)ip); 358 soc_i2c_write_byte_data(unit, saddr, 0x11, (uint8)iq); 359 soc_i2c_write_byte_data(unit, saddr, 0x0c, 2); 360 soc_i2c_write_byte_data(unit, saddr, 0x0d, 2); 361 soc_i2c_write_byte_data(unit, saddr, 0x13, tmp); 362 363 } else if ( I2C_XPLL_GET_SDRAM == opcode) { 364 uint8 p_l, p_h, q, pNot, div; 365 uint16 p; 366 367 soc_i2c_read_byte_data(unit, saddr, 0x12, &p_l); 368 soc_i2c_read_byte_data(unit, saddr, 0x13, &p_h); 369 soc_i2c_read_byte_data(unit, saddr, 0x11, &q); 370 soc_i2c_read_byte_data(unit, saddr, 0x0c, &div); 371 div &= 0x7f; 372 373 pNot = ((p_h & 0x04) >> 2); /* Bit 2 of 0x57 */ 374 p_h &= 0x03; /* Clear all bits except bits 0-1 */ 375 p = (p_h << 8) | p_l; /* 10 bits of p value */ 376 #ifdef COMPILER_HAS_DOUBLE 377 clk = 2 * ( p + 3 ) + pNot ; 378 clk *= CY2239x_REF_CLK; 379 clk /= (q+2); 380 clk /= div; 381 clk /= MHZ(1); 382 *((double *)data) = clk; 383 #else 384 iclk = 2 * (p + 3) + pNot ; 385 iclk *= CY2239x_REF_CLK / (q + 2); 386 iclk /= div; 387 *((int *)data) = iclk; 388 #endif 389 } else { 390 return SOC_E_PARAM; 391 } 392 393 return SOC_E_NONE; 394 } 395 396 /* 397 * Function: cy2239x_init 398 * 399 * Purpose: 400 * Initialize the CY2239X clock chip 401 * Parameters: 402 * unit - StrataSwitch device number or I2C bus number 403 * devno - chip device id 404 * data - not used 405 * len - not used 406 * Returns: 407 * SOC_E_NONE - no failure 408 */ 409 STATIC int 410 cy2239x_init(int unit, int devno, 411 void *data, int len) 412 { 413 #if 0 414 int i; 415 uint8 x; 416 uint8 saddr = soc_i2c_addr(unit, devno); 417 418 /* Dump register values */ 419 for (i = 0x08; i <= 0x17; i++) { 420 soc_i2c_read_byte_data(unit, saddr, (uint8)i, &x); 421 LOG_CLI((BSL_META_U(unit, 422 "pll[%x] = 0x%x\n"), i, x)); 423 } 424 for (i = 0x40; i <= 0x57; i++) { 425 soc_i2c_read_byte_data(unit, saddr, (uint8)i, &x); 426 LOG_CLI((BSL_META_U(unit, 427 "pll[%x] = 0x%x\n"), i, x)); 428 } 429 #endif 430 soc_i2c_devdesc_set(unit, devno, "Cypress W2239x clock Chip"); 431 return SOC_E_NONE; 432 } 433 434 STATIC int 435 cy2239x_read(int unit, int devno, 436 uint16 addr, uint8 *data, uint32* len) 437 { 438 *len = 1; /* Byte-write mode */ 439 return soc_i2c_read_byte_data(unit, 440 soc_i2c_addr(unit, devno), 441 (uint8)addr, data); 442 } 443 444 STATIC int 445 cy2239x_write(int unit, int devno, 446 uint16 addr, uint8 *data, uint32 len) 447 { 448 return soc_i2c_write_byte_data(unit, 449 soc_i2c_addr(unit, devno), 450 (uint8)addr, *data); 451 } 452 453 /* CY2239X/W311 Clock Chip Driver callout */ 454 i2c_driver_t _soc_i2c_cy2239x_driver = { 455 0x0, 0x0, /* System assigned bytes */ 456 CY2239X_DEVICE_TYPE, 457 cy2239x_read, 458 cy2239x_write, 459 cy2239x_ioctl, 460 cy2239x_init, 461 NULL, 462 };