📄 speed.c
字号:
/*
* (C) Copyright 2000
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <ppcboot.h>
#include <ppc_asm.tmpl>
#include <ppc4xx.h>
#include <asm/processor.h>
#include "speed.h"
/* ------------------------------------------------------------------------- */
#define ONE_BILLION 1000000000
#ifdef CONFIG_CPCI405
#if 0
#define FPGA_DEBUG
#endif
#define FPGA_PRG_SLEEP 32 /* fpga program sleep-time */
#define IBM405GP_GPIO0_OR 0xef600700 /* GPIO Output */
#define IBM405GP_GPIO0_TCR 0xef600704 /* GPIO Three-State Control */
#define IBM405GP_GPIO0_ODR 0xef600718 /* GPIO Open Drain */
#define IBM405GP_GPIO0_IR 0xef60071c /* GPIO Input */
/* fpga configuration data - generated by bit2inc */
const unsigned char fpgadata[] =
{
#include "fpgadata.c"
};
/******************************************************************************
*
* fpga_boot - Load fpga-image into fpga
*
*/
static void fpga_boot(void)
{
int i,j,index,len;
unsigned char b;
int size = sizeof(fpgadata);
/* display infos on fpgaimage */
index = 15;
for (i=0; i<4; i++)
{
len = fpgadata[index];
#ifdef FPGA_DEBUG
printf("FPGA: %s\n", &(fpgadata[index+1]));
#endif
index += len+3;
}
/* search for preamble 0xFF2X */
for (index = 0; index < size-1 ; index++)
{
if ((fpgadata[index] == 0xff) && ((fpgadata[index+1] & 0xf0) == 0x20))
break;
}
#ifdef FPGA_DEBUG
printf("FPGA: configdata starts at position 0x%x\n",index);
printf("FPGA: length of fpga-data %d\n", size-index);
#endif
/*
* Setup port pins for fpga programming
*/
out32(IBM405GP_GPIO0_ODR, 0x00000000); /* no open drain pins */
out32(IBM405GP_GPIO0_TCR, 0x07000000); /* setup for output */
out32(IBM405GP_GPIO0_OR, 0x07000000); /* set output pins to high (default) */
#ifdef FPGA_DEBUG
printf("%s\n",((in32(IBM405GP_GPIO0_IR) & 0x00800000) == 0) ? "NOT DONE" : "DONE" );
#endif
/*
* Init fpga by asserting and deasserting PROGRAM*
*/
out32(IBM405GP_GPIO0_OR, 0x03000000);
udelay(FPGA_PRG_SLEEP*1000);
#ifdef FPGA_DEBUG
printf("%s\n",((in32(IBM405GP_GPIO0_IR) & 0x00800000) == 0) ? "NOT DONE" : "DONE" );
#endif
out32(IBM405GP_GPIO0_OR, 0x07000000);
udelay(FPGA_PRG_SLEEP*1000);
#ifdef FPGA_DEBUG
printf("%s\n",((in32(IBM405GP_GPIO0_IR) & 0x00800000) == 0) ? "NOT DONE" : "DONE" );
#endif
/* write configuration-data into fpga... */
for (i=index; i<size; i++)
{
b = fpgadata[i];
for (j=0; j<8; j++)
{
if ((b & 0x80) == 0x80)
{
/*
* Write 1 to fpga
*/
out32(IBM405GP_GPIO0_OR, 0x05000000); /* set clock to 0 */
out32(IBM405GP_GPIO0_OR, 0x05000000); /* set data to 1 */
out32(IBM405GP_GPIO0_OR, 0x06000000); /* set clock to 1 */
out32(IBM405GP_GPIO0_OR, 0x07000000); /* set data to 1 */
}
else
{
/*
* Write 0 to fpga
*/
out32(IBM405GP_GPIO0_OR, 0x05000000); /* set clock to 0 */
out32(IBM405GP_GPIO0_OR, 0x04000000); /* set data to 0 */
out32(IBM405GP_GPIO0_OR, 0x06000000); /* set clock to 1 */
out32(IBM405GP_GPIO0_OR, 0x07000000); /* set data to 1 */
}
/*
* Shift to next bit
*/
b <<= 1;
}
}
udelay(FPGA_PRG_SLEEP*1000);
#ifdef FPGA_DEBUG
printf("%s\n",((in32(IBM405GP_GPIO0_IR) & 0x00800000) == 0) ? "NOT DONE" : "DONE" );
#endif
/*
* Check if fpga's DONE signal - correctly booted ?
*/
if ((in32(IBM405GP_GPIO0_IR) & 0x00800000) == 0)
{
#ifdef FPGA_DEBUG
printf("FPGA: Booting failed!\n");
#endif
}
else
{
#ifdef FPGA_DEBUG
printf("FPGA: Booting successful!\n");
#endif
}
}
#endif
#ifdef CONFIG_PPC405GP
void get_sys_info (PPC405_SYS_INFO *sysInfo)
{
unsigned long pllmr;
unsigned long sysClkPeriodNs = ONE_BILLION / CONFIG_SYS_CLK_FREQ;
/*
* Read PLL Mode register
*/
pllmr = mfdcr(pllmd);
/*
* Determine FWD_DIV.
*/
switch (pllmr & PLLMR_FWD_DIV_MASK)
{
case PLLMR_FWD_DIV_BYPASS:
sysInfo->pllFwdDiv = 1;
break;
case PLLMR_FWD_DIV_3:
sysInfo->pllFwdDiv = 3;
break;
case PLLMR_FWD_DIV_4:
sysInfo->pllFwdDiv = 4;
break;
case PLLMR_FWD_DIV_6:
sysInfo->pllFwdDiv = 6;
break;
default:
printf("\nInvalid FWDDIV bits in PLL Mode reg: %8.8lx\a\n", pllmr);
hang();
}
/*
* Determine FBK_DIV.
*/
switch (pllmr & PLLMR_FB_DIV_MASK)
{
case PLLMR_FB_DIV_1:
sysInfo->pllFbkDiv = 1;
break;
case PLLMR_FB_DIV_2:
sysInfo->pllFbkDiv = 2;
break;
case PLLMR_FB_DIV_3:
sysInfo->pllFbkDiv = 3;
break;
case PLLMR_FB_DIV_4:
sysInfo->pllFbkDiv = 4;
break;
}
/*
* Determine PLB_DIV.
*/
switch (pllmr & PLLMR_CPU_TO_PLB_MASK)
{
case PLLMR_CPU_PLB_DIV_1:
sysInfo->pllPlbDiv = 1;
break;
case PLLMR_CPU_PLB_DIV_2:
sysInfo->pllPlbDiv = 2;
break;
case PLLMR_CPU_PLB_DIV_3:
sysInfo->pllPlbDiv = 3;
break;
case PLLMR_CPU_PLB_DIV_4:
sysInfo->pllPlbDiv = 4;
break;
}
/*
* Determine PCI_DIV.
*/
switch (pllmr & PLLMR_PCI_TO_PLB_MASK)
{
case PLLMR_PCI_PLB_DIV_1:
sysInfo->pllPciDiv = 1;
break;
case PLLMR_PCI_PLB_DIV_2:
sysInfo->pllPciDiv = 2;
break;
case PLLMR_PCI_PLB_DIV_3:
sysInfo->pllPciDiv = 3;
break;
case PLLMR_PCI_PLB_DIV_4:
sysInfo->pllPciDiv = 4;
break;
}
/*
* Determine EXTBUS_DIV.
*/
switch (pllmr & PLLMR_EXB_TO_PLB_MASK)
{
case PLLMR_EXB_PLB_DIV_2:
sysInfo->pllExtBusDiv = 2;
break;
case PLLMR_EXB_PLB_DIV_3:
sysInfo->pllExtBusDiv = 3;
break;
case PLLMR_EXB_PLB_DIV_4:
sysInfo->pllExtBusDiv = 4;
break;
case PLLMR_EXB_PLB_DIV_5:
sysInfo->pllExtBusDiv = 5;
break;
}
/*
* Determine OPB_DIV.
*/
switch (pllmr & PLLMR_OPB_TO_PLB_MASK)
{
case PLLMR_OPB_PLB_DIV_1:
sysInfo->pllOpbDiv = 1;
break;
case PLLMR_OPB_PLB_DIV_2:
sysInfo->pllOpbDiv = 2;
break;
case PLLMR_OPB_PLB_DIV_3:
sysInfo->pllOpbDiv = 3;
break;
case PLLMR_OPB_PLB_DIV_4:
sysInfo->pllOpbDiv = 4;
break;
}
/*
* Check pllFwdDiv to see if running in bypass mode where the CPU speed
* is equal to the 405GP SYS_CLK_FREQ. If not in bypass mode, check VCO
* to make sure it is within the proper range.
* spec: VCO = SYS_CLOCK x FBKDIV x PLBDIV x FWDDIV
* Note freqVCO is calculated in Mhz to avoid errors introduced by rounding.
*/
if (sysInfo->pllFwdDiv == 1)
{
sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ;
sysInfo->freqPLB = CONFIG_SYS_CLK_FREQ/sysInfo->pllPlbDiv;
}
else
{
sysInfo->freqVCOMhz = (1000 * sysInfo->pllFwdDiv * sysInfo->pllFbkDiv *
sysInfo->pllPlbDiv) / sysClkPeriodNs;
if (sysInfo->freqVCOMhz >= VCO_MIN && sysInfo->freqVCOMhz <= VCO_MAX)
{
sysInfo->freqPLB = (ONE_BILLION /
((sysClkPeriodNs * 10) / sysInfo->pllFbkDiv)) * 10;
sysInfo->freqProcessor = sysInfo->freqPLB * sysInfo->pllPlbDiv;
}
else
{
printf("\nInvalid VCO frequency calculated : %ld MHz \a\n",
sysInfo->freqVCOMhz);
printf("It must be between %d-%d MHz \a\n", VCO_MIN, VCO_MAX);
printf("PLL Mode reg : %8.8lx\a\n", pllmr);
hang();
}
}
}
#endif /* CONFIG_PPC405GP */
ulong get_gclk_freq (void)
{
ulong val;
#ifdef CONFIG_PPC405GP
PPC405_SYS_INFO sys_info;
get_sys_info(&sys_info);
val = sys_info.freqProcessor;
#ifdef CONFIG_CPCI405
/*
* Boot onboard FPGA
*/
fpga_boot();
#endif /* CONFIG_CPCI405 */
#endif /* CONFIG_PPC405GP */
#ifdef CONFIG_IOP480
val = 66000000;
#endif
return val;
}
/* ------------------------------------------------------------------------- */
ulong get_bus_freq (ulong gclk_freq)
{
ulong val;
#ifdef CONFIG_PPC405GP
PPC405_SYS_INFO sys_info;
get_sys_info(&sys_info);
val = sys_info.freqPLB / 1000000;
#endif /* CONFIG_PPC405GP */
#ifdef CONFIG_IOP480
val = 66;
#endif
return val;
}
/* ------------------------------------------------------------------------- */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -