merlin16_pll_config.c (7690B)
1 /********************************************************************************** 2 ********************************************************************************** 3 * File Name : merlin16_pll_config.c * 4 * Created On : 14/07/2013 * 5 * Created By : Kiran Divakar * 6 * Description : Merlin16 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 /** @file merlin16_pll_config.c 23 * Merlin16 PLL Configuration 24 */ 25 26 27 #include "merlin16_config.h" 28 #include "merlin16_functions.h" 29 #include "merlin16_internal.h" 30 #include "merlin16_internal_error.h" 31 #include "merlin16_select_defns.h" 32 33 #define _ndiv_frac_l(x) ((x)&0xF) 34 #define _ndiv_frac_h(x) ((x)>>4) 35 36 #define _ndiv_frac_decode(l_, h_) (((l_) & 0xF) | (((h_) & 0x3FFF) << 4)) 37 38 static const uint8_t pll_fraction_width = 18; 39 40 err_code_t merlin16_INTERNAL_configure_pll(srds_access_t *sa__, 41 enum merlin16_pll_refclk_enum refclk, 42 enum merlin16_pll_div_enum div, 43 uint32_t vco_freq_khz, 44 enum merlin16_pll_option_enum pll_option) { 45 uint32_t refclk_freq_hz; 46 47 EFUN(merlin16_INTERNAL_resolve_pll_parameters(refclk, &refclk_freq_hz, &div, &vco_freq_khz, MERLIN16_PLL_OPTION_NONE)); 48 49 /* Use this to restore defaults if reprogramming the PLL under dp-reset (typically Auto-Neg FW) - Need this for DUAL_PLL (see F16) */ 50 /* EFUN(wrc_ams_pll_i_ndiv_int(0x42)); */ 51 /* EFUN(wrc_ams_pll_i_ndiv_frac_h(_ndiv_frac_h(0x0))); */ 52 /* EFUN(wrc_ams_pll_i_ndiv_frac_l(_ndiv_frac_l(0x0))); */ 53 /* EFUN(wrc_ams_pll_i_pll_frac_mode(0x2)); */ 54 55 { 56 uint8_t reset_state; 57 /* Use core_s_rstb to re-initialize all registers to default before calling this function. */ 58 ESTM(reset_state = rdc_core_dp_reset_state()); 59 60 if(reset_state < 7) { 61 EFUN_PRINTF(("ERROR: merlin16_configure_pll(..) called without core_dp_s_rstb=0\n")); 62 return (_error(ERR_CODE_CORE_DP_NOT_RESET)); 63 } 64 } 65 66 /* Clear PLL powerdown */ 67 EFUN(wrc_ams_pll_pwrdn(0)); 68 69 EFUN(wrc_ams_pll_i_ndiv_int(SRDS_INTERNAL_GET_PLL_DIV_INTEGER(div))); 70 { 71 const uint32_t pll_fraction_num = SRDS_INTERNAL_GET_PLL_DIV_FRACTION_NUM(div, pll_fraction_width); 72 const uint8_t frac_mode_en = (pll_fraction_num != 0); 73 EFUN(wrc_ams_pll_i_ndiv_frac_h (_ndiv_frac_h(pll_fraction_num))); 74 EFUN(wrc_ams_pll_i_ndiv_frac_l (_ndiv_frac_l(pll_fraction_num))); 75 EFUN(wrc_ams_pll_sel_fp3cap ((frac_mode_en) ? 0xF : 0x0)); 76 EFUN(wrc_ams_pll_i_pfd_offset ((frac_mode_en) ? 0x2 : 0x0)); 77 EFUN(wrc_ams_pll_i_ndiv_dither_en((frac_mode_en && (refclk != MERLIN16_PLL_REFCLK_50MHZ)) ? 0x1 : 0x0)); 78 EFUN(wrc_ams_pll_en_8p5g ((vco_freq_khz <= 9375000) ? 0x1 : 0x0)); /* pll_ctrl<36> */ 79 EFUN(wrc_ams_pll_en_8p5g_vco ((vco_freq_khz <= 9375000) ? 0x1 : 0x0)); /* pll_ctrl<21> */ 80 EFUN(wrc_ams_pll_en_hcur_vco (0x1)); /* pll_ctrl<31> */ 81 EFUN(wrc_ams_pll_refclk_in_bias (0x3F)); /* pll_ctrl<159:154> */ 82 EFUN(wrc_ams_pll_vco_hkvco ((vco_freq_khz <= 9375000) ? 0x1 : 0x0)); /* pll_ctrl<71>, now called VCO_HKVCO */ 83 84 /* Handle refclk PLL options */ 85 if (pll_option == MERLIN16_PLL_OPTION_REFCLK_DIV2_EN) { 86 EFUN(wrc_ams_pll_refclk_div2_frc_val(1)); 87 EFUN(wrc_ams_pll_refclk_div_frc(1)); 88 } else if (pll_option == MERLIN16_PLL_OPTION_REFCLK_DIV4_EN) { 89 EFUN(wrc_ams_pll_refclk_div4_frc_val(1)); 90 EFUN(wrc_ams_pll_refclk_div_frc(1)); 91 } 92 93 /* pll_ctrl<19:16> */ 94 if (refclk == MERLIN16_PLL_REFCLK_161P1328125MHZ) 95 if (vco_freq_khz < 9375000) EFUN(wrc_ams_pll_curr_sel(0x3)); 96 else EFUN(wrc_ams_pll_curr_sel(0x5)); 97 else if (frac_mode_en) EFUN(wrc_ams_pll_curr_sel(0x3)); 98 else EFUN(wrc_ams_pll_curr_sel(0xD)); 99 100 101 102 /* pll_ctrl<11:9> */ 103 if (refclk == MERLIN16_PLL_REFCLK_161P1328125MHZ) 104 if (vco_freq_khz < 9375000) EFUN(wrc_ams_pll_rpar(0x2)); 105 else EFUN(wrc_ams_pll_rpar(0x3)); 106 else if (refclk == MERLIN16_PLL_REFCLK_156P25MHZ) 107 if (vco_freq_khz > 12000000) EFUN(wrc_ams_pll_rpar(0x5)); 108 else if (frac_mode_en) EFUN(wrc_ams_pll_rpar(0x2)); 109 else EFUN(wrc_ams_pll_rpar(0x4)); 110 else if (refclk == MERLIN16_PLL_REFCLK_125MHZ) 111 if (frac_mode_en) EFUN(wrc_ams_pll_rpar(0x2)); 112 else if (vco_freq_khz < 9375000) EFUN(wrc_ams_pll_rpar(0x3)); 113 else EFUN(wrc_ams_pll_rpar(0x4)); 114 else if (refclk == MERLIN16_PLL_REFCLK_50MHZ) 115 if (frac_mode_en) EFUN(wrc_ams_pll_rpar(0x1)); 116 else if (vco_freq_khz < 8500000) EFUN(wrc_ams_pll_rpar(0x1)); 117 else if (vco_freq_khz < 9375000) EFUN(wrc_ams_pll_rpar(0x2)); 118 else EFUN(wrc_ams_pll_rpar(0x3)); 119 else EFUN(wrc_ams_pll_rpar(0x2)); 120 121 } 122 123 EFUN(wrc_ams_pll_i_pll_frac_mode(0x2)); 124 125 /* Toggling PLL mmd reset */ 126 EFUN(wrc_ams_pll_mmd_resetb(0x0)); 127 EFUN(wrc_ams_pll_mmd_resetb(0x1)); 128 129 /* NOTE: Might have to add some optimized PLL control bus settings post-DVT (See 28nm merlin_pll_config.c) */ 130 131 /* Update core variables with the VCO rate. */ 132 { 133 struct merlin16_uc_core_config_st core_config; 134 EFUN(merlin16_get_uc_core_config(sa__, &core_config)); 135 core_config.vco_rate_in_Mhz = (vco_freq_khz + 500) / 1000; 136 core_config.field.vco_rate = MHZ_TO_VCO_RATE(core_config.vco_rate_in_Mhz); 137 EFUN(merlin16_INTERNAL_set_uc_core_config(sa__, core_config)); 138 } 139 140 return (ERR_CODE_NONE); 141 142 } /* merlin16_configure_pll */ 143 144 err_code_t merlin16_INTERNAL_read_pll_div(srds_access_t *sa__, uint32_t *div) { 145 uint16_t ndiv_int; 146 uint32_t ndiv_frac; 147 ESTM(ndiv_int = rdc_ams_pll_i_ndiv_int()); 148 ESTM(ndiv_frac = _ndiv_frac_decode(rdc_ams_pll_i_ndiv_frac_l(), rdc_ams_pll_i_ndiv_frac_h())); 149 *div = SRDS_INTERNAL_COMPOSE_PLL_DIV(ndiv_int, ndiv_frac, pll_fraction_width); 150 return (ERR_CODE_NONE); 151 } 152