/** @fn uint32_t bcm47xx_is_csrc_enabled(clkmgr_tcsrc_t csrc); */ uint32_t bcm47xx_is_csrc_enabled(clkmgr_tcsrc_t csrc) { uint32_t csrc_stat = enable; BCM_ASSERT(csrc > ECLKMGR_TCSRC_NONE); BCM_ASSERT(csrc <= ECLKMGR_MAX_TCSRC); if (csrc == ECLKMGR_TCSRC_XTAL_32KHZ) { return(csrc_stat); //Always enabled } if (csrc >= ECLKMGR_TCSRC_PLLS) { //it is a pll csrc_stat = tahoe_opmode_is_pll_enabled((csrc - ECLKMGR_TCSRC_PLLS)); bcm_log_debug("%s : clk source PLL[%d] csrc_stat[%d]\n", __FUNCTION__, csrc, csrc_stat); } else { //it is an oscillator csrc_stat = chipmgr_is_oscillator_on((chipmgr_clk_t)csrc); bcm_log_debug("%s : clk source OSC[%d] csrc_stat[%d]\n", __FUNCTION__, csrc, csrc_stat); } return(csrc_stat); }
static void setMem(void *start, uint32_t val, uint32_t len, uint32_t unitSize) { int i; uint8_t* curPtr = start; BCM_ASSERT((unitSize == UNIT_SIZE_BYTES) || (unitSize == UNIT_SIZE_HALFWORDS) || (unitSize == UNIT_SIZE_WORDS)); BCM_ASSERT(((uint32_t)start&~(unitSize-1)) == (uint32_t)start); for (i = 0; i < len; ++i) { switch (unitSize) { case UNIT_SIZE_BYTES: { *curPtr = (uint8_t)val; break; } case UNIT_SIZE_HALFWORDS: { uint16_t *cur16Ptr = (uint16_t*)curPtr; *cur16Ptr = (uint16_t)val; break; } case UNIT_SIZE_WORDS: { uint32_t *cur32Ptr = (uint32_t*)curPtr; *cur32Ptr = (uint32_t)val; break; } default: break; } curPtr += unitSize; } }
/** @fn uint32_t bcm47xx_config_csrcs(bcm47xx_csrc_info_t *clk_srcs, , uint32_t num_csrcs) */ uint32_t bcm47xx_config_csrcs(bcm47xx_csrc_info_t *clk_srcs, uint32_t num_csrcs) { uint32_t idx, ret, fret; clkmgr_pll_t pll; BCM_ASSERT((clk_srcs != NULL) && (num_csrcs != 0)); fret = BCM_OK; for (idx = 0; idx < num_csrcs; idx++) { BCM_ASSERT(clk_srcs[idx].csrc > ECLKMGR_TCSRC_NONE); BCM_ASSERT(clk_srcs[idx].csrc <= ECLKMGR_MAX_TCSRC); //Don't touch clock sources that are in use.. if (bcm47xx_is_csrc_in_use(clk_srcs[idx].csrc)) { bcm_log_debug("%s : clk source [%d] in use, requested cfg[%d]\n", __FUNCTION__, clk_srcs[idx].csrc, clk_srcs[idx].stat); continue; } bcm_log_debug("%s : clk source [%d] csrc_stat[%d]\n", __FUNCTION__, clk_srcs[idx].csrc, clk_srcs[idx].stat); if (clk_srcs[idx].csrc < ECLKMGR_TCSRC_PLLS) { //it is an oscillator ret = chipmgr_config_oscillators(clk_srcs[idx].csrc, clk_srcs[idx].stat, TRUE); } else if (clk_srcs[idx].csrc >= ECLKMGR_TCSRC_PLLS) { //it is a pll //Note: there is no single api to config a pll just like there is one for oscillators // is because enabling a pll needs additional parameters. pll = clk_srcs[idx].csrc - ECLKMGR_TCSRC_PLLS; if (clk_srcs[idx].stat == enable) { ret = clkmgr_enable_pll(pll, bcm47xx_get_pll_default(pll)); } else { ret = clkmgr_disable_pll(pll); } } if (ret != BCM_OK) { fret = BCM_ERROR; bcm_log_error("%s : clk source [%d] could not be configured\n", __FUNCTION__, clk_srcs[idx].csrc); } }//end for each clock source return(fret); }
tahoe_stat_t bcm47xx_opmode_round_rate_set_up_pll(clkmgr_pll_t pll, clkmgr_freq_info_t *pfreq, uint32_t *pnew_div, unsigned long *pactual_freq) { tahoe_stat_t ret; unsigned long pll_freq; unsigned long deviation_percent; clkmgr_pll_settings_t *pll_defs; BCM_ASSERT(pfreq != NULL); BCM_ASSERT(pnew_div != NULL); BCM_ASSERT(pactual_freq != NULL); //Set up the pll to the desired frequency only of the freq is > min_freq that a pll can be set to.. //for 32KHz and less, we configure the pll in bypass mode. if ((pfreq->desired_freq <= CLKMGR_XTAL_32KHZ_FREQUENCY) || (pfreq->desired_freq >= CLKMGR_PLL_FREQ_MIN)) { ret = tahoe_opmode_round_rate_pll_freq(pll, pfreq->desired_freq, pfreq->tolerance_percent, pactual_freq); if (ret == OpOk) *pnew_div = 1; return(ret); } //calculate the source frequecy based on default dividers pll_defs = bcm47xx_get_pll_default(pll); pll_freq = (CLKMGR_XTAL_24MHZ_FREQUENCY * pll_defs->qdiv)/pll_defs->pdiv; bcm47xx_get_suitable_divisor(pfreq->desired_freq, pll_freq, pnew_div, CLKMGR_DIV_MIN, pfreq->max_div); *pactual_freq = bcm_udivide32_round(pll_freq, *pnew_div); deviation_percent = bcm_get_deviation_percent(pfreq->desired_freq, *pactual_freq); if (pfreq->tolerance_percent != 0) { if (deviation_percent < pfreq->tolerance_percent) { //This PLL is good... enable it... return(OpOk); } return(OpNoSuitableClkSrc); } else { //This PLL is good... enable it... return(OpOk); } }
//Not considering crystals in this function... if required, we could add them as well. uint32_t bcm47xx_find_disabled_source(clkmgr_freq_info_t *pfreq, uint32_t use_all, clkmgr_tcsrc_t *pnew_csrc, uint32_t *pnew_div, unsigned long *pactual_freq) { uint32_t pll_idx, ret=BCM_OK; BCM_ASSERT(pfreq != NULL); BCM_ASSERT(pactual_freq != NULL); BCM_ASSERT(pnew_csrc != NULL); BCM_ASSERT(pnew_div != NULL); //Ignore PLLS, the first pll... because it is dynamic and could change frequently. for (pll_idx = 1; pll_idx < CLKMGR_PLL_COUNT; pll_idx++) { if (clkmgr_is_pll_enabled((clkmgr_pll_t)pll_idx) == FALSE) { ret = bcm47xx_opmode_set_up_pll((clkmgr_pll_t)pll_idx, pfreq, pnew_div, pactual_freq); if (ret == OpOk) { *pnew_csrc = (clkmgr_tcsrc_t)pll_idx + ECLKMGR_TCSRC_PLLS; return(OpOk); } }//endif-pll-disabled }//end-for each pll //We did not find a any disabled pll or the ones we found were not able to provide us //a suitable frequency. *pnew_csrc = ECLKMGR_TCSRC_NONE; *pnew_div = 0; *pactual_freq = 0; return(BCM_ERROR); }
/* * helper function to find if there is a clock source which can be * used to generate a desired frequency */ uint32_t bcm47xx_find_suitable_source(clkmgr_freq_info_t *pfreq, uint32_t use_all, clkmgr_tcsrc_t *pnew_csrc, uint32_t *pnew_div, unsigned long *pactual_freq) { uint32_t pll_idx, i, ret=BCM_OK; int_t new_deviation = INT_MAX; uint32_t div, next_best_div=0; int_t deviation; unsigned long source_freq[CLKMGR_TCSRC_COUNT]; unsigned long new_source_freq = 0, tmp_freq, next_best_actual_freq=0; uint32_t deviation_percent; clkmgr_tcsrc_t next_best_csrc=0; BCM_ASSERT((pfreq != NULL) && (pnew_csrc != NULL) && (pnew_div != NULL) && (pactual_freq != NULL)); for (i=0; i < CLKMGR_TCSRC_COUNT; i++) source_freq[i] = 0; //gather all source frequencies source_freq[ECLKMGR_TCSRC_NONE] = 0; //TSRC_NONE is 0 if (bcm47xx_is_csrc_enabled(ECLKMGR_TCSRC_XTAL_24MHZ)) source_freq[ECLKMGR_TCSRC_XTAL_24MHZ] = CLKMGR_XTAL_24MHZ_FREQUENCY; if (use_all && (bcm47xx_is_csrc_enabled(ECLKMGR_TCSRC_XTAL_27MHZ))) //In some cases, all crystals are used { source_freq[ECLKMGR_TCSRC_XTAL_27MHZ] = CLKMGR_XTAL_27MHZ_FREQUENCY; } if (use_all && (bcm47xx_is_csrc_enabled(ECLKMGR_TCSRC_XTAL_32KHZ))) //In some cases, all crystals are used { source_freq[ECLKMGR_TCSRC_XTAL_32KHZ] = CLKMGR_XTAL_27MHZ_FREQUENCY; } //should we leave PLLS out because that could be changing too often and hence not //a stable source? // For now, we'll leave PLLS out.. source_freq[ECLKMGR_TCSRC_PLLS] = 0; for (pll_idx = ECLKMGR_TCSRC_PLL1; pll_idx < CLKMGR_TCSRC_COUNT; pll_idx++) { tahoe_opmode_get_pll_freq(pll_idx - ECLKMGR_TCSRC_PLLS, &(source_freq[pll_idx]) ); } //Find the best of the lot for (i = 0; i < CLKMGR_TCSRC_COUNT; i++) { if (source_freq[i]) //Note: in some cases, the 27MHz and the 32KHz crystals are not used { bcm47xx_get_suitable_divisor(pfreq->desired_freq, source_freq[i], &div, CLKMGR_DIV_MIN, pfreq->max_div); tmp_freq = bcm_udivide32_round(source_freq[i], div); if (tmp_freq > pfreq->desired_freq) { deviation = tmp_freq - pfreq->desired_freq; } else { deviation = pfreq->desired_freq - tmp_freq; } if (deviation < new_deviation) { /* remember the "best-suited" PLL so far */ new_deviation = deviation; new_source_freq = source_freq[i]; *pnew_csrc = (clkmgr_tcsrc_t)i; *pnew_div = div; } } } if (new_deviation != INT_MAX) { bcm_log_debug("%s : We might have a new source[%d], new_div[%d]\n",__FUNCTION__, *pnew_csrc, *pnew_div); *pactual_freq = bcm_udivide32_round(new_source_freq, *pnew_div); deviation_percent = bcm_get_deviation_percent(pfreq->desired_freq, *pactual_freq); bcm_log_debug("%s : desired_freq[%ld] actual_freq[%ld] deviation[%d] tolerance[%d]\n", __FUNCTION__, pfreq->desired_freq, *pactual_freq, deviation_percent, pfreq->tolerance_percent); if (((pfreq->tolerance_percent != 0) && (deviation_percent < pfreq->tolerance_percent)) || ((pfreq->tolerance_percent == 0) && (deviation_percent == 0))) { return(BCM_OK); } else if ((pfreq->tolerance_percent == 0) && (deviation_percent > 0)) { //NEXT_BEST_SOLN //If tolerance_percent is '0', the user is expecting the best possible //frequency. We have found one but what if there is a disabled PLL //that can use use the exact frequency? //In order to handle this, we save the current csrc, div etc and if //we can't find a disabled source, we fall back on the next best solution. next_best_csrc = *pnew_csrc; next_best_div = *pnew_div; next_best_actual_freq = *pactual_freq; } //We can't meet the tolerance requirement, see if we can enable a pll *pactual_freq = 0; ret = bcm47xx_find_disabled_source(pfreq, use_all, pnew_csrc, pnew_div, pactual_freq); if (ret == BCM_OK) { //we found a disabled PLL. bcm_log_debug("%s : We found a disabled pll that can be a suitable source\n",__FUNCTION__); return(BCM_OK); } //NEXT_BEST_SOLN if ((pfreq->tolerance_percent == 0) && (deviation_percent > 0)) { //switch back to next best values as we could not find *pnew_csrc = next_best_csrc; *pnew_div = next_best_div; *pactual_freq = next_best_actual_freq; return(BCM_OK); } return(BCM_ERROR); } //See if we can use a disabled pll to get to the desired frequency. else { //If there is any PLL (other than the system PLL) that is disabled, //we can enable and configure it to its default frequency and use //that as the source. ret = bcm47xx_find_disabled_source(pfreq, use_all, pnew_csrc, pnew_div, pactual_freq); if (ret == BCM_OK) { //we found a disabled PLL that meets the requirement. bcm_log_debug("%s : We found a disabled pll that can be a suitable source\n",__FUNCTION__); } } return(ret); }
/* * @fn bool_t bcm47xx_is_suitable_csrc(...) */ bool_t bcm47xx_is_suitable_csrc(clkmgr_tcsrc_t source, clkmgr_freq_info_t *pfreq, uint32_t *pnew_div, unsigned long *actual_freq) { unsigned long source_freq; uint32_t div; uint32_t deviation_percent; BCM_ASSERT((pfreq != NULL) && (pnew_div != NULL) && (actual_freq != NULL)); if (source == ECLKMGR_TCSRC_NONE) { return(FALSE); } //check to see if the source is enabled. if (bcm47xx_is_csrc_enabled(source) == disable) { //If it's not enabled, we can't use it and hence unsuitable return(FALSE); } if (source == ECLKMGR_TCSRC_XTAL_24MHZ) { source_freq = CLKMGR_XTAL_24MHZ_FREQUENCY; } else if (source == ECLKMGR_TCSRC_XTAL_27MHZ) { source_freq = CLKMGR_XTAL_27MHZ_FREQUENCY; } else if (source == ECLKMGR_TCSRC_XTAL_32KHZ) { source_freq = CLKMGR_XTAL_32KHZ_FREQUENCY; } else { tahoe_opmode_get_pll_freq(source - ECLKMGR_TCSRC_PLLS, &source_freq); } bcm47xx_get_suitable_divisor(pfreq->desired_freq, source_freq, &div, CLKMGR_DIV_MIN, pfreq->max_div); bcm_log_debug("%s : clk source [%d] divider[%d] source_freq[%lu]\n", __FUNCTION__, source, div, source_freq); *actual_freq = bcm_udivide32_round(source_freq, div); if( pfreq->tolerance_percent != 0 ) { deviation_percent = bcm_get_deviation_percent(pfreq->desired_freq, *actual_freq); if (deviation_percent <= pfreq->tolerance_percent) { bcm_log_debug("%s: desired_freq[%ld] actual_freq[%ld] deviation[%d] tolerance[%d] return TRUE\n", __FUNCTION__, pfreq->desired_freq, *actual_freq, deviation_percent, pfreq->tolerance_percent); *pnew_div = div; return(TRUE); } else { bcm_log_debug("%s: desired_freq[%ld] actual_freq[%ld] deviation[%d] tolerance[%d] return FALSE\n", __FUNCTION__, pfreq->desired_freq, *actual_freq, deviation_percent, pfreq->tolerance_percent); *actual_freq = 0; return(FALSE); } } else { /* in case tolerance_percent is zero, return TRUE as we are simply looking * for the best match that can be done */ bcm_log_debug("%s: desired_freq[%ld] actual_freq[%ld] tolerance[%d] return TRUE\n", __FUNCTION__, pfreq->desired_freq, *actual_freq, pfreq->tolerance_percent); *pnew_div = div; return(TRUE); } }
static void dumpHexData(void *start, uint32_t len, uint32_t unitSize, int bSpiRead) { int i; unsigned long temp; /*Force natural alignment*/ uint8_t* curPtr; BCM_ASSERT((unitSize == UNIT_SIZE_BYTES) || (unitSize == UNIT_SIZE_HALFWORDS) || (unitSize == UNIT_SIZE_WORDS)); curPtr = (uint8_t*)((uint32_t)start&(~(unitSize-1))); for (i = 0; i < len; ++i) { if (i % (4/unitSize) == 0) bcmPrint(" "); if (i % (16/unitSize) == 0) bcmPrint("\n0x%08X : ", (unsigned int)curPtr); switch (unitSize) { case UNIT_SIZE_BYTES: { if ( bSpiRead ) { spiFns.kerSysSlaveRead((unsigned long)curPtr, &temp, unitSize); bcmPrint("%02X ", (unsigned char)temp); } else { bcmPrint("%02X ", *curPtr); } break; } case UNIT_SIZE_HALFWORDS: { uint16_t *cur16Ptr = (uint16_t*)curPtr; if ( bSpiRead ) { spiFns.kerSysSlaveRead((unsigned long)curPtr, &temp, unitSize); bcmPrint("%04X ", (unsigned short)temp); } else { bcmPrint("%04X ", *cur16Ptr); } break; } case UNIT_SIZE_WORDS: { uint32_t *cur32Ptr = (uint32_t*)curPtr; if ( bSpiRead ) { spiFns.kerSysSlaveRead((unsigned long)curPtr, &temp, unitSize); bcmPrint("%08lX ", (unsigned long)temp); } else { bcmPrint("%08X ", *cur32Ptr); } break; } default: break; } curPtr += unitSize; } bcmPrint("\n"); }