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

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