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

blackhawk_pll_config.c (16246B)


      1 /**********************************************************************************
      2  **********************************************************************************
      3  *  File Name     :  blackhawk_pll_config.c                                       *
      4  *  Created On    :  11 Feb 2016                                                  *
      5  *  Created By    :  Brent Roberts                                                *
      6  *  Description   :  Blackhawk PLL Configuration API                              *
      7  *  Revision      :    *
      8  *                                                                                *
      9  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
     10  * 
     11  * Copyright 2007-2019 Broadcom Inc. All rights reserved.                                                          *
     12  *  No portions of this material may be reproduced in any form without            *
     13  *  the written permission of:                                                    *
     14  *      Broadcom Corporation                                                      *
     15  *      5300 California Avenue                                                    *
     16  *      Irvine, CA  92617                                                         *
     17  *                                                                                *
     18  *  All information contained in this document is Broadcom Corporation            *
     19  *  company private proprietary, and trade secret.                                *
     20  */
     21 
     22 
     23 /** @file blackhawk_pll_config.c
     24  * Blackhawk PLL Configuration
     25  */
     26 
     27 
     28 #include "blackhawk_tsc_config.h"
     29 #include "blackhawk_tsc_functions.h"
     30 #include "blackhawk_tsc_internal.h"
     31 #include "blackhawk_tsc_internal_error.h"
     32 #include "blackhawk_tsc_select_defns.h"
     33 
     34 
     35 #define VCO_FREQ_KHZ_NEAR(vco_freq_khz_, near_val_) (   ((vco_freq_khz_) >= (near_val_) - 10000) \
     36                                                      || ((vco_freq_khz_) <= (near_val_) + 10000))
     37 
     38 /* The pll_fracn_ndiv_int and pll_fracn_frac bitfields have this many bits. */
     39 static const uint32_t pll_fracn_ndiv_int_bits = 10;
     40 static const uint32_t pll_fracn_frac_bits     = 18;
     41 
     42 err_code_t blackhawk_tsc_INTERNAL_configure_pll(srds_access_t *sa__,
     43                                          enum blackhawk_tsc_pll_refclk_enum refclk,
     44                                          enum blackhawk_tsc_pll_div_enum srds_div,
     45                                          uint32_t vco_freq_khz,
     46                                          enum blackhawk_tsc_pll_option_enum pll_option) {
     47     uint32_t refclk_freq_hz;
     48     uint8_t int_configured;
     49 
     50     EFUN(blackhawk_tsc_INTERNAL_resolve_pll_parameters(sa__, refclk, &refclk_freq_hz, &srds_div, &vco_freq_khz, pll_option));
     51 
     52 
     53     /* Use this to restore defaults if reprogramming the PLL under dp-reset (typically Auto-Neg FW) */
     54     EFUN(wrc_pll_mode(0x7));
     55     EFUN(wrc_ams_pll_vco2_15g(0x0));
     56     EFUN(wrc_ams_pll_fracn_ndiv_int(0x0));
     57     EFUN(wrc_ams_pll_fracn_div(0x0000));
     58     EFUN(wrc_ams_pll_fracn_div_17_16(0x0));
     59     EFUN(wrc_ams_pll_fracn_bypass(0x0));
     60     EFUN(wrc_ams_pll_fracn_divrange(0x0));
     61     EFUN(wrc_ams_pll_ditheren(0x0));
     62     EFUN(wrc_ams_pll_fracn_sel(0x0));
     63     EFUN(wrc_ams_pll_kvh_force(0x0));
     64     EFUN(wrc_ams_pll_force_kvh_bw(0x0));
     65     EFUN(wrc_ams_pll_refclk_doubler(0x0));
     66     EFUN(wrc_ams_pll_doubler_res(0x0));
     67     EFUN(wrc_ams_pll_doubler_cap(0x0));
     68     EFUN(wrc_ams_pll_div2(0x0));
     69     EFUN(wrc_ams_pll_div4(0x0));
     70     EFUN(wrc_ams_pll_div4_2_sel(0x0));
     71     EFUN(wrc_ams_pll_ndiv_frac_valid(0x0));
     72     EFUN(wrc_ams_pll_pll2rx_clkbw(0x0));
     73     EFUN(wrc_refclk_divcnt(0x27));
     74     EFUN(wrc_vco_step_time(0x3));
     75     EFUN(wrc_ams_pll_fp3_rh(0x0));
     76     EFUN(wrc_ams_pll_fp3_ctrl(0x0));
     77     EFUN(wrc_ams_pll_iqp(0x4));
     78 
     79     {
     80         uint8_t reset_state;
     81         /* Use core_s_rstb to re-initialize all registers to default before calling this function. */
     82         ESTM(reset_state = rdc_core_dp_reset_state());
     83 
     84         if(reset_state < 7) {
     85             EFUN_PRINTF(("ERROR: blackhawk_tsc_configure_pll(..) called without core_dp_s_rstb=0\n"));
     86             return (blackhawk_tsc_error(sa__, ERR_CODE_CORE_DP_NOT_RESET));
     87         }
     88     }
     89 
     90     /* Clear PLL powerdown */
     91     EFUN(wrc_ams_pll_pwrdn(0));
     92 
     93     /* Per AB on 13 Nov 2015:  Use VCO2 for 22.6 GHz and below.
     94      * The next supported frequency is 23.0 GHz, so let's use 22.8 GHz as the threshold.
     95      */
     96     EFUN(wrc_ams_pll_vco2_15g((vco_freq_khz < 22800000) ? 1 : 0));
     97 
     98     int_configured = 0;
     99     if (!SRDS_INTERNAL_IS_PLL_DIV_FRACTIONAL(srds_div)) {
    100         uint8_t pll_mode;
    101         int_configured = 1;
    102         switch (SRDS_INTERNAL_GET_PLL_DIV_INTEGER(srds_div)) {
    103             case  64: pll_mode =  0; break;
    104             case  66: pll_mode =  1; break;
    105             case  80: pll_mode =  2; break;
    106             case 128: pll_mode =  3; break;
    107             case 132: pll_mode =  4; break;
    108             case 140: pll_mode =  5; break;
    109             case 160: pll_mode =  6; break;
    110             case 165: pll_mode =  7; break;
    111             case 168: pll_mode =  8; break;
    112             case 170: pll_mode =  9; break;
    113             case 175: pll_mode = 10; break;
    114             case 180: pll_mode = 11; break;
    115             case 184: pll_mode = 12; break;
    116             case 200: pll_mode = 13; break;
    117             case 224: pll_mode = 14; break;
    118             case 264: pll_mode = 15; break;
    119             case  96: pll_mode = 16; break;
    120             case 120: pll_mode = 17; break;
    121             case 144: pll_mode = 18; break;
    122             case 198: pll_mode = 19; break;
    123             default: int_configured = 0;
    124         }
    125     
    126         if (int_configured) {
    127             EFUN(wrc_pll_mode(pll_mode));
    128         }
    129     }
    130     
    131     EFUN(wrc_ams_pll_fracn_sel(int_configured ? 0 : 1));
    132 
    133     if (!int_configured) {
    134         /* Either fractional mode was requested, or integer mode doesn't support the divisor.
    135          * Get information needed for fractional mode configuration.
    136          *
    137          * The value programmed into the pll_fracn_* bitfields which must account for the
    138          * initial div2 stage after the VCO.  For instance, a divide by 147.2 must be
    139          * programmed with an integer of 73 and a fraction of 0.6.
    140          *
    141          * Start with the div value, divided by 2, composed of an integer and a wide fractional value.
    142          */
    143         const uint8_t  div_fraction_width = 28; /* Must be less than 32 due to overflow detection below. */
    144         const uint16_t div_integer        = SRDS_INTERNAL_GET_PLL_DIV_INTEGER(srds_div) >> 1;
    145         const uint32_t div_fraction       = (((SRDS_INTERNAL_GET_PLL_DIV_INTEGER(srds_div) & 1) << (div_fraction_width-1))
    146                                              | SRDS_INTERNAL_GET_PLL_DIV_FRACTION_NUM(srds_div, div_fraction_width-1));
    147 
    148         /* The div_fraction may have more precision than our pll_fracn_frac bitfield.
    149          * So round it.  Start by adding 1/2 LSB of the fraction div_fraction.
    150          */
    151         const uint32_t div_fraction_0p5 = 1 << (div_fraction_width - pll_fracn_frac_bits - 1);
    152         const uint32_t div_fraction_plus_0p5 = div_fraction + div_fraction_0p5;
    153 
    154         /* Did div_fraction_plus_p5 have a carry bit? */
    155         const uint32_t div_fraction_plus_p5_carry = div_fraction_plus_0p5 >> div_fraction_width;
    156 
    157         /* The final rounded div_fraction, including carry up to div_integer.
    158          * This removes the carry and implements the fixed point truncation.
    159          */
    160         const uint16_t pll_fracn_ndiv_int  = div_integer + div_fraction_plus_p5_carry;
    161         const uint32_t pll_fracn_div = ((div_fraction_plus_0p5 & ((1 << div_fraction_width)-1))
    162                                         >> (div_fraction_width - pll_fracn_frac_bits));
    163 
    164         if (pll_fracn_ndiv_int != (pll_fracn_ndiv_int & ((1 << pll_fracn_ndiv_int_bits)-1))) {
    165             EFUN_PRINTF(("ERROR:  PLL divide is too large for div value 0x%08X\n", srds_div));
    166             return (blackhawk_tsc_error(sa__, ERR_CODE_PLL_DIV_INVALID));
    167         }
    168 
    169         EFUN(wrc_pll_mode(0));
    170         if ((pll_fracn_ndiv_int < 12) || (pll_fracn_ndiv_int > 251)) {
    171             return (blackhawk_tsc_error(sa__, ERR_CODE_INVALID_PLL_CFG));
    172         }
    173         EFUN(wrc_ams_pll_fracn_ndiv_int (pll_fracn_ndiv_int));
    174         EFUN(wrc_ams_pll_fracn_div      (pll_fracn_div & 0xFFFF));
    175         EFUN(wrc_ams_pll_fracn_div_17_16(pll_fracn_div >> 16));
    176         EFUN(wrc_ams_pll_fracn_bypass   (0));
    177         EFUN(wrc_ams_pll_fracn_divrange ((pll_fracn_ndiv_int < 91) ? 1 : 0));
    178         if (pll_fracn_div != 0) {
    179             /* Apply settings on PLL0 to avoid coupling related jitter. See CRSRDSAPI-308. */
    180             if ((refclk_freq_hz > 300000000) && (blackhawk_tsc_get_pll_idx(sa__) == 0)) {
    181                 EFUN(wrc_ams_pll_fp3_rh(0x0));
    182                 EFUN(wrc_ams_pll_fp3_ctrl(0x0));
    183                 EFUN(wrc_ams_pll_iqp(0x4));
    184             } else if ((refclk_freq_hz > 300000000) && (blackhawk_tsc_get_pll_idx(sa__) == 1)) {
    185                 EFUN(wrc_ams_pll_fp3_rh(0x0));
    186                 EFUN(wrc_ams_pll_fp3_ctrl(0xF));
    187                 EFUN(wrc_ams_pll_iqp(0x6));
    188             } else
    189             {
    190                 EFUN(wrc_ams_pll_fp3_rh(0x1));
    191                 EFUN(wrc_ams_pll_fp3_ctrl(0xF));
    192             }
    193         }
    194         /* toggle ndiv_frac_valid high, then low to load in a new value for fracn_div. */
    195         EFUN(wrc_ams_pll_ndiv_frac_valid(1));
    196         EFUN(wrc_ams_pll_ndiv_frac_valid(0));
    197     }
    198 
    199     {
    200         uint8_t ams_tx_version_id;
    201         ESTM(ams_tx_version_id = rd_ams_tx_version_id());
    202         if ((ams_tx_version_id == 0xC0) && (refclk_freq_hz == 156250000) && (vco_freq_khz == 26562500)) {
    203             EFUN(wrc_ams_pll_iqp(0x8));
    204         }
    205     }
    206 
    207     /* Determine KVH and pll2rx_clkbw_val per Falcon16 AMS v1.1 and comments in CRSRDSAPI-137 and CRSRDSFW-138 */
    208     {
    209         uint8_t kvh_force;
    210         uint8_t pll2rx_clkbw_val;
    211 
    212         if (vco_freq_khz > 27400000) {
    213             kvh_force = 0;
    214         } else if ((vco_freq_khz <= 27400000) && (vco_freq_khz > 18750000)) {
    215             kvh_force = 1;
    216         } else {
    217             kvh_force = 3;
    218         }
    219 
    220         if (vco_freq_khz > 25781250) {
    221             pll2rx_clkbw_val = 0;
    222         } else if ((vco_freq_khz <= 25781250) && (vco_freq_khz > 22600000)) {
    223             pll2rx_clkbw_val = 1;
    224         } else {
    225             pll2rx_clkbw_val = 3;
    226         }
    227 
    228         /* Per AB on 27 Oct 2015, vco_indicator is always forced to 0. */
    229 #if defined(wrc_ams_pll_vco_indicator)
    230         EFUN(wrc_ams_pll_vco_indicator(0));
    231 #endif
    232         EFUN(wrc_ams_pll_pll2rx_clkbw(pll2rx_clkbw_val));
    233         EFUN(wrc_ams_pll_kvh_force(kvh_force));
    234         EFUN(wrc_ams_pll_force_kvh_bw(1));
    235 
    236         /* Handle refclk PLL options */
    237         pll_option = (enum blackhawk_tsc_pll_option_enum)(pll_option & BLACKHAWK_TSC_PLL_OPTION_REFCLK_MASK);
    238         if (pll_option == BLACKHAWK_TSC_PLL_OPTION_REFCLK_DOUBLER_EN) {
    239             EFUN(wrc_ams_pll_refclk_doubler(0x1));
    240             EFUN(wrc_ams_pll_doubler_res(0x6));
    241             EFUN(wrc_ams_pll_doubler_cap(0x3));
    242         } else if (pll_option == BLACKHAWK_TSC_PLL_OPTION_REFCLK_DIV2_EN) {
    243             EFUN(wrc_ams_pll_div2(1));
    244             EFUN(wrc_ams_pll_div4_2_sel(1));
    245         } else if (pll_option == BLACKHAWK_TSC_PLL_OPTION_REFCLK_DIV4_EN) {
    246             EFUN(wrc_ams_pll_div4(1));
    247             EFUN(wrc_ams_pll_div4_2_sel(1));
    248         }
    249 
    250 
    251         /* Force refclk_divcnt for refclk faster than 156.25 Mhz. See CRSRDSAPI-185. */
    252         if (refclk_freq_hz > 156250000) {
    253             uint16_t refclk_divcnt = 39 * (refclk_freq_hz/156250000);
    254             EFUN(wrc_refclk_divcnt(refclk_divcnt));
    255         }
    256 
    257         /* Force vco_step_time. See CRSRDSAPI-229. */
    258         EFUN(wrc_vco_step_time(8));
    259     }
    260 
    261     /* Update core variables with the VCO rate. */
    262     {
    263         struct blackhawk_tsc_uc_core_config_st core_config;
    264         EFUN(blackhawk_tsc_get_uc_core_config(sa__, &core_config));
    265         core_config.vco_rate_in_Mhz = (vco_freq_khz + 500) / 1000;
    266         core_config.field.vco_rate = MHZ_TO_VCO_RATE(core_config.vco_rate_in_Mhz);
    267         EFUN(blackhawk_tsc_INTERNAL_set_uc_core_config(sa__, core_config));
    268     }
    269 
    270     {
    271         uint8_t pll_idx;
    272         uint8_t other_pll_lock;
    273         ESTM(pll_idx = blackhawk_tsc_get_pll_idx(sa__));
    274         EFUN(blackhawk_tsc_set_pll_idx(sa__, ((pll_idx == 0) ? 1 : 0)));
    275         ESTM(other_pll_lock = rdc_pll_lock());
    276         if (!other_pll_lock) {
    277             uint8_t misc_ctrl_byte;
    278             ESTM(misc_ctrl_byte = rdcv_misc_ctrl_byte());
    279             if (pll_idx == 1) misc_ctrl_byte |= 1<<2;
    280             else              misc_ctrl_byte &= ~(1<<2);
    281             EFUN(wrcv_misc_ctrl_byte(misc_ctrl_byte));
    282         }
    283         EFUN(blackhawk_tsc_set_pll_idx(sa__, pll_idx));
    284     }
    285 
    286     return (ERR_CODE_NONE);
    287 } /* blackhawk_tsc_configure_pll */
    288 
    289 err_code_t blackhawk_tsc_INTERNAL_read_pll_div(srds_access_t *sa__, uint32_t *srds_div) {
    290     uint8_t fracn_sel;
    291     ESTM(fracn_sel = rdc_ams_pll_fracn_sel());
    292 
    293     if (fracn_sel) {
    294         uint16_t pll_fracn_ndiv_int;
    295         uint32_t pll_fracn_div;
    296         ESTM(pll_fracn_ndiv_int = rdc_ams_pll_fracn_ndiv_int());
    297         ESTM(pll_fracn_div = rdc_ams_pll_fracn_div() | (rdc_ams_pll_fracn_div_17_16() << 16));
    298 
    299         /* The value programmed into the pll_fracn_* bitfields which must
    300          * account for the initial div2 stage after the VCO.  For instance, a
    301          * divide by 147.2 must be programmed with an integer of 73 and a
    302          * fraction of 0.6.
    303          *
    304          * So multiply the bitfield reads by 2.
    305          */
    306         pll_fracn_ndiv_int <<= 1;
    307         pll_fracn_div      <<= 1;
    308         
    309         {
    310             /* If the post-multiplied fractional part overflows, then apply the carry to
    311              * the integer part.
    312              */
    313             const uint32_t pll_fracn_div_masked = pll_fracn_div & ((1 << pll_fracn_frac_bits)-1);
    314             if (pll_fracn_div_masked != pll_fracn_div) {
    315                 ++pll_fracn_ndiv_int;
    316                 pll_fracn_div = pll_fracn_div_masked;
    317             }
    318         }
    319     
    320         *srds_div = SRDS_INTERNAL_COMPOSE_PLL_DIV(pll_fracn_ndiv_int, pll_fracn_div, pll_fracn_frac_bits);
    321     } else {
    322         uint8_t pll_mode;
    323         ESTM(pll_mode = rdc_pll_mode());
    324         switch (pll_mode) {
    325             case  0: *srds_div = SRDS_INTERNAL_COMPOSE_PLL_DIV(  64, 0, 18); break;
    326             case  1: *srds_div = SRDS_INTERNAL_COMPOSE_PLL_DIV(  66, 0, 18); break;
    327             case  2: *srds_div = SRDS_INTERNAL_COMPOSE_PLL_DIV(  80, 0, 18); break;
    328             case  3: *srds_div = SRDS_INTERNAL_COMPOSE_PLL_DIV( 128, 0, 18); break;
    329             case  4: *srds_div = SRDS_INTERNAL_COMPOSE_PLL_DIV( 132, 0, 18); break;
    330             case  5: *srds_div = SRDS_INTERNAL_COMPOSE_PLL_DIV( 140, 0, 18); break;
    331             case  6: *srds_div = SRDS_INTERNAL_COMPOSE_PLL_DIV( 160, 0, 18); break;
    332             case  7: *srds_div = SRDS_INTERNAL_COMPOSE_PLL_DIV( 165, 0, 18); break;
    333             case  8: *srds_div = SRDS_INTERNAL_COMPOSE_PLL_DIV( 168, 0, 18); break;
    334             case  9: *srds_div = SRDS_INTERNAL_COMPOSE_PLL_DIV( 170, 0, 18); break;
    335             case 10: *srds_div = SRDS_INTERNAL_COMPOSE_PLL_DIV( 175, 0, 18); break;
    336             case 11: *srds_div = SRDS_INTERNAL_COMPOSE_PLL_DIV( 180, 0, 18); break;
    337             case 12: *srds_div = SRDS_INTERNAL_COMPOSE_PLL_DIV( 184, 0, 18); break;
    338             case 13: *srds_div = SRDS_INTERNAL_COMPOSE_PLL_DIV( 200, 0, 18); break;
    339             case 14: *srds_div = SRDS_INTERNAL_COMPOSE_PLL_DIV( 224, 0, 18); break;
    340             case 15: *srds_div = SRDS_INTERNAL_COMPOSE_PLL_DIV( 264, 0, 18); break;
    341             case 16: *srds_div = SRDS_INTERNAL_COMPOSE_PLL_DIV(  96, 0, 18); break;
    342             case 17: *srds_div = SRDS_INTERNAL_COMPOSE_PLL_DIV( 120, 0, 18); break;
    343             case 18: *srds_div = SRDS_INTERNAL_COMPOSE_PLL_DIV( 144, 0, 18); break;
    344             case 19: *srds_div = SRDS_INTERNAL_COMPOSE_PLL_DIV( 198, 0, 18); break;
    345             default:
    346                 EFUN_PRINTF(("ERROR: blackhawk_tsc_INTERNAL_read_pll_div() found invalid pll_mode value:  %d\n", pll_mode));
    347                 return (blackhawk_tsc_error(sa__, ERR_CODE_PLL_DIV_INVALID));
    348         }
    349     }
    350     return (ERR_CODE_NONE);
    351 }