📄 ar7.c
字号:
/*-----------------------------------------------------------------------------*/
/* */
/* Copyright (C) 2003 by Texas Instruments, Inc. All rights reserved. */
/* Copyright (C) 2003 Telogy Networks. */
/*-----------------------------------------------------------------------------*/
#include "_stdio.h"
#include "env.h"
#include "hw.h"
#include "main.h"
#define ABS(x) ( ((signed)(x) > 0) ? (x) : (-(x)) )
#define CEIL(x,y) ( ((x) + (y) / 2) / (y) )
#define TNETD73XX_SYSCLK_DIV 0xa8610a20
#define TNETD73XX_SYSCLK_PLL 0xa8610a30
#define MAX_DIV_VALUE 16
#define PLL_MUL_MAXFACTOR 15
#define MIN_PLL_INP_FREQ MHZ(8)
#define MAX_PLL_INP_FREQ MHZ(100)
unsigned int _SysFrequency;
unsigned int max_cpu_frequency;
static unsigned int get_base_clk()
{
bit32u bootcr, freq = 1;
/* system clock */
bootcr = REG32_R(0xa8611a00, 15, 14);
switch (bootcr)
{
case 0:
freq = CONF_AFEXTAL_FREQ;
break;
case 1:
freq = CONF_REFXTAL_FREQ;
break;
case 2:
freq = CONF_XTAL3IN_FREQ;
break;
case 3:
if (REG32_R(0xa8611a00, 25, 25) == 1)
freq = _CpuFrequency;
else
freq = CONF_REFXTAL_FREQ;
}
return freq;
}
unsigned int get_mips_freq()
{
bit32u mips_pll_setting;
bit32u mips_div_setting;
bit32u predivider;
bit32u postdivider;
unsigned int pll_factor;
unsigned int base_clk;
mips_div_setting = REG32(TNETD73XX_SYSCLK_DIV); /* Divisor is a 4 bit N+1 divisor */
predivider = (0x1f & mips_div_setting) + 1;
postdivider = ((0x1f << 16) & mips_div_setting) + 1;
base_clk = get_base_clk() /(predivider * postdivider);
mips_pll_setting = REG32(TNETD73XX_SYSCLK_PLL);
/* Get the PLL multiplication factor */
pll_factor = ((mips_pll_setting & 0xF000) >>12) + 1;
/* Check if we're in divide mode or multiply mode */
if((mips_pll_setting & 0x1) == 1)
{
if((mips_pll_setting & 0x0802) == 0x802) /* See if PLLNDIV & PLLDIV are set */
{
if(mips_pll_setting & 0x1000)
{
/* clk = base_clk * (k-1) / 4)*/
return((base_clk * (pll_factor - 1)) >>2);
}
else
{
/* clk = base_clk * k /2 */
return((base_clk * pll_factor) >> 1);
}
}
else
{
if(pll_factor == 0x10)
{
pll_factor = 1;
}
return(base_clk*pll_factor);
}
}
else /* We're in divide mode */
{
if(pll_factor < 0x10)
{
/* clk = base_clk /2 */
return(base_clk >> 1);
}
else
{
/* clk = base_clk / 4 */
return(base_clk >> 2);
}
}
return(0); /* Should never reach here */
}
static UINT32 find_gcd(UINT32 min, UINT32 max)
{
if (max % min == 0)
{
return min;
}
else
{
return find_gcd(max % min, min);
}
}
static void find_approx(UINT32 *num, UINT32 *denom, UINT32 base_freq)
{
UINT32 num1;
UINT32 denom1;
UINT32 num2;
UINT32 denom2;
INT32 closest;
INT32 prev_closest;
UINT32 temp_num;
UINT32 temp_denom;
UINT32 normalize;
UINT32 gcd;
UINT32 output;
num1 = *num;
denom1 = *denom;
prev_closest = 0x7fffffff; /* maximum possible value */
num2 = num1;
denom2 = denom1;
/* start with max */
for(temp_num = 15; temp_num >=1; temp_num--)
{
temp_denom = CEIL(temp_num * denom1, num1);
if(temp_denom < 1)
{
break;
}
else
{
normalize = CEIL(num1,temp_num);
closest = (ABS((num1 * (temp_denom) ) - (temp_num * denom1))) * normalize;
output = (temp_num * base_freq)/temp_denom;
if(closest < prev_closest && output <= max_cpu_frequency && output > SYS_MIN_F)
{
prev_closest = closest;
num2 = temp_num;
denom2 = temp_denom;
}
}
}
gcd = find_gcd(num2,denom2);
num2 = num2 / gcd;
denom2 = denom2 /gcd;
*num = num2;
*denom = denom2;
}
static void get_val(UINT32 output_freq, UINT32 base_freq,UINT32 *multiplier, UINT32 *divider)
{
UINT32 temp_mul;
UINT32 temp_div;
UINT32 gcd;
UINT32 min_freq;
UINT32 max_freq;
/* find gcd of base_freq, output_freq */
min_freq = (base_freq < output_freq) ? base_freq : output_freq;
max_freq = (base_freq > output_freq) ? base_freq : output_freq;
gcd = find_gcd(min_freq , max_freq);
/* compute values of multiplier and divider */
temp_mul = output_freq / gcd;
temp_div = base_freq / gcd;
/* set multiplier such that 1 <= multiplier <= PLL_MUL_MAXFACTOR */
if( temp_mul > PLL_MUL_MAXFACTOR )
find_approx(&temp_mul,&temp_div, base_freq);
*multiplier = temp_mul;
*divider = temp_div;
}
static UINT32 compute_prediv(UINT32 divider, UINT32 min, UINT32 max)
{
UINT16 prediv;
/* return the divider itself it it falls within the range of predivider*/
if (min <= divider && divider <= max)
return divider;
/* find a value for prediv such that it is a factor of divider */
for (prediv = max; prediv >= min ; prediv--)
if ((divider % prediv) == 0)
return prediv;
/* No such factor exists, return min as prediv */
return min;
}
static void get_div_prenpost(bit32u multiplier, bit32u divider, bit32u clk_in,
bit32u *pre, bit32u *post)
{
bit32u min_prediv, max_prediv, temp;
/* required for other modules whose input has CPU freq. */
/*compute minimum and maximum predivider values */
min_prediv = MAX(clk_in/MAX_PLL_INP_FREQ + 1, divider/MAX_DIV_VALUE + 1);
max_prediv = MIN(clk_in/MIN_PLL_INP_FREQ, MAX_DIV_VALUE);
/*adjust the value of divider so that it not less than minimum predivider value*/
if (divider < min_prediv)
{
temp = CEIL(min_prediv, divider);
if ((temp * multiplier) > PLL_MUL_MAXFACTOR) {
} else {
multiplier = temp * multiplier;
divider = min_prediv;
}
}
/* compute predivider and postdivider values */
*pre = compute_prediv(divider, min_prediv, max_prediv);
*post = CEIL(divider, *pre);
}
bit32u get_base_frequency(bit32u clk_id)
{
bit32u bootcr, freq=1;
if (clk_id == 0) { /* system clock */
bootcr = REG32_R(0xa8611a00, 15, 14);
switch (bootcr) {
case 0: freq = CONF_AFEXTAL_FREQ; break;
case 2: freq = CONF_XTAL3IN_FREQ; break;
case 1: freq = CONF_REFXTAL_FREQ; break;
case 3: freq = get_base_frequency(1);
}
} else if (clk_id == 1) { /* MIPS clock */
bootcr = REG32_R(0xa8611a00, 17, 16);
switch (bootcr) {
case 0: freq = CONF_AFEXTAL_FREQ; break;
case 2: freq = CONF_XTAL3IN_FREQ; break;
case 1:
case 3: freq = CONF_REFXTAL_FREQ;
}
} else {
sys_printf("\nInvalid clk_id");
return 0;
}
return freq;
}
#if 0
int cfg_cpufreq(bit32u freq)
{
bit32u multiplier, divider, clk_in, pre, post, mips_async;
volatile bit32u i;
char sbuf[30];
mips_async = REG32_R(0xa8611a00, 25, 25);
if (mips_async == 0) {
max_cpu_frequency = CPU_SYNC_MAX_F;
clk_in = get_base_clk();
get_val(freq, clk_in, &multiplier, ÷r);
if (clk_in >= MAX_PLL_INP_FREQ) {
get_div_prenpost(multiplier, divider, clk_in, &pre, &post);
} else {
post = divider;
pre = 1;
}
EMIF_DRAMCTL |= 0x80000000;
SioFlush();
REG32_W(0xa8610a20, ((post - 1) & 0x1F) << 16 | ((pre - 1) & 0x1F));
for(i=0;i<10100 * 75;i++); /* wait for divider to stabilize */
SetRefClkPllReg(multiplier - 1);
_CpuFrequency = (clk_in * multiplier)/(pre * post);
_SysFrequency = _CpuFrequency;
SioInit();
EMIF_DRAMCTL &= ~0x80000000;
sys_sprintf(sbuf, "%d", _CpuFrequency);
sys_setenv("cpufrequency", sbuf);
sys_sprintf(sbuf, "%d", _SysFrequency);
sys_setenv("sysfrequency", sbuf);
}
return 0;
}
#endif
int cfg_cpufreq(bit32u sysf, bit32u cpuf, bit32u dbg_opt)
{
bit32u multiplier, divider, clk_in, pre, post, mips_async;
volatile bit32u i;
char sbuf[30];
if (dbg_opt == TRUE) {
sys_printf("CPU Freq: %d", _CpuFrequency);
sys_printf("\nSYS Freq: %d\n", _SysFrequency);
return 0;
}
mips_async = REG32_R(0xa8611a00, 25, 25);
if (mips_async == 0) {
max_cpu_frequency = CPU_SYNC_MAX_F;
if (sysf == -1) sysf = cpuf;
if (sysf > max_cpu_frequency) sysf = max_cpu_frequency;
if (sysf < SYS_MIN_F) sysf = SYS_MIN_F;
clk_in = get_base_frequency(0);
get_val(sysf, clk_in, &multiplier, ÷r);
if (clk_in >= MAX_PLL_INP_FREQ) {
get_div_prenpost(multiplier, divider, clk_in, &pre, &post);
} else {
post = divider;
pre = 1;
}
EMIF_DRAMCTL |= 0x80000000;
SioFlush();
/*REG32_W(0xa8610a20, ((post - 1) & 0x1F) << 16 | ((pre - 1) & 0x1F));*/
REG32_W(0xa8610a20, ((pre - 1) & 0x1F) << 16 | ((post - 1) & 0x1F));
/* wait */for(i = 0; i < 10100 * 75; i++);
SetRefClkPllReg(multiplier - 1, 0);
_SysFrequency = _CpuFrequency = (clk_in * multiplier)/(pre * post);
REG32_RMW(0xa861080c, 12, 0, ((_SysFrequency / MHZ(1)) * 78) / 10);
/* wait */for(i = 0; i < 10100 * 75; i++);
SioInit();
EMIF_DRAMCTL &= ~0x80000000;
} else {
EMIF_DRAMCTL |= 0x80000000;
SioFlush();
if (cpuf != -1) {
max_cpu_frequency = CPU_ASYNC_MAX_F;
if (cpuf > max_cpu_frequency) cpuf = max_cpu_frequency;
if (cpuf < SYS_MIN_F) cpuf = SYS_MIN_F;
clk_in = get_base_frequency(1);
get_val(cpuf, clk_in, &multiplier, ÷r);
/*REG32_W(0xa8610a40, ((divider -1) & 0x1F) << 16);*/
REG32_W(0xa8610a40, ((divider -1) & 0x1F));
/* wait */for(i = 0; i < 10100 * 75; i++);
SetRefClkPllReg(multiplier - 1, 1);
_CpuFrequency = (clk_in * multiplier)/divider;
}
if (sysf != -1) {
clk_in = get_base_frequency(0);
if (sysf > SYS_MAX_F) sysf = SYS_MAX_F;
if (sysf < SYS_MIN_F) sysf = SYS_MIN_F;
get_val(sysf, clk_in, &multiplier, ÷r);
if (clk_in >= MAX_PLL_INP_FREQ) {
get_div_prenpost(multiplier, divider, clk_in, &pre, &post);
} else {
post = divider;
pre = 1;
}
/*REG32_W(0xa8610a20, ((post - 1) & 0x1F) << 16 | ((pre - 1) & 0x1F));*/
REG32_W(0xa8610a20, ((pre - 1) & 0x1F) << 16 | ((post - 1) & 0x1F));
/* wait */for(i = 0; i < 10100 * 75; i++);
SetRefClkPllReg(multiplier - 1, 0);
_SysFrequency = (clk_in * multiplier)/(pre * post);
REG32_RMW(0xa861080c, 12, 0, ((_CpuFrequency / MHZ(1)) * 78) / 10);
/* wait */for(i = 0; i < 10100 * 75; i++);
}
SioInit();
EMIF_DRAMCTL &= ~0x80000000;
}
sys_sprintf(sbuf, "%d", _CpuFrequency);
sys_setenv("cpufrequency",sbuf);
sys_sprintf(sbuf, "%d", _SysFrequency);
sys_setenv("sysfrequency",sbuf);
return 0;
}
void platform_init()
{
RESET_PRCR |= UART0_RESET;
RESET_PRCR |= GPIO_RESET;
#if (CONF_CPMAC_IF == 0)
/* #ifdef INTERNAL_PHY by Oleg changed back to original */
GPIO_EN = 0xf3fc3ff0;
#else
GPIO_EN = 0xfffc3ff0;
#endif
#if (CONF_CPMAC_IF == 0)
/* #ifdef INTERNAL_PHY by Oleg changed back to original */
RESET_PRCR &= (~EMAC_PHY_RESET);
RESET_PRCR |= EMAC_PHY_RESET;
#endif
RESET_PRCR |= MDIO_RESET;
#if (CONF_CPMAC_IF == 0)
/* #ifdef INTERNAL_PHY by Oleg changed back to original */
RESET_PRCR |= EMACA_RESET;
#endif
RESET_PRCR |= EMACB_RESET;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -