avionic design with actual uboot and tooling
submodule of avionic design uboot bootloader and with included tools to get you started , read readme.md and readme-tk1-loader.md
This commit is contained in:
444
u-boot/arch/powerpc/cpu/ppc4xx/40x_spd_sdram.c
Normal file
444
u-boot/arch/powerpc/cpu/ppc4xx/40x_spd_sdram.c
Normal file
@@ -0,0 +1,444 @@
|
||||
/*
|
||||
* arch/powerpc/cpu/ppc4xx/40x_spd_sdram.c
|
||||
* This SPD SDRAM detection code supports IBM/AMCC PPC44x cpu with a
|
||||
* SDRAM controller. Those are all current 405 PPC's.
|
||||
*
|
||||
* (C) Copyright 2001
|
||||
* Bill Hunter, Wave 7 Optics, williamhunter@attbi.com
|
||||
*
|
||||
* Based on code by:
|
||||
*
|
||||
* Kenneth Johansson ,Ericsson AB.
|
||||
* kenneth.johansson@etx.ericsson.se
|
||||
*
|
||||
* hacked up by bill hunter. fixed so we could run before
|
||||
* serial_init and console_init. previous version avoided this by
|
||||
* running out of cache memory during serial/console init, then running
|
||||
* this code later.
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Jun Gu, Artesyn Technology, jung@artesyncp.com
|
||||
* Support for AMCC 440 based on OpenBIOS draminit.c from IBM.
|
||||
*
|
||||
* (C) Copyright 2005
|
||||
* Stefan Roese, DENX Software Engineering, sr@denx.de.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/processor.h>
|
||||
#include <i2c.h>
|
||||
#include <asm/ppc4xx.h>
|
||||
|
||||
#if defined(CONFIG_SPD_EEPROM) && !defined(CONFIG_440)
|
||||
|
||||
/*
|
||||
* Set default values
|
||||
*/
|
||||
#define ONE_BILLION 1000000000
|
||||
|
||||
#define SDRAM0_CFG_DCE 0x80000000
|
||||
#define SDRAM0_CFG_SRE 0x40000000
|
||||
#define SDRAM0_CFG_PME 0x20000000
|
||||
#define SDRAM0_CFG_MEMCHK 0x10000000
|
||||
#define SDRAM0_CFG_REGEN 0x08000000
|
||||
#define SDRAM0_CFG_ECCDD 0x00400000
|
||||
#define SDRAM0_CFG_EMDULR 0x00200000
|
||||
#define SDRAM0_CFG_DRW_SHIFT (31-6)
|
||||
#define SDRAM0_CFG_BRPF_SHIFT (31-8)
|
||||
|
||||
#define SDRAM0_TR_CASL_SHIFT (31-8)
|
||||
#define SDRAM0_TR_PTA_SHIFT (31-13)
|
||||
#define SDRAM0_TR_CTP_SHIFT (31-15)
|
||||
#define SDRAM0_TR_LDF_SHIFT (31-17)
|
||||
#define SDRAM0_TR_RFTA_SHIFT (31-29)
|
||||
#define SDRAM0_TR_RCD_SHIFT (31-31)
|
||||
|
||||
#define SDRAM0_RTR_SHIFT (31-15)
|
||||
#define SDRAM0_ECCCFG_SHIFT (31-11)
|
||||
|
||||
/* SDRAM0_CFG enable macro */
|
||||
#define SDRAM0_CFG_BRPF(x) ( ( x & 0x3)<< SDRAM0_CFG_BRPF_SHIFT )
|
||||
|
||||
#define SDRAM0_BXCR_SZ_MASK 0x000e0000
|
||||
#define SDRAM0_BXCR_AM_MASK 0x0000e000
|
||||
|
||||
#define SDRAM0_BXCR_SZ_SHIFT (31-14)
|
||||
#define SDRAM0_BXCR_AM_SHIFT (31-18)
|
||||
|
||||
#define SDRAM0_BXCR_SZ(x) ( (( x << SDRAM0_BXCR_SZ_SHIFT) & SDRAM0_BXCR_SZ_MASK) )
|
||||
#define SDRAM0_BXCR_AM(x) ( (( x << SDRAM0_BXCR_AM_SHIFT) & SDRAM0_BXCR_AM_MASK) )
|
||||
|
||||
#ifdef CONFIG_SPDDRAM_SILENT
|
||||
# define SPD_ERR(x) do { return 0; } while (0)
|
||||
#else
|
||||
# define SPD_ERR(x) do { printf(x); return(0); } while (0)
|
||||
#endif
|
||||
|
||||
#define sdram_HZ_to_ns(hertz) (1000000000/(hertz))
|
||||
|
||||
/* function prototypes */
|
||||
int spd_read(uint addr);
|
||||
|
||||
|
||||
/*
|
||||
* This function is reading data from the DIMM module EEPROM over the SPD bus
|
||||
* and uses that to program the sdram controller.
|
||||
*
|
||||
* This works on boards that has the same schematics that the AMCC walnut has.
|
||||
*
|
||||
* Input: null for default I2C spd functions or a pointer to a custom function
|
||||
* returning spd_data.
|
||||
*/
|
||||
|
||||
long int spd_sdram(int(read_spd)(uint addr))
|
||||
{
|
||||
int tmp,row,col;
|
||||
int total_size,bank_size,bank_code;
|
||||
int mode;
|
||||
int bank_cnt;
|
||||
|
||||
int sdram0_pmit=0x07c00000;
|
||||
int sdram0_b0cr;
|
||||
int sdram0_b1cr = 0;
|
||||
#ifndef CONFIG_405EP /* not on PPC405EP */
|
||||
int sdram0_b2cr = 0;
|
||||
int sdram0_b3cr = 0;
|
||||
int sdram0_besr0 = -1;
|
||||
int sdram0_besr1 = -1;
|
||||
int sdram0_eccesr = -1;
|
||||
int sdram0_ecccfg;
|
||||
int ecc_on;
|
||||
#endif
|
||||
|
||||
int sdram0_rtr=0;
|
||||
int sdram0_tr=0;
|
||||
|
||||
int sdram0_cfg=0;
|
||||
|
||||
int t_rp;
|
||||
int t_rcd;
|
||||
int t_ras;
|
||||
int t_rc;
|
||||
int min_cas;
|
||||
|
||||
PPC4xx_SYS_INFO sys_info;
|
||||
unsigned long bus_period_x_10;
|
||||
|
||||
/*
|
||||
* get the board info
|
||||
*/
|
||||
get_sys_info(&sys_info);
|
||||
bus_period_x_10 = ONE_BILLION / (sys_info.freqPLB / 10);
|
||||
|
||||
if (read_spd == 0){
|
||||
read_spd=spd_read;
|
||||
/*
|
||||
* Make sure I2C controller is initialized
|
||||
* before continuing.
|
||||
*/
|
||||
i2c_set_bus_num(CONFIG_SYS_SPD_BUS_NUM);
|
||||
}
|
||||
|
||||
/* Make shure we are using SDRAM */
|
||||
if (read_spd(2) != 0x04) {
|
||||
SPD_ERR("SDRAM - non SDRAM memory module found\n");
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
* configure memory timing register
|
||||
*
|
||||
* data from DIMM:
|
||||
* 27 IN Row Precharge Time ( t RP)
|
||||
* 29 MIN RAS to CAS Delay ( t RCD)
|
||||
* 127 Component and Clock Detail ,clk0-clk3, junction temp, CAS
|
||||
* -------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* first figure out which cas latency mode to use
|
||||
* use the min supported mode
|
||||
*/
|
||||
|
||||
tmp = read_spd(127) & 0x6;
|
||||
if (tmp == 0x02) { /* only cas = 2 supported */
|
||||
min_cas = 2;
|
||||
/* t_ck = read_spd(9); */
|
||||
/* t_ac = read_spd(10); */
|
||||
} else if (tmp == 0x04) { /* only cas = 3 supported */
|
||||
min_cas = 3;
|
||||
/* t_ck = read_spd(9); */
|
||||
/* t_ac = read_spd(10); */
|
||||
} else if (tmp == 0x06) { /* 2,3 supported, so use 2 */
|
||||
min_cas = 2;
|
||||
/* t_ck = read_spd(23); */
|
||||
/* t_ac = read_spd(24); */
|
||||
} else {
|
||||
SPD_ERR("SDRAM - unsupported CAS latency \n");
|
||||
}
|
||||
|
||||
/* get some timing values, t_rp,t_rcd,t_ras,t_rc
|
||||
*/
|
||||
t_rp = read_spd(27);
|
||||
t_rcd = read_spd(29);
|
||||
t_ras = read_spd(30);
|
||||
t_rc = t_ras + t_rp;
|
||||
|
||||
/* The following timing calcs subtract 1 before deviding.
|
||||
* this has effect of using ceiling instead of floor rounding,
|
||||
* and also subtracting 1 to convert number to reg value
|
||||
*/
|
||||
/* set up CASL */
|
||||
sdram0_tr = (min_cas - 1) << SDRAM0_TR_CASL_SHIFT;
|
||||
/* set up PTA */
|
||||
sdram0_tr |= ((((t_rp - 1) * 10)/bus_period_x_10) & 0x3) << SDRAM0_TR_PTA_SHIFT;
|
||||
/* set up CTP */
|
||||
tmp = (((t_rc - t_rcd - t_rp -1) * 10) / bus_period_x_10) & 0x3;
|
||||
if (tmp < 1)
|
||||
tmp = 1;
|
||||
sdram0_tr |= tmp << SDRAM0_TR_CTP_SHIFT;
|
||||
/* set LDF = 2 cycles, reg value = 1 */
|
||||
sdram0_tr |= 1 << SDRAM0_TR_LDF_SHIFT;
|
||||
/* set RFTA = t_rfc/bus_period, use t_rfc = t_rc */
|
||||
tmp = (((t_rc - 1) * 10) / bus_period_x_10) - 3;
|
||||
if (tmp < 0)
|
||||
tmp = 0;
|
||||
if (tmp > 6)
|
||||
tmp = 6;
|
||||
sdram0_tr |= tmp << SDRAM0_TR_RFTA_SHIFT;
|
||||
/* set RCD = t_rcd/bus_period*/
|
||||
sdram0_tr |= ((((t_rcd - 1) * 10) / bus_period_x_10) &0x3) << SDRAM0_TR_RCD_SHIFT ;
|
||||
|
||||
|
||||
/*------------------------------------------------------------------
|
||||
* configure RTR register
|
||||
* -------------------------------------------------------------------*/
|
||||
row = read_spd(3);
|
||||
col = read_spd(4);
|
||||
tmp = read_spd(12) & 0x7f ; /* refresh type less self refresh bit */
|
||||
switch (tmp) {
|
||||
case 0x00:
|
||||
tmp = 15625;
|
||||
break;
|
||||
case 0x01:
|
||||
tmp = 15625 / 4;
|
||||
break;
|
||||
case 0x02:
|
||||
tmp = 15625 / 2;
|
||||
break;
|
||||
case 0x03:
|
||||
tmp = 15625 * 2;
|
||||
break;
|
||||
case 0x04:
|
||||
tmp = 15625 * 4;
|
||||
break;
|
||||
case 0x05:
|
||||
tmp = 15625 * 8;
|
||||
break;
|
||||
default:
|
||||
SPD_ERR("SDRAM - Bad refresh period \n");
|
||||
}
|
||||
/* convert from nsec to bus cycles */
|
||||
tmp = (tmp * 10) / bus_period_x_10;
|
||||
sdram0_rtr = (tmp & 0x3ff8) << SDRAM0_RTR_SHIFT;
|
||||
|
||||
/*------------------------------------------------------------------
|
||||
* determine the number of banks used
|
||||
* -------------------------------------------------------------------*/
|
||||
/* byte 7:6 is module data width */
|
||||
if (read_spd(7) != 0)
|
||||
SPD_ERR("SDRAM - unsupported module width\n");
|
||||
tmp = read_spd(6);
|
||||
if (tmp < 32)
|
||||
SPD_ERR("SDRAM - unsupported module width\n");
|
||||
else if (tmp < 64)
|
||||
bank_cnt = 1; /* one bank per sdram side */
|
||||
else if (tmp < 73)
|
||||
bank_cnt = 2; /* need two banks per side */
|
||||
else if (tmp < 161)
|
||||
bank_cnt = 4; /* need four banks per side */
|
||||
else
|
||||
SPD_ERR("SDRAM - unsupported module width\n");
|
||||
|
||||
/* byte 5 is the module row count (refered to as dimm "sides") */
|
||||
tmp = read_spd(5);
|
||||
if (tmp == 1)
|
||||
;
|
||||
else if (tmp==2)
|
||||
bank_cnt *= 2;
|
||||
else if (tmp==4)
|
||||
bank_cnt *= 4;
|
||||
else
|
||||
bank_cnt = 8; /* 8 is an error code */
|
||||
|
||||
if (bank_cnt > 4) /* we only have 4 banks to work with */
|
||||
SPD_ERR("SDRAM - unsupported module rows for this width\n");
|
||||
|
||||
#ifndef CONFIG_405EP /* not on PPC405EP */
|
||||
/* now check for ECC ability of module. We only support ECC
|
||||
* on 32 bit wide devices with 8 bit ECC.
|
||||
*/
|
||||
if ((read_spd(11)==2) && (read_spd(6)==40) && (read_spd(14)==8)) {
|
||||
sdram0_ecccfg = 0xf << SDRAM0_ECCCFG_SHIFT;
|
||||
ecc_on = 1;
|
||||
} else {
|
||||
sdram0_ecccfg = 0;
|
||||
ecc_on = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*------------------------------------------------------------------
|
||||
* calculate total size
|
||||
* -------------------------------------------------------------------*/
|
||||
/* calculate total size and do sanity check */
|
||||
tmp = read_spd(31);
|
||||
total_size = 1 << 22; /* total_size = 4MB */
|
||||
/* now multiply 4M by the smallest device row density */
|
||||
/* note that we don't support asymetric rows */
|
||||
while (((tmp & 0x0001) == 0) && (tmp != 0)) {
|
||||
total_size = total_size << 1;
|
||||
tmp = tmp >> 1;
|
||||
}
|
||||
total_size *= read_spd(5); /* mult by module rows (dimm sides) */
|
||||
|
||||
/*------------------------------------------------------------------
|
||||
* map rows * cols * banks to a mode
|
||||
* -------------------------------------------------------------------*/
|
||||
|
||||
switch (row) {
|
||||
case 11:
|
||||
switch (col) {
|
||||
case 8:
|
||||
mode=4; /* mode 5 */
|
||||
break;
|
||||
case 9:
|
||||
case 10:
|
||||
mode=0; /* mode 1 */
|
||||
break;
|
||||
default:
|
||||
SPD_ERR("SDRAM - unsupported mode\n");
|
||||
}
|
||||
break;
|
||||
case 12:
|
||||
switch (col) {
|
||||
case 8:
|
||||
mode=3; /* mode 4 */
|
||||
break;
|
||||
case 9:
|
||||
case 10:
|
||||
mode=1; /* mode 2 */
|
||||
break;
|
||||
default:
|
||||
SPD_ERR("SDRAM - unsupported mode\n");
|
||||
}
|
||||
break;
|
||||
case 13:
|
||||
switch (col) {
|
||||
case 8:
|
||||
mode=5; /* mode 6 */
|
||||
break;
|
||||
case 9:
|
||||
case 10:
|
||||
if (read_spd(17) == 2)
|
||||
mode = 6; /* mode 7 */
|
||||
else
|
||||
mode = 2; /* mode 3 */
|
||||
break;
|
||||
case 11:
|
||||
mode = 2; /* mode 3 */
|
||||
break;
|
||||
default:
|
||||
SPD_ERR("SDRAM - unsupported mode\n");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
SPD_ERR("SDRAM - unsupported mode\n");
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------
|
||||
* using the calculated values, compute the bank
|
||||
* config register values.
|
||||
* -------------------------------------------------------------------*/
|
||||
|
||||
/* compute the size of each bank */
|
||||
bank_size = total_size / bank_cnt;
|
||||
/* convert bank size to bank size code for ppc4xx
|
||||
by takeing log2(bank_size) - 22 */
|
||||
tmp = bank_size; /* start with tmp = bank_size */
|
||||
bank_code = 0; /* and bank_code = 0 */
|
||||
while (tmp > 1) { /* this takes log2 of tmp */
|
||||
bank_code++; /* and stores result in bank_code */
|
||||
tmp = tmp >> 1;
|
||||
} /* bank_code is now log2(bank_size) */
|
||||
bank_code -= 22; /* subtract 22 to get the code */
|
||||
|
||||
tmp = SDRAM0_BXCR_SZ(bank_code) | SDRAM0_BXCR_AM(mode) | 1;
|
||||
sdram0_b0cr = (bank_size * 0) | tmp;
|
||||
#ifndef CONFIG_405EP /* not on PPC405EP */
|
||||
if (bank_cnt > 1)
|
||||
sdram0_b2cr = (bank_size * 1) | tmp;
|
||||
if (bank_cnt > 2)
|
||||
sdram0_b1cr = (bank_size * 2) | tmp;
|
||||
if (bank_cnt > 3)
|
||||
sdram0_b3cr = (bank_size * 3) | tmp;
|
||||
#else
|
||||
/* PPC405EP chip only supports two SDRAM banks */
|
||||
if (bank_cnt > 1)
|
||||
sdram0_b1cr = (bank_size * 1) | tmp;
|
||||
if (bank_cnt > 2)
|
||||
total_size = 2 * bank_size;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* enable sdram controller DCE=1
|
||||
* enable burst read prefetch to 32 bytes BRPF=2
|
||||
* leave other functions off
|
||||
*/
|
||||
|
||||
/*------------------------------------------------------------------
|
||||
* now that we've done our calculations, we are ready to
|
||||
* program all the registers.
|
||||
* -------------------------------------------------------------------*/
|
||||
|
||||
/* disable memcontroller so updates work */
|
||||
mtsdram(SDRAM0_CFG, 0);
|
||||
|
||||
#ifndef CONFIG_405EP /* not on PPC405EP */
|
||||
mtsdram(SDRAM0_BESR0, sdram0_besr0);
|
||||
mtsdram(SDRAM0_BESR1, sdram0_besr1);
|
||||
mtsdram(SDRAM0_ECCCFG, sdram0_ecccfg);
|
||||
mtsdram(SDRAM0_ECCESR, sdram0_eccesr);
|
||||
#endif
|
||||
mtsdram(SDRAM0_RTR, sdram0_rtr);
|
||||
mtsdram(SDRAM0_PMIT, sdram0_pmit);
|
||||
mtsdram(SDRAM0_B0CR, sdram0_b0cr);
|
||||
mtsdram(SDRAM0_B1CR, sdram0_b1cr);
|
||||
#ifndef CONFIG_405EP /* not on PPC405EP */
|
||||
mtsdram(SDRAM0_B2CR, sdram0_b2cr);
|
||||
mtsdram(SDRAM0_B3CR, sdram0_b3cr);
|
||||
#endif
|
||||
mtsdram(SDRAM0_TR, sdram0_tr);
|
||||
|
||||
/* SDRAM have a power on delay, 500 micro should do */
|
||||
udelay(500);
|
||||
sdram0_cfg = SDRAM0_CFG_DCE | SDRAM0_CFG_BRPF(1) | SDRAM0_CFG_ECCDD | SDRAM0_CFG_EMDULR;
|
||||
#ifndef CONFIG_405EP /* not on PPC405EP */
|
||||
if (ecc_on)
|
||||
sdram0_cfg |= SDRAM0_CFG_MEMCHK;
|
||||
#endif
|
||||
mtsdram(SDRAM0_CFG, sdram0_cfg);
|
||||
|
||||
return (total_size);
|
||||
}
|
||||
|
||||
int spd_read(uint addr)
|
||||
{
|
||||
uchar data[2];
|
||||
|
||||
if (i2c_read(SPD_EEPROM_ADDRESS, addr, 1, data, 1) == 0)
|
||||
return (int)data[0];
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SPD_EEPROM */
|
||||
1224
u-boot/arch/powerpc/cpu/ppc4xx/44x_spd_ddr.c
Normal file
1224
u-boot/arch/powerpc/cpu/ppc4xx/44x_spd_ddr.c
Normal file
File diff suppressed because it is too large
Load Diff
3147
u-boot/arch/powerpc/cpu/ppc4xx/44x_spd_ddr2.c
Normal file
3147
u-boot/arch/powerpc/cpu/ppc4xx/44x_spd_ddr2.c
Normal file
File diff suppressed because it is too large
Load Diff
1227
u-boot/arch/powerpc/cpu/ppc4xx/4xx_ibm_ddr2_autocalib.c
Normal file
1227
u-boot/arch/powerpc/cpu/ppc4xx/4xx_ibm_ddr2_autocalib.c
Normal file
File diff suppressed because it is too large
Load Diff
860
u-boot/arch/powerpc/cpu/ppc4xx/4xx_pci.c
Normal file
860
u-boot/arch/powerpc/cpu/ppc4xx/4xx_pci.c
Normal file
@@ -0,0 +1,860 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0 IBM-pibs
|
||||
*
|
||||
* File Name: 405gp_pci.c
|
||||
*
|
||||
* Function: Initialization code for the 405GP PCI Configuration regs.
|
||||
*
|
||||
* Author: Mark Game
|
||||
*
|
||||
* Change Activity-
|
||||
*
|
||||
* Date Description of Change BY
|
||||
* --------- --------------------- ---
|
||||
* 09-Sep-98 Created MCG
|
||||
* 02-Nov-98 Removed External arbiter selected message JWB
|
||||
* 27-Nov-98 Zero out PTMBAR2 and disable in PTM2MS JWB
|
||||
* 04-Jan-99 Zero out other unused PMM and PTM regs. Change bus scan MCG
|
||||
* from (0 to n) to (1 to n).
|
||||
* 17-May-99 Port to Walnut JWB
|
||||
* 17-Jun-99 Updated for VGA support JWB
|
||||
* 21-Jun-99 Updated to allow SRAM region to be a target from PCI bus JWB
|
||||
* 19-Jul-99 Updated for 405GP pass 1 errata #26 (Low PCI subsequent MCG
|
||||
* target latency timer values are not supported).
|
||||
* Should be fixed in pass 2.
|
||||
* 09-Sep-99 Removed use of PTM2 since the SRAM region no longer needs JWB
|
||||
* to be a PCI target. Zero out PTMBAR2 and disable in PTM2MS.
|
||||
* 10-Dec-99 Updated PCI_Write_CFG_Reg for pass2 errata #6 JWB
|
||||
* 11-Jan-00 Ensure PMMxMAs disabled before setting PMMxLAs. This is not
|
||||
* really required after a reset since PMMxMAs are already
|
||||
* disabled but is a good practice nonetheless. JWB
|
||||
* 12-Jun-01 stefan.roese@esd-electronics.com
|
||||
* - PCI host/adapter handling reworked
|
||||
* 09-Jul-01 stefan.roese@esd-electronics.com
|
||||
* - PCI host now configures from device 0 (not 1) to max_dev,
|
||||
* (host configures itself)
|
||||
* - On CPCI-405 pci base address and size is generated from
|
||||
* SDRAM and FLASH size (CFG regs not used anymore)
|
||||
* - Some minor changes for CPCI-405-A (adapter version)
|
||||
* 14-Sep-01 stefan.roese@esd-electronics.com
|
||||
* - CONFIG_PCI_SCAN_SHOW added to print pci devices upon startup
|
||||
* 28-Sep-01 stefan.roese@esd-electronics.com
|
||||
* - Changed pci master configuration for linux compatibility
|
||||
* (no need for bios_fixup() anymore)
|
||||
* 26-Feb-02 stefan.roese@esd-electronics.com
|
||||
* - Bug fixed in pci configuration (Andrew May)
|
||||
* - Removed pci class code init for CPCI405 board
|
||||
* 15-May-02 stefan.roese@esd-electronics.com
|
||||
* - New vga device handling
|
||||
* 29-May-02 stefan.roese@esd-electronics.com
|
||||
* - PCI class code init added (if defined)
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <asm/4xx_pci.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/io.h>
|
||||
#include <pci.h>
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#if defined(CONFIG_405GP) || defined(CONFIG_405EP)
|
||||
|
||||
/*#define DEBUG*/
|
||||
|
||||
/*
|
||||
* Board-specific pci initialization
|
||||
* Platform code can reimplement pci_pre_init() if needed
|
||||
*/
|
||||
int __pci_pre_init(struct pci_controller *hose)
|
||||
{
|
||||
#if defined(CONFIG_405EP)
|
||||
/*
|
||||
* Enable the internal PCI arbiter by default.
|
||||
*
|
||||
* On 405EP CPUs the internal arbiter can be controlled
|
||||
* by the I2C strapping EEPROM. If you want to do so
|
||||
* or if you want to disable the arbiter pci_pre_init()
|
||||
* must be reimplemented without enabling the arbiter.
|
||||
* The arbiter is enabled in this place because of
|
||||
* compatibility reasons.
|
||||
*/
|
||||
mtdcr(CPC0_PCI, mfdcr(CPC0_PCI) | CPC0_PCI_ARBIT_EN);
|
||||
#endif /* CONFIG_405EP */
|
||||
|
||||
return 1;
|
||||
}
|
||||
int pci_pre_init(struct pci_controller *hose)
|
||||
__attribute__((weak, alias("__pci_pre_init")));
|
||||
|
||||
int __is_pci_host(struct pci_controller *hose)
|
||||
{
|
||||
#if defined(CONFIG_405GP)
|
||||
if (mfdcr(CPC0_PSR) & PSR_PCI_ARBIT_EN)
|
||||
return 1;
|
||||
#elif defined (CONFIG_405EP)
|
||||
if (mfdcr(CPC0_PCI) & CPC0_PCI_ARBIT_EN)
|
||||
return 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
int is_pci_host(struct pci_controller *hose) __attribute__((weak, alias("__is_pci_host")));
|
||||
|
||||
/*-----------------------------------------------------------------------------+
|
||||
* pci_init. Initializes the 405GP PCI Configuration regs.
|
||||
*-----------------------------------------------------------------------------*/
|
||||
void pci_405gp_init(struct pci_controller *hose)
|
||||
{
|
||||
int i, reg_num = 0;
|
||||
bd_t *bd = gd->bd;
|
||||
|
||||
unsigned short temp_short;
|
||||
unsigned long ptmpcila[2] = {CONFIG_SYS_PCI_PTM1PCI, CONFIG_SYS_PCI_PTM2PCI};
|
||||
#if defined(CONFIG_PCI_4xx_PTM_OVERWRITE)
|
||||
char *ptmla_str, *ptmms_str;
|
||||
#endif
|
||||
unsigned long ptmla[2] = {CONFIG_SYS_PCI_PTM1LA, CONFIG_SYS_PCI_PTM2LA};
|
||||
unsigned long ptmms[2] = {CONFIG_SYS_PCI_PTM1MS, CONFIG_SYS_PCI_PTM2MS};
|
||||
#if defined(CONFIG_PIP405) || defined (CONFIG_MIP405)
|
||||
unsigned long pmmla[3] = {0x80000000, 0xA0000000, 0};
|
||||
unsigned long pmmma[3] = {0xE0000001, 0xE0000001, 0};
|
||||
unsigned long pmmpcila[3] = {0x80000000, 0x00000000, 0};
|
||||
unsigned long pmmpciha[3] = {0x00000000, 0x00000000, 0};
|
||||
#else
|
||||
unsigned long pmmla[3] = {0x80000000, 0,0};
|
||||
unsigned long pmmma[3] = {0xC0000001, 0,0};
|
||||
unsigned long pmmpcila[3] = {0x80000000, 0,0};
|
||||
unsigned long pmmpciha[3] = {0x00000000, 0,0};
|
||||
#endif
|
||||
#ifdef CONFIG_PCI_PNP
|
||||
#if (CONFIG_PCI_HOST == PCI_HOST_AUTO)
|
||||
char *s;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_PCI_4xx_PTM_OVERWRITE)
|
||||
ptmla_str = getenv("ptm1la");
|
||||
ptmms_str = getenv("ptm1ms");
|
||||
if(NULL != ptmla_str && NULL != ptmms_str ) {
|
||||
ptmla[0] = simple_strtoul (ptmla_str, NULL, 16);
|
||||
ptmms[0] = simple_strtoul (ptmms_str, NULL, 16);
|
||||
}
|
||||
|
||||
ptmla_str = getenv("ptm2la");
|
||||
ptmms_str = getenv("ptm2ms");
|
||||
if(NULL != ptmla_str && NULL != ptmms_str ) {
|
||||
ptmla[1] = simple_strtoul (ptmla_str, NULL, 16);
|
||||
ptmms[1] = simple_strtoul (ptmms_str, NULL, 16);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Register the hose
|
||||
*/
|
||||
hose->first_busno = 0;
|
||||
hose->last_busno = 0xff;
|
||||
|
||||
/* ISA/PCI I/O space */
|
||||
pci_set_region(hose->regions + reg_num++,
|
||||
MIN_PCI_PCI_IOADDR,
|
||||
MIN_PLB_PCI_IOADDR,
|
||||
0x10000,
|
||||
PCI_REGION_IO);
|
||||
|
||||
/* PCI I/O space */
|
||||
pci_set_region(hose->regions + reg_num++,
|
||||
0x00800000,
|
||||
0xe8800000,
|
||||
0x03800000,
|
||||
PCI_REGION_IO);
|
||||
|
||||
reg_num = 2;
|
||||
|
||||
/* Memory spaces */
|
||||
for (i=0; i<2; i++)
|
||||
if (ptmms[i] & 1)
|
||||
{
|
||||
if (!i) hose->pci_fb = hose->regions + reg_num;
|
||||
|
||||
pci_set_region(hose->regions + reg_num++,
|
||||
ptmpcila[i], ptmla[i],
|
||||
~(ptmms[i] & 0xfffff000) + 1,
|
||||
PCI_REGION_MEM |
|
||||
PCI_REGION_SYS_MEMORY);
|
||||
}
|
||||
|
||||
/* PCI memory spaces */
|
||||
for (i=0; i<3; i++)
|
||||
if (pmmma[i] & 1)
|
||||
{
|
||||
pci_set_region(hose->regions + reg_num++,
|
||||
pmmpcila[i], pmmla[i],
|
||||
~(pmmma[i] & 0xfffff000) + 1,
|
||||
PCI_REGION_MEM);
|
||||
}
|
||||
|
||||
hose->region_count = reg_num;
|
||||
|
||||
pci_setup_indirect(hose,
|
||||
PCICFGADR,
|
||||
PCICFGDATA);
|
||||
|
||||
if (hose->pci_fb)
|
||||
pciauto_region_init(hose->pci_fb);
|
||||
|
||||
/* Let board change/modify hose & do initial checks */
|
||||
if (pci_pre_init(hose) == 0) {
|
||||
printf("PCI: Board-specific initialization failed.\n");
|
||||
printf("PCI: Configuration aborted.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pci_register_hose(hose);
|
||||
|
||||
/*--------------------------------------------------------------------------+
|
||||
* 405GP PCI Master configuration.
|
||||
* Map one 512 MB range of PLB/processor addresses to PCI memory space.
|
||||
* PLB address 0x80000000-0xBFFFFFFF ==> PCI address 0x80000000-0xBFFFFFFF
|
||||
* Use byte reversed out routines to handle endianess.
|
||||
*--------------------------------------------------------------------------*/
|
||||
out32r(PMM0MA, (pmmma[0]&~0x1)); /* disable, configure PMMxLA, PMMxPCILA first */
|
||||
out32r(PMM0LA, pmmla[0]);
|
||||
out32r(PMM0PCILA, pmmpcila[0]);
|
||||
out32r(PMM0PCIHA, pmmpciha[0]);
|
||||
out32r(PMM0MA, pmmma[0]);
|
||||
|
||||
/*--------------------------------------------------------------------------+
|
||||
* PMM1 is not used. Initialize them to zero.
|
||||
*--------------------------------------------------------------------------*/
|
||||
out32r(PMM1MA, (pmmma[1]&~0x1));
|
||||
out32r(PMM1LA, pmmla[1]);
|
||||
out32r(PMM1PCILA, pmmpcila[1]);
|
||||
out32r(PMM1PCIHA, pmmpciha[1]);
|
||||
out32r(PMM1MA, pmmma[1]);
|
||||
|
||||
/*--------------------------------------------------------------------------+
|
||||
* PMM2 is not used. Initialize them to zero.
|
||||
*--------------------------------------------------------------------------*/
|
||||
out32r(PMM2MA, (pmmma[2]&~0x1));
|
||||
out32r(PMM2LA, pmmla[2]);
|
||||
out32r(PMM2PCILA, pmmpcila[2]);
|
||||
out32r(PMM2PCIHA, pmmpciha[2]);
|
||||
out32r(PMM2MA, pmmma[2]);
|
||||
|
||||
/*--------------------------------------------------------------------------+
|
||||
* 405GP PCI Target configuration. (PTM1)
|
||||
* Note: PTM1MS is hardwire enabled but we set the enable bit anyway.
|
||||
*--------------------------------------------------------------------------*/
|
||||
out32r(PTM1LA, ptmla[0]); /* insert address */
|
||||
out32r(PTM1MS, ptmms[0]); /* insert size, enable bit is 1 */
|
||||
pci_write_config_dword(PCIDEVID_405GP, PCI_BASE_ADDRESS_1, ptmpcila[0]);
|
||||
|
||||
/*--------------------------------------------------------------------------+
|
||||
* 405GP PCI Target configuration. (PTM2)
|
||||
*--------------------------------------------------------------------------*/
|
||||
out32r(PTM2LA, ptmla[1]); /* insert address */
|
||||
pci_write_config_dword(PCIDEVID_405GP, PCI_BASE_ADDRESS_2, ptmpcila[1]);
|
||||
|
||||
if (ptmms[1] == 0)
|
||||
{
|
||||
out32r(PTM2MS, 0x00000001); /* set enable bit */
|
||||
pci_write_config_dword(PCIDEVID_405GP, PCI_BASE_ADDRESS_2, 0x00000000);
|
||||
out32r(PTM2MS, 0x00000000); /* disable */
|
||||
}
|
||||
else
|
||||
{
|
||||
out32r(PTM2MS, ptmms[1]); /* insert size, enable bit is 1 */
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert Subsystem Vendor and Device ID
|
||||
*/
|
||||
pci_write_config_word(PCIDEVID_405GP, PCI_SUBSYSTEM_VENDOR_ID, CONFIG_SYS_PCI_SUBSYS_VENDORID);
|
||||
#ifdef CONFIG_CPCI405
|
||||
if (is_pci_host(hose))
|
||||
pci_write_config_word(PCIDEVID_405GP, PCI_SUBSYSTEM_ID, CONFIG_SYS_PCI_SUBSYS_DEVICEID);
|
||||
else
|
||||
pci_write_config_word(PCIDEVID_405GP, PCI_SUBSYSTEM_ID, CONFIG_SYS_PCI_SUBSYS_DEVICEID2);
|
||||
#else
|
||||
pci_write_config_word(PCIDEVID_405GP, PCI_SUBSYSTEM_ID, CONFIG_SYS_PCI_SUBSYS_DEVICEID);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Insert Class-code
|
||||
*/
|
||||
#ifdef CONFIG_SYS_PCI_CLASSCODE
|
||||
pci_write_config_word(PCIDEVID_405GP, PCI_CLASS_SUB_CODE, CONFIG_SYS_PCI_CLASSCODE);
|
||||
#endif /* CONFIG_SYS_PCI_CLASSCODE */
|
||||
|
||||
/*--------------------------------------------------------------------------+
|
||||
* If PCI speed = 66MHz, set 66MHz capable bit.
|
||||
*--------------------------------------------------------------------------*/
|
||||
if (bd->bi_pci_busfreq >= 66000000) {
|
||||
pci_read_config_word(PCIDEVID_405GP, PCI_STATUS, &temp_short);
|
||||
pci_write_config_word(PCIDEVID_405GP,PCI_STATUS,(temp_short|PCI_STATUS_66MHZ));
|
||||
}
|
||||
|
||||
#if (CONFIG_PCI_HOST != PCI_HOST_ADAPTER)
|
||||
#if (CONFIG_PCI_HOST == PCI_HOST_AUTO)
|
||||
if (is_pci_host(hose) ||
|
||||
(((s = getenv("pciscan")) != NULL) && (strcmp(s, "yes") == 0)))
|
||||
#endif
|
||||
{
|
||||
/*--------------------------------------------------------------------------+
|
||||
* Write the 405GP PCI Configuration regs.
|
||||
* Enable 405GP to be a master on the PCI bus (PMM).
|
||||
* Enable 405GP to act as a PCI memory target (PTM).
|
||||
*--------------------------------------------------------------------------*/
|
||||
pci_read_config_word(PCIDEVID_405GP, PCI_COMMAND, &temp_short);
|
||||
pci_write_config_word(PCIDEVID_405GP, PCI_COMMAND, temp_short |
|
||||
PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_405EP)
|
||||
/*
|
||||
* on ppc405ep vendor/device id is not set
|
||||
* The user manual says 0x1014 (IBM) / 0x0156 (405GP!)
|
||||
* are the correct values.
|
||||
*/
|
||||
pci_write_config_word(PCIDEVID_405GP, PCI_VENDOR_ID, PCI_VENDOR_ID_IBM);
|
||||
pci_write_config_word(PCIDEVID_405GP,
|
||||
PCI_DEVICE_ID, PCI_DEVICE_ID_IBM_405GP);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Set HCE bit (Host Configuration Enabled)
|
||||
*/
|
||||
pci_read_config_word(PCIDEVID_405GP, PCIBRDGOPT2, &temp_short);
|
||||
pci_write_config_word(PCIDEVID_405GP, PCIBRDGOPT2, (temp_short | 0x0001));
|
||||
|
||||
#ifdef CONFIG_PCI_PNP
|
||||
/*--------------------------------------------------------------------------+
|
||||
* Scan the PCI bus and configure devices found.
|
||||
*--------------------------------------------------------------------------*/
|
||||
#if (CONFIG_PCI_HOST == PCI_HOST_AUTO)
|
||||
if (is_pci_host(hose) ||
|
||||
(((s = getenv("pciscan")) != NULL) && (strcmp(s, "yes") == 0)))
|
||||
#endif
|
||||
{
|
||||
#ifdef CONFIG_PCI_SCAN_SHOW
|
||||
printf("PCI: Bus Dev VenId DevId Class Int\n");
|
||||
#endif
|
||||
hose->last_busno = pci_hose_scan(hose);
|
||||
}
|
||||
#endif /* CONFIG_PCI_PNP */
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* drivers/pci/pci.c skips every host bridge but the 405GP since it could
|
||||
* be set as an Adapter.
|
||||
*
|
||||
* I (Andrew May) don't know what we should do here, but I don't want
|
||||
* the auto setup of a PCI device disabling what is done pci_405gp_init
|
||||
* as has happened before.
|
||||
*/
|
||||
void pci_405gp_setup_bridge(struct pci_controller *hose, pci_dev_t dev,
|
||||
struct pci_config_table *entry)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("405gp_setup_bridge\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
|
||||
void pci_405gp_fixup_irq(struct pci_controller *hose, pci_dev_t dev)
|
||||
{
|
||||
unsigned char int_line = 0xff;
|
||||
|
||||
/*
|
||||
* Write pci interrupt line register (cpci405 specific)
|
||||
*/
|
||||
switch (PCI_DEV(dev) & 0x03)
|
||||
{
|
||||
case 0:
|
||||
int_line = 27 + 2;
|
||||
break;
|
||||
case 1:
|
||||
int_line = 27 + 3;
|
||||
break;
|
||||
case 2:
|
||||
int_line = 27 + 0;
|
||||
break;
|
||||
case 3:
|
||||
int_line = 27 + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
pci_hose_write_config_byte(hose, dev, PCI_INTERRUPT_LINE, int_line);
|
||||
}
|
||||
|
||||
void pci_405gp_setup_vga(struct pci_controller *hose, pci_dev_t dev,
|
||||
struct pci_config_table *entry)
|
||||
{
|
||||
unsigned int cmdstat = 0;
|
||||
|
||||
pciauto_setup_device(hose, dev, 6, hose->pci_mem, hose->pci_prefetch, hose->pci_io);
|
||||
|
||||
/* always enable io space on vga boards */
|
||||
pci_hose_read_config_dword(hose, dev, PCI_COMMAND, &cmdstat);
|
||||
cmdstat |= PCI_COMMAND_IO;
|
||||
pci_hose_write_config_dword(hose, dev, PCI_COMMAND, cmdstat);
|
||||
}
|
||||
|
||||
#if !(defined(CONFIG_PIP405) || defined (CONFIG_MIP405))
|
||||
|
||||
/*
|
||||
*As is these functs get called out of flash Not a horrible
|
||||
*thing, but something to keep in mind. (no statics?)
|
||||
*/
|
||||
static struct pci_config_table pci_405gp_config_table[] = {
|
||||
/*if VendID is 0 it terminates the table search (ie Walnut)*/
|
||||
#ifdef CONFIG_SYS_PCI_SUBSYS_VENDORID
|
||||
{CONFIG_SYS_PCI_SUBSYS_VENDORID, PCI_ANY_ID, PCI_CLASS_BRIDGE_HOST,
|
||||
PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, pci_405gp_setup_bridge},
|
||||
#endif
|
||||
{PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA,
|
||||
PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, pci_405gp_setup_vga},
|
||||
|
||||
{PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NOT_DEFINED_VGA,
|
||||
PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, pci_405gp_setup_vga},
|
||||
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct pci_controller hose = {
|
||||
fixup_irq: pci_405gp_fixup_irq,
|
||||
config_table: pci_405gp_config_table,
|
||||
};
|
||||
|
||||
void pci_init_board(void)
|
||||
{
|
||||
/*we want the ptrs to RAM not flash (ie don't use init list)*/
|
||||
hose.fixup_irq = pci_405gp_fixup_irq;
|
||||
hose.config_table = pci_405gp_config_table;
|
||||
pci_405gp_init(&hose);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_405GP */
|
||||
|
||||
/*-----------------------------------------------------------------------------+
|
||||
* CONFIG_440
|
||||
*-----------------------------------------------------------------------------*/
|
||||
#if defined(CONFIG_440)
|
||||
|
||||
#if defined(CONFIG_SYS_PCI_MASTER_INIT) || defined(CONFIG_SYS_PCI_TARGET_INIT)
|
||||
static struct pci_controller ppc440_hose = {0};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This routine is called to determine if a pci scan should be
|
||||
* performed. With various hardware environments (especially cPCI and
|
||||
* PPMC) it's insufficient to depend on the state of the arbiter enable
|
||||
* bit in the strap register, or generic host/adapter assumptions.
|
||||
*
|
||||
* Rather than hard-code a bad assumption in the general 440 code, the
|
||||
* 440 pci code requires the board to decide at runtime.
|
||||
*
|
||||
* Return 0 for adapter mode, non-zero for host (monarch) mode.
|
||||
*
|
||||
* Weak default implementation: "Normal" boards implement the PCI
|
||||
* host functionality. This can be overridden for PCI adapter boards.
|
||||
*/
|
||||
int __is_pci_host(struct pci_controller *hose)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
int is_pci_host(struct pci_controller *hose)
|
||||
__attribute__((weak, alias("__is_pci_host")));
|
||||
|
||||
#if defined(CONFIG_440EP) || defined(CONFIG_440EPX) || \
|
||||
defined(CONFIG_440GR) || defined(CONFIG_440GRX)
|
||||
|
||||
#if defined(CONFIG_SYS_PCI_TARGET_INIT)
|
||||
/*
|
||||
* pci_target_init
|
||||
*
|
||||
* The bootstrap configuration provides default settings for the pci
|
||||
* inbound map (PIM). But the bootstrap config choices are limited and
|
||||
* may not be sufficient for a given board.
|
||||
*/
|
||||
void __pci_target_init(struct pci_controller *hose)
|
||||
{
|
||||
/*
|
||||
* Set up Direct MMIO registers
|
||||
*/
|
||||
|
||||
/*
|
||||
* PowerPC440 EP PCI Master configuration.
|
||||
* Map one 1Gig range of PLB/processor addresses to PCI memory space.
|
||||
* PLB address 0xA0000000-0xDFFFFFFF ==> PCI address 0xA0000000-0xDFFFFFFF
|
||||
* Use byte reversed out routines to handle endianess.
|
||||
* Make this region non-prefetchable.
|
||||
*/
|
||||
/* PMM0 Mask/Attribute - disabled b4 setting */
|
||||
out_le32((void *)PCIL0_PMM0MA, 0x00000000);
|
||||
/* PMM0 Local Address */
|
||||
out_le32((void *)PCIL0_PMM0LA, CONFIG_SYS_PCI_MEMBASE);
|
||||
/* PMM0 PCI Low Address */
|
||||
out_le32((void *)PCIL0_PMM0PCILA, CONFIG_SYS_PCI_MEMBASE);
|
||||
/* PMM0 PCI High Address */
|
||||
out_le32((void *)PCIL0_PMM0PCIHA, 0x00000000);
|
||||
/* 512M + No prefetching, and enable region */
|
||||
out_le32((void *)PCIL0_PMM0MA, 0xE0000001);
|
||||
|
||||
/* PMM1 Mask/Attribute - disabled b4 setting */
|
||||
out_le32((void *)PCIL0_PMM1MA, 0x00000000);
|
||||
/* PMM1 Local Address */
|
||||
out_le32((void *)PCIL0_PMM1LA, CONFIG_SYS_PCI_MEMBASE2);
|
||||
/* PMM1 PCI Low Address */
|
||||
out_le32((void *)PCIL0_PMM1PCILA, CONFIG_SYS_PCI_MEMBASE2);
|
||||
/* PMM1 PCI High Address */
|
||||
out_le32((void *)PCIL0_PMM1PCIHA, 0x00000000);
|
||||
/* 512M + No prefetching, and enable region */
|
||||
out_le32((void *)PCIL0_PMM1MA, 0xE0000001);
|
||||
|
||||
out_le32((void *)PCIL0_PTM1MS, 0x00000001); /* Memory Size/Attribute */
|
||||
out_le32((void *)PCIL0_PTM1LA, 0); /* Local Addr. Reg */
|
||||
out_le32((void *)PCIL0_PTM2MS, 0); /* Memory Size/Attribute */
|
||||
out_le32((void *)PCIL0_PTM2LA, 0); /* Local Addr. Reg */
|
||||
|
||||
/*
|
||||
* Set up Configuration registers
|
||||
*/
|
||||
|
||||
/* Program the board's subsystem id/vendor id */
|
||||
pci_write_config_word(0, PCI_SUBSYSTEM_VENDOR_ID,
|
||||
CONFIG_SYS_PCI_SUBSYS_VENDORID);
|
||||
pci_write_config_word(0, PCI_SUBSYSTEM_ID, CONFIG_SYS_PCI_SUBSYS_ID);
|
||||
|
||||
/* Configure command register as bus master */
|
||||
pci_write_config_word(0, PCI_COMMAND, PCI_COMMAND_MASTER);
|
||||
|
||||
/* 240nS PCI clock */
|
||||
pci_write_config_word(0, PCI_LATENCY_TIMER, 1);
|
||||
|
||||
/* No error reporting */
|
||||
pci_write_config_word(0, PCI_ERREN, 0);
|
||||
|
||||
pci_write_config_dword(0, PCI_BRDGOPT2, 0x00000101);
|
||||
}
|
||||
#endif /* CONFIG_SYS_PCI_TARGET_INIT */
|
||||
|
||||
/*
|
||||
* pci_pre_init
|
||||
*
|
||||
* This routine is called just prior to registering the hose and gives
|
||||
* the board the opportunity to check things. Returning a value of zero
|
||||
* indicates that things are bad & PCI initialization should be aborted.
|
||||
*
|
||||
* Different boards may wish to customize the pci controller structure
|
||||
* (add regions, override default access routines, etc) or perform
|
||||
* certain pre-initialization actions.
|
||||
*
|
||||
*/
|
||||
int __pci_pre_init(struct pci_controller *hose)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
/*
|
||||
* Set priority for all PLB3 devices to 0.
|
||||
* Set PLB3 arbiter to fair mode.
|
||||
*/
|
||||
mfsdr(SDR0_AMP1, reg);
|
||||
mtsdr(SDR0_AMP1, (reg & 0x000000FF) | 0x0000FF00);
|
||||
reg = mfdcr(PLB3A0_ACR);
|
||||
mtdcr(PLB3A0_ACR, reg | 0x80000000);
|
||||
|
||||
/*
|
||||
* Set priority for all PLB4 devices to 0.
|
||||
*/
|
||||
mfsdr(SDR0_AMP0, reg);
|
||||
mtsdr(SDR0_AMP0, (reg & 0x000000FF) | 0x0000FF00);
|
||||
reg = mfdcr(PLB4A0_ACR) | 0xa0000000;
|
||||
mtdcr(PLB4A0_ACR, reg);
|
||||
|
||||
/*
|
||||
* Set Nebula PLB4 arbiter to fair mode.
|
||||
*/
|
||||
/* Segment0 */
|
||||
reg = (mfdcr(PLB4A0_ACR) & ~PLB4Ax_ACR_PPM_MASK) | PLB4Ax_ACR_PPM_FAIR;
|
||||
reg = (reg & ~PLB4Ax_ACR_HBU_MASK) | PLB4Ax_ACR_HBU_ENABLED;
|
||||
reg = (reg & ~PLB4Ax_ACR_RDP_MASK) | PLB4Ax_ACR_RDP_4DEEP;
|
||||
reg = (reg & ~PLB4Ax_ACR_WRP_MASK) | PLB4Ax_ACR_WRP_2DEEP;
|
||||
mtdcr(PLB4A0_ACR, reg);
|
||||
|
||||
/* Segment1 */
|
||||
reg = (mfdcr(PLB4A1_ACR) & ~PLB4Ax_ACR_PPM_MASK) | PLB4Ax_ACR_PPM_FAIR;
|
||||
reg = (reg & ~PLB4Ax_ACR_HBU_MASK) | PLB4Ax_ACR_HBU_ENABLED;
|
||||
reg = (reg & ~PLB4Ax_ACR_RDP_MASK) | PLB4Ax_ACR_RDP_4DEEP;
|
||||
reg = (reg & ~PLB4Ax_ACR_WRP_MASK) | PLB4Ax_ACR_WRP_2DEEP;
|
||||
mtdcr(PLB4A1_ACR, reg);
|
||||
|
||||
#if defined(CONFIG_SYS_PCI_BOARD_FIXUP_IRQ)
|
||||
hose->fixup_irq = board_pci_fixup_irq;
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#else /* defined(CONFIG_440EP) ... */
|
||||
|
||||
#if defined(CONFIG_SYS_PCI_TARGET_INIT)
|
||||
void __pci_target_init(struct pci_controller * hose)
|
||||
{
|
||||
/*
|
||||
* Disable everything
|
||||
*/
|
||||
out_le32((void *)PCIL0_PIM0SA, 0); /* disable */
|
||||
out_le32((void *)PCIL0_PIM1SA, 0); /* disable */
|
||||
out_le32((void *)PCIL0_PIM2SA, 0); /* disable */
|
||||
out_le32((void *)PCIL0_EROMBA, 0); /* disable expansion rom */
|
||||
|
||||
/*
|
||||
* Map all of SDRAM to PCI address 0x0000_0000. Note that the 440
|
||||
* strapping options do not support sizes such as 128/256 MB.
|
||||
*/
|
||||
out_le32((void *)PCIL0_PIM0LAL, CONFIG_SYS_SDRAM_BASE);
|
||||
out_le32((void *)PCIL0_PIM0LAH, 0);
|
||||
out_le32((void *)PCIL0_PIM0SA, ~(gd->ram_size - 1) | 1);
|
||||
out_le32((void *)PCIL0_BAR0, 0);
|
||||
|
||||
/*
|
||||
* Program the board's subsystem id/vendor id
|
||||
*/
|
||||
out_le16((void *)PCIL0_SBSYSVID, CONFIG_SYS_PCI_SUBSYS_VENDORID);
|
||||
out_le16((void *)PCIL0_SBSYSID, CONFIG_SYS_PCI_SUBSYS_DEVICEID);
|
||||
|
||||
out_le16((void *)PCIL0_CMD, in_le16((void *)PCIL0_CMD) |
|
||||
PCI_COMMAND_MEMORY);
|
||||
}
|
||||
#endif /* CONFIG_SYS_PCI_TARGET_INIT */
|
||||
|
||||
int __pci_pre_init(struct pci_controller *hose)
|
||||
{
|
||||
/*
|
||||
* This board is always configured as the host & requires the
|
||||
* PCI arbiter to be enabled.
|
||||
*/
|
||||
if (!pci_arbiter_enabled()) {
|
||||
printf("PCI: PCI Arbiter disabled!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* defined(CONFIG_440EP) ... */
|
||||
|
||||
#if defined(CONFIG_SYS_PCI_TARGET_INIT)
|
||||
void pci_target_init(struct pci_controller * hose)
|
||||
__attribute__((weak, alias("__pci_target_init")));
|
||||
#endif /* CONFIG_SYS_PCI_TARGET_INIT */
|
||||
|
||||
int pci_pre_init(struct pci_controller *hose)
|
||||
__attribute__((weak, alias("__pci_pre_init")));
|
||||
|
||||
#if defined(CONFIG_SYS_PCI_MASTER_INIT)
|
||||
void __pci_master_init(struct pci_controller *hose)
|
||||
{
|
||||
u16 reg;
|
||||
|
||||
/*
|
||||
* Write the PowerPC440 EP PCI Configuration regs.
|
||||
* Enable PowerPC440 EP to be a master on the PCI bus (PMM).
|
||||
* Enable PowerPC440 EP to act as a PCI memory target (PTM).
|
||||
*/
|
||||
pci_read_config_word(0, PCI_COMMAND, ®);
|
||||
pci_write_config_word(0, PCI_COMMAND, reg |
|
||||
PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
|
||||
}
|
||||
void pci_master_init(struct pci_controller *hose)
|
||||
__attribute__((weak, alias("__pci_master_init")));
|
||||
#endif /* CONFIG_SYS_PCI_MASTER_INIT */
|
||||
|
||||
#if defined(CONFIG_SYS_PCI_MASTER_INIT) || defined(CONFIG_SYS_PCI_TARGET_INIT)
|
||||
static int pci_440_init (struct pci_controller *hose)
|
||||
{
|
||||
int reg_num = 0;
|
||||
|
||||
#ifndef CONFIG_DISABLE_PISE_TEST
|
||||
/*--------------------------------------------------------------------------+
|
||||
* The PCI initialization sequence enable bit must be set ... if not abort
|
||||
* pci setup since updating the bit requires chip reset.
|
||||
*--------------------------------------------------------------------------*/
|
||||
#if defined(CONFIG_440GX) || defined(CONFIG_440SP) || defined(CONFIG_440SPE)
|
||||
unsigned long strap;
|
||||
|
||||
mfsdr(SDR0_SDSTP1,strap);
|
||||
if ((strap & SDR0_SDSTP1_PISE_MASK) == 0) {
|
||||
printf("PCI: SDR0_STRP1[PISE] not set.\n");
|
||||
printf("PCI: Configuration aborted.\n");
|
||||
return -1;
|
||||
}
|
||||
#elif defined(CONFIG_440GP)
|
||||
unsigned long strap;
|
||||
|
||||
strap = mfdcr(CPC0_STRP1);
|
||||
if ((strap & CPC0_STRP1_PISE_MASK) == 0) {
|
||||
printf("PCI: CPC0_STRP1[PISE] not set.\n");
|
||||
printf("PCI: Configuration aborted.\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
#endif /* CONFIG_DISABLE_PISE_TEST */
|
||||
|
||||
/*--------------------------------------------------------------------------+
|
||||
* PCI controller init
|
||||
*--------------------------------------------------------------------------*/
|
||||
hose->first_busno = 0;
|
||||
hose->last_busno = 0;
|
||||
|
||||
/* PCI I/O space */
|
||||
pci_set_region(hose->regions + reg_num++,
|
||||
0x00000000,
|
||||
PCIL0_IOBASE,
|
||||
0x10000,
|
||||
PCI_REGION_IO);
|
||||
|
||||
/* PCI memory space */
|
||||
pci_set_region(hose->regions + reg_num++,
|
||||
CONFIG_SYS_PCI_TARGBASE,
|
||||
CONFIG_SYS_PCI_MEMBASE,
|
||||
#ifdef CONFIG_SYS_PCI_MEMSIZE
|
||||
CONFIG_SYS_PCI_MEMSIZE,
|
||||
#else
|
||||
0x10000000,
|
||||
#endif
|
||||
PCI_REGION_MEM );
|
||||
|
||||
#if defined(CONFIG_PCI_SYS_MEM_BUS) && defined(CONFIG_PCI_SYS_MEM_PHYS) && \
|
||||
defined(CONFIG_PCI_SYS_MEM_SIZE)
|
||||
/* System memory space */
|
||||
pci_set_region(hose->regions + reg_num++,
|
||||
CONFIG_PCI_SYS_MEM_BUS,
|
||||
CONFIG_PCI_SYS_MEM_PHYS,
|
||||
CONFIG_PCI_SYS_MEM_SIZE,
|
||||
PCI_REGION_MEM | PCI_REGION_SYS_MEMORY );
|
||||
#endif
|
||||
|
||||
hose->region_count = reg_num;
|
||||
|
||||
pci_setup_indirect(hose, PCIL0_CFGADR, PCIL0_CFGDATA);
|
||||
|
||||
/* Let board change/modify hose & do initial checks */
|
||||
if (pci_pre_init(hose) == 0) {
|
||||
printf("PCI: Board-specific initialization failed.\n");
|
||||
printf("PCI: Configuration aborted.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pci_register_hose( hose );
|
||||
|
||||
/*--------------------------------------------------------------------------+
|
||||
* PCI target init
|
||||
*--------------------------------------------------------------------------*/
|
||||
#if defined(CONFIG_SYS_PCI_TARGET_INIT)
|
||||
pci_target_init(hose); /* Let board setup pci target */
|
||||
#else
|
||||
out16r( PCIL0_SBSYSVID, CONFIG_SYS_PCI_SUBSYS_VENDORID );
|
||||
out16r( PCIL0_SBSYSID, CONFIG_SYS_PCI_SUBSYS_ID );
|
||||
out16r( PCIL0_CLS, 0x00060000 ); /* Bridge, host bridge */
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_440GX) || defined(CONFIG_440SPE) || \
|
||||
defined(CONFIG_460EX) || defined(CONFIG_460GT)
|
||||
out32r( PCIL0_BRDGOPT1, 0x04000060 ); /* PLB Rq pri highest */
|
||||
out32r( PCIL0_BRDGOPT2, in32(PCIL0_BRDGOPT2) | 0x83 ); /* Enable host config, clear Timeout, ensure int src1 */
|
||||
#elif defined(PCIL0_BRDGOPT1)
|
||||
out32r( PCIL0_BRDGOPT1, 0x10000060 ); /* PLB Rq pri highest */
|
||||
out32r( PCIL0_BRDGOPT2, in32(PCIL0_BRDGOPT2) | 1 ); /* Enable host config */
|
||||
#endif
|
||||
|
||||
/*--------------------------------------------------------------------------+
|
||||
* PCI master init: default is one 256MB region for PCI memory:
|
||||
* 0x3_00000000 - 0x3_0FFFFFFF ==> CONFIG_SYS_PCI_MEMBASE
|
||||
*--------------------------------------------------------------------------*/
|
||||
#if defined(CONFIG_SYS_PCI_MASTER_INIT)
|
||||
pci_master_init(hose); /* Let board setup pci master */
|
||||
#else
|
||||
out32r( PCIL0_POM0SA, 0 ); /* disable */
|
||||
out32r( PCIL0_POM1SA, 0 ); /* disable */
|
||||
out32r( PCIL0_POM2SA, 0 ); /* disable */
|
||||
#if defined(CONFIG_440SPE)
|
||||
out32r( PCIL0_POM0LAL, 0x10000000 );
|
||||
out32r( PCIL0_POM0LAH, 0x0000000c );
|
||||
#elif defined(CONFIG_460EX) || defined(CONFIG_460GT)
|
||||
out32r( PCIL0_POM0LAL, 0x20000000 );
|
||||
out32r( PCIL0_POM0LAH, 0x0000000c );
|
||||
#else
|
||||
out32r( PCIL0_POM0LAL, 0x00000000 );
|
||||
out32r( PCIL0_POM0LAH, 0x00000003 );
|
||||
#endif
|
||||
out32r( PCIL0_POM0PCIAL, CONFIG_SYS_PCI_MEMBASE );
|
||||
out32r( PCIL0_POM0PCIAH, 0x00000000 );
|
||||
out32r( PCIL0_POM0SA, 0xf0000001 ); /* 256MB, enabled */
|
||||
out32r( PCIL0_STS, in32r( PCIL0_STS ) & ~0x0000fff8 );
|
||||
#endif
|
||||
|
||||
/*--------------------------------------------------------------------------+
|
||||
* PCI host configuration -- we don't make any assumptions here ... the
|
||||
* _board_must_indicate_ what to do -- there's just too many runtime
|
||||
* scenarios in environments like cPCI, PPMC, etc. to make a determination
|
||||
* based on hard-coded values or state of arbiter enable.
|
||||
*--------------------------------------------------------------------------*/
|
||||
if (is_pci_host(hose)) {
|
||||
#ifdef CONFIG_PCI_SCAN_SHOW
|
||||
printf("PCI: Bus Dev VenId DevId Class Int\n");
|
||||
#endif
|
||||
#if !defined(CONFIG_440EP) && !defined(CONFIG_440GR) && \
|
||||
!defined(CONFIG_440EPX) && !defined(CONFIG_440GRX)
|
||||
out16r( PCIL0_CMD, in16r( PCIL0_CMD ) | PCI_COMMAND_MASTER);
|
||||
#endif
|
||||
hose->last_busno = pci_hose_scan(hose);
|
||||
}
|
||||
return hose->last_busno;
|
||||
}
|
||||
#endif
|
||||
|
||||
void pci_init_board(void)
|
||||
{
|
||||
int busno = 0;
|
||||
|
||||
/*
|
||||
* Only init PCI when either master or target functionality
|
||||
* is selected.
|
||||
*/
|
||||
#if defined(CONFIG_SYS_PCI_MASTER_INIT) || defined(CONFIG_SYS_PCI_TARGET_INIT)
|
||||
busno = pci_440_init(&ppc440_hose);
|
||||
if (busno < 0)
|
||||
return;
|
||||
#endif
|
||||
#if (defined(CONFIG_440SPE) || \
|
||||
defined(CONFIG_460EX) || defined(CONFIG_460GT)) && \
|
||||
!defined(CONFIG_PCI_DISABLE_PCIE)
|
||||
pcie_setup_hoses(busno + 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* CONFIG_440 */
|
||||
|
||||
#if defined(CONFIG_405EX)
|
||||
void pci_init_board(void)
|
||||
{
|
||||
#ifdef CONFIG_PCI_SCAN_SHOW
|
||||
printf("PCI: Bus Dev VenId DevId Class Int\n");
|
||||
#endif
|
||||
pcie_setup_hoses(0);
|
||||
}
|
||||
#endif /* CONFIG_405EX */
|
||||
|
||||
#endif /* CONFIG_PCI */
|
||||
1280
u-boot/arch/powerpc/cpu/ppc4xx/4xx_pcie.c
Normal file
1280
u-boot/arch/powerpc/cpu/ppc4xx/4xx_pcie.c
Normal file
File diff suppressed because it is too large
Load Diff
268
u-boot/arch/powerpc/cpu/ppc4xx/4xx_uart.c
Normal file
268
u-boot/arch/powerpc/cpu/ppc4xx/4xx_uart.c
Normal file
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
* (C) Copyright 2000-2006
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*
|
||||
* (C) Copyright 2010
|
||||
* Stefan Roese, DENX Software Engineering, sr@denx.de.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0 IBM-pibs
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <commproc.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/io.h>
|
||||
#include <watchdog.h>
|
||||
#include <asm/ppc4xx.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#if defined(CONFIG_405GP) || \
|
||||
defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
|
||||
defined(CONFIG_405EX) || defined(CONFIG_440)
|
||||
|
||||
#if defined(CONFIG_440)
|
||||
|
||||
#if defined(CONFIG_440GP)
|
||||
#define CR0_MASK 0x3fff0000
|
||||
#define CR0_EXTCLK_ENA 0x00600000
|
||||
#define CR0_UDIV_POS 16
|
||||
#define UDIV_SUBTRACT 1
|
||||
#define UART0_SDR CPC0_CR0
|
||||
#define MFREG(a, d) d = mfdcr(a)
|
||||
#define MTREG(a, d) mtdcr(a, d)
|
||||
#else /* #if defined(CONFIG_440GP) */
|
||||
/* all other 440 PPC's access clock divider via sdr register */
|
||||
#define CR0_MASK 0xdfffffff
|
||||
#define CR0_EXTCLK_ENA 0x00800000
|
||||
#define CR0_UDIV_POS 0
|
||||
#define UDIV_SUBTRACT 0
|
||||
#define UART0_SDR SDR0_UART0
|
||||
#define UART1_SDR SDR0_UART1
|
||||
#if defined(CONFIG_440EP) || defined(CONFIG_440EPX) || \
|
||||
defined(CONFIG_440GR) || defined(CONFIG_440GRX) || \
|
||||
defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
|
||||
defined(CONFIG_460EX) || defined(CONFIG_460GT)
|
||||
#define UART2_SDR SDR0_UART2
|
||||
#endif
|
||||
#if defined(CONFIG_440EP) || defined(CONFIG_440EPX) || \
|
||||
defined(CONFIG_440GR) || defined(CONFIG_440GRX) || \
|
||||
defined(CONFIG_460EX) || defined(CONFIG_460GT)
|
||||
#define UART3_SDR SDR0_UART3
|
||||
#endif
|
||||
#define MFREG(a, d) mfsdr(a, d)
|
||||
#define MTREG(a, d) mtsdr(a, d)
|
||||
#endif /* #if defined(CONFIG_440GP) */
|
||||
#elif defined(CONFIG_405EP) || defined(CONFIG_405EZ)
|
||||
#define UCR0_MASK 0x0000007f
|
||||
#define UCR1_MASK 0x00007f00
|
||||
#define UCR0_UDIV_POS 0
|
||||
#define UCR1_UDIV_POS 8
|
||||
#define UDIV_MAX 127
|
||||
#elif defined(CONFIG_405EX)
|
||||
#define MFREG(a, d) mfsdr(a, d)
|
||||
#define MTREG(a, d) mtsdr(a, d)
|
||||
#define CR0_MASK 0x000000ff
|
||||
#define CR0_EXTCLK_ENA 0x00800000
|
||||
#define CR0_UDIV_POS 0
|
||||
#define UDIV_SUBTRACT 0
|
||||
#define UART0_SDR SDR0_UART0
|
||||
#define UART1_SDR SDR0_UART1
|
||||
#else /* CONFIG_405GP */
|
||||
#define CR0_MASK 0x00001fff
|
||||
#define CR0_EXTCLK_ENA 0x000000c0
|
||||
#define CR0_UDIV_POS 1
|
||||
#define UDIV_MAX 32
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_405EP) && defined(CONFIG_SYS_EXT_SERIAL_CLOCK)
|
||||
#error "External serial clock not supported on AMCC PPC405EP!"
|
||||
#endif
|
||||
|
||||
#if (defined(CONFIG_405EX) || defined(CONFIG_405EZ) || \
|
||||
defined(CONFIG_440)) && !defined(CONFIG_SYS_EXT_SERIAL_CLOCK)
|
||||
/*
|
||||
* For some SoC's, the cpu clock is on divider chain A, UART on
|
||||
* divider chain B ... so cpu clock is irrelevant. Get the
|
||||
* "optimized" values that are subject to the 1/2 opb clock
|
||||
* constraint.
|
||||
*/
|
||||
static u16 serial_bdiv(int baudrate, u32 *udiv)
|
||||
{
|
||||
sys_info_t sysinfo;
|
||||
u32 div; /* total divisor udiv * bdiv */
|
||||
u32 umin; /* minimum udiv */
|
||||
u16 diff; /* smallest diff */
|
||||
u16 idiff; /* current diff */
|
||||
u16 ibdiv; /* current bdiv */
|
||||
u32 i;
|
||||
u32 est; /* current estimate */
|
||||
u32 max;
|
||||
#if defined(CONFIG_405EZ)
|
||||
u32 cpr_pllc;
|
||||
u32 plloutb;
|
||||
u32 reg;
|
||||
#endif
|
||||
|
||||
get_sys_info(&sysinfo);
|
||||
|
||||
#if defined(CONFIG_405EZ)
|
||||
/* check the pll feedback source */
|
||||
mfcpr(CPR0_PLLC, cpr_pllc);
|
||||
plloutb = ((CONFIG_SYS_CLK_FREQ * ((cpr_pllc & PLLC_SRC_MASK) ?
|
||||
sysinfo.pllFwdDivB : sysinfo.pllFwdDiv) *
|
||||
sysinfo.pllFbkDiv) / sysinfo.pllFwdDivB);
|
||||
div = plloutb / (16 * baudrate); /* total divisor */
|
||||
umin = (plloutb / get_OPB_freq()) << 1; /* 2 x OPB divisor */
|
||||
max = 256; /* highest possible */
|
||||
#else /* 405EZ */
|
||||
div = sysinfo.freqPLB / (16 * baudrate); /* total divisor */
|
||||
umin = sysinfo.pllOpbDiv << 1; /* 2 x OPB divisor */
|
||||
max = 32; /* highest possible */
|
||||
#endif /* 405EZ */
|
||||
|
||||
*udiv = diff = max;
|
||||
|
||||
/*
|
||||
* i is the test udiv value -- start with the largest
|
||||
* possible (max) to minimize serial clock and constrain
|
||||
* search to umin.
|
||||
*/
|
||||
for (i = max; i > umin; i--) {
|
||||
ibdiv = div / i;
|
||||
est = i * ibdiv;
|
||||
idiff = (est > div) ? (est - div) : (div - est);
|
||||
if (idiff == 0) {
|
||||
*udiv = i;
|
||||
break; /* can't do better */
|
||||
} else if (idiff < diff) {
|
||||
*udiv = i; /* best so far */
|
||||
diff = idiff; /* update lowest diff*/
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_405EZ)
|
||||
mfcpr(CPR0_PERD0, reg);
|
||||
reg &= ~0x0000ffff;
|
||||
reg |= ((*udiv - 0) << 8) | (*udiv - 0);
|
||||
mtcpr(CPR0_PERD0, reg);
|
||||
#endif
|
||||
|
||||
return div / *udiv;
|
||||
}
|
||||
#endif /* #if (defined(CONFIG_405EP) ... */
|
||||
|
||||
/*
|
||||
* This function returns the UART clock used by the common
|
||||
* NS16550 driver. Additionally the SoC internal divisors for
|
||||
* optimal UART baudrate are configured.
|
||||
*/
|
||||
int get_serial_clock(void)
|
||||
{
|
||||
u32 clk;
|
||||
u32 udiv;
|
||||
#if !defined(CONFIG_405EZ)
|
||||
u32 reg;
|
||||
#endif
|
||||
#if !defined(CONFIG_SYS_EXT_SERIAL_CLOCK)
|
||||
PPC4xx_SYS_INFO sys_info;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Programming of the internal divisors is SoC specific.
|
||||
* Let's handle this in some #ifdef's for the SoC's.
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_405GP)
|
||||
reg = mfdcr(CPC0_CR0) & ~CR0_MASK;
|
||||
#ifdef CONFIG_SYS_EXT_SERIAL_CLOCK
|
||||
clk = CONFIG_SYS_EXT_SERIAL_CLOCK;
|
||||
udiv = 1;
|
||||
reg |= CR0_EXTCLK_ENA;
|
||||
#else /* CONFIG_SYS_EXT_SERIAL_CLOCK */
|
||||
clk = gd->cpu_clk;
|
||||
#ifdef CONFIG_SYS_405_UART_ERRATA_59
|
||||
udiv = 31; /* Errata 59: stuck at 31 */
|
||||
#else /* CONFIG_SYS_405_UART_ERRATA_59 */
|
||||
{
|
||||
u32 tmp = CONFIG_SYS_BASE_BAUD * 16;
|
||||
|
||||
udiv = (clk + tmp / 2) / tmp;
|
||||
}
|
||||
if (udiv > UDIV_MAX) /* max. n bits for udiv */
|
||||
udiv = UDIV_MAX;
|
||||
#endif /* CONFIG_SYS_405_UART_ERRATA_59 */
|
||||
#endif /* CONFIG_SYS_EXT_SERIAL_CLOCK */
|
||||
reg |= (udiv - 1) << CR0_UDIV_POS; /* set the UART divisor */
|
||||
mtdcr (CPC0_CR0, reg);
|
||||
#ifdef CONFIG_SYS_EXT_SERIAL_CLOCK
|
||||
clk = CONFIG_SYS_EXT_SERIAL_CLOCK;
|
||||
#else
|
||||
clk = CONFIG_SYS_BASE_BAUD * 16;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_405EP)
|
||||
{
|
||||
u32 tmp = CONFIG_SYS_BASE_BAUD * 16;
|
||||
|
||||
reg = mfdcr(CPC0_UCR) & ~(UCR0_MASK | UCR1_MASK);
|
||||
clk = gd->cpu_clk;
|
||||
udiv = (clk + tmp / 2) / tmp;
|
||||
if (udiv > UDIV_MAX) /* max. n bits for udiv */
|
||||
udiv = UDIV_MAX;
|
||||
}
|
||||
reg |= udiv << UCR0_UDIV_POS; /* set the UART divisor */
|
||||
reg |= udiv << UCR1_UDIV_POS; /* set the UART divisor */
|
||||
mtdcr(CPC0_UCR, reg);
|
||||
clk = CONFIG_SYS_BASE_BAUD * 16;
|
||||
#endif /* CONFIG_405EP */
|
||||
|
||||
#if defined(CONFIG_405EX) || defined(CONFIG_440)
|
||||
MFREG(UART0_SDR, reg);
|
||||
reg &= ~CR0_MASK;
|
||||
|
||||
#ifdef CONFIG_SYS_EXT_SERIAL_CLOCK
|
||||
reg |= CR0_EXTCLK_ENA;
|
||||
udiv = 1;
|
||||
clk = CONFIG_SYS_EXT_SERIAL_CLOCK;
|
||||
#else /* CONFIG_SYS_EXT_SERIAL_CLOCK */
|
||||
clk = gd->baudrate * serial_bdiv(gd->baudrate, &udiv) * 16;
|
||||
#endif /* CONFIG_SYS_EXT_SERIAL_CLOCK */
|
||||
|
||||
reg |= (udiv - UDIV_SUBTRACT) << CR0_UDIV_POS; /* set the UART divisor */
|
||||
|
||||
/*
|
||||
* Configure input clock to baudrate generator for all
|
||||
* available serial ports here
|
||||
*/
|
||||
MTREG(UART0_SDR, reg);
|
||||
#if defined(UART1_SDR)
|
||||
MTREG(UART1_SDR, reg);
|
||||
#endif
|
||||
#if defined(UART2_SDR)
|
||||
MTREG(UART2_SDR, reg);
|
||||
#endif
|
||||
#if defined(UART3_SDR)
|
||||
MTREG(UART3_SDR, reg);
|
||||
#endif
|
||||
#endif /* CONFIG_405EX ... */
|
||||
|
||||
#if defined(CONFIG_405EZ)
|
||||
clk = gd->baudrate * serial_bdiv(gd->baudrate, &udiv) * 16;
|
||||
#endif /* CONFIG_405EZ */
|
||||
|
||||
/*
|
||||
* Correct UART frequency in bd-info struct now that
|
||||
* the UART divisor is available
|
||||
*/
|
||||
#ifdef CONFIG_SYS_EXT_SERIAL_CLOCK
|
||||
gd->arch.uart_clk = CONFIG_SYS_EXT_SERIAL_CLOCK;
|
||||
#else
|
||||
get_sys_info(&sys_info);
|
||||
gd->arch.uart_clk = sys_info.freqUART / udiv;
|
||||
#endif
|
||||
|
||||
return clk;
|
||||
}
|
||||
#endif /* CONFIG_405GP */
|
||||
161
u-boot/arch/powerpc/cpu/ppc4xx/Kconfig
Normal file
161
u-boot/arch/powerpc/cpu/ppc4xx/Kconfig
Normal file
@@ -0,0 +1,161 @@
|
||||
menu "ppc4xx CPU"
|
||||
depends on 4xx
|
||||
|
||||
config SYS_CPU
|
||||
default "ppc4xx"
|
||||
|
||||
choice
|
||||
prompt "Target select"
|
||||
optional
|
||||
|
||||
config TARGET_LWMON5
|
||||
bool "Support lwmon5"
|
||||
|
||||
config TARGET_T3CORP
|
||||
bool "Support t3corp"
|
||||
|
||||
config TARGET_ACADIA
|
||||
bool "Support acadia"
|
||||
|
||||
config TARGET_BAMBOO
|
||||
bool "Support bamboo"
|
||||
|
||||
config TARGET_BUBINGA
|
||||
bool "Support bubinga"
|
||||
|
||||
config TARGET_CANYONLANDS
|
||||
bool "Support canyonlands"
|
||||
select DM
|
||||
select DM_SERIAL
|
||||
|
||||
config TARGET_KATMAI
|
||||
bool "Support katmai"
|
||||
|
||||
config TARGET_KILAUEA
|
||||
bool "Support kilauea"
|
||||
|
||||
config TARGET_LUAN
|
||||
bool "Support luan"
|
||||
|
||||
config TARGET_MAKALU
|
||||
bool "Support makalu"
|
||||
|
||||
config TARGET_REDWOOD
|
||||
bool "Support redwood"
|
||||
|
||||
config TARGET_SEQUOIA
|
||||
bool "Support sequoia"
|
||||
|
||||
config TARGET_WALNUT
|
||||
bool "Support walnut"
|
||||
|
||||
config TARGET_YOSEMITE
|
||||
bool "Support yosemite"
|
||||
|
||||
config TARGET_YUCCA
|
||||
bool "Support yucca"
|
||||
|
||||
config TARGET_CPCI2DP
|
||||
bool "Support CPCI2DP"
|
||||
|
||||
config TARGET_CPCI4052
|
||||
bool "Support CPCI4052"
|
||||
|
||||
config TARGET_PLU405
|
||||
bool "Support PLU405"
|
||||
|
||||
config TARGET_PMC405DE
|
||||
bool "Support PMC405DE"
|
||||
|
||||
config TARGET_PMC440
|
||||
bool "Support PMC440"
|
||||
|
||||
config TARGET_VOM405
|
||||
bool "Support VOM405"
|
||||
|
||||
config TARGET_DLVISION_10G
|
||||
bool "Support dlvision-10g"
|
||||
|
||||
config TARGET_IO
|
||||
bool "Support io"
|
||||
|
||||
config TARGET_IOCON
|
||||
bool "Support iocon"
|
||||
|
||||
config TARGET_NEO
|
||||
bool "Support neo"
|
||||
|
||||
config TARGET_IO64
|
||||
bool "Support io64"
|
||||
|
||||
config TARGET_DLVISION
|
||||
bool "Support dlvision"
|
||||
|
||||
config TARGET_GDPPC440ETX
|
||||
bool "Support gdppc440etx"
|
||||
|
||||
config TARGET_INTIP
|
||||
bool "Support intip"
|
||||
|
||||
config TARGET_ICON
|
||||
bool "Support icon"
|
||||
|
||||
config TARGET_MIP405
|
||||
bool "Support MIP405"
|
||||
|
||||
config TARGET_PIP405
|
||||
bool "Support PIP405"
|
||||
|
||||
config TARGET_XPEDITE1000
|
||||
bool "Support xpedite1000"
|
||||
|
||||
config TARGET_XILINX_PPC405_GENERIC
|
||||
bool "Support xilinx-ppc405-generic"
|
||||
select SUPPORT_SPL
|
||||
select OF_CONTROL
|
||||
select DM
|
||||
select DM_SERIAL
|
||||
|
||||
config TARGET_XILINX_PPC440_GENERIC
|
||||
bool "Support xilinx-ppc440-generic"
|
||||
select SUPPORT_SPL
|
||||
select OF_CONTROL
|
||||
select DM
|
||||
select DM_SERIAL
|
||||
|
||||
endchoice
|
||||
|
||||
source "board/amcc/acadia/Kconfig"
|
||||
source "board/amcc/bamboo/Kconfig"
|
||||
source "board/amcc/bubinga/Kconfig"
|
||||
source "board/amcc/canyonlands/Kconfig"
|
||||
source "board/amcc/katmai/Kconfig"
|
||||
source "board/amcc/kilauea/Kconfig"
|
||||
source "board/amcc/luan/Kconfig"
|
||||
source "board/amcc/makalu/Kconfig"
|
||||
source "board/amcc/redwood/Kconfig"
|
||||
source "board/amcc/sequoia/Kconfig"
|
||||
source "board/amcc/walnut/Kconfig"
|
||||
source "board/amcc/yosemite/Kconfig"
|
||||
source "board/amcc/yucca/Kconfig"
|
||||
source "board/esd/cpci2dp/Kconfig"
|
||||
source "board/esd/cpci405/Kconfig"
|
||||
source "board/esd/plu405/Kconfig"
|
||||
source "board/esd/pmc405de/Kconfig"
|
||||
source "board/esd/pmc440/Kconfig"
|
||||
source "board/esd/vom405/Kconfig"
|
||||
source "board/gdsys/405ep/Kconfig"
|
||||
source "board/gdsys/405ex/Kconfig"
|
||||
source "board/gdsys/dlvision/Kconfig"
|
||||
source "board/gdsys/gdppc440etx/Kconfig"
|
||||
source "board/gdsys/intip/Kconfig"
|
||||
source "board/liebherr/lwmon5/Kconfig"
|
||||
source "board/mosaixtech/icon/Kconfig"
|
||||
source "board/mpl/mip405/Kconfig"
|
||||
source "board/mpl/pip405/Kconfig"
|
||||
source "board/t3corp/Kconfig"
|
||||
source "board/xes/xpedite1000/Kconfig"
|
||||
source "board/xilinx/ppc405-generic/Kconfig"
|
||||
source "board/xilinx/ppc440-generic/Kconfig"
|
||||
|
||||
endmenu
|
||||
49
u-boot/arch/powerpc/cpu/ppc4xx/Makefile
Normal file
49
u-boot/arch/powerpc/cpu/ppc4xx/Makefile
Normal file
@@ -0,0 +1,49 @@
|
||||
#
|
||||
# (C) Copyright 2000-2006
|
||||
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
extra-y := resetvec.o
|
||||
extra-y += start.o
|
||||
|
||||
obj-y := cache.o
|
||||
obj-y += dcr.o
|
||||
obj-y += kgdb.o
|
||||
|
||||
obj-y += 40x_spd_sdram.o
|
||||
|
||||
obj-y += 44x_spd_ddr.o
|
||||
obj-$(CONFIG_SDRAM_PPC4xx_IBM_DDR2) += 44x_spd_ddr2.o
|
||||
obj-$(CONFIG_PPC4xx_DDR_AUTOCALIBRATION) += 4xx_ibm_ddr2_autocalib.o
|
||||
obj-y += 4xx_pci.o
|
||||
obj-y += 4xx_pcie.o
|
||||
obj-y += bedbug_405.o
|
||||
obj-$(CONFIG_CMD_CHIP_CONFIG) += cmd_chip_config.o
|
||||
obj-y += cpu.o
|
||||
obj-y += cpu_init.o
|
||||
obj-y += denali_data_eye.o
|
||||
obj-y += denali_spd_ddr2.o
|
||||
obj-y += ecc.o
|
||||
obj-$(CONFIG_CMD_ECCTEST) += cmd_ecctest.o
|
||||
obj-y += fdt.o
|
||||
obj-y += interrupts.o
|
||||
obj-$(CONFIG_CMD_REGINFO) += reginfo.o
|
||||
obj-y += sdram.o
|
||||
obj-y += speed.o
|
||||
obj-y += tlb.o
|
||||
obj-y += traps.o
|
||||
obj-y += usb.o
|
||||
obj-y += usb_ohci.o
|
||||
obj-$(CONFIG_XILINX_440) += xilinx_irq.o
|
||||
ifndef CONFIG_XILINX_440
|
||||
obj-y += 4xx_uart.o
|
||||
obj-y += gpio.o
|
||||
obj-y += miiphy.o
|
||||
obj-y += uic.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_SPL_BUILD
|
||||
obj-y += spl_boot.o
|
||||
endif
|
||||
308
u-boot/arch/powerpc/cpu/ppc4xx/bedbug_405.c
Normal file
308
u-boot/arch/powerpc/cpu/ppc4xx/bedbug_405.c
Normal file
@@ -0,0 +1,308 @@
|
||||
/*
|
||||
* Bedbug Functions specific to the PPC405 chip
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <bedbug/type.h>
|
||||
#include <bedbug/bedbug.h>
|
||||
#include <bedbug/regs.h>
|
||||
#include <bedbug/ppc.h>
|
||||
|
||||
#if defined(CONFIG_CMD_BEDBUG) && defined(CONFIG_4xx)
|
||||
|
||||
#define MAX_BREAK_POINTS 4
|
||||
|
||||
extern CPU_DEBUG_CTX bug_ctx;
|
||||
|
||||
void bedbug405_init __P ((void));
|
||||
void bedbug405_do_break __P ((cmd_tbl_t *, int, int, char * const []));
|
||||
void bedbug405_break_isr __P ((struct pt_regs *));
|
||||
int bedbug405_find_empty __P ((void));
|
||||
int bedbug405_set __P ((int, unsigned long));
|
||||
int bedbug405_clear __P ((int));
|
||||
|
||||
|
||||
/* ======================================================================
|
||||
* Initialize the global bug_ctx structure for the AMCC PPC405. Clear all
|
||||
* of the breakpoints.
|
||||
* ====================================================================== */
|
||||
|
||||
void bedbug405_init (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* -------------------------------------------------- */
|
||||
|
||||
bug_ctx.hw_debug_enabled = 0;
|
||||
bug_ctx.stopped = 0;
|
||||
bug_ctx.current_bp = 0;
|
||||
bug_ctx.regs = NULL;
|
||||
|
||||
bug_ctx.do_break = bedbug405_do_break;
|
||||
bug_ctx.break_isr = bedbug405_break_isr;
|
||||
bug_ctx.find_empty = bedbug405_find_empty;
|
||||
bug_ctx.set = bedbug405_set;
|
||||
bug_ctx.clear = bedbug405_clear;
|
||||
|
||||
for (i = 1; i <= MAX_BREAK_POINTS; ++i)
|
||||
(*bug_ctx.clear) (i);
|
||||
|
||||
puts ("BEDBUG:ready\n");
|
||||
return;
|
||||
} /* bedbug_init_breakpoints */
|
||||
|
||||
|
||||
|
||||
/* ======================================================================
|
||||
* Set/clear/show one of the hardware breakpoints for the 405. The "off"
|
||||
* string will disable a specific breakpoint. The "show" string will
|
||||
* display the current breakpoints. Otherwise an address will set a
|
||||
* breakpoint at that address. Setting a breakpoint uses the CPU-specific
|
||||
* set routine which will assign a breakpoint number.
|
||||
* ====================================================================== */
|
||||
|
||||
void bedbug405_do_break (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
long addr = 0; /* Address to break at */
|
||||
int which_bp; /* Breakpoint number */
|
||||
|
||||
/* -------------------------------------------------- */
|
||||
|
||||
if (argc < 2) {
|
||||
cmd_usage(cmdtp);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Turn off a breakpoint */
|
||||
|
||||
if (strcmp (argv[1], "off") == 0) {
|
||||
if (bug_ctx.hw_debug_enabled == 0) {
|
||||
printf ("No breakpoints enabled\n");
|
||||
return;
|
||||
}
|
||||
|
||||
which_bp = simple_strtoul (argv[2], NULL, 10);
|
||||
|
||||
if (bug_ctx.clear)
|
||||
(*bug_ctx.clear) (which_bp);
|
||||
|
||||
printf ("Breakpoint %d removed\n", which_bp);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Show a list of breakpoints */
|
||||
|
||||
if (strcmp (argv[1], "show") == 0) {
|
||||
for (which_bp = 1; which_bp <= MAX_BREAK_POINTS; ++which_bp) {
|
||||
|
||||
switch (which_bp) {
|
||||
case 1:
|
||||
addr = GET_IAC1 ();
|
||||
break;
|
||||
case 2:
|
||||
addr = GET_IAC2 ();
|
||||
break;
|
||||
case 3:
|
||||
addr = GET_IAC3 ();
|
||||
break;
|
||||
case 4:
|
||||
addr = GET_IAC4 ();
|
||||
break;
|
||||
}
|
||||
|
||||
printf ("Breakpoint [%d]: ", which_bp);
|
||||
if (addr == 0)
|
||||
printf ("NOT SET\n");
|
||||
else
|
||||
disppc ((unsigned char *) addr, 0, 1, bedbug_puts,
|
||||
F_RADHEX);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set a breakpoint at the address */
|
||||
|
||||
if (!isdigit (argv[1][0])) {
|
||||
cmd_usage(cmdtp);
|
||||
return;
|
||||
}
|
||||
|
||||
addr = simple_strtoul (argv[1], NULL, 16) & 0xfffffffc;
|
||||
|
||||
if ((bug_ctx.set) && (which_bp = (*bug_ctx.set) (0, addr)) > 0) {
|
||||
printf ("Breakpoint [%d]: ", which_bp);
|
||||
disppc ((unsigned char *) addr, 0, 1, bedbug_puts, F_RADHEX);
|
||||
}
|
||||
|
||||
return;
|
||||
} /* bedbug405_do_break */
|
||||
|
||||
|
||||
|
||||
/* ======================================================================
|
||||
* Handle a breakpoint. First determine which breakpoint was hit by
|
||||
* looking at the DeBug Status Register (DBSR), clear the breakpoint
|
||||
* and enter a mini main loop. Stay in the loop until the stopped flag
|
||||
* in the debug context is cleared.
|
||||
* ====================================================================== */
|
||||
|
||||
void bedbug405_break_isr (struct pt_regs *regs)
|
||||
{
|
||||
unsigned long dbsr_val; /* Value of the DBSR */
|
||||
unsigned long addr = 0; /* Address stopped at */
|
||||
|
||||
/* -------------------------------------------------- */
|
||||
|
||||
dbsr_val = GET_DBSR ();
|
||||
|
||||
if (dbsr_val & DBSR_IA1) {
|
||||
bug_ctx.current_bp = 1;
|
||||
addr = GET_IAC1 ();
|
||||
SET_DBSR (DBSR_IA1); /* Write a 1 to clear */
|
||||
} else if (dbsr_val & DBSR_IA2) {
|
||||
bug_ctx.current_bp = 2;
|
||||
addr = GET_IAC2 ();
|
||||
SET_DBSR (DBSR_IA2); /* Write a 1 to clear */
|
||||
} else if (dbsr_val & DBSR_IA3) {
|
||||
bug_ctx.current_bp = 3;
|
||||
addr = GET_IAC3 ();
|
||||
SET_DBSR (DBSR_IA3); /* Write a 1 to clear */
|
||||
} else if (dbsr_val & DBSR_IA4) {
|
||||
bug_ctx.current_bp = 4;
|
||||
addr = GET_IAC4 ();
|
||||
SET_DBSR (DBSR_IA4); /* Write a 1 to clear */
|
||||
}
|
||||
|
||||
bedbug_main_loop (addr, regs);
|
||||
return;
|
||||
} /* bedbug405_break_isr */
|
||||
|
||||
|
||||
|
||||
/* ======================================================================
|
||||
* Look through all of the hardware breakpoints available to see if one
|
||||
* is unused.
|
||||
* ====================================================================== */
|
||||
|
||||
int bedbug405_find_empty (void)
|
||||
{
|
||||
/* -------------------------------------------------- */
|
||||
|
||||
if (GET_IAC1 () == 0)
|
||||
return 1;
|
||||
|
||||
if (GET_IAC2 () == 0)
|
||||
return 2;
|
||||
|
||||
if (GET_IAC3 () == 0)
|
||||
return 3;
|
||||
|
||||
if (GET_IAC4 () == 0)
|
||||
return 4;
|
||||
|
||||
return 0;
|
||||
} /* bedbug405_find_empty */
|
||||
|
||||
|
||||
|
||||
/* ======================================================================
|
||||
* Set a breakpoint. If 'which_bp' is zero then find an unused breakpoint
|
||||
* number, otherwise reassign the given breakpoint. If hardware debugging
|
||||
* is not enabled, then turn it on via the MSR and DBCR0. Set the break
|
||||
* address in the appropriate IACx register and enable proper address
|
||||
* beakpoint in DBCR0.
|
||||
* ====================================================================== */
|
||||
|
||||
int bedbug405_set (int which_bp, unsigned long addr)
|
||||
{
|
||||
/* -------------------------------------------------- */
|
||||
|
||||
/* Only look if which_bp == 0, else use which_bp */
|
||||
if ((bug_ctx.find_empty) && (!which_bp) &&
|
||||
(which_bp = (*bug_ctx.find_empty) ()) == 0) {
|
||||
printf ("All breakpoints in use\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (which_bp < 1 || which_bp > MAX_BREAK_POINTS) {
|
||||
printf ("Invalid break point # %d\n", which_bp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!bug_ctx.hw_debug_enabled) {
|
||||
SET_MSR (GET_MSR () | 0x200); /* set MSR[ DE ] */
|
||||
SET_DBCR0 (GET_DBCR0 () | DBCR0_IDM);
|
||||
bug_ctx.hw_debug_enabled = 1;
|
||||
}
|
||||
|
||||
switch (which_bp) {
|
||||
case 1:
|
||||
SET_IAC1 (addr);
|
||||
SET_DBCR0 (GET_DBCR0 () | DBCR0_IA1);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
SET_IAC2 (addr);
|
||||
SET_DBCR0 (GET_DBCR0 () | DBCR0_IA2);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
SET_IAC3 (addr);
|
||||
SET_DBCR0 (GET_DBCR0 () | DBCR0_IA3);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
SET_IAC4 (addr);
|
||||
SET_DBCR0 (GET_DBCR0 () | DBCR0_IA4);
|
||||
break;
|
||||
}
|
||||
|
||||
return which_bp;
|
||||
} /* bedbug405_set */
|
||||
|
||||
|
||||
|
||||
/* ======================================================================
|
||||
* Disable a specific breakoint by setting the appropriate IACx register
|
||||
* to zero and claring the instruction address breakpoint in DBCR0.
|
||||
* ====================================================================== */
|
||||
|
||||
int bedbug405_clear (int which_bp)
|
||||
{
|
||||
/* -------------------------------------------------- */
|
||||
|
||||
if (which_bp < 1 || which_bp > MAX_BREAK_POINTS) {
|
||||
printf ("Invalid break point # (%d)\n", which_bp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (which_bp) {
|
||||
case 1:
|
||||
SET_IAC1 (0);
|
||||
SET_DBCR0 (GET_DBCR0 () & ~DBCR0_IA1);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
SET_IAC2 (0);
|
||||
SET_DBCR0 (GET_DBCR0 () & ~DBCR0_IA2);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
SET_IAC3 (0);
|
||||
SET_DBCR0 (GET_DBCR0 () & ~DBCR0_IA3);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
SET_IAC4 (0);
|
||||
SET_DBCR0 (GET_DBCR0 () & ~DBCR0_IA4);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
} /* bedbug405_clear */
|
||||
|
||||
|
||||
/* ====================================================================== */
|
||||
#endif
|
||||
188
u-boot/arch/powerpc/cpu/ppc4xx/cache.S
Normal file
188
u-boot/arch/powerpc/cpu/ppc4xx/cache.S
Normal file
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* This file contains miscellaneous low-level functions.
|
||||
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
|
||||
*
|
||||
* Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
|
||||
* and Paul Mackerras.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <config.h>
|
||||
#include <asm/ppc4xx.h>
|
||||
#include <ppc_asm.tmpl>
|
||||
#include <ppc_defs.h>
|
||||
#include <asm/cache.h>
|
||||
#include <asm/mmu.h>
|
||||
|
||||
/*
|
||||
* Flush instruction cache.
|
||||
*/
|
||||
_GLOBAL(invalidate_icache)
|
||||
iccci r0,r0
|
||||
isync
|
||||
blr
|
||||
|
||||
/*
|
||||
* Write any modified data cache blocks out to memory
|
||||
* and invalidate the corresponding instruction cache blocks.
|
||||
*
|
||||
* flush_icache_range(unsigned long start, unsigned long stop)
|
||||
*/
|
||||
_GLOBAL(flush_icache_range)
|
||||
li r5,L1_CACHE_BYTES-1
|
||||
andc r3,r3,r5
|
||||
subf r4,r3,r4
|
||||
add r4,r4,r5
|
||||
srwi. r4,r4,L1_CACHE_SHIFT
|
||||
beqlr
|
||||
mtctr r4
|
||||
mr r6,r3
|
||||
1: dcbst 0,r3
|
||||
addi r3,r3,L1_CACHE_BYTES
|
||||
bdnz 1b
|
||||
sync /* wait for dcbst's to get to ram */
|
||||
mtctr r4
|
||||
2: icbi 0,r6
|
||||
addi r6,r6,L1_CACHE_BYTES
|
||||
bdnz 2b
|
||||
sync /* additional sync needed on g4 */
|
||||
isync
|
||||
blr
|
||||
|
||||
/*
|
||||
* Write any modified data cache blocks out to memory.
|
||||
* Does not invalidate the corresponding cache lines (especially for
|
||||
* any corresponding instruction cache).
|
||||
*
|
||||
* clean_dcache_range(unsigned long start, unsigned long stop)
|
||||
*/
|
||||
_GLOBAL(clean_dcache_range)
|
||||
li r5,L1_CACHE_BYTES-1
|
||||
andc r3,r3,r5
|
||||
subf r4,r3,r4
|
||||
add r4,r4,r5
|
||||
srwi. r4,r4,L1_CACHE_SHIFT
|
||||
beqlr
|
||||
mtctr r4
|
||||
|
||||
1: dcbst 0,r3
|
||||
addi r3,r3,L1_CACHE_BYTES
|
||||
bdnz 1b
|
||||
sync /* wait for dcbst's to get to ram */
|
||||
blr
|
||||
|
||||
/*
|
||||
* 40x cores have 8K or 16K dcache and 32 byte line size.
|
||||
* 44x has a 32K dcache and 32 byte line size.
|
||||
* 8xx has 1, 2, 4, 8K variants.
|
||||
* For now, cover the worst case of the 44x.
|
||||
* Must be called with external interrupts disabled.
|
||||
*/
|
||||
#define CACHE_NWAYS 64
|
||||
#define CACHE_NLINES 32
|
||||
|
||||
_GLOBAL(flush_dcache)
|
||||
li r4,(2 * CACHE_NWAYS * CACHE_NLINES)
|
||||
mtctr r4
|
||||
lis r5,0
|
||||
1: lwz r3,0(r5) /* Load one word from every line */
|
||||
addi r5,r5,L1_CACHE_BYTES
|
||||
bdnz 1b
|
||||
sync
|
||||
blr
|
||||
|
||||
_GLOBAL(invalidate_dcache)
|
||||
addi r6,0,0x0000 /* clear GPR 6 */
|
||||
/* Do loop for # of dcache congruence classes. */
|
||||
lis r7,(CONFIG_SYS_DCACHE_SIZE / L1_CACHE_BYTES / 2)@ha /* TBS for large sized cache */
|
||||
ori r7,r7,(CONFIG_SYS_DCACHE_SIZE / L1_CACHE_BYTES / 2)@l
|
||||
/* NOTE: dccci invalidates both */
|
||||
mtctr r7 /* ways in the D cache */
|
||||
..dcloop:
|
||||
dccci 0,r6 /* invalidate line */
|
||||
addi r6,r6,L1_CACHE_BYTES /* bump to next line */
|
||||
bdnz ..dcloop
|
||||
sync
|
||||
blr
|
||||
|
||||
/*
|
||||
* Cache functions.
|
||||
*
|
||||
* NOTE: currently the 440s run with dcache _disabled_ once relocated to DRAM,
|
||||
* although for some cache-ralated calls stubs have to be provided to satisfy
|
||||
* symbols resolution.
|
||||
* Icache-related functions are used in POST framework.
|
||||
*
|
||||
*/
|
||||
#ifdef CONFIG_440
|
||||
|
||||
.globl dcache_disable
|
||||
.globl dcache_enable
|
||||
.globl icache_disable
|
||||
.globl icache_enable
|
||||
dcache_disable:
|
||||
dcache_enable:
|
||||
icache_disable:
|
||||
icache_enable:
|
||||
blr
|
||||
|
||||
.globl dcache_status
|
||||
.globl icache_status
|
||||
dcache_status:
|
||||
icache_status:
|
||||
mr r3, 0
|
||||
blr
|
||||
|
||||
#else /* CONFIG_440 */
|
||||
|
||||
.globl icache_enable
|
||||
icache_enable:
|
||||
mflr r8
|
||||
bl invalidate_icache
|
||||
mtlr r8
|
||||
isync
|
||||
addis r3,r0, 0xc000 /* set bit 0 */
|
||||
mticcr r3
|
||||
blr
|
||||
|
||||
.globl icache_disable
|
||||
icache_disable:
|
||||
addis r3,r0, 0x0000 /* clear bit 0 */
|
||||
mticcr r3
|
||||
isync
|
||||
blr
|
||||
|
||||
.globl icache_status
|
||||
icache_status:
|
||||
mficcr r3
|
||||
srwi r3, r3, 31 /* >>31 => select bit 0 */
|
||||
blr
|
||||
|
||||
.globl dcache_enable
|
||||
dcache_enable:
|
||||
mflr r8
|
||||
bl invalidate_dcache
|
||||
mtlr r8
|
||||
isync
|
||||
addis r3,r0, 0x8000 /* set bit 0 */
|
||||
mtdccr r3
|
||||
blr
|
||||
|
||||
.globl dcache_disable
|
||||
dcache_disable:
|
||||
mflr r8
|
||||
bl flush_dcache
|
||||
mtlr r8
|
||||
addis r3,r0, 0x0000 /* clear bit 0 */
|
||||
mtdccr r3
|
||||
blr
|
||||
|
||||
.globl dcache_status
|
||||
dcache_status:
|
||||
mfdccr r3
|
||||
srwi r3, r3, 31 /* >>31 => select bit 0 */
|
||||
blr
|
||||
|
||||
#endif /* CONFIG_440 */
|
||||
131
u-boot/arch/powerpc/cpu/ppc4xx/cmd_chip_config.c
Normal file
131
u-boot/arch/powerpc/cpu/ppc4xx/cmd_chip_config.c
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* (C) Copyright 2008-2009
|
||||
* Stefan Roese, DENX Software Engineering, sr@denx.de.
|
||||
*
|
||||
* (C) Copyright 2009
|
||||
* Dirk Eibach, Guntermann & Drunck GmbH, eibach@gdsys.de
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <i2c.h>
|
||||
#include <asm/ppc4xx_config.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
static void print_configs(int cur_config_nr)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ppc4xx_config_count; i++) {
|
||||
printf("%-16s - %s", ppc4xx_config_val[i].label,
|
||||
ppc4xx_config_val[i].description);
|
||||
if (i == cur_config_nr)
|
||||
printf(" ***");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int do_chip_config(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
int i;
|
||||
int ret;
|
||||
int cur_config_nr = -1;
|
||||
u8 cur_config[CONFIG_4xx_CONFIG_BLOCKSIZE];
|
||||
|
||||
/*
|
||||
* First switch to correct I2C bus. This is I2C bus 0
|
||||
* for all currently available 4xx derivats.
|
||||
*/
|
||||
i2c_set_bus_num(0);
|
||||
|
||||
#ifdef CONFIG_CMD_EEPROM
|
||||
ret = eeprom_read(CONFIG_4xx_CONFIG_I2C_EEPROM_ADDR,
|
||||
CONFIG_4xx_CONFIG_I2C_EEPROM_OFFSET,
|
||||
cur_config, CONFIG_4xx_CONFIG_BLOCKSIZE);
|
||||
#else
|
||||
ret = i2c_read(CONFIG_4xx_CONFIG_I2C_EEPROM_ADDR,
|
||||
CONFIG_4xx_CONFIG_I2C_EEPROM_OFFSET,
|
||||
1, cur_config, CONFIG_4xx_CONFIG_BLOCKSIZE);
|
||||
#endif
|
||||
if (ret) {
|
||||
printf("Error reading EEPROM at addr 0x%x\n",
|
||||
CONFIG_4xx_CONFIG_I2C_EEPROM_ADDR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Search the current configuration
|
||||
*/
|
||||
for (i = 0; i < ppc4xx_config_count; i++) {
|
||||
if (memcmp(cur_config, ppc4xx_config_val[i].val,
|
||||
CONFIG_4xx_CONFIG_BLOCKSIZE) == 0)
|
||||
cur_config_nr = i;
|
||||
}
|
||||
|
||||
if (cur_config_nr == -1) {
|
||||
printf("Warning: The I2C bootstrap values don't match any"
|
||||
" of the available options!\n");
|
||||
printf("I2C bootstrap EEPROM values are (I2C address 0x%02x):\n",
|
||||
CONFIG_4xx_CONFIG_I2C_EEPROM_ADDR);
|
||||
for (i = 0; i < CONFIG_4xx_CONFIG_BLOCKSIZE; i++) {
|
||||
printf("%02x ", cur_config[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if (argc < 2) {
|
||||
printf("Available configurations (I2C address 0x%02x):\n",
|
||||
CONFIG_4xx_CONFIG_I2C_EEPROM_ADDR);
|
||||
print_configs(cur_config_nr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < ppc4xx_config_count; i++) {
|
||||
/*
|
||||
* Search for configuration name/label
|
||||
*/
|
||||
if (strcmp(argv[1], ppc4xx_config_val[i].label) == 0) {
|
||||
printf("Using configuration:\n%-16s - %s\n",
|
||||
ppc4xx_config_val[i].label,
|
||||
ppc4xx_config_val[i].description);
|
||||
|
||||
#ifdef CONFIG_CMD_EEPROM
|
||||
ret = eeprom_write(CONFIG_4xx_CONFIG_I2C_EEPROM_ADDR,
|
||||
CONFIG_4xx_CONFIG_I2C_EEPROM_OFFSET,
|
||||
ppc4xx_config_val[i].val,
|
||||
CONFIG_4xx_CONFIG_BLOCKSIZE);
|
||||
#else
|
||||
ret = i2c_write(CONFIG_4xx_CONFIG_I2C_EEPROM_ADDR,
|
||||
CONFIG_4xx_CONFIG_I2C_EEPROM_OFFSET,
|
||||
1, ppc4xx_config_val[i].val,
|
||||
CONFIG_4xx_CONFIG_BLOCKSIZE);
|
||||
#endif
|
||||
udelay(CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS * 1000);
|
||||
if (ret) {
|
||||
printf("Error updating EEPROM at addr 0x%x\n",
|
||||
CONFIG_4xx_CONFIG_I2C_EEPROM_ADDR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("done (dump via 'i2c md %x 0.1 %x')\n",
|
||||
CONFIG_4xx_CONFIG_I2C_EEPROM_ADDR,
|
||||
CONFIG_4xx_CONFIG_BLOCKSIZE);
|
||||
printf("Reset the board for the changes to"
|
||||
" take effect\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
printf("Configuration %s not found!\n", argv[1]);
|
||||
print_configs(cur_config_nr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
chip_config, 2, 0, do_chip_config,
|
||||
"program the I2C bootstrap EEPROM",
|
||||
"[config-label]"
|
||||
);
|
||||
262
u-boot/arch/powerpc/cpu/ppc4xx/cmd_ecctest.c
Normal file
262
u-boot/arch/powerpc/cpu/ppc4xx/cmd_ecctest.c
Normal file
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
* (C) Copyright 2010
|
||||
* Stefan Roese, DENX Software Engineering, sr@denx.de.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/ppc4xx.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/cache.h>
|
||||
|
||||
#if defined(CONFIG_SDRAM_PPC4xx_IBM_DDR) || \
|
||||
defined(CONFIG_SDRAM_PPC4xx_IBM_DDR2)
|
||||
#if defined(CONFIG_DDR_ECC) || defined(CONFIG_SDRAM_ECC)
|
||||
|
||||
#if defined(CONFIG_405EX)
|
||||
/*
|
||||
* Currently only 405EX uses 16bit data bus width as an alternative
|
||||
* option to 32bit data width (SDRAM0_MCOPT1_WDTH)
|
||||
*/
|
||||
#define SDRAM_DATA_ALT_WIDTH 2
|
||||
#else
|
||||
#define SDRAM_DATA_ALT_WIDTH 8
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SYS_OCM_BASE)
|
||||
#define CONFIG_FUNC_ISRAM_ADDR CONFIG_SYS_OCM_BASE
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SYS_ISRAM_BASE)
|
||||
#define CONFIG_FUNC_ISRAM_ADDR CONFIG_SYS_ISRAM_BASE
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_FUNC_ISRAM_ADDR)
|
||||
#error "No internal SRAM/OCM provided!"
|
||||
#endif
|
||||
|
||||
#define force_inline inline __attribute__ ((always_inline))
|
||||
|
||||
static inline void machine_check_disable(void)
|
||||
{
|
||||
mtmsr(mfmsr() & ~MSR_ME);
|
||||
}
|
||||
|
||||
static inline void machine_check_enable(void)
|
||||
{
|
||||
mtmsr(mfmsr() | MSR_ME);
|
||||
}
|
||||
|
||||
/*
|
||||
* These helper functions need to be inlined, since they
|
||||
* are called from the functions running from internal SRAM.
|
||||
* SDRAM operation is forbidden at that time, so calling
|
||||
* functions in SDRAM has to be avoided.
|
||||
*/
|
||||
static force_inline void wait_ddr_idle(void)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
do {
|
||||
mfsdram(SDRAM_MCSTAT, val);
|
||||
} while ((val & SDRAM_MCSTAT_IDLE_MASK) == SDRAM_MCSTAT_IDLE_NOT);
|
||||
}
|
||||
|
||||
static force_inline void recalibrate_ddr(void)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
/*
|
||||
* Rewrite RQDC & RFDC to calibrate again. If this is not
|
||||
* done, the SDRAM controller is working correctly after
|
||||
* changing the MCOPT1_MCHK bits.
|
||||
*/
|
||||
mfsdram(SDRAM_RQDC, val);
|
||||
mtsdram(SDRAM_RQDC, val);
|
||||
mfsdram(SDRAM_RFDC, val);
|
||||
mtsdram(SDRAM_RFDC, val);
|
||||
}
|
||||
|
||||
static force_inline void set_mcopt1_mchk(u32 bits)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
wait_ddr_idle();
|
||||
mfsdram(SDRAM_MCOPT1, val);
|
||||
mtsdram(SDRAM_MCOPT1, (val & ~SDRAM_MCOPT1_MCHK_MASK) | bits);
|
||||
recalibrate_ddr();
|
||||
}
|
||||
|
||||
/*
|
||||
* The next 2 functions are copied to internal SRAM/OCM and run
|
||||
* there. No function calls allowed here. No SDRAM acitivity should
|
||||
* be done here.
|
||||
*/
|
||||
static void inject_ecc_error(void *ptr, int par)
|
||||
{
|
||||
/*
|
||||
* Taken from PPC460EX/EXr/GT users manual (Rev 1.21)
|
||||
* 22.2.17.13 ECC Diagnostics
|
||||
*
|
||||
* Items 1 ... 5 are already done by now, running from RAM
|
||||
* with ECC enabled
|
||||
*/
|
||||
|
||||
out_be32(ptr, 0x00000000);
|
||||
in_be32(ptr);
|
||||
|
||||
/* 6. Set memory controller to no error checking */
|
||||
set_mcopt1_mchk(SDRAM_MCOPT1_MCHK_NON);
|
||||
|
||||
/* 7. Modify one or two bits for error simulation */
|
||||
if (par == 1)
|
||||
out_be32(ptr, in_be32(ptr) ^ 0x00000001);
|
||||
else
|
||||
out_be32(ptr, in_be32(ptr) ^ 0x00000003);
|
||||
|
||||
/* 8. Wait for SDRAM idle */
|
||||
in_be32(ptr);
|
||||
set_mcopt1_mchk(SDRAM_MCOPT1_MCHK_CHK_REP);
|
||||
|
||||
/* Wait for SDRAM idle */
|
||||
wait_ddr_idle();
|
||||
|
||||
/* Continue with 9. in calling function... */
|
||||
}
|
||||
|
||||
static void rewrite_ecc_parity(void *ptr, int par)
|
||||
{
|
||||
u32 current_address = (u32)ptr;
|
||||
u32 end_address;
|
||||
u32 address_increment;
|
||||
u32 mcopt1;
|
||||
|
||||
/*
|
||||
* Fill ECC parity byte again. Otherwise further accesses to
|
||||
* the failure address will result in exceptions.
|
||||
*/
|
||||
|
||||
/* Wait for SDRAM idle */
|
||||
in_be32(0x00000000);
|
||||
set_mcopt1_mchk(SDRAM_MCOPT1_MCHK_GEN);
|
||||
|
||||
/* ECC bit set method for non-cached memory */
|
||||
mfsdram(SDRAM_MCOPT1, mcopt1);
|
||||
if ((mcopt1 & SDRAM_MCOPT1_DMWD_MASK) == SDRAM_MCOPT1_DMWD_32)
|
||||
address_increment = 4;
|
||||
else
|
||||
address_increment = SDRAM_DATA_ALT_WIDTH;
|
||||
end_address = current_address + CONFIG_SYS_CACHELINE_SIZE;
|
||||
|
||||
while (current_address < end_address) {
|
||||
*((unsigned long *)current_address) = 0;
|
||||
current_address += address_increment;
|
||||
}
|
||||
|
||||
set_mcopt1_mchk(SDRAM_MCOPT1_MCHK_CHK_REP);
|
||||
|
||||
/* Wait for SDRAM idle */
|
||||
wait_ddr_idle();
|
||||
}
|
||||
|
||||
static int do_ecctest(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
u32 old_val;
|
||||
u32 val;
|
||||
u32 *ptr;
|
||||
void (*sram_func)(u32 *, int);
|
||||
int error;
|
||||
|
||||
if (argc < 3) {
|
||||
return cmd_usage(cmdtp);
|
||||
}
|
||||
|
||||
ptr = (u32 *)simple_strtoul(argv[1], NULL, 16);
|
||||
error = simple_strtoul(argv[2], NULL, 16);
|
||||
if ((error < 1) || (error > 2)) {
|
||||
return cmd_usage(cmdtp);
|
||||
}
|
||||
|
||||
printf("Using address %p for %d bit ECC error injection\n",
|
||||
ptr, error);
|
||||
|
||||
/*
|
||||
* Save value to restore it later on
|
||||
*/
|
||||
old_val = in_be32(ptr);
|
||||
|
||||
/*
|
||||
* Copy ECC injection function into internal SRAM/OCM
|
||||
*/
|
||||
sram_func = (void *)CONFIG_FUNC_ISRAM_ADDR;
|
||||
memcpy((void *)CONFIG_FUNC_ISRAM_ADDR, inject_ecc_error, 0x10000);
|
||||
|
||||
/*
|
||||
* Disable interrupts and exceptions before calling this
|
||||
* function in internal SRAM/OCM
|
||||
*/
|
||||
disable_interrupts();
|
||||
machine_check_disable();
|
||||
eieio();
|
||||
|
||||
/*
|
||||
* Jump to ECC simulation function in internal SRAM/OCM
|
||||
*/
|
||||
(*sram_func)(ptr, error);
|
||||
|
||||
/* 10. Read the corresponding address */
|
||||
val = in_be32(ptr);
|
||||
|
||||
/*
|
||||
* Read and print ECC status register/info:
|
||||
* The faulting address is only known upon uncorrectable ECC
|
||||
* errors.
|
||||
*/
|
||||
mfsdram(SDRAM_ECCES, val);
|
||||
if (val & SDRAM_ECCES_CE)
|
||||
printf("ECC: Correctable error\n");
|
||||
if (val & SDRAM_ECCES_UE) {
|
||||
printf("ECC: Uncorrectable error at 0x%02x%08x\n",
|
||||
mfdcr(SDRAM_ERRADDULL), mfdcr(SDRAM_ERRADDLLL));
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear pending interrupts/exceptions
|
||||
*/
|
||||
mtsdram(SDRAM_ECCES, 0xffffffff);
|
||||
mtdcr(SDRAM_ERRSTATLL, 0xff000000);
|
||||
set_mcsr(get_mcsr());
|
||||
|
||||
/* Now enable interrupts and exceptions again */
|
||||
eieio();
|
||||
machine_check_enable();
|
||||
enable_interrupts();
|
||||
|
||||
/*
|
||||
* The ECC parity byte need to be re-written for the
|
||||
* corresponding address. Otherwise future accesses to it
|
||||
* will result in exceptions.
|
||||
*
|
||||
* Jump to ECC parity generation function
|
||||
*/
|
||||
memcpy((void *)CONFIG_FUNC_ISRAM_ADDR, rewrite_ecc_parity, 0x10000);
|
||||
(*sram_func)(ptr, 0);
|
||||
|
||||
/*
|
||||
* Restore value in corresponding address
|
||||
*/
|
||||
out_be32(ptr, old_val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
ecctest, 3, 0, do_ecctest,
|
||||
"Test ECC by single and double error bit injection",
|
||||
"address 1/2"
|
||||
);
|
||||
|
||||
#endif /* defined(CONFIG_DDR_ECC) || defined(CONFIG_SDRAM_ECC) */
|
||||
#endif /* defined(CONFIG_SDRAM_PPC4xx_IBM_DDR)... */
|
||||
14
u-boot/arch/powerpc/cpu/ppc4xx/config.mk
Normal file
14
u-boot/arch/powerpc/cpu/ppc4xx/config.mk
Normal file
@@ -0,0 +1,14 @@
|
||||
#
|
||||
# (C) Copyright 2000-2010
|
||||
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
PLATFORM_CPPFLAGS += -mstring -msoft-float
|
||||
|
||||
ifneq (,$(CONFIG_440))
|
||||
PLATFORM_CPPFLAGS += -Wa,-m440 -mcpu=440
|
||||
else
|
||||
PLATFORM_CPPFLAGS += -Wa,-m405 -mcpu=405
|
||||
endif
|
||||
702
u-boot/arch/powerpc/cpu/ppc4xx/cpu.c
Normal file
702
u-boot/arch/powerpc/cpu/ppc4xx/cpu.c
Normal file
@@ -0,0 +1,702 @@
|
||||
/*
|
||||
* (C) Copyright 2000-2007
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
/*
|
||||
* CPU specific code
|
||||
*
|
||||
* written or collected and sometimes rewritten by
|
||||
* Magnus Damm <damm@bitsmart.com>
|
||||
*
|
||||
* minor modifications by
|
||||
* Wolfgang Denk <wd@denx.de>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <watchdog.h>
|
||||
#include <command.h>
|
||||
#include <asm/cache.h>
|
||||
#include <asm/ppc4xx.h>
|
||||
#include <netdev.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
void board_reset(void);
|
||||
|
||||
/*
|
||||
* To provide an interface to detect CPU number for boards that support
|
||||
* more then one CPU, we implement the "weak" default functions here.
|
||||
*
|
||||
* Returns CPU number
|
||||
*/
|
||||
int __get_cpu_num(void)
|
||||
{
|
||||
return NA_OR_UNKNOWN_CPU;
|
||||
}
|
||||
int get_cpu_num(void) __attribute__((weak, alias("__get_cpu_num")));
|
||||
|
||||
#if defined(CONFIG_PCI)
|
||||
#if defined(CONFIG_405GP) || \
|
||||
defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
|
||||
defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
|
||||
|
||||
#define PCI_ASYNC
|
||||
|
||||
static int pci_async_enabled(void)
|
||||
{
|
||||
#if defined(CONFIG_405GP)
|
||||
return (mfdcr(CPC0_PSR) & PSR_PCI_ASYNC_EN);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
|
||||
defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
|
||||
defined(CONFIG_460EX) || defined(CONFIG_460GT)
|
||||
unsigned long val;
|
||||
|
||||
mfsdr(SDR0_SDSTP1, val);
|
||||
return (val & SDR0_SDSTP1_PAME_MASK);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#endif /* CONFIG_PCI */
|
||||
|
||||
#if defined(CONFIG_PCI) && \
|
||||
!defined(CONFIG_405) && !defined(CONFIG_405EX)
|
||||
int pci_arbiter_enabled(void)
|
||||
{
|
||||
#if defined(CONFIG_405GP)
|
||||
return (mfdcr(CPC0_PSR) & PSR_PCI_ARBIT_EN);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_405EP)
|
||||
return (mfdcr(CPC0_PCI) & CPC0_PCI_ARBIT_EN);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_440GP)
|
||||
return (mfdcr(CPC0_STRP1) & CPC0_STRP1_PAE_MASK);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_440GX) || defined(CONFIG_440SP) || defined(CONFIG_440SPE)
|
||||
unsigned long val;
|
||||
|
||||
mfsdr(SDR0_XCR0, val);
|
||||
return (val & SDR0_XCR0_PAE_MASK);
|
||||
#endif
|
||||
#if defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
|
||||
defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
|
||||
defined(CONFIG_460EX) || defined(CONFIG_460GT)
|
||||
unsigned long val;
|
||||
|
||||
mfsdr(SDR0_PCI0, val);
|
||||
return (val & SDR0_PCI0_PAE_MASK);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_405EP)
|
||||
#define I2C_BOOTROM
|
||||
|
||||
static int i2c_bootrom_enabled(void)
|
||||
{
|
||||
#if defined(CONFIG_405EP)
|
||||
return (mfdcr(CPC0_BOOT) & CPC0_BOOT_SEP);
|
||||
#else
|
||||
unsigned long val;
|
||||
|
||||
mfsdr(SDR0_SDCS0, val);
|
||||
return (val & SDR0_SDCS_SDD);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_440GX)
|
||||
#define SDR0_PINSTP_SHIFT 29
|
||||
static char *bootstrap_str[] = {
|
||||
"EBC (16 bits)",
|
||||
"EBC (8 bits)",
|
||||
"EBC (32 bits)",
|
||||
"EBC (8 bits)",
|
||||
"PCI",
|
||||
"I2C (Addr 0x54)",
|
||||
"Reserved",
|
||||
"I2C (Addr 0x50)",
|
||||
};
|
||||
static char bootstrap_char[] = { 'A', 'B', 'C', 'B', 'D', 'E', 'x', 'F' };
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_440SP) || defined(CONFIG_440SPE)
|
||||
#define SDR0_PINSTP_SHIFT 30
|
||||
static char *bootstrap_str[] = {
|
||||
"EBC (8 bits)",
|
||||
"PCI",
|
||||
"I2C (Addr 0x54)",
|
||||
"I2C (Addr 0x50)",
|
||||
};
|
||||
static char bootstrap_char[] = { 'A', 'B', 'C', 'D'};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_440EP) || defined(CONFIG_440GR)
|
||||
#define SDR0_PINSTP_SHIFT 29
|
||||
static char *bootstrap_str[] = {
|
||||
"EBC (8 bits)",
|
||||
"PCI",
|
||||
"NAND (8 bits)",
|
||||
"EBC (16 bits)",
|
||||
"EBC (16 bits)",
|
||||
"I2C (Addr 0x54)",
|
||||
"PCI",
|
||||
"I2C (Addr 0x52)",
|
||||
};
|
||||
static char bootstrap_char[] = { 'A', 'B', 'C', 'D', 'E', 'G', 'F', 'H' };
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
|
||||
#define SDR0_PINSTP_SHIFT 29
|
||||
static char *bootstrap_str[] = {
|
||||
"EBC (8 bits)",
|
||||
"EBC (16 bits)",
|
||||
"EBC (16 bits)",
|
||||
"NAND (8 bits)",
|
||||
"PCI",
|
||||
"I2C (Addr 0x54)",
|
||||
"PCI",
|
||||
"I2C (Addr 0x52)",
|
||||
};
|
||||
static char bootstrap_char[] = { 'A', 'B', 'C', 'D', 'E', 'G', 'F', 'H' };
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
|
||||
#define SDR0_PINSTP_SHIFT 29
|
||||
static char *bootstrap_str[] = {
|
||||
"EBC (8 bits)",
|
||||
"EBC (16 bits)",
|
||||
"PCI",
|
||||
"PCI",
|
||||
"EBC (16 bits)",
|
||||
"NAND (8 bits)",
|
||||
"I2C (Addr 0x54)", /* A8 */
|
||||
"I2C (Addr 0x52)", /* A4 */
|
||||
};
|
||||
static char bootstrap_char[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H' };
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_460SX)
|
||||
#define SDR0_PINSTP_SHIFT 29
|
||||
static char *bootstrap_str[] = {
|
||||
"EBC (8 bits)",
|
||||
"EBC (16 bits)",
|
||||
"EBC (32 bits)",
|
||||
"NAND (8 bits)",
|
||||
"I2C (Addr 0x54)", /* A8 */
|
||||
"I2C (Addr 0x52)", /* A4 */
|
||||
};
|
||||
static char bootstrap_char[] = { 'A', 'B', 'C', 'D', 'E', 'G' };
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_405EZ)
|
||||
#define SDR0_PINSTP_SHIFT 28
|
||||
static char *bootstrap_str[] = {
|
||||
"EBC (8 bits)",
|
||||
"SPI (fast)",
|
||||
"NAND (512 page, 4 addr cycle)",
|
||||
"I2C (Addr 0x50)",
|
||||
"EBC (32 bits)",
|
||||
"I2C (Addr 0x50)",
|
||||
"NAND (2K page, 5 addr cycle)",
|
||||
"I2C (Addr 0x50)",
|
||||
"EBC (16 bits)",
|
||||
"Reserved",
|
||||
"NAND (2K page, 4 addr cycle)",
|
||||
"I2C (Addr 0x50)",
|
||||
"NAND (512 page, 3 addr cycle)",
|
||||
"I2C (Addr 0x50)",
|
||||
"SPI (slow)",
|
||||
"I2C (Addr 0x50)",
|
||||
};
|
||||
static char bootstrap_char[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', \
|
||||
'I', 'x', 'K', 'L', 'M', 'N', 'O', 'P' };
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_405EX)
|
||||
#define SDR0_PINSTP_SHIFT 29
|
||||
static char *bootstrap_str[] = {
|
||||
"EBC (8 bits)",
|
||||
"EBC (16 bits)",
|
||||
"EBC (16 bits)",
|
||||
"NAND (8 bits)",
|
||||
"NAND (8 bits)",
|
||||
"I2C (Addr 0x54)",
|
||||
"EBC (8 bits)",
|
||||
"I2C (Addr 0x52)",
|
||||
};
|
||||
static char bootstrap_char[] = { 'A', 'B', 'C', 'D', 'E', 'G', 'F', 'H' };
|
||||
#endif
|
||||
|
||||
#if defined(SDR0_PINSTP_SHIFT)
|
||||
static int bootstrap_option(void)
|
||||
{
|
||||
unsigned long val;
|
||||
|
||||
mfsdr(SDR0_PINSTP, val);
|
||||
return ((val & 0xf0000000) >> SDR0_PINSTP_SHIFT);
|
||||
}
|
||||
#endif /* SDR0_PINSTP_SHIFT */
|
||||
|
||||
|
||||
#if defined(CONFIG_440GP)
|
||||
static int do_chip_reset (unsigned long sys0, unsigned long sys1)
|
||||
{
|
||||
/* Changes to CPC0_SYS0 and CPC0_SYS1 require chip
|
||||
* reset.
|
||||
*/
|
||||
mtdcr (CPC0_CR0, mfdcr (CPC0_CR0) | 0x80000000); /* Set SWE */
|
||||
mtdcr (CPC0_SYS0, sys0);
|
||||
mtdcr (CPC0_SYS1, sys1);
|
||||
mtdcr (CPC0_CR0, mfdcr (CPC0_CR0) & ~0x80000000); /* Clr SWE */
|
||||
mtspr (SPRN_DBCR0, 0x20000000); /* Reset the chip */
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif /* CONFIG_440GP */
|
||||
|
||||
|
||||
int checkcpu (void)
|
||||
{
|
||||
#if !defined(CONFIG_405) /* not used on Xilinx 405 FPGA implementations */
|
||||
uint pvr = get_pvr();
|
||||
ulong clock = gd->cpu_clk;
|
||||
char buf[32];
|
||||
#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
|
||||
u32 reg;
|
||||
#endif
|
||||
|
||||
char addstr[64] = "";
|
||||
sys_info_t sys_info;
|
||||
int cpu_num;
|
||||
|
||||
cpu_num = get_cpu_num();
|
||||
if (cpu_num >= 0)
|
||||
printf("CPU%d: ", cpu_num);
|
||||
else
|
||||
puts("CPU: ");
|
||||
|
||||
get_sys_info(&sys_info);
|
||||
|
||||
#if defined(CONFIG_XILINX_440)
|
||||
puts("IBM PowerPC ");
|
||||
#else
|
||||
puts("AMCC PowerPC ");
|
||||
#endif
|
||||
|
||||
switch (pvr) {
|
||||
|
||||
#if !defined(CONFIG_440)
|
||||
case PVR_405GP_RB:
|
||||
puts("405GP Rev. B");
|
||||
break;
|
||||
|
||||
case PVR_405GP_RC:
|
||||
puts("405GP Rev. C");
|
||||
break;
|
||||
|
||||
case PVR_405GP_RD:
|
||||
puts("405GP Rev. D");
|
||||
break;
|
||||
|
||||
case PVR_405GP_RE:
|
||||
puts("405GP Rev. E");
|
||||
break;
|
||||
|
||||
case PVR_405GPR_RB:
|
||||
puts("405GPr Rev. B");
|
||||
break;
|
||||
|
||||
case PVR_405EP_RB:
|
||||
puts("405EP Rev. B");
|
||||
break;
|
||||
|
||||
case PVR_405EZ_RA:
|
||||
puts("405EZ Rev. A");
|
||||
break;
|
||||
|
||||
case PVR_405EX1_RA:
|
||||
puts("405EX Rev. A");
|
||||
strcpy(addstr, "Security support");
|
||||
break;
|
||||
|
||||
case PVR_405EXR2_RA:
|
||||
puts("405EXr Rev. A");
|
||||
strcpy(addstr, "No Security support");
|
||||
break;
|
||||
|
||||
case PVR_405EX1_RC:
|
||||
puts("405EX Rev. C");
|
||||
strcpy(addstr, "Security support");
|
||||
break;
|
||||
|
||||
case PVR_405EX2_RC:
|
||||
puts("405EX Rev. C");
|
||||
strcpy(addstr, "No Security support");
|
||||
break;
|
||||
|
||||
case PVR_405EXR1_RC:
|
||||
puts("405EXr Rev. C");
|
||||
strcpy(addstr, "Security support");
|
||||
break;
|
||||
|
||||
case PVR_405EXR2_RC:
|
||||
puts("405EXr Rev. C");
|
||||
strcpy(addstr, "No Security support");
|
||||
break;
|
||||
|
||||
case PVR_405EX1_RD:
|
||||
puts("405EX Rev. D");
|
||||
strcpy(addstr, "Security support");
|
||||
break;
|
||||
|
||||
case PVR_405EX2_RD:
|
||||
puts("405EX Rev. D");
|
||||
strcpy(addstr, "No Security support");
|
||||
break;
|
||||
|
||||
case PVR_405EXR1_RD:
|
||||
puts("405EXr Rev. D");
|
||||
strcpy(addstr, "Security support");
|
||||
break;
|
||||
|
||||
case PVR_405EXR2_RD:
|
||||
puts("405EXr Rev. D");
|
||||
strcpy(addstr, "No Security support");
|
||||
break;
|
||||
|
||||
#else /* CONFIG_440 */
|
||||
|
||||
#if defined(CONFIG_440GP)
|
||||
case PVR_440GP_RB:
|
||||
puts("440GP Rev. B");
|
||||
/* See errata 1.12: CHIP_4 */
|
||||
if ((mfdcr(CPC0_SYS0) != mfdcr(CPC0_STRP0)) ||
|
||||
(mfdcr(CPC0_SYS1) != mfdcr(CPC0_STRP1)) ){
|
||||
puts ( "\n\t CPC0_SYSx DCRs corrupted. "
|
||||
"Resetting chip ...\n");
|
||||
udelay( 1000 * 1000 ); /* Give time for serial buf to clear */
|
||||
do_chip_reset ( mfdcr(CPC0_STRP0),
|
||||
mfdcr(CPC0_STRP1) );
|
||||
}
|
||||
break;
|
||||
|
||||
case PVR_440GP_RC:
|
||||
puts("440GP Rev. C");
|
||||
break;
|
||||
#endif /* CONFIG_440GP */
|
||||
|
||||
case PVR_440GX_RA:
|
||||
puts("440GX Rev. A");
|
||||
break;
|
||||
|
||||
case PVR_440GX_RB:
|
||||
puts("440GX Rev. B");
|
||||
break;
|
||||
|
||||
case PVR_440GX_RC:
|
||||
puts("440GX Rev. C");
|
||||
break;
|
||||
|
||||
case PVR_440GX_RF:
|
||||
puts("440GX Rev. F");
|
||||
break;
|
||||
|
||||
case PVR_440EP_RA:
|
||||
puts("440EP Rev. A");
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_440EP
|
||||
case PVR_440EP_RB: /* 440EP rev B and 440GR rev A have same PVR */
|
||||
puts("440EP Rev. B");
|
||||
break;
|
||||
|
||||
case PVR_440EP_RC: /* 440EP rev C and 440GR rev B have same PVR */
|
||||
puts("440EP Rev. C");
|
||||
break;
|
||||
#endif /* CONFIG_440EP */
|
||||
|
||||
#ifdef CONFIG_440GR
|
||||
case PVR_440GR_RA: /* 440EP rev B and 440GR rev A have same PVR */
|
||||
puts("440GR Rev. A");
|
||||
break;
|
||||
|
||||
case PVR_440GR_RB: /* 440EP rev C and 440GR rev B have same PVR */
|
||||
puts("440GR Rev. B");
|
||||
break;
|
||||
#endif /* CONFIG_440GR */
|
||||
|
||||
#ifdef CONFIG_440EPX
|
||||
case PVR_440EPX1_RA: /* 440EPx rev A and 440GRx rev A have same PVR */
|
||||
puts("440EPx Rev. A");
|
||||
strcpy(addstr, "Security/Kasumi support");
|
||||
break;
|
||||
|
||||
case PVR_440EPX2_RA: /* 440EPx rev A and 440GRx rev A have same PVR */
|
||||
puts("440EPx Rev. A");
|
||||
strcpy(addstr, "No Security/Kasumi support");
|
||||
break;
|
||||
#endif /* CONFIG_440EPX */
|
||||
|
||||
#ifdef CONFIG_440GRX
|
||||
case PVR_440GRX1_RA: /* 440EPx rev A and 440GRx rev A have same PVR */
|
||||
puts("440GRx Rev. A");
|
||||
strcpy(addstr, "Security/Kasumi support");
|
||||
break;
|
||||
|
||||
case PVR_440GRX2_RA: /* 440EPx rev A and 440GRx rev A have same PVR */
|
||||
puts("440GRx Rev. A");
|
||||
strcpy(addstr, "No Security/Kasumi support");
|
||||
break;
|
||||
#endif /* CONFIG_440GRX */
|
||||
|
||||
case PVR_440SP_6_RAB:
|
||||
puts("440SP Rev. A/B");
|
||||
strcpy(addstr, "RAID 6 support");
|
||||
break;
|
||||
|
||||
case PVR_440SP_RAB:
|
||||
puts("440SP Rev. A/B");
|
||||
strcpy(addstr, "No RAID 6 support");
|
||||
break;
|
||||
|
||||
case PVR_440SP_6_RC:
|
||||
puts("440SP Rev. C");
|
||||
strcpy(addstr, "RAID 6 support");
|
||||
break;
|
||||
|
||||
case PVR_440SP_RC:
|
||||
puts("440SP Rev. C");
|
||||
strcpy(addstr, "No RAID 6 support");
|
||||
break;
|
||||
|
||||
case PVR_440SPe_6_RA:
|
||||
puts("440SPe Rev. A");
|
||||
strcpy(addstr, "RAID 6 support");
|
||||
break;
|
||||
|
||||
case PVR_440SPe_RA:
|
||||
puts("440SPe Rev. A");
|
||||
strcpy(addstr, "No RAID 6 support");
|
||||
break;
|
||||
|
||||
case PVR_440SPe_6_RB:
|
||||
puts("440SPe Rev. B");
|
||||
strcpy(addstr, "RAID 6 support");
|
||||
break;
|
||||
|
||||
case PVR_440SPe_RB:
|
||||
puts("440SPe Rev. B");
|
||||
strcpy(addstr, "No RAID 6 support");
|
||||
break;
|
||||
|
||||
#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
|
||||
case PVR_460EX_RA:
|
||||
puts("460EX Rev. A");
|
||||
strcpy(addstr, "No Security/Kasumi support");
|
||||
break;
|
||||
|
||||
case PVR_460EX_SE_RA:
|
||||
puts("460EX Rev. A");
|
||||
strcpy(addstr, "Security/Kasumi support");
|
||||
break;
|
||||
|
||||
case PVR_460EX_RB:
|
||||
puts("460EX Rev. B");
|
||||
mfsdr(SDR0_ECID3, reg);
|
||||
if (reg & 0x00100000)
|
||||
strcpy(addstr, "No Security/Kasumi support");
|
||||
else
|
||||
strcpy(addstr, "Security/Kasumi support");
|
||||
break;
|
||||
|
||||
case PVR_460GT_RA:
|
||||
puts("460GT Rev. A");
|
||||
strcpy(addstr, "No Security/Kasumi support");
|
||||
break;
|
||||
|
||||
case PVR_460GT_SE_RA:
|
||||
puts("460GT Rev. A");
|
||||
strcpy(addstr, "Security/Kasumi support");
|
||||
break;
|
||||
|
||||
case PVR_460GT_RB:
|
||||
puts("460GT Rev. B");
|
||||
mfsdr(SDR0_ECID3, reg);
|
||||
if (reg & 0x00100000)
|
||||
strcpy(addstr, "No Security/Kasumi support");
|
||||
else
|
||||
strcpy(addstr, "Security/Kasumi support");
|
||||
break;
|
||||
#endif
|
||||
|
||||
case PVR_460SX_RA:
|
||||
puts("460SX Rev. A");
|
||||
strcpy(addstr, "Security support");
|
||||
break;
|
||||
|
||||
case PVR_460SX_RA_V1:
|
||||
puts("460SX Rev. A");
|
||||
strcpy(addstr, "No Security support");
|
||||
break;
|
||||
|
||||
case PVR_460GX_RA:
|
||||
puts("460GX Rev. A");
|
||||
strcpy(addstr, "Security support");
|
||||
break;
|
||||
|
||||
case PVR_460GX_RA_V1:
|
||||
puts("460GX Rev. A");
|
||||
strcpy(addstr, "No Security support");
|
||||
break;
|
||||
|
||||
case PVR_APM821XX_RA:
|
||||
puts("APM821XX Rev. A");
|
||||
strcpy(addstr, "Security support");
|
||||
break;
|
||||
|
||||
case PVR_VIRTEX5:
|
||||
puts("440x5 VIRTEX5");
|
||||
break;
|
||||
#endif /* CONFIG_440 */
|
||||
|
||||
default:
|
||||
printf (" UNKNOWN (PVR=%08x)", pvr);
|
||||
break;
|
||||
}
|
||||
|
||||
printf (" at %s MHz (PLB=%lu OPB=%lu EBC=%lu",
|
||||
strmhz(buf, clock),
|
||||
sys_info.freqPLB / 1000000,
|
||||
get_OPB_freq() / 1000000,
|
||||
sys_info.freqEBC / 1000000);
|
||||
#if defined(CONFIG_PCI) && \
|
||||
(defined(CONFIG_440EP) || defined(CONFIG_440EPX) || \
|
||||
defined(CONFIG_440GR) || defined(CONFIG_440GRX))
|
||||
printf(" PCI=%lu MHz", sys_info.freqPCI / 1000000);
|
||||
#endif
|
||||
printf(")\n");
|
||||
|
||||
if (addstr[0] != 0)
|
||||
printf(" %s\n", addstr);
|
||||
|
||||
#if defined(I2C_BOOTROM)
|
||||
printf (" I2C boot EEPROM %sabled\n", i2c_bootrom_enabled() ? "en" : "dis");
|
||||
#endif /* I2C_BOOTROM */
|
||||
#if defined(SDR0_PINSTP_SHIFT)
|
||||
printf (" Bootstrap Option %c - ", bootstrap_char[bootstrap_option()]);
|
||||
printf ("Boot ROM Location %s", bootstrap_str[bootstrap_option()]);
|
||||
putc('\n');
|
||||
#endif /* SDR0_PINSTP_SHIFT */
|
||||
|
||||
#if defined(CONFIG_PCI) && !defined(CONFIG_405EX)
|
||||
printf (" Internal PCI arbiter %sabled", pci_arbiter_enabled() ? "en" : "dis");
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_PCI) && defined(PCI_ASYNC)
|
||||
if (pci_async_enabled()) {
|
||||
printf (", PCI async ext clock used");
|
||||
} else {
|
||||
printf (", PCI sync clock at %lu MHz",
|
||||
sys_info.freqPLB / sys_info.pllPciDiv / 1000000);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_PCI) && !defined(CONFIG_405EX)
|
||||
putc('\n');
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_405EP) || defined(CONFIG_405EZ) || defined(CONFIG_405EX)
|
||||
printf(" 16 KiB I-Cache 16 KiB D-Cache");
|
||||
#elif defined(CONFIG_440)
|
||||
printf(" 32 KiB I-Cache 32 KiB D-Cache");
|
||||
#else
|
||||
printf(" 16 KiB I-Cache %d KiB D-Cache",
|
||||
((pvr | 0x00000001) == PVR_405GPR_RB) ? 16 : 8);
|
||||
#endif
|
||||
|
||||
#endif /* !defined(CONFIG_405) */
|
||||
|
||||
putc ('\n');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ppc440spe_revB() {
|
||||
unsigned int pvr;
|
||||
|
||||
pvr = get_pvr();
|
||||
if ((pvr == PVR_440SPe_6_RB) || (pvr == PVR_440SPe_RB))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
#if defined(CONFIG_BOARD_RESET)
|
||||
board_reset();
|
||||
#else
|
||||
#if defined(CONFIG_SYS_4xx_RESET_TYPE)
|
||||
mtspr(SPRN_DBCR0, CONFIG_SYS_4xx_RESET_TYPE << 28);
|
||||
#else
|
||||
/*
|
||||
* Initiate system reset in debug control register DBCR
|
||||
*/
|
||||
mtspr(SPRN_DBCR0, 0x30000000);
|
||||
#endif /* defined(CONFIG_SYS_4xx_RESET_TYPE) */
|
||||
#endif /* defined(CONFIG_BOARD_RESET) */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get timebase clock frequency
|
||||
*/
|
||||
unsigned long get_tbclk (void)
|
||||
{
|
||||
sys_info_t sys_info;
|
||||
|
||||
get_sys_info(&sys_info);
|
||||
return (sys_info.freqProcessor);
|
||||
}
|
||||
|
||||
|
||||
#if defined(CONFIG_WATCHDOG)
|
||||
void watchdog_reset(void)
|
||||
{
|
||||
int re_enable = disable_interrupts();
|
||||
reset_4xx_watchdog();
|
||||
if (re_enable) enable_interrupts();
|
||||
}
|
||||
|
||||
void reset_4xx_watchdog(void)
|
||||
{
|
||||
/*
|
||||
* Clear TSR(WIS) bit
|
||||
*/
|
||||
mtspr(SPRN_TSR, 0x40000000);
|
||||
}
|
||||
#endif /* CONFIG_WATCHDOG */
|
||||
|
||||
/*
|
||||
* Initializes on-chip ethernet controllers.
|
||||
* to override, implement board_eth_init()
|
||||
*/
|
||||
int cpu_eth_init(bd_t *bis)
|
||||
{
|
||||
#if defined(CONFIG_PPC4xx_EMAC)
|
||||
ppc_4xx_eth_initialize(bis);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
541
u-boot/arch/powerpc/cpu/ppc4xx/cpu_init.c
Normal file
541
u-boot/arch/powerpc/cpu/ppc4xx/cpu_init.c
Normal file
@@ -0,0 +1,541 @@
|
||||
/*
|
||||
* (C) Copyright 2000-2007
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <watchdog.h>
|
||||
#include <asm/ppc4xx-emac.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/ppc4xx-gpio.h>
|
||||
#include <asm/ppc4xx.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#ifndef CONFIG_SYS_PLL_RECONFIG
|
||||
#define CONFIG_SYS_PLL_RECONFIG 0
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_440EPX) || \
|
||||
defined(CONFIG_460EX) || defined(CONFIG_460GT)
|
||||
static void reset_with_rli(void)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
/*
|
||||
* Set reload inhibit so configuration will persist across
|
||||
* processor resets
|
||||
*/
|
||||
mfcpr(CPR0_ICFG, reg);
|
||||
reg |= CPR0_ICFG_RLI_MASK;
|
||||
mtcpr(CPR0_ICFG, reg);
|
||||
|
||||
/* Reset processor if configuration changed */
|
||||
__asm__ __volatile__ ("sync; isync");
|
||||
mtspr(SPRN_DBCR0, 0x20000000);
|
||||
}
|
||||
#endif
|
||||
|
||||
void reconfigure_pll(u32 new_cpu_freq)
|
||||
{
|
||||
#if defined(CONFIG_440EPX)
|
||||
int reset_needed = 0;
|
||||
u32 reg, temp;
|
||||
u32 prbdv0, target_prbdv0, /* CLK_PRIMBD */
|
||||
fwdva, target_fwdva, fwdvb, target_fwdvb, /* CLK_PLLD */
|
||||
fbdv, target_fbdv, lfbdv, target_lfbdv,
|
||||
perdv0, target_perdv0, /* CLK_PERD */
|
||||
spcid0, target_spcid0; /* CLK_SPCID */
|
||||
|
||||
/* Reconfigure clocks if necessary.
|
||||
* See PPC440EPx User's Manual, sections 8.2 and 14 */
|
||||
if (new_cpu_freq == 667) {
|
||||
target_prbdv0 = 2;
|
||||
target_fwdva = 2;
|
||||
target_fwdvb = 4;
|
||||
target_fbdv = 20;
|
||||
target_lfbdv = 1;
|
||||
target_perdv0 = 4;
|
||||
target_spcid0 = 4;
|
||||
|
||||
mfcpr(CPR0_PRIMBD0, reg);
|
||||
temp = (reg & PRBDV_MASK) >> 24;
|
||||
prbdv0 = temp ? temp : 8;
|
||||
if (prbdv0 != target_prbdv0) {
|
||||
reg &= ~PRBDV_MASK;
|
||||
reg |= ((target_prbdv0 == 8 ? 0 : target_prbdv0) << 24);
|
||||
mtcpr(CPR0_PRIMBD0, reg);
|
||||
reset_needed = 1;
|
||||
}
|
||||
|
||||
mfcpr(CPR0_PLLD, reg);
|
||||
|
||||
temp = (reg & PLLD_FWDVA_MASK) >> 16;
|
||||
fwdva = temp ? temp : 16;
|
||||
|
||||
temp = (reg & PLLD_FWDVB_MASK) >> 8;
|
||||
fwdvb = temp ? temp : 8;
|
||||
|
||||
temp = (reg & PLLD_FBDV_MASK) >> 24;
|
||||
fbdv = temp ? temp : 32;
|
||||
|
||||
temp = (reg & PLLD_LFBDV_MASK);
|
||||
lfbdv = temp ? temp : 64;
|
||||
|
||||
if (fwdva != target_fwdva || fbdv != target_fbdv || lfbdv != target_lfbdv) {
|
||||
reg &= ~(PLLD_FWDVA_MASK | PLLD_FWDVB_MASK |
|
||||
PLLD_FBDV_MASK | PLLD_LFBDV_MASK);
|
||||
reg |= ((target_fwdva == 16 ? 0 : target_fwdva) << 16) |
|
||||
((target_fwdvb == 8 ? 0 : target_fwdvb) << 8) |
|
||||
((target_fbdv == 32 ? 0 : target_fbdv) << 24) |
|
||||
(target_lfbdv == 64 ? 0 : target_lfbdv);
|
||||
mtcpr(CPR0_PLLD, reg);
|
||||
reset_needed = 1;
|
||||
}
|
||||
|
||||
mfcpr(CPR0_PERD, reg);
|
||||
perdv0 = (reg & CPR0_PERD_PERDV0_MASK) >> 24;
|
||||
if (perdv0 != target_perdv0) {
|
||||
reg &= ~CPR0_PERD_PERDV0_MASK;
|
||||
reg |= (target_perdv0 << 24);
|
||||
mtcpr(CPR0_PERD, reg);
|
||||
reset_needed = 1;
|
||||
}
|
||||
|
||||
mfcpr(CPR0_SPCID, reg);
|
||||
temp = (reg & CPR0_SPCID_SPCIDV0_MASK) >> 24;
|
||||
spcid0 = temp ? temp : 4;
|
||||
if (spcid0 != target_spcid0) {
|
||||
reg &= ~CPR0_SPCID_SPCIDV0_MASK;
|
||||
reg |= ((target_spcid0 == 4 ? 0 : target_spcid0) << 24);
|
||||
mtcpr(CPR0_SPCID, reg);
|
||||
reset_needed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get current value of FWDVA.*/
|
||||
mfcpr(CPR0_PLLD, reg);
|
||||
temp = (reg & PLLD_FWDVA_MASK) >> 16;
|
||||
|
||||
/*
|
||||
* Check to see if FWDVA has been set to value of 1. if it has we must
|
||||
* modify it.
|
||||
*/
|
||||
if (temp == 1) {
|
||||
/*
|
||||
* Load register that contains current boot strapping option.
|
||||
*/
|
||||
mfcpr(CPR0_ICFG, reg);
|
||||
/*
|
||||
* Strapping option bits (ICS) are already in correct position,
|
||||
* only masking needed.
|
||||
*/
|
||||
reg &= CPR0_ICFG_ICS_MASK;
|
||||
|
||||
if ((reg == BOOT_STRAP_OPTION_A) || (reg == BOOT_STRAP_OPTION_B) ||
|
||||
(reg == BOOT_STRAP_OPTION_D) || (reg == BOOT_STRAP_OPTION_E)) {
|
||||
mfcpr(CPR0_PLLD, reg);
|
||||
|
||||
/* Get current value of fbdv. */
|
||||
temp = (reg & PLLD_FBDV_MASK) >> 24;
|
||||
fbdv = temp ? temp : 32;
|
||||
|
||||
/* Get current value of lfbdv. */
|
||||
temp = (reg & PLLD_LFBDV_MASK);
|
||||
lfbdv = temp ? temp : 64;
|
||||
|
||||
/*
|
||||
* Get current value of FWDVA. Assign current FWDVA to
|
||||
* new FWDVB.
|
||||
*/
|
||||
mfcpr(CPR0_PLLD, reg);
|
||||
target_fwdvb = (reg & PLLD_FWDVA_MASK) >> 16;
|
||||
fwdvb = target_fwdvb ? target_fwdvb : 8;
|
||||
|
||||
/*
|
||||
* Get current value of FWDVB. Assign current FWDVB to
|
||||
* new FWDVA.
|
||||
*/
|
||||
target_fwdva = (reg & PLLD_FWDVB_MASK) >> 8;
|
||||
fwdva = target_fwdva ? target_fwdva : 16;
|
||||
|
||||
/*
|
||||
* Update CPR0_PLLD with switched FWDVA and FWDVB.
|
||||
*/
|
||||
reg &= ~(PLLD_FWDVA_MASK | PLLD_FWDVB_MASK |
|
||||
PLLD_FBDV_MASK | PLLD_LFBDV_MASK);
|
||||
reg |= ((fwdva == 16 ? 0 : fwdva) << 16) |
|
||||
((fwdvb == 8 ? 0 : fwdvb) << 8) |
|
||||
((fbdv == 32 ? 0 : fbdv) << 24) |
|
||||
(lfbdv == 64 ? 0 : lfbdv);
|
||||
mtcpr(CPR0_PLLD, reg);
|
||||
|
||||
/* Acknowledge that a reset is required. */
|
||||
reset_needed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now reset the CPU if needed */
|
||||
if (reset_needed)
|
||||
reset_with_rli();
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
|
||||
u32 reg;
|
||||
|
||||
/*
|
||||
* See "9.2.1.1 Booting with Option E" in the 460EX/GT
|
||||
* users manual
|
||||
*/
|
||||
mfcpr(CPR0_PLLC, reg);
|
||||
if ((reg & (CPR0_PLLC_RST | CPR0_PLLC_ENG)) == CPR0_PLLC_RST) {
|
||||
/*
|
||||
* Set engage bit
|
||||
*/
|
||||
reg = (reg & ~CPR0_PLLC_RST) | CPR0_PLLC_ENG;
|
||||
mtcpr(CPR0_PLLC, reg);
|
||||
|
||||
/* Now reset the CPU */
|
||||
reset_with_rli();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYS_4xx_CHIP_21_ERRATA
|
||||
void
|
||||
chip_21_errata(void)
|
||||
{
|
||||
/*
|
||||
* See rev 1.09 of the 405EX/405EXr errata. CHIP_21 says that
|
||||
* sometimes reading the PVR and/or SDR0_ECID results in incorrect
|
||||
* values. Since the rev-D chip uses the SDR0_ECID bits to control
|
||||
* internal features, that means the second PCIe or ethernet of an EX
|
||||
* variant could fail to work. Also, security features of both EX and
|
||||
* EXr might be incorrectly disabled.
|
||||
*
|
||||
* The suggested workaround is as follows (covering rev-C and rev-D):
|
||||
*
|
||||
* 1.Read the PVR and SDR0_ECID3.
|
||||
*
|
||||
* 2.If the PVR matches an expected Revision C PVR value AND if
|
||||
* SDR0_ECID3[12:15] is different from PVR[28:31], then processor is
|
||||
* Revision C: continue executing the initialization code (no reset
|
||||
* required). else go to step 3.
|
||||
*
|
||||
* 3.If the PVR matches an expected Revision D PVR value AND if
|
||||
* SDR0_ECID3[10:11] matches its expected value, then continue
|
||||
* executing initialization code, no reset required. else write
|
||||
* DBCR0[RST] = 0b11 to generate a SysReset.
|
||||
*/
|
||||
|
||||
u32 pvr;
|
||||
u32 pvr_28_31;
|
||||
u32 ecid3;
|
||||
u32 ecid3_10_11;
|
||||
u32 ecid3_12_15;
|
||||
|
||||
/* Step 1: */
|
||||
pvr = get_pvr();
|
||||
mfsdr(SDR0_ECID3, ecid3);
|
||||
|
||||
/* Step 2: */
|
||||
pvr_28_31 = pvr & 0xf;
|
||||
ecid3_10_11 = (ecid3 >> 20) & 0x3;
|
||||
ecid3_12_15 = (ecid3 >> 16) & 0xf;
|
||||
if ((pvr == CONFIG_405EX_CHIP21_PVR_REV_C) &&
|
||||
(pvr_28_31 != ecid3_12_15)) {
|
||||
/* No reset required. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Step 3: */
|
||||
if ((pvr == CONFIG_405EX_CHIP21_PVR_REV_D) &&
|
||||
(ecid3_10_11 == CONFIG_405EX_CHIP21_ECID3_REV_D)) {
|
||||
/* No reset required. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Reset required. */
|
||||
__asm__ __volatile__ ("sync; isync");
|
||||
mtspr(SPRN_DBCR0, 0x30000000);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Breath some life into the CPU...
|
||||
*
|
||||
* Reconfigure PLL if necessary,
|
||||
* set up the memory map,
|
||||
* initialize a bunch of registers
|
||||
*/
|
||||
void
|
||||
cpu_init_f (void)
|
||||
{
|
||||
#if defined(CONFIG_WATCHDOG) || defined(CONFIG_440GX) || defined(CONFIG_460EX)
|
||||
u32 val;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_4xx_CHIP_21_ERRATA
|
||||
chip_21_errata();
|
||||
#endif
|
||||
|
||||
reconfigure_pll(CONFIG_SYS_PLL_RECONFIG);
|
||||
|
||||
#if (defined(CONFIG_405EP) || defined (CONFIG_405EX)) && \
|
||||
!defined(CONFIG_SYS_4xx_GPIO_TABLE)
|
||||
/*
|
||||
* GPIO0 setup (select GPIO or alternate function)
|
||||
*/
|
||||
#if defined(CONFIG_SYS_GPIO0_OR)
|
||||
out32(GPIO0_OR, CONFIG_SYS_GPIO0_OR); /* set initial state of output pins */
|
||||
#endif
|
||||
#if defined(CONFIG_SYS_GPIO0_ODR)
|
||||
out32(GPIO0_ODR, CONFIG_SYS_GPIO0_ODR); /* open-drain select */
|
||||
#endif
|
||||
out32(GPIO0_OSRH, CONFIG_SYS_GPIO0_OSRH); /* output select */
|
||||
out32(GPIO0_OSRL, CONFIG_SYS_GPIO0_OSRL);
|
||||
out32(GPIO0_ISR1H, CONFIG_SYS_GPIO0_ISR1H); /* input select */
|
||||
out32(GPIO0_ISR1L, CONFIG_SYS_GPIO0_ISR1L);
|
||||
out32(GPIO0_TSRH, CONFIG_SYS_GPIO0_TSRH); /* three-state select */
|
||||
out32(GPIO0_TSRL, CONFIG_SYS_GPIO0_TSRL);
|
||||
#if defined(CONFIG_SYS_GPIO0_ISR2H)
|
||||
out32(GPIO0_ISR2H, CONFIG_SYS_GPIO0_ISR2H);
|
||||
out32(GPIO0_ISR2L, CONFIG_SYS_GPIO0_ISR2L);
|
||||
#endif
|
||||
#if defined (CONFIG_SYS_GPIO0_TCR)
|
||||
out32(GPIO0_TCR, CONFIG_SYS_GPIO0_TCR); /* enable output driver for outputs */
|
||||
#endif
|
||||
#endif /* CONFIG_405EP ... && !CONFIG_SYS_4xx_GPIO_TABLE */
|
||||
|
||||
#if defined (CONFIG_405EP)
|
||||
/*
|
||||
* Set EMAC noise filter bits
|
||||
*/
|
||||
mtdcr(CPC0_EPCTL, CPC0_EPCTL_E0NFE | CPC0_EPCTL_E1NFE);
|
||||
#endif /* CONFIG_405EP */
|
||||
|
||||
#if defined(CONFIG_SYS_4xx_GPIO_TABLE)
|
||||
gpio_set_chip_configuration();
|
||||
#endif /* CONFIG_SYS_4xx_GPIO_TABLE */
|
||||
|
||||
/*
|
||||
* External Bus Controller (EBC) Setup
|
||||
*/
|
||||
#if (defined(CONFIG_SYS_EBC_PB0AP) && defined(CONFIG_SYS_EBC_PB0CR))
|
||||
#if (defined(CONFIG_405GP) || \
|
||||
defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
|
||||
defined(CONFIG_405EX) || defined(CONFIG_405))
|
||||
/*
|
||||
* Move the next instructions into icache, since these modify the flash
|
||||
* we are running from!
|
||||
*/
|
||||
asm volatile(" bl 0f" ::: "lr");
|
||||
asm volatile("0: mflr 3" ::: "r3");
|
||||
asm volatile(" addi 4, 0, 14" ::: "r4");
|
||||
asm volatile(" mtctr 4" ::: "ctr");
|
||||
asm volatile("1: icbt 0, 3");
|
||||
asm volatile(" addi 3, 3, 32" ::: "r3");
|
||||
asm volatile(" bdnz 1b" ::: "ctr", "cr0");
|
||||
asm volatile(" addis 3, 0, 0x0" ::: "r3");
|
||||
asm volatile(" ori 3, 3, 0xA000" ::: "r3");
|
||||
asm volatile(" mtctr 3" ::: "ctr");
|
||||
asm volatile("2: bdnz 2b" ::: "ctr", "cr0");
|
||||
#endif
|
||||
|
||||
mtebc(PB0AP, CONFIG_SYS_EBC_PB0AP);
|
||||
mtebc(PB0CR, CONFIG_SYS_EBC_PB0CR);
|
||||
#endif
|
||||
|
||||
#if (defined(CONFIG_SYS_EBC_PB1AP) && defined(CONFIG_SYS_EBC_PB1CR) && !(CONFIG_SYS_INIT_DCACHE_CS == 1))
|
||||
mtebc(PB1AP, CONFIG_SYS_EBC_PB1AP);
|
||||
mtebc(PB1CR, CONFIG_SYS_EBC_PB1CR);
|
||||
#endif
|
||||
|
||||
#if (defined(CONFIG_SYS_EBC_PB2AP) && defined(CONFIG_SYS_EBC_PB2CR) && !(CONFIG_SYS_INIT_DCACHE_CS == 2))
|
||||
mtebc(PB2AP, CONFIG_SYS_EBC_PB2AP);
|
||||
mtebc(PB2CR, CONFIG_SYS_EBC_PB2CR);
|
||||
#endif
|
||||
|
||||
#if (defined(CONFIG_SYS_EBC_PB3AP) && defined(CONFIG_SYS_EBC_PB3CR) && !(CONFIG_SYS_INIT_DCACHE_CS == 3))
|
||||
mtebc(PB3AP, CONFIG_SYS_EBC_PB3AP);
|
||||
mtebc(PB3CR, CONFIG_SYS_EBC_PB3CR);
|
||||
#endif
|
||||
|
||||
#if (defined(CONFIG_SYS_EBC_PB4AP) && defined(CONFIG_SYS_EBC_PB4CR) && !(CONFIG_SYS_INIT_DCACHE_CS == 4))
|
||||
mtebc(PB4AP, CONFIG_SYS_EBC_PB4AP);
|
||||
mtebc(PB4CR, CONFIG_SYS_EBC_PB4CR);
|
||||
#endif
|
||||
|
||||
#if (defined(CONFIG_SYS_EBC_PB5AP) && defined(CONFIG_SYS_EBC_PB5CR) && !(CONFIG_SYS_INIT_DCACHE_CS == 5))
|
||||
mtebc(PB5AP, CONFIG_SYS_EBC_PB5AP);
|
||||
mtebc(PB5CR, CONFIG_SYS_EBC_PB5CR);
|
||||
#endif
|
||||
|
||||
#if (defined(CONFIG_SYS_EBC_PB6AP) && defined(CONFIG_SYS_EBC_PB6CR) && !(CONFIG_SYS_INIT_DCACHE_CS == 6))
|
||||
mtebc(PB6AP, CONFIG_SYS_EBC_PB6AP);
|
||||
mtebc(PB6CR, CONFIG_SYS_EBC_PB6CR);
|
||||
#endif
|
||||
|
||||
#if (defined(CONFIG_SYS_EBC_PB7AP) && defined(CONFIG_SYS_EBC_PB7CR) && !(CONFIG_SYS_INIT_DCACHE_CS == 7))
|
||||
mtebc(PB7AP, CONFIG_SYS_EBC_PB7AP);
|
||||
mtebc(PB7CR, CONFIG_SYS_EBC_PB7CR);
|
||||
#endif
|
||||
|
||||
#if defined (CONFIG_SYS_EBC_CFG)
|
||||
mtebc(EBC0_CFG, CONFIG_SYS_EBC_CFG);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_WATCHDOG)
|
||||
val = mfspr(SPRN_TCR);
|
||||
#if defined(CONFIG_440EP) || defined(CONFIG_440GR)
|
||||
val |= 0xb8000000; /* generate system reset after 1.34 seconds */
|
||||
#elif defined(CONFIG_440EPX)
|
||||
val |= 0xb0000000; /* generate system reset after 1.34 seconds */
|
||||
#else
|
||||
val |= 0xf0000000; /* generate system reset after 2.684 seconds */
|
||||
#endif
|
||||
#if defined(CONFIG_SYS_4xx_RESET_TYPE)
|
||||
val &= ~0x30000000; /* clear WRC bits */
|
||||
val |= CONFIG_SYS_4xx_RESET_TYPE << 28; /* set board specific WRC type */
|
||||
#endif
|
||||
mtspr(SPRN_TCR, val);
|
||||
|
||||
val = mfspr(SPRN_TSR);
|
||||
val |= 0x80000000; /* enable watchdog timer */
|
||||
mtspr(SPRN_TSR, val);
|
||||
|
||||
reset_4xx_watchdog();
|
||||
#endif /* CONFIG_WATCHDOG */
|
||||
|
||||
#if defined(CONFIG_440GX)
|
||||
/* Take the GX out of compatibility mode
|
||||
* Travis Sawyer, 9 Mar 2004
|
||||
* NOTE: 440gx user manual inconsistency here
|
||||
* Compatibility mode and Ethernet Clock select are not
|
||||
* correct in the manual
|
||||
*/
|
||||
mfsdr(SDR0_MFR, val);
|
||||
val &= ~0x10000000;
|
||||
mtsdr(SDR0_MFR,val);
|
||||
#endif /* CONFIG_440GX */
|
||||
|
||||
#if defined(CONFIG_460EX)
|
||||
/*
|
||||
* Set SDR0_AHB_CFG[A2P_INCR4] (bit 24) and
|
||||
* clear SDR0_AHB_CFG[A2P_PROT2] (bit 25) for a new 460EX errata
|
||||
* regarding concurrent use of AHB USB OTG, USB 2.0 host and SATA
|
||||
*/
|
||||
mfsdr(SDR0_AHB_CFG, val);
|
||||
val |= 0x80;
|
||||
val &= ~0x40;
|
||||
mtsdr(SDR0_AHB_CFG, val);
|
||||
mfsdr(SDR0_USB2HOST_CFG, val);
|
||||
val &= ~0xf00;
|
||||
val |= 0x400;
|
||||
mtsdr(SDR0_USB2HOST_CFG, val);
|
||||
#endif /* CONFIG_460EX */
|
||||
|
||||
#if defined(CONFIG_405EX) || \
|
||||
defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
|
||||
defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
|
||||
defined(CONFIG_460SX)
|
||||
/*
|
||||
* Set PLB4 arbiter (Segment 0 and 1) to 4 deep pipeline read
|
||||
*/
|
||||
mtdcr(PLB4A0_ACR, (mfdcr(PLB4A0_ACR) & ~PLB4Ax_ACR_RDP_MASK) |
|
||||
PLB4Ax_ACR_RDP_4DEEP);
|
||||
mtdcr(PLB4A1_ACR, (mfdcr(PLB4A1_ACR) & ~PLB4Ax_ACR_RDP_MASK) |
|
||||
PLB4Ax_ACR_RDP_4DEEP);
|
||||
#endif /* CONFIG_440SP/SPE || CONFIG_460EX/GT || CONFIG_405EX */
|
||||
}
|
||||
|
||||
/*
|
||||
* initialize higher level parts of CPU like time base and timers
|
||||
*/
|
||||
int cpu_init_r (void)
|
||||
{
|
||||
#if defined(CONFIG_405GP)
|
||||
uint pvr = get_pvr();
|
||||
|
||||
/*
|
||||
* Set edge conditioning circuitry on PPC405GPr
|
||||
* for compatibility to existing PPC405GP designs.
|
||||
*/
|
||||
if ((pvr & 0xfffffff0) == (PVR_405GPR_RB & 0xfffffff0)) {
|
||||
mtdcr(CPC0_ECR, 0x60606000);
|
||||
}
|
||||
#endif /* defined(CONFIG_405GP) */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_PCI) && \
|
||||
(defined(CONFIG_440EP) || defined(CONFIG_440EPX) || \
|
||||
defined(CONFIG_440GR) || defined(CONFIG_440GRX))
|
||||
/*
|
||||
* 440EP(x)/GR(x) PCI async/sync clocking restriction:
|
||||
*
|
||||
* In asynchronous PCI mode, the synchronous PCI clock must meet
|
||||
* certain requirements. The following equation describes the
|
||||
* relationship that must be maintained between the asynchronous PCI
|
||||
* clock and synchronous PCI clock. Select an appropriate PCI:PLB
|
||||
* ratio to maintain the relationship:
|
||||
*
|
||||
* AsyncPCIClk - 1MHz <= SyncPCIclock <= (2 * AsyncPCIClk) - 1MHz
|
||||
*/
|
||||
static int ppc4xx_pci_sync_clock_ok(u32 sync, u32 async)
|
||||
{
|
||||
if (((async - 1000000) > sync) || (sync > ((2 * async) - 1000000)))
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ppc4xx_pci_sync_clock_config(u32 async)
|
||||
{
|
||||
sys_info_t sys_info;
|
||||
u32 sync;
|
||||
int div;
|
||||
u32 reg;
|
||||
u32 spcid_val[] = {
|
||||
CPR0_SPCID_SPCIDV0_DIV1, CPR0_SPCID_SPCIDV0_DIV2,
|
||||
CPR0_SPCID_SPCIDV0_DIV3, CPR0_SPCID_SPCIDV0_DIV4 };
|
||||
|
||||
get_sys_info(&sys_info);
|
||||
sync = sys_info.freqPCI;
|
||||
|
||||
/*
|
||||
* First check if the equation above is met
|
||||
*/
|
||||
if (!ppc4xx_pci_sync_clock_ok(sync, async)) {
|
||||
/*
|
||||
* Reconfigure PCI sync clock to meet the equation.
|
||||
* Start with highest possible PCI sync frequency
|
||||
* (divider 1).
|
||||
*/
|
||||
for (div = 1; div <= 4; div++) {
|
||||
sync = sys_info.freqPLB / div;
|
||||
if (ppc4xx_pci_sync_clock_ok(sync, async))
|
||||
break;
|
||||
}
|
||||
|
||||
if (div <= 4) {
|
||||
mtcpr(CPR0_SPCID, spcid_val[div]);
|
||||
|
||||
mfcpr(CPR0_ICFG, reg);
|
||||
reg |= CPR0_ICFG_RLI_MASK;
|
||||
mtcpr(CPR0_ICFG, reg);
|
||||
|
||||
/* do chip reset */
|
||||
mtspr(SPRN_DBCR0, 0x20000000);
|
||||
} else {
|
||||
/* Impossible to configure the PCI sync clock */
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
180
u-boot/arch/powerpc/cpu/ppc4xx/dcr.S
Normal file
180
u-boot/arch/powerpc/cpu/ppc4xx/dcr.S
Normal file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* (C) Copyright 2001
|
||||
* Erik Theisen, Wave 7 Optics, etheisen@mindspring.com
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
#include <config.h>
|
||||
|
||||
#if defined(CONFIG_4xx) && defined(CONFIG_CMD_SETGETDCR)
|
||||
|
||||
#include <asm/ppc4xx.h>
|
||||
|
||||
#include <ppc_asm.tmpl>
|
||||
#include <ppc_defs.h>
|
||||
|
||||
#include <asm/cache.h>
|
||||
#include <asm/mmu.h>
|
||||
|
||||
#define _ASMLANGUAGE
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* XXX - DANGER
|
||||
* These routines make use of self modifying code. DO NOT CALL THEM
|
||||
* UNTIL THEY ARE RELOCATED TO RAM. Additionally, I do not
|
||||
* recommend them for use in anything other than an interactive
|
||||
* debugging environment. This is mainly due to performance reasons.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* static void _create_MFDCR(unsigned short dcrn)
|
||||
*
|
||||
* Builds a 'mfdcr' instruction for get_dcr
|
||||
* function.
|
||||
*/
|
||||
.section ".text"
|
||||
.align 2
|
||||
.type _create_MFDCR,@function
|
||||
_create_MFDCR:
|
||||
/*
|
||||
* Build up a 'mfdcr' instruction formatted as follows:
|
||||
*
|
||||
* OPCD | RT | DCRF | XO | CR |
|
||||
* ---------------|--------------|--------------|----|
|
||||
* 0 5 | 6 10 | 11 20 | 21 30 | 31 |
|
||||
* | | DCRN | | |
|
||||
* 31 | %r3 | (5..9|0..4) | 323 | 0 |
|
||||
*
|
||||
* Where:
|
||||
* OPCD = opcode - 31
|
||||
* RT = destination register - %r3 return register
|
||||
* DCRF = DCRN # with upper and lower halves swapped
|
||||
* XO = extended opcode - 323
|
||||
* CR = CR[CR0] NOT undefined - 0
|
||||
*/
|
||||
rlwinm r0, r3, 27, 27, 31 /* OPCD = 31 */
|
||||
rlwinm r3, r3, 5, 22, 26
|
||||
or r3, r3, r0
|
||||
slwi r3, r3, 10
|
||||
oris r3, r3, 0x3e30 /* RT = %r3 */
|
||||
ori r3, r3, 323 /* XO = 323 */
|
||||
slwi r3, r3, 1 /* CR = 0 */
|
||||
|
||||
mflr r4
|
||||
stw r3, 0(r4) /* Store instr in get_dcr() */
|
||||
dcbst r0, r4 /* Make sure val is written out */
|
||||
sync /* Wait for write to complete */
|
||||
icbi r0, r4 /* Make sure old instr is dumped */
|
||||
isync /* Wait for icbi to complete */
|
||||
|
||||
blr
|
||||
.Lfe1: .size _create_MFDCR,.Lfe1-_create_MFDCR
|
||||
/* end _create_MFDCR() */
|
||||
|
||||
/*
|
||||
* static void _create_MTDCR(unsigned short dcrn, unsigned long value)
|
||||
*
|
||||
* Builds a 'mtdcr' instruction for set_dcr
|
||||
* function.
|
||||
*/
|
||||
.section ".text"
|
||||
.align 2
|
||||
.type _create_MTDCR,@function
|
||||
_create_MTDCR:
|
||||
/*
|
||||
* Build up a 'mtdcr' instruction formatted as follows:
|
||||
*
|
||||
* OPCD | RS | DCRF | XO | CR |
|
||||
* ---------------|--------------|--------------|----|
|
||||
* 0 5 | 6 10 | 11 20 | 21 30 | 31 |
|
||||
* | | DCRN | | |
|
||||
* 31 | %r3 | (5..9|0..4) | 451 | 0 |
|
||||
*
|
||||
* Where:
|
||||
* OPCD = opcode - 31
|
||||
* RS = source register - %r4
|
||||
* DCRF = dest. DCRN # with upper and lower halves swapped
|
||||
* XO = extended opcode - 451
|
||||
* CR = CR[CR0] NOT undefined - 0
|
||||
*/
|
||||
rlwinm r0, r3, 27, 27, 31 /* OPCD = 31 */
|
||||
rlwinm r3, r3, 5, 22, 26
|
||||
or r3, r3, r0
|
||||
slwi r3, r3, 10
|
||||
oris r3, r3, 0x3e40 /* RS = %r4 */
|
||||
ori r3, r3, 451 /* XO = 451 */
|
||||
slwi r3, r3, 1 /* CR = 0 */
|
||||
|
||||
mflr r5
|
||||
stw r3, 0(r5) /* Store instr in set_dcr() */
|
||||
dcbst r0, r5 /* Make sure val is written out */
|
||||
sync /* Wait for write to complete */
|
||||
icbi r0, r5 /* Make sure old instr is dumped */
|
||||
isync /* Wait for icbi to complete */
|
||||
|
||||
blr
|
||||
.Lfe2: .size _create_MTDCR,.Lfe2-_create_MTDCR
|
||||
/* end _create_MTDCR() */
|
||||
|
||||
|
||||
/*
|
||||
* unsigned long get_dcr(unsigned short dcrn)
|
||||
*
|
||||
* Return a given DCR's value.
|
||||
*/
|
||||
/* */
|
||||
/* XXX - This is self modifying code, hence */
|
||||
/* it is in the data section. */
|
||||
/* */
|
||||
.section ".data"
|
||||
.align 2
|
||||
.globl get_dcr
|
||||
.type get_dcr,@function
|
||||
get_dcr:
|
||||
mflr r0 /* Get link register */
|
||||
stwu r1, -32(r1) /* Save back chain and move SP */
|
||||
stw r0, +36(r1) /* Save link register */
|
||||
|
||||
bl _create_MFDCR /* Build following instruction */
|
||||
/* XXX - we build this instuction up on the fly. */
|
||||
.long 0 /* Get DCR's value */
|
||||
|
||||
lwz r0, +36(r1) /* Get saved link register */
|
||||
mtlr r0 /* Restore link register */
|
||||
addi r1, r1, +32 /* Remove frame from stack */
|
||||
blr /* Return to calling function */
|
||||
.Lfe3: .size get_dcr,.Lfe3-get_dcr
|
||||
/* end get_dcr() */
|
||||
|
||||
|
||||
/*
|
||||
* unsigned void set_dcr(unsigned short dcrn, unsigned long value)
|
||||
*
|
||||
* Return a given DCR's value.
|
||||
*/
|
||||
/*
|
||||
* XXX - This is self modifying code, hence
|
||||
* it is in the data section.
|
||||
*/
|
||||
.section ".data"
|
||||
.align 2
|
||||
.globl set_dcr
|
||||
.type set_dcr,@function
|
||||
set_dcr:
|
||||
mflr r0 /* Get link register */
|
||||
stwu r1, -32(r1) /* Save back chain and move SP */
|
||||
stw r0, +36(r1) /* Save link register */
|
||||
|
||||
bl _create_MTDCR /* Build following instruction */
|
||||
/* XXX - we build this instuction up on the fly. */
|
||||
.long 0 /* Set DCR's value */
|
||||
|
||||
lwz r0, +36(r1) /* Get saved link register */
|
||||
mtlr r0 /* Restore link register */
|
||||
addi r1, r1, +32 /* Remove frame from stack */
|
||||
blr /* Return to calling function */
|
||||
.Lfe4: .size set_dcr,.Lfe4-set_dcr
|
||||
/* end set_dcr() */
|
||||
#endif
|
||||
376
u-boot/arch/powerpc/cpu/ppc4xx/denali_data_eye.c
Normal file
376
u-boot/arch/powerpc/cpu/ppc4xx/denali_data_eye.c
Normal file
@@ -0,0 +1,376 @@
|
||||
/*
|
||||
* arch/powerpc/cpu/ppc4xx/denali_data_eye.c
|
||||
* Extracted from board/amcc/sequoia/sdram.c by Larry Johnson <lrj@acm.org>.
|
||||
*
|
||||
* (C) Copyright 2006
|
||||
* Sylvie Gohl, AMCC/IBM, gohl.sylvie@fr.ibm.com
|
||||
* Jacqueline Pira-Ferriol, AMCC/IBM, jpira-ferriol@fr.ibm.com
|
||||
* Thierry Roman, AMCC/IBM, thierry_roman@fr.ibm.com
|
||||
* Alain Saurel, AMCC/IBM, alain.saurel@fr.ibm.com
|
||||
* Robert Snyder, AMCC/IBM, rob.snyder@fr.ibm.com
|
||||
*
|
||||
* (C) Copyright 2006-2007
|
||||
* Stefan Roese, DENX Software Engineering, sr@denx.de.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
/* define DEBUG for debugging output (obviously ;-)) */
|
||||
#if 0
|
||||
#define DEBUG
|
||||
#endif
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/ppc4xx.h>
|
||||
|
||||
#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
|
||||
/*-----------------------------------------------------------------------------+
|
||||
* denali_wait_for_dlllock.
|
||||
+----------------------------------------------------------------------------*/
|
||||
int denali_wait_for_dlllock(void)
|
||||
{
|
||||
u32 val;
|
||||
int wait;
|
||||
|
||||
/* -----------------------------------------------------------+
|
||||
* Wait for the DCC master delay line to finish calibration
|
||||
* ----------------------------------------------------------*/
|
||||
for (wait = 0; wait != 0xffff; ++wait) {
|
||||
mfsdram(DDR0_17, val);
|
||||
if (DDR0_17_DLLLOCKREG_DECODE(val)) {
|
||||
/* dlllockreg bit on */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
debug("0x%04x: DDR0_17 Value (dlllockreg bit): 0x%08x\n", wait, val);
|
||||
debug("Waiting for dlllockreg bit to raise\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_DDR_DATA_EYE)
|
||||
#define DDR_DCR_BASE 0x10
|
||||
#define ddrcfga (DDR_DCR_BASE+0x0) /* DDR configuration address reg */
|
||||
#define ddrcfgd (DDR_DCR_BASE+0x1) /* DDR configuration data reg */
|
||||
|
||||
/*-----------------------------------------------------------------------------+
|
||||
* wait_for_dram_init_complete.
|
||||
+----------------------------------------------------------------------------*/
|
||||
static int wait_for_dram_init_complete(void)
|
||||
{
|
||||
unsigned long val;
|
||||
int wait = 0;
|
||||
|
||||
/* --------------------------------------------------------------+
|
||||
* Wait for 'DRAM initialization complete' bit in status register
|
||||
* -------------------------------------------------------------*/
|
||||
mtdcr(ddrcfga, DDR0_00);
|
||||
|
||||
while (wait != 0xffff) {
|
||||
val = mfdcr(ddrcfgd);
|
||||
if ((val & DDR0_00_INT_STATUS_BIT6) == DDR0_00_INT_STATUS_BIT6)
|
||||
/* 'DRAM initialization complete' bit */
|
||||
return 0;
|
||||
else
|
||||
wait++;
|
||||
}
|
||||
debug("DRAM initialization complete bit in status register did not "
|
||||
"rise\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define NUM_TRIES 64
|
||||
#define NUM_READS 10
|
||||
|
||||
/*-----------------------------------------------------------------------------+
|
||||
* denali_core_search_data_eye.
|
||||
+----------------------------------------------------------------------------*/
|
||||
void denali_core_search_data_eye(void)
|
||||
{
|
||||
int k, j;
|
||||
u32 val;
|
||||
u32 wr_dqs_shift, dqs_out_shift, dll_dqs_delay_X;
|
||||
u32 max_passing_cases = 0, wr_dqs_shift_with_max_passing_cases = 0;
|
||||
u32 passing_cases = 0, dll_dqs_delay_X_sw_val = 0;
|
||||
u32 dll_dqs_delay_X_start_window = 0, dll_dqs_delay_X_end_window = 0;
|
||||
volatile u32 *ram_pointer;
|
||||
u32 test[NUM_TRIES] = {
|
||||
0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
|
||||
0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
|
||||
0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
|
||||
0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
|
||||
0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555,
|
||||
0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555,
|
||||
0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA,
|
||||
0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA,
|
||||
0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A,
|
||||
0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A,
|
||||
0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5,
|
||||
0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5,
|
||||
0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA,
|
||||
0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA,
|
||||
0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55,
|
||||
0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55
|
||||
};
|
||||
|
||||
ram_pointer = (volatile u32 *)(CONFIG_SYS_SDRAM_BASE);
|
||||
|
||||
for (wr_dqs_shift = 64; wr_dqs_shift < 96; wr_dqs_shift++) {
|
||||
/* for (wr_dqs_shift=1; wr_dqs_shift<96; wr_dqs_shift++) { */
|
||||
|
||||
/* -----------------------------------------------------------+
|
||||
* De-assert 'start' parameter.
|
||||
* ----------------------------------------------------------*/
|
||||
mtdcr(ddrcfga, DDR0_02);
|
||||
val = (mfdcr(ddrcfgd) & ~DDR0_02_START_MASK) |
|
||||
DDR0_02_START_OFF;
|
||||
mtdcr(ddrcfgd, val);
|
||||
|
||||
/* -----------------------------------------------------------+
|
||||
* Set 'wr_dqs_shift'
|
||||
* ----------------------------------------------------------*/
|
||||
mtdcr(ddrcfga, DDR0_09);
|
||||
val = (mfdcr(ddrcfgd) & ~DDR0_09_WR_DQS_SHIFT_MASK) |
|
||||
DDR0_09_WR_DQS_SHIFT_ENCODE(wr_dqs_shift);
|
||||
mtdcr(ddrcfgd, val);
|
||||
|
||||
/* -----------------------------------------------------------+
|
||||
* Set 'dqs_out_shift' = wr_dqs_shift + 32
|
||||
* ----------------------------------------------------------*/
|
||||
dqs_out_shift = wr_dqs_shift + 32;
|
||||
mtdcr(ddrcfga, DDR0_22);
|
||||
val = (mfdcr(ddrcfgd) & ~DDR0_22_DQS_OUT_SHIFT_MASK) |
|
||||
DDR0_22_DQS_OUT_SHIFT_ENCODE(dqs_out_shift);
|
||||
mtdcr(ddrcfgd, val);
|
||||
|
||||
passing_cases = 0;
|
||||
|
||||
for (dll_dqs_delay_X = 1; dll_dqs_delay_X < 64;
|
||||
dll_dqs_delay_X++) {
|
||||
/* for (dll_dqs_delay_X=1; dll_dqs_delay_X<128;
|
||||
dll_dqs_delay_X++) { */
|
||||
/* -----------------------------------------------------------+
|
||||
* Set 'dll_dqs_delay_X'.
|
||||
* ----------------------------------------------------------*/
|
||||
/* dll_dqs_delay_0 */
|
||||
mtdcr(ddrcfga, DDR0_17);
|
||||
val = (mfdcr(ddrcfgd) & ~DDR0_17_DLL_DQS_DELAY_0_MASK)
|
||||
| DDR0_17_DLL_DQS_DELAY_0_ENCODE(dll_dqs_delay_X);
|
||||
mtdcr(ddrcfgd, val);
|
||||
/* dll_dqs_delay_1 to dll_dqs_delay_4 */
|
||||
mtdcr(ddrcfga, DDR0_18);
|
||||
val = (mfdcr(ddrcfgd) & ~DDR0_18_DLL_DQS_DELAY_X_MASK)
|
||||
| DDR0_18_DLL_DQS_DELAY_4_ENCODE(dll_dqs_delay_X)
|
||||
| DDR0_18_DLL_DQS_DELAY_3_ENCODE(dll_dqs_delay_X)
|
||||
| DDR0_18_DLL_DQS_DELAY_2_ENCODE(dll_dqs_delay_X)
|
||||
| DDR0_18_DLL_DQS_DELAY_1_ENCODE(dll_dqs_delay_X);
|
||||
mtdcr(ddrcfgd, val);
|
||||
/* dll_dqs_delay_5 to dll_dqs_delay_8 */
|
||||
mtdcr(ddrcfga, DDR0_19);
|
||||
val = (mfdcr(ddrcfgd) & ~DDR0_19_DLL_DQS_DELAY_X_MASK)
|
||||
| DDR0_19_DLL_DQS_DELAY_8_ENCODE(dll_dqs_delay_X)
|
||||
| DDR0_19_DLL_DQS_DELAY_7_ENCODE(dll_dqs_delay_X)
|
||||
| DDR0_19_DLL_DQS_DELAY_6_ENCODE(dll_dqs_delay_X)
|
||||
| DDR0_19_DLL_DQS_DELAY_5_ENCODE(dll_dqs_delay_X);
|
||||
mtdcr(ddrcfgd, val);
|
||||
/* clear any ECC errors */
|
||||
mtdcr(ddrcfga, DDR0_00);
|
||||
mtdcr(ddrcfgd,
|
||||
mfdcr(ddrcfgd) | DDR0_00_INT_ACK_ENCODE(0x3C));
|
||||
|
||||
sync();
|
||||
eieio();
|
||||
|
||||
/* -----------------------------------------------------------+
|
||||
* Assert 'start' parameter.
|
||||
* ----------------------------------------------------------*/
|
||||
mtdcr(ddrcfga, DDR0_02);
|
||||
val = (mfdcr(ddrcfgd) & ~DDR0_02_START_MASK) |
|
||||
DDR0_02_START_ON;
|
||||
mtdcr(ddrcfgd, val);
|
||||
|
||||
sync();
|
||||
eieio();
|
||||
|
||||
/* -----------------------------------------------------------+
|
||||
* Wait for the DCC master delay line to finish calibration
|
||||
* ----------------------------------------------------------*/
|
||||
if (denali_wait_for_dlllock() != 0) {
|
||||
printf("dll lock did not occur !!!\n");
|
||||
printf("denali_core_search_data_eye!!!\n");
|
||||
printf("wr_dqs_shift = %d - dll_dqs_delay_X = "
|
||||
"%d\n", wr_dqs_shift, dll_dqs_delay_X);
|
||||
hang();
|
||||
}
|
||||
sync();
|
||||
eieio();
|
||||
|
||||
if (wait_for_dram_init_complete() != 0) {
|
||||
printf("dram init complete did not occur!!!\n");
|
||||
printf("denali_core_search_data_eye!!!\n");
|
||||
printf("wr_dqs_shift = %d - dll_dqs_delay_X = "
|
||||
"%d\n", wr_dqs_shift, dll_dqs_delay_X);
|
||||
hang();
|
||||
}
|
||||
udelay(100); /* wait 100us to ensure init is really completed !!! */
|
||||
|
||||
/* write values */
|
||||
for (j = 0; j < NUM_TRIES; j++) {
|
||||
ram_pointer[j] = test[j];
|
||||
|
||||
/* clear any cache at ram location */
|
||||
__asm__("dcbf 0,%0": :"r"(&ram_pointer[j]));
|
||||
}
|
||||
|
||||
/* read values back */
|
||||
for (j = 0; j < NUM_TRIES; j++) {
|
||||
for (k = 0; k < NUM_READS; k++) {
|
||||
/* clear any cache at ram location */
|
||||
__asm__("dcbf 0,%0": :"r"(&ram_pointer
|
||||
[j]));
|
||||
|
||||
if (ram_pointer[j] != test[j])
|
||||
break;
|
||||
}
|
||||
|
||||
/* read error */
|
||||
if (k != NUM_READS)
|
||||
break;
|
||||
}
|
||||
|
||||
/* See if the dll_dqs_delay_X value passed. */
|
||||
mtdcr(ddrcfga, DDR0_00);
|
||||
if (j < NUM_TRIES
|
||||
|| (DDR0_00_INT_STATUS_DECODE(mfdcr(ddrcfgd)) &
|
||||
0x3F)) {
|
||||
/* Failed */
|
||||
passing_cases = 0;
|
||||
/* break; */
|
||||
} else {
|
||||
/* Passed */
|
||||
if (passing_cases == 0)
|
||||
dll_dqs_delay_X_sw_val =
|
||||
dll_dqs_delay_X;
|
||||
passing_cases++;
|
||||
if (passing_cases >= max_passing_cases) {
|
||||
max_passing_cases = passing_cases;
|
||||
wr_dqs_shift_with_max_passing_cases =
|
||||
wr_dqs_shift;
|
||||
dll_dqs_delay_X_start_window =
|
||||
dll_dqs_delay_X_sw_val;
|
||||
dll_dqs_delay_X_end_window =
|
||||
dll_dqs_delay_X;
|
||||
}
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------+
|
||||
* De-assert 'start' parameter.
|
||||
* ----------------------------------------------------------*/
|
||||
mtdcr(ddrcfga, DDR0_02);
|
||||
val = (mfdcr(ddrcfgd) & ~DDR0_02_START_MASK) |
|
||||
DDR0_02_START_OFF;
|
||||
mtdcr(ddrcfgd, val);
|
||||
} /* for (dll_dqs_delay_X=0; dll_dqs_delay_X<128; dll_dqs_delay_X++) */
|
||||
} /* for (wr_dqs_shift=0; wr_dqs_shift<96; wr_dqs_shift++) */
|
||||
|
||||
/* -----------------------------------------------------------+
|
||||
* Largest passing window is now detected.
|
||||
* ----------------------------------------------------------*/
|
||||
|
||||
/* Compute dll_dqs_delay_X value */
|
||||
dll_dqs_delay_X = (dll_dqs_delay_X_end_window +
|
||||
dll_dqs_delay_X_start_window) / 2;
|
||||
wr_dqs_shift = wr_dqs_shift_with_max_passing_cases;
|
||||
|
||||
debug("DQS calibration - Window detected:\n");
|
||||
debug("max_passing_cases = %d\n", max_passing_cases);
|
||||
debug("wr_dqs_shift = %d\n", wr_dqs_shift);
|
||||
debug("dll_dqs_delay_X = %d\n", dll_dqs_delay_X);
|
||||
debug("dll_dqs_delay_X window = %d - %d\n",
|
||||
dll_dqs_delay_X_start_window, dll_dqs_delay_X_end_window);
|
||||
|
||||
/* -----------------------------------------------------------+
|
||||
* De-assert 'start' parameter.
|
||||
* ----------------------------------------------------------*/
|
||||
mtdcr(ddrcfga, DDR0_02);
|
||||
val = (mfdcr(ddrcfgd) & ~DDR0_02_START_MASK) | DDR0_02_START_OFF;
|
||||
mtdcr(ddrcfgd, val);
|
||||
|
||||
/* -----------------------------------------------------------+
|
||||
* Set 'wr_dqs_shift'
|
||||
* ----------------------------------------------------------*/
|
||||
mtdcr(ddrcfga, DDR0_09);
|
||||
val = (mfdcr(ddrcfgd) & ~DDR0_09_WR_DQS_SHIFT_MASK)
|
||||
| DDR0_09_WR_DQS_SHIFT_ENCODE(wr_dqs_shift);
|
||||
mtdcr(ddrcfgd, val);
|
||||
debug("DDR0_09=0x%08x\n", val);
|
||||
|
||||
/* -----------------------------------------------------------+
|
||||
* Set 'dqs_out_shift' = wr_dqs_shift + 32
|
||||
* ----------------------------------------------------------*/
|
||||
dqs_out_shift = wr_dqs_shift + 32;
|
||||
mtdcr(ddrcfga, DDR0_22);
|
||||
val = (mfdcr(ddrcfgd) & ~DDR0_22_DQS_OUT_SHIFT_MASK)
|
||||
| DDR0_22_DQS_OUT_SHIFT_ENCODE(dqs_out_shift);
|
||||
mtdcr(ddrcfgd, val);
|
||||
debug("DDR0_22=0x%08x\n", val);
|
||||
|
||||
/* -----------------------------------------------------------+
|
||||
* Set 'dll_dqs_delay_X'.
|
||||
* ----------------------------------------------------------*/
|
||||
/* dll_dqs_delay_0 */
|
||||
mtdcr(ddrcfga, DDR0_17);
|
||||
val = (mfdcr(ddrcfgd) & ~DDR0_17_DLL_DQS_DELAY_0_MASK)
|
||||
| DDR0_17_DLL_DQS_DELAY_0_ENCODE(dll_dqs_delay_X);
|
||||
mtdcr(ddrcfgd, val);
|
||||
debug("DDR0_17=0x%08x\n", val);
|
||||
|
||||
/* dll_dqs_delay_1 to dll_dqs_delay_4 */
|
||||
mtdcr(ddrcfga, DDR0_18);
|
||||
val = (mfdcr(ddrcfgd) & ~DDR0_18_DLL_DQS_DELAY_X_MASK)
|
||||
| DDR0_18_DLL_DQS_DELAY_4_ENCODE(dll_dqs_delay_X)
|
||||
| DDR0_18_DLL_DQS_DELAY_3_ENCODE(dll_dqs_delay_X)
|
||||
| DDR0_18_DLL_DQS_DELAY_2_ENCODE(dll_dqs_delay_X)
|
||||
| DDR0_18_DLL_DQS_DELAY_1_ENCODE(dll_dqs_delay_X);
|
||||
mtdcr(ddrcfgd, val);
|
||||
debug("DDR0_18=0x%08x\n", val);
|
||||
|
||||
/* dll_dqs_delay_5 to dll_dqs_delay_8 */
|
||||
mtdcr(ddrcfga, DDR0_19);
|
||||
val = (mfdcr(ddrcfgd) & ~DDR0_19_DLL_DQS_DELAY_X_MASK)
|
||||
| DDR0_19_DLL_DQS_DELAY_8_ENCODE(dll_dqs_delay_X)
|
||||
| DDR0_19_DLL_DQS_DELAY_7_ENCODE(dll_dqs_delay_X)
|
||||
| DDR0_19_DLL_DQS_DELAY_6_ENCODE(dll_dqs_delay_X)
|
||||
| DDR0_19_DLL_DQS_DELAY_5_ENCODE(dll_dqs_delay_X);
|
||||
mtdcr(ddrcfgd, val);
|
||||
debug("DDR0_19=0x%08x\n", val);
|
||||
|
||||
/* -----------------------------------------------------------+
|
||||
* Assert 'start' parameter.
|
||||
* ----------------------------------------------------------*/
|
||||
mtdcr(ddrcfga, DDR0_02);
|
||||
val = (mfdcr(ddrcfgd) & ~DDR0_02_START_MASK) | DDR0_02_START_ON;
|
||||
mtdcr(ddrcfgd, val);
|
||||
|
||||
sync();
|
||||
eieio();
|
||||
|
||||
/* -----------------------------------------------------------+
|
||||
* Wait for the DCC master delay line to finish calibration
|
||||
* ----------------------------------------------------------*/
|
||||
if (denali_wait_for_dlllock() != 0) {
|
||||
printf("dll lock did not occur !!!\n");
|
||||
hang();
|
||||
}
|
||||
sync();
|
||||
eieio();
|
||||
|
||||
if (wait_for_dram_init_complete() != 0) {
|
||||
printf("dram init complete did not occur !!!\n");
|
||||
hang();
|
||||
}
|
||||
udelay(100); /* wait 100us to ensure init is really completed !!! */
|
||||
}
|
||||
#endif /* defined(CONFIG_DDR_DATA_EYE) */
|
||||
#endif /* defined(CONFIG_440EPX) || defined(CONFIG_440GRX) */
|
||||
1231
u-boot/arch/powerpc/cpu/ppc4xx/denali_spd_ddr2.c
Normal file
1231
u-boot/arch/powerpc/cpu/ppc4xx/denali_spd_ddr2.c
Normal file
File diff suppressed because it is too large
Load Diff
188
u-boot/arch/powerpc/cpu/ppc4xx/ecc.c
Normal file
188
u-boot/arch/powerpc/cpu/ppc4xx/ecc.c
Normal file
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Nuovation System Designs, LLC
|
||||
* Grant Erickson <gerickson@nuovations.com>
|
||||
*
|
||||
* (C) Copyright 2005-2009
|
||||
* Stefan Roese, DENX Software Engineering, sr@denx.de.
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Jun Gu, Artesyn Technology, jung@artesyncp.com
|
||||
*
|
||||
* (C) Copyright 2001
|
||||
* Bill Hunter, Wave 7 Optics, williamhunter@attbi.com
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* Description:
|
||||
* This file implements generic DRAM ECC initialization for
|
||||
* PowerPC processors using a SDRAM DDR/DDR2 controller,
|
||||
* including the 405EX(r), 440GP/GX/EP/GR, 440SP(E), and
|
||||
* 460EX/GT.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/ppc4xx.h>
|
||||
#include <ppc_asm.tmpl>
|
||||
#include <ppc_defs.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/mmu.h>
|
||||
#include <asm/cache.h>
|
||||
|
||||
#include "ecc.h"
|
||||
|
||||
#if defined(CONFIG_SDRAM_PPC4xx_IBM_DDR) || \
|
||||
defined(CONFIG_SDRAM_PPC4xx_IBM_DDR2)
|
||||
#if defined(CONFIG_DDR_ECC) || defined(CONFIG_SDRAM_ECC)
|
||||
|
||||
#if defined(CONFIG_405EX)
|
||||
/*
|
||||
* Currently only 405EX uses 16bit data bus width as an alternative
|
||||
* option to 32bit data width (SDRAM0_MCOPT1_WDTH)
|
||||
*/
|
||||
#define SDRAM_DATA_ALT_WIDTH 2
|
||||
#else
|
||||
#define SDRAM_DATA_ALT_WIDTH 8
|
||||
#endif
|
||||
|
||||
static void wait_ddr_idle(void)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
do {
|
||||
mfsdram(SDRAM_MCSTAT, val);
|
||||
} while ((val & SDRAM_MCSTAT_IDLE_MASK) == SDRAM_MCSTAT_IDLE_NOT);
|
||||
}
|
||||
|
||||
static void program_ecc_addr(unsigned long start_address,
|
||||
unsigned long num_bytes,
|
||||
unsigned long tlb_word2_i_value)
|
||||
{
|
||||
unsigned long current_address;
|
||||
unsigned long end_address;
|
||||
unsigned long address_increment;
|
||||
unsigned long mcopt1;
|
||||
char str[] = "ECC generation -";
|
||||
char slash[] = "\\|/-\\|/-";
|
||||
int loop = 0;
|
||||
int loopi = 0;
|
||||
|
||||
current_address = start_address;
|
||||
mfsdram(SDRAM_MCOPT1, mcopt1);
|
||||
if ((mcopt1 & SDRAM_MCOPT1_MCHK_MASK) != SDRAM_MCOPT1_MCHK_NON) {
|
||||
mtsdram(SDRAM_MCOPT1,
|
||||
(mcopt1 & ~SDRAM_MCOPT1_MCHK_MASK) | SDRAM_MCOPT1_MCHK_GEN);
|
||||
sync();
|
||||
eieio();
|
||||
wait_ddr_idle();
|
||||
|
||||
puts(str);
|
||||
|
||||
#ifdef CONFIG_440
|
||||
if (tlb_word2_i_value == TLB_WORD2_I_ENABLE) {
|
||||
#endif
|
||||
/* ECC bit set method for non-cached memory */
|
||||
if ((mcopt1 & SDRAM_MCOPT1_DMWD_MASK) == SDRAM_MCOPT1_DMWD_32)
|
||||
address_increment = 4;
|
||||
else
|
||||
address_increment = SDRAM_DATA_ALT_WIDTH;
|
||||
end_address = current_address + num_bytes;
|
||||
|
||||
while (current_address < end_address) {
|
||||
*((unsigned long *)current_address) = 0;
|
||||
current_address += address_increment;
|
||||
|
||||
if ((loop++ % (2 << 20)) == 0) {
|
||||
putc('\b');
|
||||
putc(slash[loopi++ % 8]);
|
||||
}
|
||||
}
|
||||
#ifdef CONFIG_440
|
||||
} else {
|
||||
/* ECC bit set method for cached memory */
|
||||
dcbz_area(start_address, num_bytes);
|
||||
/* Write modified dcache lines back to memory */
|
||||
clean_dcache_range(start_address, start_address + num_bytes);
|
||||
}
|
||||
#endif /* CONFIG_440 */
|
||||
|
||||
blank_string(strlen(str));
|
||||
|
||||
sync();
|
||||
eieio();
|
||||
wait_ddr_idle();
|
||||
|
||||
/* clear ECC error repoting registers */
|
||||
mtsdram(SDRAM_ECCES, 0xffffffff);
|
||||
#if defined(CONFIG_SDRAM_PPC4xx_IBM_DDR)
|
||||
/*
|
||||
* IBM DDR(1) core (440GX):
|
||||
* Clear Mx bits in SDRAM0_BESR0/1
|
||||
*/
|
||||
mtsdram(SDRAM0_BESR0, 0xffffffff);
|
||||
mtsdram(SDRAM0_BESR1, 0xffffffff);
|
||||
#elif defined(CONFIG_440)
|
||||
/*
|
||||
* 440/460 DDR2 core:
|
||||
* Clear EMID (Error PLB Master ID) in MQ0_ESL
|
||||
*/
|
||||
mtdcr(SDRAM_ERRSTATLL, 0xfff00000);
|
||||
#else
|
||||
/*
|
||||
* 405EX(r) DDR2 core:
|
||||
* Clear M0ID (Error PLB Master ID) in SDRAM_BESR
|
||||
*/
|
||||
mtsdram(SDRAM_BESR, 0xf0000000);
|
||||
#endif
|
||||
|
||||
mtsdram(SDRAM_MCOPT1,
|
||||
(mcopt1 & ~SDRAM_MCOPT1_MCHK_MASK) | SDRAM_MCOPT1_MCHK_CHK_REP);
|
||||
sync();
|
||||
eieio();
|
||||
wait_ddr_idle();
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SDRAM_PPC4xx_IBM_DDR)
|
||||
void ecc_init(unsigned long * const start, unsigned long size)
|
||||
{
|
||||
/*
|
||||
* Init ECC with cache disabled (on PPC's with IBM DDR
|
||||
* controller (non DDR2), not tested with cache enabled yet
|
||||
*/
|
||||
program_ecc_addr((u32)start, size, TLB_WORD2_I_ENABLE);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SDRAM_PPC4xx_IBM_DDR2)
|
||||
void do_program_ecc(unsigned long tlb_word2_i_value)
|
||||
{
|
||||
unsigned long mcopt1;
|
||||
unsigned long mcopt2;
|
||||
unsigned long mcstat;
|
||||
phys_size_t memsize = sdram_memsize();
|
||||
|
||||
if (memsize > CONFIG_MAX_MEM_MAPPED) {
|
||||
printf("\nWarning: Can't enable ECC on systems with more than 2GB of SDRAM!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mfsdram(SDRAM_MCOPT1, mcopt1);
|
||||
mfsdram(SDRAM_MCOPT2, mcopt2);
|
||||
|
||||
if ((mcopt1 & SDRAM_MCOPT1_MCHK_MASK) != SDRAM_MCOPT1_MCHK_NON) {
|
||||
/* DDR controller must be enabled and not in self-refresh. */
|
||||
mfsdram(SDRAM_MCSTAT, mcstat);
|
||||
if (((mcopt2 & SDRAM_MCOPT2_DCEN_MASK) == SDRAM_MCOPT2_DCEN_ENABLE)
|
||||
&& ((mcopt2 & SDRAM_MCOPT2_SREN_MASK) == SDRAM_MCOPT2_SREN_EXIT)
|
||||
&& ((mcstat & (SDRAM_MCSTAT_MIC_MASK | SDRAM_MCSTAT_SRMS_MASK))
|
||||
== (SDRAM_MCSTAT_MIC_COMP | SDRAM_MCSTAT_SRMS_NOT_SF))) {
|
||||
|
||||
program_ecc_addr(0, memsize, tlb_word2_i_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* defined(CONFIG_DDR_ECC) || defined(CONFIG_SDRAM_ECC) */
|
||||
#endif /* defined(CONFIG_SDRAM_PPC4xx_IBM_DDR)... */
|
||||
58
u-boot/arch/powerpc/cpu/ppc4xx/ecc.h
Normal file
58
u-boot/arch/powerpc/cpu/ppc4xx/ecc.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Nuovation System Designs, LLC
|
||||
* Grant Erickson <gerickson@nuovations.com>
|
||||
*
|
||||
* Copyright (c) 2007-2009 DENX Software Engineering, GmbH
|
||||
* Stefan Roese <sr@denx.de>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* Description:
|
||||
* This file implements ECC initialization for PowerPC processors
|
||||
* using the IBM SDRAM DDR1 & DDR2 controller.
|
||||
*/
|
||||
|
||||
#ifndef _ECC_H_
|
||||
#define _ECC_H_
|
||||
|
||||
/*
|
||||
* Since the IBM DDR controller used on 440GP/GX/EP/GR is not register
|
||||
* compatible to the IBM DDR/2 controller used on 405EX/440SP/SPe/460EX/GT
|
||||
* we need to make some processor dependant defines used later on by the
|
||||
* driver.
|
||||
*/
|
||||
|
||||
/* For 440GP/GX/EP/GR */
|
||||
#if defined(CONFIG_SDRAM_PPC4xx_IBM_DDR)
|
||||
#define SDRAM_MCOPT1 SDRAM_CFG0
|
||||
#define SDRAM_MCOPT1_MCHK_MASK SDRAM_CFG0_MCHK_MASK
|
||||
#define SDRAM_MCOPT1_MCHK_NON SDRAM_CFG0_MCHK_NON
|
||||
#define SDRAM_MCOPT1_MCHK_GEN SDRAM_CFG0_MCHK_GEN
|
||||
#define SDRAM_MCOPT1_MCHK_CHK SDRAM_CFG0_MCHK_CHK
|
||||
#define SDRAM_MCOPT1_MCHK_CHK_REP SDRAM_CFG0_MCHK_CHK
|
||||
#define SDRAM_MCOPT1_DMWD_MASK SDRAM_CFG0_DMWD_MASK
|
||||
#define SDRAM_MCOPT1_DMWD_32 SDRAM_CFG0_DMWD_32
|
||||
|
||||
#define SDRAM_MCSTAT SDRAM0_MCSTS
|
||||
#define SDRAM_MCSTAT_IDLE_MASK SDRAM_MCSTS_CIS
|
||||
#define SDRAM_MCSTAT_IDLE_NOT SDRAM_MCSTS_IDLE_NOT
|
||||
|
||||
#define SDRAM_ECCES SDRAM0_ECCESR
|
||||
#endif
|
||||
|
||||
void ecc_init(unsigned long * const start, unsigned long size);
|
||||
void do_program_ecc(unsigned long tlb_word2_i_value);
|
||||
|
||||
static void inline blank_string(int size)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
putc('\b');
|
||||
for (i = 0; i < size; i++)
|
||||
putc(' ');
|
||||
for (i = 0; i < size; i++)
|
||||
putc('\b');
|
||||
}
|
||||
|
||||
#endif /* _ECC_H_ */
|
||||
163
u-boot/arch/powerpc/cpu/ppc4xx/fdt.c
Normal file
163
u-boot/arch/powerpc/cpu/ppc4xx/fdt.c
Normal file
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* (C) Copyright 2007-2008
|
||||
* Stefan Roese, DENX Software Engineering, sr@denx.de.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <watchdog.h>
|
||||
#include <command.h>
|
||||
#include <asm/cache.h>
|
||||
#include <asm/ppc4xx.h>
|
||||
|
||||
#ifdef CONFIG_OF_BOARD_SETUP
|
||||
#include <libfdt.h>
|
||||
#include <fdt_support.h>
|
||||
#include <asm/4xx_pcie.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
int __ft_board_setup(void *blob, bd_t *bd)
|
||||
{
|
||||
int rc;
|
||||
int i;
|
||||
u32 bxcr;
|
||||
u32 ranges[EBC_NUM_BANKS * 4];
|
||||
u32 *p = ranges;
|
||||
char ebc_path[] = "/plb/opb/ebc";
|
||||
|
||||
ft_cpu_setup(blob, bd);
|
||||
|
||||
/*
|
||||
* Read 4xx EBC bus bridge registers to get mappings of the
|
||||
* peripheral banks into the OPB/PLB address space
|
||||
*/
|
||||
for (i = 0; i < EBC_NUM_BANKS; i++) {
|
||||
mtdcr(EBC0_CFGADDR, EBC_BXCR(i));
|
||||
bxcr = mfdcr(EBC0_CFGDATA);
|
||||
|
||||
if ((bxcr & EBC_BXCR_BU_MASK) != EBC_BXCR_BU_NONE) {
|
||||
*p++ = i;
|
||||
*p++ = 0;
|
||||
*p++ = bxcr & EBC_BXCR_BAS_MASK;
|
||||
*p++ = EBC_BXCR_BANK_SIZE(bxcr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_FDT_FIXUP_NOR_FLASH_SIZE
|
||||
/* Update reg property in all nor flash nodes too */
|
||||
fdt_fixup_nor_flash_size(blob);
|
||||
#endif
|
||||
|
||||
/* Some 405 PPC's have EBC as direct PLB child in the dts */
|
||||
if (fdt_path_offset(blob, ebc_path) < 0)
|
||||
strcpy(ebc_path, "/plb/ebc");
|
||||
rc = fdt_find_and_setprop(blob, ebc_path, "ranges", ranges,
|
||||
(p - ranges) * sizeof(u32), 1);
|
||||
if (rc) {
|
||||
printf("Unable to update property EBC mappings, err=%s\n",
|
||||
fdt_strerror(rc));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
int ft_board_setup(void *blob, bd_t *bd)
|
||||
__attribute__((weak, alias("__ft_board_setup")));
|
||||
|
||||
/*
|
||||
* Fixup all PCIe nodes by setting the device_type property
|
||||
* to "pci-endpoint" instead is "pci" for endpoint ports.
|
||||
* This property will get checked later by the Linux driver
|
||||
* to properly configure the PCIe port in Linux (again).
|
||||
*/
|
||||
void fdt_pcie_setup(void *blob)
|
||||
{
|
||||
const char *compat = "ibm,plb-pciex";
|
||||
const char *prop = "device_type";
|
||||
const char *prop_val = "pci-endpoint";
|
||||
const u32 *port;
|
||||
int no;
|
||||
int rc;
|
||||
|
||||
/* Search first PCIe node */
|
||||
no = fdt_node_offset_by_compatible(blob, -1, compat);
|
||||
while (no != -FDT_ERR_NOTFOUND) {
|
||||
port = fdt_getprop(blob, no, "port", NULL);
|
||||
if (port == NULL) {
|
||||
printf("WARNING: could not find port property\n");
|
||||
} else {
|
||||
if (is_end_point(*port)) {
|
||||
rc = fdt_setprop(blob, no, prop, prop_val,
|
||||
strlen(prop_val) + 1);
|
||||
if (rc < 0)
|
||||
printf("WARNING: could not set %s for %s: %s.\n",
|
||||
prop, compat, fdt_strerror(rc));
|
||||
}
|
||||
}
|
||||
|
||||
/* Jump to next PCIe node */
|
||||
no = fdt_node_offset_by_compatible(blob, no, compat);
|
||||
}
|
||||
}
|
||||
|
||||
void ft_cpu_setup(void *blob, bd_t *bd)
|
||||
{
|
||||
sys_info_t sys_info;
|
||||
int off, ndepth = 0;
|
||||
|
||||
get_sys_info(&sys_info);
|
||||
|
||||
do_fixup_by_prop_u32(blob, "device_type", "cpu", 4, "timebase-frequency",
|
||||
bd->bi_intfreq, 1);
|
||||
do_fixup_by_prop_u32(blob, "device_type", "cpu", 4, "clock-frequency",
|
||||
bd->bi_intfreq, 1);
|
||||
do_fixup_by_path_u32(blob, "/plb", "clock-frequency", sys_info.freqPLB, 1);
|
||||
do_fixup_by_path_u32(blob, "/plb/opb", "clock-frequency", sys_info.freqOPB, 1);
|
||||
|
||||
if (fdt_path_offset(blob, "/plb/opb/ebc") >= 0)
|
||||
do_fixup_by_path_u32(blob, "/plb/opb/ebc", "clock-frequency",
|
||||
sys_info.freqEBC, 1);
|
||||
else
|
||||
do_fixup_by_path_u32(blob, "/plb/ebc", "clock-frequency",
|
||||
sys_info.freqEBC, 1);
|
||||
|
||||
fdt_fixup_memory(blob, (u64)bd->bi_memstart, (u64)bd->bi_memsize);
|
||||
|
||||
/*
|
||||
* Fixup all UART clocks for CPU internal UARTs
|
||||
* (only these UARTs are definitely clocked by gd->arch.uart_clk)
|
||||
*
|
||||
* These UARTs are direct childs of /plb/opb. This code
|
||||
* does not touch any UARTs that are connected to the ebc.
|
||||
*/
|
||||
off = fdt_path_offset(blob, "/plb/opb");
|
||||
while ((off = fdt_next_node(blob, off, &ndepth)) >= 0) {
|
||||
/*
|
||||
* process all sub nodes and stop when we are back
|
||||
* at the starting depth
|
||||
*/
|
||||
if (ndepth <= 0)
|
||||
break;
|
||||
|
||||
/* only update direct childs */
|
||||
if ((ndepth == 1) &&
|
||||
(fdt_node_check_compatible(blob, off, "ns16550") == 0))
|
||||
fdt_setprop(blob, off,
|
||||
"clock-frequency",
|
||||
(void *)&gd->arch.uart_clk, 4);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fixup all ethernet nodes
|
||||
* Note: aliases in the dts are required for this
|
||||
*/
|
||||
fdt_fixup_ethernet(blob);
|
||||
|
||||
/*
|
||||
* Fixup all available PCIe nodes by setting the device_type property
|
||||
*/
|
||||
fdt_pcie_setup(blob);
|
||||
}
|
||||
#endif /* CONFIG_OF_BOARD_SETUP */
|
||||
244
u-boot/arch/powerpc/cpu/ppc4xx/gpio.c
Normal file
244
u-boot/arch/powerpc/cpu/ppc4xx/gpio.c
Normal file
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
* (C) Copyright 2007-2008
|
||||
* Stefan Roese, DENX Software Engineering, sr@denx.de.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/ppc4xx-gpio.h>
|
||||
|
||||
/* Only compile this file for boards with GPIO support */
|
||||
#if defined(GPIO0_BASE)
|
||||
|
||||
#if defined(CONFIG_SYS_4xx_GPIO_TABLE)
|
||||
gpio_param_s const gpio_tab[GPIO_GROUP_MAX][GPIO_MAX] = CONFIG_SYS_4xx_GPIO_TABLE;
|
||||
#endif
|
||||
|
||||
#if defined(GPIO0_OSRL)
|
||||
/* Only some 4xx variants support alternate funtions on the GPIO's */
|
||||
void gpio_config(int pin, int in_out, int gpio_alt, int out_val)
|
||||
{
|
||||
u32 mask;
|
||||
u32 mask2;
|
||||
u32 val;
|
||||
u32 offs = 0;
|
||||
u32 offs2 = 0;
|
||||
int pin2 = pin << 1;
|
||||
|
||||
if (pin >= GPIO_MAX) {
|
||||
offs = 0x100;
|
||||
pin -= GPIO_MAX;
|
||||
}
|
||||
|
||||
if (pin >= GPIO_MAX/2) {
|
||||
offs2 = 0x4;
|
||||
pin2 = (pin - GPIO_MAX/2) << 1;
|
||||
}
|
||||
|
||||
mask = 0x80000000 >> pin;
|
||||
mask2 = 0xc0000000 >> pin2;
|
||||
|
||||
/* first set TCR to 0 */
|
||||
out_be32((void *)GPIO0_TCR + offs, in_be32((void *)GPIO0_TCR + offs) & ~mask);
|
||||
|
||||
if (in_out == GPIO_OUT) {
|
||||
val = in_be32((void *)GPIO0_OSRL + offs + offs2) & ~mask2;
|
||||
switch (gpio_alt) {
|
||||
case GPIO_ALT1:
|
||||
val |= GPIO_ALT1_SEL >> pin2;
|
||||
break;
|
||||
case GPIO_ALT2:
|
||||
val |= GPIO_ALT2_SEL >> pin2;
|
||||
break;
|
||||
case GPIO_ALT3:
|
||||
val |= GPIO_ALT3_SEL >> pin2;
|
||||
break;
|
||||
}
|
||||
out_be32((void *)GPIO0_OSRL + offs + offs2, val);
|
||||
|
||||
/* setup requested output value */
|
||||
if (out_val == GPIO_OUT_0)
|
||||
out_be32((void *)GPIO0_OR + offs,
|
||||
in_be32((void *)GPIO0_OR + offs) & ~mask);
|
||||
else if (out_val == GPIO_OUT_1)
|
||||
out_be32((void *)GPIO0_OR + offs,
|
||||
in_be32((void *)GPIO0_OR + offs) | mask);
|
||||
|
||||
/* now configure TCR to drive output if selected */
|
||||
out_be32((void *)GPIO0_TCR + offs,
|
||||
in_be32((void *)GPIO0_TCR + offs) | mask);
|
||||
} else {
|
||||
val = in_be32((void *)GPIO0_ISR1L + offs + offs2) & ~mask2;
|
||||
val |= GPIO_IN_SEL >> pin2;
|
||||
out_be32((void *)GPIO0_ISR1L + offs + offs2, val);
|
||||
}
|
||||
}
|
||||
#endif /* GPIO_OSRL */
|
||||
|
||||
void gpio_write_bit(int pin, int val)
|
||||
{
|
||||
u32 offs = 0;
|
||||
|
||||
if (pin >= GPIO_MAX) {
|
||||
offs = 0x100;
|
||||
pin -= GPIO_MAX;
|
||||
}
|
||||
|
||||
if (val)
|
||||
out_be32((void *)GPIO0_OR + offs,
|
||||
in_be32((void *)GPIO0_OR + offs) | GPIO_VAL(pin));
|
||||
else
|
||||
out_be32((void *)GPIO0_OR + offs,
|
||||
in_be32((void *)GPIO0_OR + offs) & ~GPIO_VAL(pin));
|
||||
}
|
||||
|
||||
int gpio_read_out_bit(int pin)
|
||||
{
|
||||
u32 offs = 0;
|
||||
|
||||
if (pin >= GPIO_MAX) {
|
||||
offs = 0x100;
|
||||
pin -= GPIO_MAX;
|
||||
}
|
||||
|
||||
return (in_be32((void *)GPIO0_OR + offs) & GPIO_VAL(pin) ? 1 : 0);
|
||||
}
|
||||
|
||||
int gpio_read_in_bit(int pin)
|
||||
{
|
||||
u32 offs = 0;
|
||||
|
||||
if (pin >= GPIO_MAX) {
|
||||
offs = 0x100;
|
||||
pin -= GPIO_MAX;
|
||||
}
|
||||
|
||||
return (in_be32((void *)GPIO0_IR + offs) & GPIO_VAL(pin) ? 1 : 0);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SYS_4xx_GPIO_TABLE)
|
||||
void gpio_set_chip_configuration(void)
|
||||
{
|
||||
unsigned char i=0, j=0, offs=0, gpio_core;
|
||||
unsigned long reg, core_add;
|
||||
|
||||
for (gpio_core=0; gpio_core<GPIO_GROUP_MAX; gpio_core++) {
|
||||
j = 0;
|
||||
offs = 0;
|
||||
/* GPIO config of the GPIOs 0 to 31 */
|
||||
for (i=0; i<GPIO_MAX; i++, j++) {
|
||||
if (i == GPIO_MAX/2) {
|
||||
offs = 4;
|
||||
j = i-16;
|
||||
}
|
||||
|
||||
core_add = gpio_tab[gpio_core][i].add;
|
||||
|
||||
if ((gpio_tab[gpio_core][i].in_out == GPIO_IN) ||
|
||||
(gpio_tab[gpio_core][i].in_out == GPIO_BI)) {
|
||||
|
||||
switch (gpio_tab[gpio_core][i].alt_nb) {
|
||||
case GPIO_SEL:
|
||||
break;
|
||||
|
||||
case GPIO_ALT1:
|
||||
reg = in_be32((void *)GPIO_IS1(core_add+offs))
|
||||
& ~(GPIO_MASK >> (j*2));
|
||||
reg = reg | (GPIO_IN_SEL >> (j*2));
|
||||
out_be32((void *)GPIO_IS1(core_add+offs), reg);
|
||||
break;
|
||||
|
||||
case GPIO_ALT2:
|
||||
reg = in_be32((void *)GPIO_IS2(core_add+offs))
|
||||
& ~(GPIO_MASK >> (j*2));
|
||||
reg = reg | (GPIO_IN_SEL >> (j*2));
|
||||
out_be32((void *)GPIO_IS2(core_add+offs), reg);
|
||||
break;
|
||||
|
||||
case GPIO_ALT3:
|
||||
reg = in_be32((void *)GPIO_IS3(core_add+offs))
|
||||
& ~(GPIO_MASK >> (j*2));
|
||||
reg = reg | (GPIO_IN_SEL >> (j*2));
|
||||
out_be32((void *)GPIO_IS3(core_add+offs), reg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((gpio_tab[gpio_core][i].in_out == GPIO_OUT) ||
|
||||
(gpio_tab[gpio_core][i].in_out == GPIO_BI)) {
|
||||
|
||||
u32 gpio_alt_sel = 0;
|
||||
|
||||
switch (gpio_tab[gpio_core][i].alt_nb) {
|
||||
case GPIO_SEL:
|
||||
/*
|
||||
* Setup output value
|
||||
* 1 -> high level
|
||||
* 0 -> low level
|
||||
* else -> don't touch
|
||||
*/
|
||||
reg = in_be32((void *)GPIO_OR(core_add));
|
||||
if (gpio_tab[gpio_core][i].out_val == GPIO_OUT_1)
|
||||
reg |= (0x80000000 >> (i));
|
||||
else if (gpio_tab[gpio_core][i].out_val == GPIO_OUT_0)
|
||||
reg &= ~(0x80000000 >> (i));
|
||||
out_be32((void *)GPIO_OR(core_add), reg);
|
||||
|
||||
reg = in_be32((void *)GPIO_TCR(core_add)) |
|
||||
(0x80000000 >> (i));
|
||||
out_be32((void *)GPIO_TCR(core_add), reg);
|
||||
|
||||
reg = in_be32((void *)GPIO_OS(core_add+offs))
|
||||
& ~(GPIO_MASK >> (j*2));
|
||||
out_be32((void *)GPIO_OS(core_add+offs), reg);
|
||||
reg = in_be32((void *)GPIO_TS(core_add+offs))
|
||||
& ~(GPIO_MASK >> (j*2));
|
||||
out_be32((void *)GPIO_TS(core_add+offs), reg);
|
||||
break;
|
||||
|
||||
case GPIO_ALT1:
|
||||
gpio_alt_sel = GPIO_ALT1_SEL;
|
||||
break;
|
||||
|
||||
case GPIO_ALT2:
|
||||
gpio_alt_sel = GPIO_ALT2_SEL;
|
||||
break;
|
||||
|
||||
case GPIO_ALT3:
|
||||
gpio_alt_sel = GPIO_ALT3_SEL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (0 != gpio_alt_sel) {
|
||||
reg = in_be32((void *)GPIO_OS(core_add+offs))
|
||||
& ~(GPIO_MASK >> (j*2));
|
||||
reg = reg | (gpio_alt_sel >> (j*2));
|
||||
out_be32((void *)GPIO_OS(core_add+offs), reg);
|
||||
|
||||
if (gpio_tab[gpio_core][i].out_val == GPIO_OUT_1) {
|
||||
reg = in_be32((void *)GPIO_TCR(core_add))
|
||||
| (0x80000000 >> (i));
|
||||
out_be32((void *)GPIO_TCR(core_add), reg);
|
||||
reg = in_be32((void *)GPIO_TS(core_add+offs))
|
||||
& ~(GPIO_MASK >> (j*2));
|
||||
out_be32((void *)GPIO_TS(core_add+offs), reg);
|
||||
} else {
|
||||
reg = in_be32((void *)GPIO_TCR(core_add))
|
||||
& ~(0x80000000 >> (i));
|
||||
out_be32((void *)GPIO_TCR(core_add), reg);
|
||||
reg = in_be32((void *)GPIO_TS(core_add+offs))
|
||||
& ~(GPIO_MASK >> (j*2));
|
||||
reg = reg | (gpio_alt_sel >> (j*2));
|
||||
out_be32((void *)GPIO_TS(core_add+offs), reg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* GPIO0_BASE */
|
||||
#endif /* CONFIG_SYS_4xx_GPIO_TABLE */
|
||||
193
u-boot/arch/powerpc/cpu/ppc4xx/interrupts.c
Normal file
193
u-boot/arch/powerpc/cpu/ppc4xx/interrupts.c
Normal file
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* (C) Copyright 2000-2002
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*
|
||||
* (C) Copyright 2002 (440 port)
|
||||
* Scott McNutt, Artesyn Communication Producs, smcnutt@artsyncp.com
|
||||
*
|
||||
* (C) Copyright 2003 (440GX port)
|
||||
* Travis B. Sawyer, Sandburst Corporation, tsawyer@sandburst.com
|
||||
*
|
||||
* (C) Copyright 2008 (PPC440X05 port for Virtex 5 FX)
|
||||
* Ricardo Ribalda-Universidad Autonoma de Madrid-ricardo.ribalda@gmail.com
|
||||
* Work supported by Qtechnology (htpp://qtec.com)
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <watchdog.h>
|
||||
#include <command.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/interrupt.h>
|
||||
#include <asm/ppc4xx.h>
|
||||
#include <ppc_asm.tmpl>
|
||||
#include <commproc.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/*
|
||||
* CPM interrupt vector functions.
|
||||
*/
|
||||
struct irq_action {
|
||||
interrupt_handler_t *handler;
|
||||
void *arg;
|
||||
int count;
|
||||
};
|
||||
static struct irq_action irq_vecs[IRQ_MAX];
|
||||
|
||||
#if defined(CONFIG_440)
|
||||
|
||||
/* SPRN changed in 440 */
|
||||
static __inline__ void set_evpr(unsigned long val)
|
||||
{
|
||||
asm volatile("mtspr 0x03f,%0" : : "r" (val));
|
||||
}
|
||||
|
||||
#else /* !defined(CONFIG_440) */
|
||||
|
||||
static __inline__ void set_pit(unsigned long val)
|
||||
{
|
||||
asm volatile("mtpit %0" : : "r" (val));
|
||||
}
|
||||
|
||||
static __inline__ void set_evpr(unsigned long val)
|
||||
{
|
||||
asm volatile("mtevpr %0" : : "r" (val));
|
||||
}
|
||||
#endif /* defined(CONFIG_440 */
|
||||
|
||||
int interrupt_init_cpu (unsigned *decrementer_count)
|
||||
{
|
||||
int vec;
|
||||
unsigned long val;
|
||||
|
||||
/* decrementer is automatically reloaded */
|
||||
*decrementer_count = 0;
|
||||
|
||||
/*
|
||||
* Mark all irqs as free
|
||||
*/
|
||||
for (vec = 0; vec < IRQ_MAX; vec++) {
|
||||
irq_vecs[vec].handler = NULL;
|
||||
irq_vecs[vec].arg = NULL;
|
||||
irq_vecs[vec].count = 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_4xx
|
||||
/*
|
||||
* Init PIT
|
||||
*/
|
||||
#if defined(CONFIG_440)
|
||||
val = mfspr( SPRN_TCR );
|
||||
val &= (~0x04400000); /* clear DIS & ARE */
|
||||
mtspr( SPRN_TCR, val );
|
||||
mtspr( SPRN_DEC, 0 ); /* Prevent exception after TSR clear*/
|
||||
mtspr( SPRN_DECAR, 0 ); /* clear reload */
|
||||
mtspr( SPRN_TSR, 0x08000000 ); /* clear DEC status */
|
||||
val = gd->bd->bi_intfreq/1000; /* 1 msec */
|
||||
mtspr( SPRN_DECAR, val ); /* Set auto-reload value */
|
||||
mtspr( SPRN_DEC, val ); /* Set inital val */
|
||||
#else
|
||||
set_pit(gd->bd->bi_intfreq / 1000);
|
||||
#endif
|
||||
#endif /* CONFIG_4xx */
|
||||
|
||||
#ifdef CONFIG_ADCIOP
|
||||
/*
|
||||
* Init PIT
|
||||
*/
|
||||
set_pit(66000);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Enable PIT
|
||||
*/
|
||||
val = mfspr(SPRN_TCR);
|
||||
val |= 0x04400000;
|
||||
mtspr(SPRN_TCR, val);
|
||||
|
||||
/*
|
||||
* Set EVPR to 0
|
||||
*/
|
||||
set_evpr(0x00000000);
|
||||
|
||||
/*
|
||||
* Call uic or xilinx_irq pic_enable
|
||||
*/
|
||||
pic_enable();
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void timer_interrupt_cpu(struct pt_regs *regs)
|
||||
{
|
||||
/* nothing to do here */
|
||||
return;
|
||||
}
|
||||
|
||||
void interrupt_run_handler(int vec)
|
||||
{
|
||||
irq_vecs[vec].count++;
|
||||
|
||||
if (irq_vecs[vec].handler != NULL) {
|
||||
/* call isr */
|
||||
(*irq_vecs[vec].handler) (irq_vecs[vec].arg);
|
||||
} else {
|
||||
pic_irq_disable(vec);
|
||||
printf("Masking bogus interrupt vector %d\n", vec);
|
||||
}
|
||||
|
||||
pic_irq_ack(vec);
|
||||
return;
|
||||
}
|
||||
|
||||
void irq_install_handler(int vec, interrupt_handler_t * handler, void *arg)
|
||||
{
|
||||
/*
|
||||
* Print warning when replacing with a different irq vector
|
||||
*/
|
||||
if ((irq_vecs[vec].handler != NULL) && (irq_vecs[vec].handler != handler)) {
|
||||
printf("Interrupt vector %d: handler 0x%x replacing 0x%x\n",
|
||||
vec, (uint) handler, (uint) irq_vecs[vec].handler);
|
||||
}
|
||||
irq_vecs[vec].handler = handler;
|
||||
irq_vecs[vec].arg = arg;
|
||||
|
||||
pic_irq_enable(vec);
|
||||
return;
|
||||
}
|
||||
|
||||
void irq_free_handler(int vec)
|
||||
{
|
||||
debug("Free interrupt for vector %d ==> %p\n",
|
||||
vec, irq_vecs[vec].handler);
|
||||
|
||||
pic_irq_disable(vec);
|
||||
|
||||
irq_vecs[vec].handler = NULL;
|
||||
irq_vecs[vec].arg = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_CMD_IRQ)
|
||||
int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
int vec;
|
||||
|
||||
printf ("Interrupt-Information:\n");
|
||||
printf ("Nr Routine Arg Count\n");
|
||||
|
||||
for (vec = 0; vec < IRQ_MAX; vec++) {
|
||||
if (irq_vecs[vec].handler != NULL) {
|
||||
printf ("%02d %08lx %08lx %d\n",
|
||||
vec,
|
||||
(ulong)irq_vecs[vec].handler,
|
||||
(ulong)irq_vecs[vec].arg,
|
||||
irq_vecs[vec].count);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
60
u-boot/arch/powerpc/cpu/ppc4xx/kgdb.S
Normal file
60
u-boot/arch/powerpc/cpu/ppc4xx/kgdb.S
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2000 Murray Jensen <Murray.Jensen@cmst.csiro.au>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <command.h>
|
||||
#include <asm/ppc4xx.h>
|
||||
|
||||
#define CONFIG_405GP 1 /* needed for Linux kernel header files */
|
||||
|
||||
#include <ppc_asm.tmpl>
|
||||
#include <ppc_defs.h>
|
||||
|
||||
#include <asm/cache.h>
|
||||
#include <asm/mmu.h>
|
||||
|
||||
#if defined(CONFIG_CMD_KGDB)
|
||||
/*
|
||||
* cache flushing routines for kgdb
|
||||
*/
|
||||
|
||||
.globl kgdb_flush_cache_all
|
||||
kgdb_flush_cache_all:
|
||||
/* icache */
|
||||
iccci r0,r0 /* iccci invalidates the entire I cache */
|
||||
/* dcache */
|
||||
addi r6,0,0x0000 /* clear GPR 6 */
|
||||
addi r7,r0, 128 /* do loop for # of dcache lines */
|
||||
/* NOTE: dccci invalidates both */
|
||||
mtctr r7 /* ways in the D cache */
|
||||
..dcloop:
|
||||
dccci 0,r6 /* invalidate line */
|
||||
addi r6,r6, 32 /* bump to next line */
|
||||
bdnz ..dcloop
|
||||
blr
|
||||
|
||||
.globl kgdb_flush_cache_range
|
||||
kgdb_flush_cache_range:
|
||||
li r5,L1_CACHE_BYTES-1
|
||||
andc r3,r3,r5
|
||||
subf r4,r3,r4
|
||||
add r4,r4,r5
|
||||
srwi. r4,r4,L1_CACHE_SHIFT
|
||||
beqlr
|
||||
mtctr r4
|
||||
mr r6,r3
|
||||
1: dcbst 0,r3
|
||||
addi r3,r3,L1_CACHE_BYTES
|
||||
bdnz 1b
|
||||
sync /* wait for dcbst's to get to ram */
|
||||
mtctr r4
|
||||
2: icbi 0,r6
|
||||
addi r6,r6,L1_CACHE_BYTES
|
||||
bdnz 2b
|
||||
SYNC
|
||||
blr
|
||||
|
||||
#endif
|
||||
346
u-boot/arch/powerpc/cpu/ppc4xx/miiphy.c
Normal file
346
u-boot/arch/powerpc/cpu/ppc4xx/miiphy.c
Normal file
@@ -0,0 +1,346 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0 IBM-pibs
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------+
|
||||
|
|
||||
| File Name: miiphy.c
|
||||
|
|
||||
| Function: This module has utilities for accessing the MII PHY through
|
||||
| the EMAC3 macro.
|
||||
|
|
||||
| Author: Mark Wisner
|
||||
|
|
||||
+-----------------------------------------------------------------------------*/
|
||||
|
||||
/* define DEBUG for debugging output (obviously ;-)) */
|
||||
#if 0
|
||||
#define DEBUG
|
||||
#endif
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/io.h>
|
||||
#include <ppc_asm.tmpl>
|
||||
#include <commproc.h>
|
||||
#include <asm/ppc4xx-emac.h>
|
||||
#include <asm/ppc4xx-mal.h>
|
||||
#include <miiphy.h>
|
||||
|
||||
#if !defined(CONFIG_PHY_CLK_FREQ)
|
||||
#define CONFIG_PHY_CLK_FREQ 0
|
||||
#endif
|
||||
|
||||
/***********************************************************/
|
||||
/* Dump out to the screen PHY regs */
|
||||
/***********************************************************/
|
||||
|
||||
void miiphy_dump (char *devname, unsigned char addr)
|
||||
{
|
||||
unsigned long i;
|
||||
unsigned short data;
|
||||
|
||||
for (i = 0; i < 0x1A; i++) {
|
||||
if (miiphy_read (devname, addr, i, &data)) {
|
||||
printf ("read error for reg %lx\n", i);
|
||||
return;
|
||||
}
|
||||
printf ("Phy reg %lx ==> %4x\n", i, data);
|
||||
|
||||
/* jump to the next set of regs */
|
||||
if (i == 0x07)
|
||||
i = 0x0f;
|
||||
|
||||
} /* end for loop */
|
||||
} /* end dump */
|
||||
|
||||
/***********************************************************/
|
||||
/* (Re)start autonegotiation */
|
||||
/***********************************************************/
|
||||
int phy_setup_aneg (char *devname, unsigned char addr)
|
||||
{
|
||||
u16 bmcr;
|
||||
|
||||
#if defined(CONFIG_PHY_DYNAMIC_ANEG)
|
||||
/*
|
||||
* Set up advertisement based on capablilities reported by the PHY.
|
||||
* This should work for both copper and fiber.
|
||||
*/
|
||||
u16 bmsr;
|
||||
#if defined(CONFIG_PHY_GIGE)
|
||||
u16 exsr = 0x0000;
|
||||
#endif
|
||||
|
||||
miiphy_read (devname, addr, MII_BMSR, &bmsr);
|
||||
|
||||
#if defined(CONFIG_PHY_GIGE)
|
||||
if (bmsr & BMSR_ESTATEN)
|
||||
miiphy_read (devname, addr, MII_ESTATUS, &exsr);
|
||||
|
||||
if (exsr & (ESTATUS_1000XF | ESTATUS_1000XH)) {
|
||||
/* 1000BASE-X */
|
||||
u16 anar = 0x0000;
|
||||
|
||||
if (exsr & ESTATUS_1000XF)
|
||||
anar |= ADVERTISE_1000XFULL;
|
||||
|
||||
if (exsr & ESTATUS_1000XH)
|
||||
anar |= ADVERTISE_1000XHALF;
|
||||
|
||||
miiphy_write (devname, addr, MII_ADVERTISE, anar);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
u16 anar, btcr;
|
||||
|
||||
miiphy_read (devname, addr, MII_ADVERTISE, &anar);
|
||||
anar &= ~(0x5000 | LPA_100BASE4 | LPA_100FULL |
|
||||
LPA_100HALF | LPA_10FULL | LPA_10HALF);
|
||||
|
||||
miiphy_read (devname, addr, MII_CTRL1000, &btcr);
|
||||
btcr &= ~(0x00FF | PHY_1000BTCR_1000FD | PHY_1000BTCR_1000HD);
|
||||
|
||||
if (bmsr & BMSR_100BASE4)
|
||||
anar |= LPA_100BASE4;
|
||||
|
||||
if (bmsr & BMSR_100FULL)
|
||||
anar |= LPA_100FULL;
|
||||
|
||||
if (bmsr & BMSR_100HALF)
|
||||
anar |= LPA_100HALF;
|
||||
|
||||
if (bmsr & BMSR_10FULL)
|
||||
anar |= LPA_10FULL;
|
||||
|
||||
if (bmsr & BMSR_10HALF)
|
||||
anar |= LPA_10HALF;
|
||||
|
||||
miiphy_write (devname, addr, MII_ADVERTISE, anar);
|
||||
|
||||
#if defined(CONFIG_PHY_GIGE)
|
||||
if (exsr & ESTATUS_1000_TFULL)
|
||||
btcr |= PHY_1000BTCR_1000FD;
|
||||
|
||||
if (exsr & ESTATUS_1000_THALF)
|
||||
btcr |= PHY_1000BTCR_1000HD;
|
||||
|
||||
miiphy_write (devname, addr, MII_CTRL1000, btcr);
|
||||
#endif
|
||||
}
|
||||
|
||||
#else /* defined(CONFIG_PHY_DYNAMIC_ANEG) */
|
||||
/*
|
||||
* Set up standard advertisement
|
||||
*/
|
||||
u16 adv;
|
||||
|
||||
miiphy_read (devname, addr, MII_ADVERTISE, &adv);
|
||||
adv |= (LPA_LPACK | LPA_100FULL | LPA_100HALF |
|
||||
LPA_10FULL | LPA_10HALF);
|
||||
miiphy_write (devname, addr, MII_ADVERTISE, adv);
|
||||
|
||||
miiphy_read (devname, addr, MII_CTRL1000, &adv);
|
||||
adv |= (0x0300);
|
||||
miiphy_write (devname, addr, MII_CTRL1000, adv);
|
||||
|
||||
#endif /* defined(CONFIG_PHY_DYNAMIC_ANEG) */
|
||||
|
||||
/* Start/Restart aneg */
|
||||
miiphy_read (devname, addr, MII_BMCR, &bmcr);
|
||||
bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
|
||||
miiphy_write (devname, addr, MII_BMCR, bmcr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***********************************************************/
|
||||
/* read a phy reg and return the value with a rc */
|
||||
/***********************************************************/
|
||||
/* AMCC_TODO:
|
||||
* Find out of the choice for the emac for MDIO is from the bridges,
|
||||
* i.e. ZMII or RGMII as approporiate. If the bridges are not used
|
||||
* to determine the emac for MDIO, then is the SDR0_ETH_CFG[MDIO_SEL]
|
||||
* used? If so, then this routine below does not apply to the 460EX/GT.
|
||||
*
|
||||
* sr: Currently on 460EX only EMAC0 works with MDIO, so we always
|
||||
* return EMAC0 offset here
|
||||
* vg: For 460EX/460GT if internal GPCS PHY address is specified
|
||||
* return appropriate EMAC offset
|
||||
*/
|
||||
unsigned int miiphy_getemac_offset(u8 addr)
|
||||
{
|
||||
#if defined(CONFIG_440) && \
|
||||
!defined(CONFIG_440SP) && !defined(CONFIG_440SPE) && \
|
||||
!defined(CONFIG_460EX) && !defined(CONFIG_460GT)
|
||||
unsigned long zmii;
|
||||
unsigned long eoffset;
|
||||
|
||||
/* Need to find out which mdi port we're using */
|
||||
zmii = in_be32((void *)ZMII0_FER);
|
||||
|
||||
if (zmii & (ZMII_FER_MDI << ZMII_FER_V (0)))
|
||||
/* using port 0 */
|
||||
eoffset = 0;
|
||||
|
||||
else if (zmii & (ZMII_FER_MDI << ZMII_FER_V (1)))
|
||||
/* using port 1 */
|
||||
eoffset = 0x100;
|
||||
|
||||
else if (zmii & (ZMII_FER_MDI << ZMII_FER_V (2)))
|
||||
/* using port 2 */
|
||||
eoffset = 0x400;
|
||||
|
||||
else if (zmii & (ZMII_FER_MDI << ZMII_FER_V (3)))
|
||||
/* using port 3 */
|
||||
eoffset = 0x600;
|
||||
|
||||
else {
|
||||
/* None of the mdi ports are enabled! */
|
||||
/* enable port 0 */
|
||||
zmii |= ZMII_FER_MDI << ZMII_FER_V (0);
|
||||
out_be32((void *)ZMII0_FER, zmii);
|
||||
eoffset = 0;
|
||||
/* need to soft reset port 0 */
|
||||
zmii = in_be32((void *)EMAC0_MR0);
|
||||
zmii |= EMAC_MR0_SRST;
|
||||
out_be32((void *)EMAC0_MR0, zmii);
|
||||
}
|
||||
|
||||
return (eoffset);
|
||||
#else
|
||||
|
||||
#if defined(CONFIG_405EX)
|
||||
unsigned long rgmii;
|
||||
int devnum = 1;
|
||||
|
||||
rgmii = in_be32((void *)RGMII_FER);
|
||||
if (rgmii & (1 << (19 - devnum)))
|
||||
return 0x100;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
|
||||
u32 eoffset = 0;
|
||||
|
||||
switch (addr) {
|
||||
#if defined(CONFIG_HAS_ETH1) && defined(CONFIG_GPCS_PHY1_ADDR)
|
||||
case CONFIG_GPCS_PHY1_ADDR:
|
||||
if (addr == EMAC_MR1_IPPA_GET(in_be32((void *)EMAC0_MR1 + 0x100)))
|
||||
eoffset = 0x100;
|
||||
break;
|
||||
#endif
|
||||
#if defined(CONFIG_HAS_ETH2) && defined(CONFIG_GPCS_PHY2_ADDR)
|
||||
case CONFIG_GPCS_PHY2_ADDR:
|
||||
if (addr == EMAC_MR1_IPPA_GET(in_be32((void *)EMAC0_MR1 + 0x300)))
|
||||
eoffset = 0x300;
|
||||
break;
|
||||
#endif
|
||||
#if defined(CONFIG_HAS_ETH3) && defined(CONFIG_GPCS_PHY3_ADDR)
|
||||
case CONFIG_GPCS_PHY3_ADDR:
|
||||
if (addr == EMAC_MR1_IPPA_GET(in_be32((void *)EMAC0_MR1 + 0x400)))
|
||||
eoffset = 0x400;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
eoffset = 0;
|
||||
break;
|
||||
}
|
||||
return eoffset;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int emac_miiphy_wait(u32 emac_reg)
|
||||
{
|
||||
u32 sta_reg;
|
||||
int i;
|
||||
|
||||
/* wait for completion */
|
||||
i = 0;
|
||||
do {
|
||||
sta_reg = in_be32((void *)EMAC0_STACR + emac_reg);
|
||||
if (i++ > 5) {
|
||||
debug("%s [%d]: Timeout! EMAC0_STACR=0x%0x\n", __func__,
|
||||
__LINE__, sta_reg);
|
||||
return -1;
|
||||
}
|
||||
udelay(10);
|
||||
} while ((sta_reg & EMAC_STACR_OC) == EMAC_STACR_OC_MASK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int emac_miiphy_command(u8 addr, u8 reg, int cmd, u16 value)
|
||||
{
|
||||
u32 emac_reg;
|
||||
u32 sta_reg;
|
||||
|
||||
emac_reg = miiphy_getemac_offset(addr);
|
||||
|
||||
/* wait for completion */
|
||||
if (emac_miiphy_wait(emac_reg) != 0)
|
||||
return -1;
|
||||
|
||||
sta_reg = reg; /* reg address */
|
||||
|
||||
/* set clock (50MHz) and read flags */
|
||||
#if defined(CONFIG_440GX) || defined(CONFIG_440SPE) || \
|
||||
defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
|
||||
defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
|
||||
defined(CONFIG_405EX)
|
||||
#if defined(CONFIG_IBM_EMAC4_V4) /* EMAC4 V4 changed bit setting */
|
||||
sta_reg = (sta_reg & ~EMAC_STACR_OP_MASK) | cmd;
|
||||
#else
|
||||
sta_reg |= cmd;
|
||||
#endif
|
||||
#else
|
||||
sta_reg = (sta_reg | cmd) & ~EMAC_STACR_CLK_100MHZ;
|
||||
#endif
|
||||
|
||||
/* Some boards (mainly 405EP based) define the PHY clock freqency fixed */
|
||||
sta_reg = sta_reg | CONFIG_PHY_CLK_FREQ;
|
||||
sta_reg = sta_reg | ((u32)addr << 5); /* Phy address */
|
||||
sta_reg = sta_reg | EMAC_STACR_OC_MASK; /* new IBM emac v4 */
|
||||
if (cmd == EMAC_STACR_WRITE)
|
||||
memcpy(&sta_reg, &value, 2); /* put in data */
|
||||
|
||||
out_be32((void *)EMAC0_STACR + emac_reg, sta_reg);
|
||||
debug("%s [%d]: sta_reg=%08x\n", __func__, __LINE__, sta_reg);
|
||||
|
||||
/* wait for completion */
|
||||
if (emac_miiphy_wait(emac_reg) != 0)
|
||||
return -1;
|
||||
|
||||
debug("%s [%d]: sta_reg=%08x\n", __func__, __LINE__, sta_reg);
|
||||
if ((sta_reg & EMAC_STACR_PHYE) != 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int emac4xx_miiphy_read (const char *devname, unsigned char addr, unsigned char reg,
|
||||
unsigned short *value)
|
||||
{
|
||||
unsigned long sta_reg;
|
||||
unsigned long emac_reg;
|
||||
|
||||
emac_reg = miiphy_getemac_offset(addr);
|
||||
|
||||
if (emac_miiphy_command(addr, reg, EMAC_STACR_READ, 0) != 0)
|
||||
return -1;
|
||||
|
||||
sta_reg = in_be32((void *)EMAC0_STACR + emac_reg);
|
||||
*value = sta_reg >> 16;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***********************************************************/
|
||||
/* write a phy reg and return the value with a rc */
|
||||
/***********************************************************/
|
||||
|
||||
int emac4xx_miiphy_write (const char *devname, unsigned char addr, unsigned char reg,
|
||||
unsigned short value)
|
||||
{
|
||||
return emac_miiphy_command(addr, reg, EMAC_STACR_WRITE, value);
|
||||
}
|
||||
357
u-boot/arch/powerpc/cpu/ppc4xx/reginfo.c
Normal file
357
u-boot/arch/powerpc/cpu/ppc4xx/reginfo.c
Normal file
@@ -0,0 +1,357 @@
|
||||
/*
|
||||
*(C) Copyright 2005-2009 Netstal Maschinen AG
|
||||
* Bruno Hars (Bruno.Hars@netstal.com)
|
||||
* Niklaus Giger (Niklaus.Giger@netstal.com)
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
/*
|
||||
* reginfo.c - register dump of HW-configuratin register for PPC4xx based board
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/ppc4xx-uic.h>
|
||||
#include <asm/ppc4xx-emac.h>
|
||||
|
||||
enum REGISTER_TYPE {
|
||||
IDCR1, /* Indirectly Accessed DCR via SDRAM0_CFGADDR/SDRAM0_CFGDATA */
|
||||
IDCR2, /* Indirectly Accessed DCR via EBC0_CFGADDR/EBC0_CFGDATA */
|
||||
IDCR3, /* Indirectly Accessed DCR via EBM0_CFGADDR/EBM0_CFGDATA */
|
||||
IDCR4, /* Indirectly Accessed DCR via PPM0_CFGADDR/PPM0_CFGDATA */
|
||||
IDCR5, /* Indirectly Accessed DCR via CPR0_CFGADDR/CPR0_CFGDATA */
|
||||
IDCR6, /* Indirectly Accessed DCR via SDR0_CFGADDR/SDR0_CFGDATA */
|
||||
MM /* Directly Accessed MMIO Register */
|
||||
};
|
||||
|
||||
struct cpu_register {
|
||||
char *name;
|
||||
enum REGISTER_TYPE type;
|
||||
u32 address;
|
||||
};
|
||||
|
||||
/*
|
||||
* PPC440EPx registers ordered for output
|
||||
* name type addr size
|
||||
* -------------------------------------------
|
||||
*/
|
||||
|
||||
const struct cpu_register ppc4xx_reg[] = {
|
||||
{"PB0CR", IDCR2, PB0CR},
|
||||
{"PB0AP", IDCR2, PB0AP},
|
||||
{"PB1CR", IDCR2, PB1CR},
|
||||
{"PB1AP", IDCR2, PB1AP},
|
||||
{"PB2CR", IDCR2, PB2CR},
|
||||
{"PB2AP", IDCR2, PB2AP},
|
||||
{"PB3CR", IDCR2, PB3CR},
|
||||
{"PB3AP", IDCR2, PB3AP},
|
||||
|
||||
{"PB4CR", IDCR2, PB4CR},
|
||||
{"PB4AP", IDCR2, PB4AP},
|
||||
#if !defined(CONFIG_405EP)
|
||||
{"PB5CR", IDCR2, PB5CR},
|
||||
{"PB5AP", IDCR2, PB5AP},
|
||||
{"PB6CR", IDCR2, PB6CR},
|
||||
{"PB6AP", IDCR2, PB6AP},
|
||||
{"PB7CR", IDCR2, PB7CR},
|
||||
{"PB7AP", IDCR2, PB7AP},
|
||||
#endif
|
||||
|
||||
{"PBEAR", IDCR2, PBEAR},
|
||||
#if defined(CONFIG_405EP) || defined (CONFIG_405GP)
|
||||
{"PBESR0", IDCR2, PBESR0},
|
||||
{"PBESR1", IDCR2, PBESR1},
|
||||
#endif
|
||||
{"EBC0_CFG", IDCR2, EBC0_CFG},
|
||||
|
||||
#ifdef CONFIG_405GP
|
||||
{"SDRAM0_BESR0", IDCR1, SDRAM0_BESR0},
|
||||
{"SDRAM0_BESRS0", IDCR1, SDRAM0_BESRS0},
|
||||
{"SDRAM0_BESR1", IDCR1, SDRAM0_BESR1},
|
||||
{"SDRAM0_BESRS1", IDCR1, SDRAM0_BESRS1},
|
||||
{"SDRAM0_BEAR", IDCR1, SDRAM0_BEAR},
|
||||
{"SDRAM0_CFG", IDCR1, SDRAM0_CFG},
|
||||
{"SDRAM0_RTR", IDCR1, SDRAM0_RTR},
|
||||
{"SDRAM0_PMIT", IDCR1, SDRAM0_PMIT},
|
||||
|
||||
{"SDRAM0_B0CR", IDCR1, SDRAM0_B0CR},
|
||||
{"SDRAM0_B1CR", IDCR1, SDRAM0_B1CR},
|
||||
{"SDRAM0_B2CR", IDCR1, SDRAM0_B2CR},
|
||||
{"SDRAM0_B3CR", IDCR1, SDRAM0_B1CR},
|
||||
{"SDRAM0_TR", IDCR1, SDRAM0_TR},
|
||||
{"SDRAM0_ECCCFG", IDCR1, SDRAM0_B1CR},
|
||||
{"SDRAM0_ECCESR", IDCR1, SDRAM0_ECCESR},
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_440EPX
|
||||
{"SDR0_SDSTP0", IDCR6, SDR0_SDSTP0},
|
||||
{"SDR0_SDSTP1", IDCR6, SDR0_SDSTP1},
|
||||
{"SDR0_SDSTP2", IDCR6, SDR0_SDSTP2},
|
||||
{"SDR0_SDSTP3", IDCR6, SDR0_SDSTP3},
|
||||
{"SDR0_CUST0", IDCR6, SDR0_CUST0},
|
||||
{"SDR0_CUST1", IDCR6, SDR0_CUST1},
|
||||
{"SDR0_EBC", IDCR6, SDR0_EBC},
|
||||
{"SDR0_AMP0", IDCR6, SDR0_AMP0},
|
||||
{"SDR0_AMP1", IDCR6, SDR0_AMP1},
|
||||
{"SDR0_CP440", IDCR6, SDR0_CP440},
|
||||
{"SDR0_CRYP0", IDCR6, SDR0_CRYP0},
|
||||
{"SDR0_DDRCFG", IDCR6, SDR0_DDRCFG},
|
||||
{"SDR0_EMAC0RXST", IDCR6, SDR0_EMAC0RXST},
|
||||
{"SDR0_EMAC0TXST", IDCR6, SDR0_EMAC0TXST},
|
||||
{"SDR0_MFR", IDCR6, SDR0_MFR},
|
||||
{"SDR0_PCI0", IDCR6, SDR0_PCI0},
|
||||
{"SDR0_PFC0", IDCR6, SDR0_PFC0},
|
||||
{"SDR0_PFC1", IDCR6, SDR0_PFC1},
|
||||
{"SDR0_PFC2", IDCR6, SDR0_PFC2},
|
||||
{"SDR0_PFC4", IDCR6, SDR0_PFC4},
|
||||
{"SDR0_UART0", IDCR6, SDR0_UART0},
|
||||
{"SDR0_UART1", IDCR6, SDR0_UART1},
|
||||
{"SDR0_UART2", IDCR6, SDR0_UART2},
|
||||
{"SDR0_UART3", IDCR6, SDR0_UART3},
|
||||
{"DDR0_02", IDCR1, DDR0_02},
|
||||
{"DDR0_00", IDCR1, DDR0_00},
|
||||
{"DDR0_01", IDCR1, DDR0_01},
|
||||
{"DDR0_03", IDCR1, DDR0_03},
|
||||
{"DDR0_04", IDCR1, DDR0_04},
|
||||
{"DDR0_05", IDCR1, DDR0_05},
|
||||
{"DDR0_06", IDCR1, DDR0_06},
|
||||
{"DDR0_07", IDCR1, DDR0_07},
|
||||
{"DDR0_08", IDCR1, DDR0_08},
|
||||
{"DDR0_09", IDCR1, DDR0_09},
|
||||
{"DDR0_10", IDCR1, DDR0_10},
|
||||
{"DDR0_11", IDCR1, DDR0_11},
|
||||
{"DDR0_12", IDCR1, DDR0_12},
|
||||
{"DDR0_14", IDCR1, DDR0_14},
|
||||
{"DDR0_17", IDCR1, DDR0_17},
|
||||
{"DDR0_18", IDCR1, DDR0_18},
|
||||
{"DDR0_19", IDCR1, DDR0_19},
|
||||
{"DDR0_20", IDCR1, DDR0_20},
|
||||
{"DDR0_21", IDCR1, DDR0_21},
|
||||
{"DDR0_22", IDCR1, DDR0_22},
|
||||
{"DDR0_23", IDCR1, DDR0_23},
|
||||
{"DDR0_24", IDCR1, DDR0_24},
|
||||
{"DDR0_25", IDCR1, DDR0_25},
|
||||
{"DDR0_26", IDCR1, DDR0_26},
|
||||
{"DDR0_27", IDCR1, DDR0_27},
|
||||
{"DDR0_28", IDCR1, DDR0_28},
|
||||
{"DDR0_31", IDCR1, DDR0_31},
|
||||
{"DDR0_32", IDCR1, DDR0_32},
|
||||
{"DDR0_33", IDCR1, DDR0_33},
|
||||
{"DDR0_34", IDCR1, DDR0_34},
|
||||
{"DDR0_35", IDCR1, DDR0_35},
|
||||
{"DDR0_36", IDCR1, DDR0_36},
|
||||
{"DDR0_37", IDCR1, DDR0_37},
|
||||
{"DDR0_38", IDCR1, DDR0_38},
|
||||
{"DDR0_39", IDCR1, DDR0_39},
|
||||
{"DDR0_40", IDCR1, DDR0_40},
|
||||
{"DDR0_41", IDCR1, DDR0_41},
|
||||
{"DDR0_42", IDCR1, DDR0_42},
|
||||
{"DDR0_43", IDCR1, DDR0_43},
|
||||
{"DDR0_44", IDCR1, DDR0_44},
|
||||
{"CPR0_ICFG", IDCR5, CPR0_ICFG},
|
||||
{"CPR0_MALD", IDCR5, CPR0_MALD},
|
||||
{"CPR0_OPBD00", IDCR5, CPR0_OPBD0},
|
||||
{"CPR0_PERD0", IDCR5, CPR0_PERD},
|
||||
{"CPR0_PLLC0", IDCR5, CPR0_PLLC},
|
||||
{"CPR0_PLLD0", IDCR5, CPR0_PLLD},
|
||||
{"CPR0_PRIMAD0", IDCR5, CPR0_PRIMAD0},
|
||||
{"CPR0_PRIMBD0", IDCR5, CPR0_PRIMBD0},
|
||||
{"CPR0_SPCID", IDCR5, CPR0_SPCID},
|
||||
{"SPI0_MODE", MM, SPI0_MODE},
|
||||
{"IIC0_CLKDIV", MM, PCIL0_PMM1MA},
|
||||
{"PCIL0_PMM0MA", MM, PCIL0_PMM0MA},
|
||||
{"PCIL0_PMM1MA", MM, PCIL0_PMM1MA},
|
||||
{"PCIL0_PTM1LA", MM, PCIL0_PMM1MA},
|
||||
{"PCIL0_PTM1MS", MM, PCIL0_PTM1MS},
|
||||
{"PCIL0_PTM2LA", MM, PCIL0_PMM1MA},
|
||||
{"PCIL0_PTM2MS", MM, PCIL0_PTM2MS},
|
||||
{"ZMII0_FER", MM, ZMII0_FER},
|
||||
{"ZMII0_SSR", MM, ZMII0_SSR},
|
||||
{"EMAC0_IPGVR", MM, EMAC0_IPGVR},
|
||||
{"EMAC0_MR1", MM, EMAC0_MR1},
|
||||
{"EMAC0_PTR", MM, EMAC0_PTR},
|
||||
{"EMAC0_RWMR", MM, EMAC0_RWMR},
|
||||
{"EMAC0_STACR", MM, EMAC0_STACR},
|
||||
{"EMAC0_TMR0", MM, EMAC0_TMR0},
|
||||
{"EMAC0_TMR1", MM, EMAC0_TMR1},
|
||||
{"EMAC0_TRTR", MM, EMAC0_TRTR},
|
||||
{"EMAC1_MR1", MM, EMAC1_MR1},
|
||||
{"GPIO0_OR", MM, GPIO0_OR},
|
||||
{"GPIO1_OR", MM, GPIO1_OR},
|
||||
{"GPIO0_TCR", MM, GPIO0_TCR},
|
||||
{"GPIO1_TCR", MM, GPIO1_TCR},
|
||||
{"GPIO0_ODR", MM, GPIO0_ODR},
|
||||
{"GPIO1_ODR", MM, GPIO1_ODR},
|
||||
{"GPIO0_OSRL", MM, GPIO0_OSRL},
|
||||
{"GPIO0_OSRH", MM, GPIO0_OSRH},
|
||||
{"GPIO1_OSRL", MM, GPIO1_OSRL},
|
||||
{"GPIO1_OSRH", MM, GPIO1_OSRH},
|
||||
{"GPIO0_TSRL", MM, GPIO0_TSRL},
|
||||
{"GPIO0_TSRH", MM, GPIO0_TSRH},
|
||||
{"GPIO1_TSRL", MM, GPIO1_TSRL},
|
||||
{"GPIO1_TSRH", MM, GPIO1_TSRH},
|
||||
{"GPIO0_IR", MM, GPIO0_IR},
|
||||
{"GPIO1_IR", MM, GPIO1_IR},
|
||||
{"GPIO0_ISR1L", MM, GPIO0_ISR1L},
|
||||
{"GPIO0_ISR1H", MM, GPIO0_ISR1H},
|
||||
{"GPIO1_ISR1L", MM, GPIO1_ISR1L},
|
||||
{"GPIO1_ISR1H", MM, GPIO1_ISR1H},
|
||||
{"GPIO0_ISR2L", MM, GPIO0_ISR2L},
|
||||
{"GPIO0_ISR2H", MM, GPIO0_ISR2H},
|
||||
{"GPIO1_ISR2L", MM, GPIO1_ISR2L},
|
||||
{"GPIO1_ISR2H", MM, GPIO1_ISR2H},
|
||||
{"GPIO0_ISR3L", MM, GPIO0_ISR3L},
|
||||
{"GPIO0_ISR3H", MM, GPIO0_ISR3H},
|
||||
{"GPIO1_ISR3L", MM, GPIO1_ISR3L},
|
||||
{"GPIO1_ISR3H", MM, GPIO1_ISR3H},
|
||||
{"SDR0_USB2PHY0CR", IDCR6, SDR0_USB2PHY0CR},
|
||||
{"SDR0_USB2H0CR", IDCR6, SDR0_USB2H0CR},
|
||||
{"SDR0_USB2D0CR", IDCR6, SDR0_USB2D0CR},
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* CPU Register dump of PPC4xx HW configuration registers
|
||||
* Output: first all DCR-registers, then in order of struct ppc4xx_reg
|
||||
*/
|
||||
#define PRINT_DCR(dcr) printf("0x%08x %-16s: 0x%08x\n", dcr,#dcr, mfdcr(dcr));
|
||||
|
||||
void ppc4xx_reginfo(void)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int n;
|
||||
u32 value;
|
||||
enum REGISTER_TYPE type;
|
||||
#if defined (CONFIG_405EP)
|
||||
printf("Dump PPC405EP HW configuration registers\n\n");
|
||||
#elif CONFIG_405GP
|
||||
printf ("Dump 405GP HW configuration registers\n\n");
|
||||
#elif CONFIG_440EPX
|
||||
printf("Dump PPC440EPx HW configuration registers\n\n");
|
||||
#endif
|
||||
printf("MSR: 0x%08x\n", mfmsr());
|
||||
|
||||
printf ("\nUniversal Interrupt Controller Regs\n");
|
||||
PRINT_DCR(UIC0SR);
|
||||
PRINT_DCR(UIC0ER);
|
||||
PRINT_DCR(UIC0CR);
|
||||
PRINT_DCR(UIC0PR);
|
||||
PRINT_DCR(UIC0TR);
|
||||
PRINT_DCR(UIC0MSR);
|
||||
PRINT_DCR(UIC0VR);
|
||||
PRINT_DCR(UIC0VCR);
|
||||
|
||||
#if (UIC_MAX > 1)
|
||||
PRINT_DCR(UIC2SR);
|
||||
PRINT_DCR(UIC2ER);
|
||||
PRINT_DCR(UIC2CR);
|
||||
PRINT_DCR(UIC2PR);
|
||||
PRINT_DCR(UIC2TR);
|
||||
PRINT_DCR(UIC2MSR);
|
||||
PRINT_DCR(UIC2VR);
|
||||
PRINT_DCR(UIC2VCR);
|
||||
#endif
|
||||
|
||||
#if (UIC_MAX > 2)
|
||||
PRINT_DCR(UIC2SR);
|
||||
PRINT_DCR(UIC2ER);
|
||||
PRINT_DCR(UIC2CR);
|
||||
PRINT_DCR(UIC2PR);
|
||||
PRINT_DCR(UIC2TR);
|
||||
PRINT_DCR(UIC2MSR);
|
||||
PRINT_DCR(UIC2VR);
|
||||
PRINT_DCR(UIC2VCR);
|
||||
#endif
|
||||
|
||||
#if (UIC_MAX > 3)
|
||||
PRINT_DCR(UIC3SR);
|
||||
PRINT_DCR(UIC3ER);
|
||||
PRINT_DCR(UIC3CR);
|
||||
PRINT_DCR(UIC3PR);
|
||||
PRINT_DCR(UIC3TR);
|
||||
PRINT_DCR(UIC3MSR);
|
||||
PRINT_DCR(UIC3VR);
|
||||
PRINT_DCR(UIC3VCR);
|
||||
#endif
|
||||
|
||||
#if defined (CONFIG_405EP) || defined (CONFIG_405GP)
|
||||
printf ("\n\nDMA Channels\n");
|
||||
PRINT_DCR(DMASR);
|
||||
PRINT_DCR(DMASGC);
|
||||
PRINT_DCR(DMAADR);
|
||||
|
||||
PRINT_DCR(DMACR0);
|
||||
PRINT_DCR(DMACT0);
|
||||
PRINT_DCR(DMADA0);
|
||||
PRINT_DCR(DMASA0);
|
||||
PRINT_DCR(DMASB0);
|
||||
|
||||
PRINT_DCR(DMACR1);
|
||||
PRINT_DCR(DMACT1);
|
||||
PRINT_DCR(DMADA1);
|
||||
PRINT_DCR(DMASA1);
|
||||
PRINT_DCR(DMASB1);
|
||||
|
||||
PRINT_DCR(DMACR2);
|
||||
PRINT_DCR(DMACT2);
|
||||
PRINT_DCR(DMADA2);
|
||||
PRINT_DCR(DMASA2);
|
||||
PRINT_DCR(DMASB2);
|
||||
|
||||
PRINT_DCR(DMACR3);
|
||||
PRINT_DCR(DMACT3);
|
||||
PRINT_DCR(DMADA3);
|
||||
PRINT_DCR(DMASA3);
|
||||
PRINT_DCR(DMASB3);
|
||||
#endif
|
||||
|
||||
printf ("\n\nVarious HW-Configuration registers\n");
|
||||
#if defined (CONFIG_440EPX)
|
||||
PRINT_DCR(MAL0_CFG);
|
||||
PRINT_DCR(CPM0_ER);
|
||||
PRINT_DCR(CPM1_ER);
|
||||
PRINT_DCR(PLB4A0_ACR);
|
||||
PRINT_DCR(PLB4A1_ACR);
|
||||
PRINT_DCR(PLB3A0_ACR);
|
||||
PRINT_DCR(OPB2PLB40_BCTRL);
|
||||
PRINT_DCR(P4P3BO0_CFG);
|
||||
#endif
|
||||
n = ARRAY_SIZE(ppc4xx_reg);
|
||||
for (i = 0; i < n; i++) {
|
||||
value = 0;
|
||||
type = ppc4xx_reg[i].type;
|
||||
switch (type) {
|
||||
case IDCR1: /* Indirect via SDRAM0_CFGADDR/DDR0_CFGDATA */
|
||||
mtdcr(SDRAM0_CFGADDR, ppc4xx_reg[i].address);
|
||||
value = mfdcr(SDRAM0_CFGDATA);
|
||||
break;
|
||||
case IDCR2: /* Indirect via EBC0_CFGADDR/EBC0_CFGDATA */
|
||||
mtdcr(EBC0_CFGADDR, ppc4xx_reg[i].address);
|
||||
value = mfdcr(EBC0_CFGDATA);
|
||||
break;
|
||||
case IDCR5: /* Indirect via CPR0_CFGADDR/CPR0_CFGDATA */
|
||||
mtdcr(CPR0_CFGADDR, ppc4xx_reg[i].address);
|
||||
value = mfdcr(CPR0_CFGDATA);
|
||||
break;
|
||||
case IDCR6: /* Indirect via SDR0_CFGADDR/SDR0_CFGDATA */
|
||||
mtdcr(SDR0_CFGADDR, ppc4xx_reg[i].address);
|
||||
value = mfdcr(SDR0_CFGDATA);
|
||||
break;
|
||||
case MM: /* Directly Accessed MMIO Register */
|
||||
value = in_be32((const volatile unsigned __iomem *)
|
||||
ppc4xx_reg[i].address);
|
||||
break;
|
||||
default:
|
||||
printf("\nERROR: struct entry %d: unknown register"
|
||||
"type\n", i);
|
||||
break;
|
||||
}
|
||||
printf("0x%08x %-16s: 0x%08x\n",ppc4xx_reg[i].address,
|
||||
ppc4xx_reg[i].name, value);
|
||||
}
|
||||
}
|
||||
12
u-boot/arch/powerpc/cpu/ppc4xx/resetvec.S
Normal file
12
u-boot/arch/powerpc/cpu/ppc4xx/resetvec.S
Normal file
@@ -0,0 +1,12 @@
|
||||
/* Copyright MontaVista Software Incorporated, 2000 */
|
||||
#include <config.h>
|
||||
.section .resetvec,"ax"
|
||||
#if defined(CONFIG_440)
|
||||
b _start_440
|
||||
#else
|
||||
#if defined(CONFIG_BOOT_PCI) && defined(CONFIG_MIP405)
|
||||
b _start_pci
|
||||
#else
|
||||
b _start
|
||||
#endif
|
||||
#endif
|
||||
452
u-boot/arch/powerpc/cpu/ppc4xx/sdram.c
Normal file
452
u-boot/arch/powerpc/cpu/ppc4xx/sdram.c
Normal file
@@ -0,0 +1,452 @@
|
||||
/*
|
||||
* (C) Copyright 2005-2007
|
||||
* Stefan Roese, DENX Software Engineering, sr@denx.de.
|
||||
*
|
||||
* (C) Copyright 2006
|
||||
* DAVE Srl <www.dave-tech.it>
|
||||
*
|
||||
* (C) Copyright 2002-2004
|
||||
* Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/ppc4xx.h>
|
||||
#include <asm/processor.h>
|
||||
#include "sdram.h"
|
||||
#include "ecc.h"
|
||||
|
||||
#ifdef CONFIG_SDRAM_BANK0
|
||||
|
||||
#ifndef CONFIG_440
|
||||
|
||||
#ifndef CONFIG_SYS_SDRAM_TABLE
|
||||
sdram_conf_t mb0cf[] = {
|
||||
{(128 << 20), 13, 0x000A4001}, /* (0-128MB) Address Mode 3, 13x10(4) */
|
||||
{(64 << 20), 13, 0x00084001}, /* (0-64MB) Address Mode 3, 13x9(4) */
|
||||
{(32 << 20), 12, 0x00062001}, /* (0-32MB) Address Mode 2, 12x9(4) */
|
||||
{(16 << 20), 12, 0x00046001}, /* (0-16MB) Address Mode 4, 12x8(4) */
|
||||
{(4 << 20), 11, 0x00008001}, /* (0-4MB) Address Mode 5, 11x8(2) */
|
||||
};
|
||||
#else
|
||||
sdram_conf_t mb0cf[] = CONFIG_SYS_SDRAM_TABLE;
|
||||
#endif
|
||||
|
||||
#define N_MB0CF (ARRAY_SIZE(mb0cf))
|
||||
|
||||
#ifdef CONFIG_SYS_SDRAM_CASL
|
||||
static ulong ns2clks(ulong ns)
|
||||
{
|
||||
ulong bus_period_x_10 = ONE_BILLION / (get_bus_freq(0) / 10);
|
||||
|
||||
return ((ns * 10) + bus_period_x_10) / bus_period_x_10;
|
||||
}
|
||||
#endif /* CONFIG_SYS_SDRAM_CASL */
|
||||
|
||||
static ulong compute_sdtr1(ulong speed)
|
||||
{
|
||||
#ifdef CONFIG_SYS_SDRAM_CASL
|
||||
ulong tmp;
|
||||
ulong sdtr1 = 0;
|
||||
|
||||
/* CASL */
|
||||
if (CONFIG_SYS_SDRAM_CASL < 2)
|
||||
sdtr1 |= (1 << SDRAM0_TR_CASL);
|
||||
else
|
||||
if (CONFIG_SYS_SDRAM_CASL > 4)
|
||||
sdtr1 |= (3 << SDRAM0_TR_CASL);
|
||||
else
|
||||
sdtr1 |= ((CONFIG_SYS_SDRAM_CASL-1) << SDRAM0_TR_CASL);
|
||||
|
||||
/* PTA */
|
||||
tmp = ns2clks(CONFIG_SYS_SDRAM_PTA);
|
||||
if ((tmp >= 2) && (tmp <= 4))
|
||||
sdtr1 |= ((tmp-1) << SDRAM0_TR_PTA);
|
||||
else
|
||||
sdtr1 |= ((4-1) << SDRAM0_TR_PTA);
|
||||
|
||||
/* CTP */
|
||||
tmp = ns2clks(CONFIG_SYS_SDRAM_CTP);
|
||||
if ((tmp >= 2) && (tmp <= 4))
|
||||
sdtr1 |= ((tmp-1) << SDRAM0_TR_CTP);
|
||||
else
|
||||
sdtr1 |= ((4-1) << SDRAM0_TR_CTP);
|
||||
|
||||
/* LDF */
|
||||
tmp = ns2clks(CONFIG_SYS_SDRAM_LDF);
|
||||
if ((tmp >= 2) && (tmp <= 4))
|
||||
sdtr1 |= ((tmp-1) << SDRAM0_TR_LDF);
|
||||
else
|
||||
sdtr1 |= ((2-1) << SDRAM0_TR_LDF);
|
||||
|
||||
/* RFTA */
|
||||
tmp = ns2clks(CONFIG_SYS_SDRAM_RFTA);
|
||||
if ((tmp >= 4) && (tmp <= 10))
|
||||
sdtr1 |= ((tmp-4) << SDRAM0_TR_RFTA);
|
||||
else
|
||||
sdtr1 |= ((10-4) << SDRAM0_TR_RFTA);
|
||||
|
||||
/* RCD */
|
||||
tmp = ns2clks(CONFIG_SYS_SDRAM_RCD);
|
||||
if ((tmp >= 2) && (tmp <= 4))
|
||||
sdtr1 |= ((tmp-1) << SDRAM0_TR_RCD);
|
||||
else
|
||||
sdtr1 |= ((4-1) << SDRAM0_TR_RCD);
|
||||
|
||||
return sdtr1;
|
||||
#else /* CONFIG_SYS_SDRAM_CASL */
|
||||
/*
|
||||
* If no values are configured in the board config file
|
||||
* use the default values, which seem to be ok for most
|
||||
* boards.
|
||||
*
|
||||
* REMARK:
|
||||
* For new board ports we strongly recommend to define the
|
||||
* correct values for the used SDRAM chips in your board
|
||||
* config file (see PPChameleonEVB.h)
|
||||
*/
|
||||
if (speed > 100000000) {
|
||||
/*
|
||||
* 133 MHz SDRAM
|
||||
*/
|
||||
return 0x01074015;
|
||||
} else {
|
||||
/*
|
||||
* default: 100 MHz SDRAM
|
||||
*/
|
||||
return 0x0086400d;
|
||||
}
|
||||
#endif /* CONFIG_SYS_SDRAM_CASL */
|
||||
}
|
||||
|
||||
/* refresh is expressed in ms */
|
||||
static ulong compute_rtr(ulong speed, ulong rows, ulong refresh)
|
||||
{
|
||||
#ifdef CONFIG_SYS_SDRAM_CASL
|
||||
ulong tmp;
|
||||
|
||||
tmp = ((refresh*1000*1000) / (1 << rows)) * (speed / 1000);
|
||||
tmp /= 1000000;
|
||||
|
||||
return ((tmp & 0x00003FF8) << 16);
|
||||
#else /* CONFIG_SYS_SDRAM_CASL */
|
||||
if (speed > 100000000) {
|
||||
/*
|
||||
* 133 MHz SDRAM
|
||||
*/
|
||||
return 0x07f00000;
|
||||
} else {
|
||||
/*
|
||||
* default: 100 MHz SDRAM
|
||||
*/
|
||||
return 0x05f00000;
|
||||
}
|
||||
#endif /* CONFIG_SYS_SDRAM_CASL */
|
||||
}
|
||||
|
||||
/*
|
||||
* Autodetect onboard SDRAM on 405 platforms
|
||||
*/
|
||||
phys_size_t initdram(int board_type)
|
||||
{
|
||||
ulong speed;
|
||||
ulong sdtr1;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Determine SDRAM speed
|
||||
*/
|
||||
speed = get_bus_freq(0); /* parameter not used on ppc4xx */
|
||||
|
||||
/*
|
||||
* sdtr1 (register SDRAM0_TR) must take into account timings listed
|
||||
* in SDRAM chip datasheet. rtr (register SDRAM0_RTR) must take into
|
||||
* account actual SDRAM size. So we can set up sdtr1 according to what
|
||||
* is specified in board configuration file while rtr dependds on SDRAM
|
||||
* size we are assuming before detection.
|
||||
*/
|
||||
sdtr1 = compute_sdtr1(speed);
|
||||
|
||||
for (i=0; i<N_MB0CF; i++) {
|
||||
/*
|
||||
* Disable memory controller.
|
||||
*/
|
||||
mtsdram(SDRAM0_CFG, 0x00000000);
|
||||
|
||||
/*
|
||||
* Set MB0CF for bank 0.
|
||||
*/
|
||||
mtsdram(SDRAM0_B0CR, mb0cf[i].reg);
|
||||
mtsdram(SDRAM0_TR, sdtr1);
|
||||
mtsdram(SDRAM0_RTR, compute_rtr(speed, mb0cf[i].rows, 64));
|
||||
|
||||
udelay(200);
|
||||
|
||||
/*
|
||||
* Set memory controller options reg, MCOPT1.
|
||||
* Set DC_EN to '1' and BRD_PRF to '01' for 16 byte PLB Burst
|
||||
* read/prefetch.
|
||||
*/
|
||||
mtsdram(SDRAM0_CFG, 0x80800000);
|
||||
|
||||
udelay(10000);
|
||||
|
||||
if (get_ram_size(0, mb0cf[i].size) == mb0cf[i].size) {
|
||||
phys_size_t size = mb0cf[i].size;
|
||||
|
||||
/*
|
||||
* OK, size detected. Enable second bank if
|
||||
* defined (assumes same type as bank 0)
|
||||
*/
|
||||
#ifdef CONFIG_SDRAM_BANK1
|
||||
mtsdram(SDRAM0_CFG, 0x00000000);
|
||||
mtsdram(SDRAM0_B1CR, mb0cf[i].size | mb0cf[i].reg);
|
||||
mtsdram(SDRAM0_CFG, 0x80800000);
|
||||
udelay(10000);
|
||||
|
||||
/*
|
||||
* Check if 2nd bank is really available.
|
||||
* If the size not equal to the size of the first
|
||||
* bank, then disable the 2nd bank completely.
|
||||
*/
|
||||
if (get_ram_size((long *)mb0cf[i].size, mb0cf[i].size) !=
|
||||
mb0cf[i].size) {
|
||||
mtsdram(SDRAM0_B1CR, 0);
|
||||
mtsdram(SDRAM0_CFG, 0);
|
||||
} else {
|
||||
/*
|
||||
* We have two identical banks, so the size
|
||||
* is twice the bank size
|
||||
*/
|
||||
size = 2 * size;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* OK, size detected -> all done
|
||||
*/
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* CONFIG_440 */
|
||||
|
||||
/*
|
||||
* Define some default values. Those can be overwritten in the
|
||||
* board config file.
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_SYS_SDRAM_TABLE
|
||||
sdram_conf_t mb0cf[] = {
|
||||
{(256 << 20), 13, 0x000C4001}, /* 256MB mode 3, 13x10(4) */
|
||||
{(128 << 20), 13, 0x000A4001}, /* 128MB mode 3, 13x10(4) */
|
||||
{(64 << 20), 12, 0x00082001} /* 64MB mode 2, 12x9(4) */
|
||||
};
|
||||
#else
|
||||
sdram_conf_t mb0cf[] = CONFIG_SYS_SDRAM_TABLE;
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SYS_SDRAM0_TR0
|
||||
#define CONFIG_SYS_SDRAM0_TR0 0x41094012
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SYS_SDRAM0_WDDCTR
|
||||
#define CONFIG_SYS_SDRAM0_WDDCTR 0x00000000 /* wrcp=0 dcd=0 */
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SYS_SDRAM0_RTR
|
||||
#define CONFIG_SYS_SDRAM0_RTR 0x04100000 /* 7.8us @ 133MHz PLB */
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SYS_SDRAM0_CFG0
|
||||
#define CONFIG_SYS_SDRAM0_CFG0 0x82000000 /* DCEN=1, PMUD=0, 64-bit */
|
||||
#endif
|
||||
|
||||
#define N_MB0CF (ARRAY_SIZE(mb0cf))
|
||||
|
||||
#define NUM_TRIES 64
|
||||
#define NUM_READS 10
|
||||
|
||||
static void sdram_tr1_set(int ram_address, int* tr1_value)
|
||||
{
|
||||
int i;
|
||||
int j, k;
|
||||
volatile unsigned int* ram_pointer = (unsigned int *)ram_address;
|
||||
int first_good = -1, last_bad = 0x1ff;
|
||||
|
||||
unsigned long test[NUM_TRIES] = {
|
||||
0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
|
||||
0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
|
||||
0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
|
||||
0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
|
||||
0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555,
|
||||
0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555,
|
||||
0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA,
|
||||
0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA,
|
||||
0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A,
|
||||
0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A,
|
||||
0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5,
|
||||
0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5,
|
||||
0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA,
|
||||
0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA,
|
||||
0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55,
|
||||
0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55 };
|
||||
|
||||
/* go through all possible SDRAM0_TR1[RDCT] values */
|
||||
for (i=0; i<=0x1ff; i++) {
|
||||
/* set the current value for TR1 */
|
||||
mtsdram(SDRAM0_TR1, (0x80800800 | i));
|
||||
|
||||
/* write values */
|
||||
for (j=0; j<NUM_TRIES; j++) {
|
||||
ram_pointer[j] = test[j];
|
||||
|
||||
/* clear any cache at ram location */
|
||||
__asm__("dcbf 0,%0": :"r" (&ram_pointer[j]));
|
||||
}
|
||||
|
||||
/* read values back */
|
||||
for (j=0; j<NUM_TRIES; j++) {
|
||||
for (k=0; k<NUM_READS; k++) {
|
||||
/* clear any cache at ram location */
|
||||
__asm__("dcbf 0,%0": :"r" (&ram_pointer[j]));
|
||||
|
||||
if (ram_pointer[j] != test[j])
|
||||
break;
|
||||
}
|
||||
|
||||
/* read error */
|
||||
if (k != NUM_READS)
|
||||
break;
|
||||
}
|
||||
|
||||
/* we have a SDRAM0_TR1[RDCT] that is part of the window */
|
||||
if (j == NUM_TRIES) {
|
||||
if (first_good == -1)
|
||||
first_good = i; /* found beginning of window */
|
||||
} else { /* bad read */
|
||||
/* if we have not had a good read then don't care */
|
||||
if (first_good != -1) {
|
||||
/* first failure after a good read */
|
||||
last_bad = i-1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* return the current value for TR1 */
|
||||
*tr1_value = (first_good + last_bad) / 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Autodetect onboard DDR SDRAM on 440 platforms
|
||||
*
|
||||
* NOTE: Some of the hardcoded values are hardware dependant,
|
||||
* so this should be extended for other future boards
|
||||
* using this routine!
|
||||
*/
|
||||
phys_size_t initdram(int board_type)
|
||||
{
|
||||
int i;
|
||||
int tr1_bank1;
|
||||
|
||||
#if defined(CONFIG_440GX) || defined(CONFIG_440EP) || \
|
||||
defined(CONFIG_440GR) || defined(CONFIG_440SP)
|
||||
/*
|
||||
* Soft-reset SDRAM controller.
|
||||
*/
|
||||
mtsdr(SDR0_SRST, SDR0_SRST_DMC);
|
||||
mtsdr(SDR0_SRST, 0x00000000);
|
||||
#endif
|
||||
|
||||
for (i=0; i<N_MB0CF; i++) {
|
||||
/*
|
||||
* Disable memory controller.
|
||||
*/
|
||||
mtsdram(SDRAM0_CFG0, 0x00000000);
|
||||
|
||||
/*
|
||||
* Setup some default
|
||||
*/
|
||||
mtsdram(SDRAM0_UABBA, 0x00000000); /* ubba=0 (default) */
|
||||
mtsdram(SDRAM0_SLIO, 0x00000000); /* rdre=0 wrre=0 rarw=0 */
|
||||
mtsdram(SDRAM0_DEVOPT, 0x00000000); /* dll=0 ds=0 (normal) */
|
||||
mtsdram(SDRAM0_WDDCTR, CONFIG_SYS_SDRAM0_WDDCTR);
|
||||
mtsdram(SDRAM0_CLKTR, 0x40000000); /* clkp=1 (90 deg wr) dcdt=0 */
|
||||
|
||||
/*
|
||||
* Following for CAS Latency = 2.5 @ 133 MHz PLB
|
||||
*/
|
||||
mtsdram(SDRAM0_B0CR, mb0cf[i].reg);
|
||||
mtsdram(SDRAM0_TR0, CONFIG_SYS_SDRAM0_TR0);
|
||||
mtsdram(SDRAM0_TR1, 0x80800800); /* SS=T2 SL=STAGE 3 CD=1 CT=0x00*/
|
||||
mtsdram(SDRAM0_RTR, CONFIG_SYS_SDRAM0_RTR);
|
||||
mtsdram(SDRAM0_CFG1, 0x00000000); /* Self-refresh exit, disable PM*/
|
||||
udelay(400); /* Delay 200 usecs (min) */
|
||||
|
||||
/*
|
||||
* Enable the controller, then wait for DCEN to complete
|
||||
*/
|
||||
mtsdram(SDRAM0_CFG0, CONFIG_SYS_SDRAM0_CFG0);
|
||||
udelay(10000);
|
||||
|
||||
if (get_ram_size(0, mb0cf[i].size) == mb0cf[i].size) {
|
||||
phys_size_t size = mb0cf[i].size;
|
||||
/*
|
||||
* Optimize TR1 to current hardware environment
|
||||
*/
|
||||
sdram_tr1_set(0x00000000, &tr1_bank1);
|
||||
mtsdram(SDRAM0_TR1, (tr1_bank1 | 0x80800800));
|
||||
|
||||
|
||||
/*
|
||||
* OK, size detected. Enable second bank if
|
||||
* defined (assumes same type as bank 0)
|
||||
*/
|
||||
#ifdef CONFIG_SDRAM_BANK1
|
||||
mtsdram(SDRAM0_CFG0, 0);
|
||||
mtsdram(SDRAM0_B1CR, mb0cf[i].size | mb0cf[i].reg);
|
||||
mtsdram(SDRAM0_CFG0, CONFIG_SYS_SDRAM0_CFG0);
|
||||
udelay(10000);
|
||||
|
||||
/*
|
||||
* Check if 2nd bank is really available.
|
||||
* If the size not equal to the size of the first
|
||||
* bank, then disable the 2nd bank completely.
|
||||
*/
|
||||
if (get_ram_size((long *)mb0cf[i].size, mb0cf[i].size)
|
||||
!= mb0cf[i].size) {
|
||||
mtsdram(SDRAM0_CFG0, 0);
|
||||
mtsdram(SDRAM0_B1CR, 0);
|
||||
mtsdram(SDRAM0_CFG0, CONFIG_SYS_SDRAM0_CFG0);
|
||||
udelay(10000);
|
||||
} else {
|
||||
/*
|
||||
* We have two identical banks, so the size
|
||||
* is twice the bank size
|
||||
*/
|
||||
size = 2 * size;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SDRAM_ECC
|
||||
ecc_init(0, size);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* OK, size detected -> all done
|
||||
*/
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
return 0; /* nothing found ! */
|
||||
}
|
||||
|
||||
#endif /* CONFIG_440 */
|
||||
|
||||
#endif /* CONFIG_SDRAM_BANK0 */
|
||||
60
u-boot/arch/powerpc/cpu/ppc4xx/sdram.h
Normal file
60
u-boot/arch/powerpc/cpu/ppc4xx/sdram.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* (C) Copyright 2006
|
||||
* Stefan Roese, DENX Software Engineering, sr@denx.de.
|
||||
*
|
||||
* (C) Copyright 2006
|
||||
* DAVE Srl <www.dave-tech.it>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef _SDRAM_H_
|
||||
#define _SDRAM_H_
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#define ONE_BILLION 1000000000
|
||||
|
||||
struct sdram_conf_s {
|
||||
unsigned long size;
|
||||
int rows;
|
||||
unsigned long reg;
|
||||
};
|
||||
|
||||
typedef struct sdram_conf_s sdram_conf_t;
|
||||
|
||||
/* Bitfields offsets */
|
||||
#define SDRAM0_TR_CASL (31 - 8)
|
||||
#define SDRAM0_TR_PTA (31 - 13)
|
||||
#define SDRAM0_TR_CTP (31 - 15)
|
||||
#define SDRAM0_TR_LDF (31 - 17)
|
||||
#define SDRAM0_TR_RFTA (31 - 29)
|
||||
#define SDRAM0_TR_RCD (31 - 31)
|
||||
|
||||
#ifdef CONFIG_SYS_SDRAM_CL
|
||||
/* SDRAM timings [ns] according to AMCC/IBM names (see SDRAM_faq.doc) */
|
||||
#define CONFIG_SYS_SDRAM_CASL CONFIG_SYS_SDRAM_CL
|
||||
#define CONFIG_SYS_SDRAM_PTA CONFIG_SYS_SDRAM_tRP
|
||||
#define CONFIG_SYS_SDRAM_CTP (CONFIG_SYS_SDRAM_tRC - CONFIG_SYS_SDRAM_tRCD - CONFIG_SYS_SDRAM_tRP)
|
||||
#define CONFIG_SYS_SDRAM_LDF 0
|
||||
#ifdef CONFIG_SYS_SDRAM_tRFC
|
||||
#define CONFIG_SYS_SDRAM_RFTA CONFIG_SYS_SDRAM_tRFC
|
||||
#else
|
||||
#define CONFIG_SYS_SDRAM_RFTA CONFIG_SYS_SDRAM_tRC
|
||||
#endif
|
||||
#define CONFIG_SYS_SDRAM_RCD CONFIG_SYS_SDRAM_tRCD
|
||||
#endif /* #ifdef CONFIG_SYS_SDRAM_CL */
|
||||
|
||||
/*
|
||||
* Some defines for the 440 DDR controller
|
||||
*/
|
||||
#define SDRAM_CFG0_DC_EN 0x80000000 /* SDRAM Controller Enable */
|
||||
#define SDRAM_CFG0_MEMCHK 0x30000000 /* Memory data error checking mask*/
|
||||
#define SDRAM_CFG0_MEMCHK_NON 0x00000000 /* No ECC generation */
|
||||
#define SDRAM_CFG0_MEMCHK_GEN 0x20000000 /* ECC generation */
|
||||
#define SDRAM_CFG0_MEMCHK_CHK 0x30000000 /* ECC generation and checking */
|
||||
#define SDRAM_CFG0_DRAMWDTH 0x02000000 /* DRAM width mask */
|
||||
#define SDRAM_CFG0_DRAMWDTH_32 0x00000000 /* 32 bits */
|
||||
#define SDRAM_CFG0_DRAMWDTH_64 0x02000000 /* 64 bits */
|
||||
|
||||
#endif
|
||||
1134
u-boot/arch/powerpc/cpu/ppc4xx/speed.c
Normal file
1134
u-boot/arch/powerpc/cpu/ppc4xx/speed.c
Normal file
File diff suppressed because it is too large
Load Diff
61
u-boot/arch/powerpc/cpu/ppc4xx/spl_boot.c
Normal file
61
u-boot/arch/powerpc/cpu/ppc4xx/spl_boot.c
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Stefan Roese <sr@denx.de>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <spl.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/*
|
||||
* Return selected boot device. On PPC4xx its only NOR flash right now.
|
||||
*/
|
||||
u32 spl_boot_device(void)
|
||||
{
|
||||
return BOOT_DEVICE_NOR;
|
||||
}
|
||||
|
||||
/*
|
||||
* SPL version of board_init_f()
|
||||
*/
|
||||
void board_init_f(ulong bootflag)
|
||||
{
|
||||
/*
|
||||
* First we need to initialize the SDRAM, so that the real
|
||||
* U-Boot or the OS (Linux) can be loaded
|
||||
*/
|
||||
initdram(0);
|
||||
|
||||
/* Clear bss */
|
||||
memset(__bss_start, '\0', __bss_end - __bss_start);
|
||||
|
||||
/*
|
||||
* Init global_data pointer. Has to be done before calling
|
||||
* get_clocks(), as it stores some clock values into gd needed
|
||||
* later on in the serial driver.
|
||||
*/
|
||||
/* Pointer is writable since we allocated a register for it */
|
||||
gd = (gd_t *)(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET);
|
||||
/* Clear initial global data */
|
||||
memset((void *)gd, 0, sizeof(gd_t));
|
||||
|
||||
/*
|
||||
* get_clocks() needs to be called so that the serial driver
|
||||
* works correctly
|
||||
*/
|
||||
get_clocks();
|
||||
|
||||
/*
|
||||
* Do rudimental console / serial setup
|
||||
*/
|
||||
preloader_console_init();
|
||||
|
||||
/*
|
||||
* Call board_init_r() (SPL framework version) to load and boot
|
||||
* real U-Boot or OS
|
||||
*/
|
||||
board_init_r(NULL, 0);
|
||||
/* Does not return!!! */
|
||||
}
|
||||
1928
u-boot/arch/powerpc/cpu/ppc4xx/start.S
Normal file
1928
u-boot/arch/powerpc/cpu/ppc4xx/start.S
Normal file
File diff suppressed because it is too large
Load Diff
336
u-boot/arch/powerpc/cpu/ppc4xx/tlb.c
Normal file
336
u-boot/arch/powerpc/cpu/ppc4xx/tlb.c
Normal file
@@ -0,0 +1,336 @@
|
||||
/*
|
||||
* (C) Copyright 2007
|
||||
* Stefan Roese, DENX Software Engineering, sr@denx.de.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
|
||||
#if defined(CONFIG_440)
|
||||
|
||||
#include <asm/ppc440.h>
|
||||
#include <asm/cache.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/mmu.h>
|
||||
|
||||
typedef struct region {
|
||||
u64 base;
|
||||
u32 size;
|
||||
u32 tlb_word2_i_value;
|
||||
} region_t;
|
||||
|
||||
void remove_tlb(u32 vaddr, u32 size)
|
||||
{
|
||||
int i;
|
||||
u32 tlb_word0_value;
|
||||
u32 tlb_vaddr;
|
||||
u32 tlb_size = 0;
|
||||
|
||||
for (i=0; i<PPC4XX_TLB_SIZE; i++) {
|
||||
tlb_word0_value = mftlb1(i);
|
||||
tlb_vaddr = TLB_WORD0_EPN_DECODE(tlb_word0_value);
|
||||
if (((tlb_word0_value & TLB_WORD0_V_MASK) == TLB_WORD0_V_ENABLE) &&
|
||||
(tlb_vaddr >= vaddr)) {
|
||||
/*
|
||||
* TLB is enabled and start address is lower or equal
|
||||
* than the area we are looking for. Now we only have
|
||||
* to check the size/end address for a match.
|
||||
*/
|
||||
switch (tlb_word0_value & TLB_WORD0_SIZE_MASK) {
|
||||
case TLB_WORD0_SIZE_1KB:
|
||||
tlb_size = 1 << 10;
|
||||
break;
|
||||
case TLB_WORD0_SIZE_4KB:
|
||||
tlb_size = 4 << 10;
|
||||
break;
|
||||
case TLB_WORD0_SIZE_16KB:
|
||||
tlb_size = 16 << 10;
|
||||
break;
|
||||
case TLB_WORD0_SIZE_64KB:
|
||||
tlb_size = 64 << 10;
|
||||
break;
|
||||
case TLB_WORD0_SIZE_256KB:
|
||||
tlb_size = 256 << 10;
|
||||
break;
|
||||
case TLB_WORD0_SIZE_1MB:
|
||||
tlb_size = 1 << 20;
|
||||
break;
|
||||
case TLB_WORD0_SIZE_16MB:
|
||||
tlb_size = 16 << 20;
|
||||
break;
|
||||
case TLB_WORD0_SIZE_256MB:
|
||||
tlb_size = 256 << 20;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now check the end-address if it's in the range
|
||||
*/
|
||||
if ((tlb_vaddr + tlb_size - 1) <= (vaddr + size - 1))
|
||||
/*
|
||||
* Found a TLB in the range.
|
||||
* Disable it by writing 0 to tlb0 word.
|
||||
*/
|
||||
mttlb1(i, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Execute an ISYNC instruction so that the new TLB entry takes effect */
|
||||
asm("isync");
|
||||
}
|
||||
|
||||
/*
|
||||
* Change the I attribute (cache inhibited) of a TLB or multiple TLB's.
|
||||
* This function is used to either turn cache on or off in a specific
|
||||
* memory area.
|
||||
*/
|
||||
void change_tlb(u32 vaddr, u32 size, u32 tlb_word2_i_value)
|
||||
{
|
||||
int i;
|
||||
u32 tlb_word0_value;
|
||||
u32 tlb_word2_value;
|
||||
u32 tlb_vaddr;
|
||||
u32 tlb_size = 0;
|
||||
|
||||
for (i=0; i<PPC4XX_TLB_SIZE; i++) {
|
||||
tlb_word0_value = mftlb1(i);
|
||||
tlb_vaddr = TLB_WORD0_EPN_DECODE(tlb_word0_value);
|
||||
if (((tlb_word0_value & TLB_WORD0_V_MASK) == TLB_WORD0_V_ENABLE) &&
|
||||
(tlb_vaddr >= vaddr)) {
|
||||
/*
|
||||
* TLB is enabled and start address is lower or equal
|
||||
* than the area we are looking for. Now we only have
|
||||
* to check the size/end address for a match.
|
||||
*/
|
||||
switch (tlb_word0_value & TLB_WORD0_SIZE_MASK) {
|
||||
case TLB_WORD0_SIZE_1KB:
|
||||
tlb_size = 1 << 10;
|
||||
break;
|
||||
case TLB_WORD0_SIZE_4KB:
|
||||
tlb_size = 4 << 10;
|
||||
break;
|
||||
case TLB_WORD0_SIZE_16KB:
|
||||
tlb_size = 16 << 10;
|
||||
break;
|
||||
case TLB_WORD0_SIZE_64KB:
|
||||
tlb_size = 64 << 10;
|
||||
break;
|
||||
case TLB_WORD0_SIZE_256KB:
|
||||
tlb_size = 256 << 10;
|
||||
break;
|
||||
case TLB_WORD0_SIZE_1MB:
|
||||
tlb_size = 1 << 20;
|
||||
break;
|
||||
case TLB_WORD0_SIZE_16MB:
|
||||
tlb_size = 16 << 20;
|
||||
break;
|
||||
case TLB_WORD0_SIZE_256MB:
|
||||
tlb_size = 256 << 20;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now check the end-address if it's in the range
|
||||
*/
|
||||
if (((tlb_vaddr + tlb_size - 1) <= (vaddr + size - 1)) ||
|
||||
((tlb_vaddr < (vaddr + size - 1)) &&
|
||||
((tlb_vaddr + tlb_size - 1) > (vaddr + size - 1)))) {
|
||||
/*
|
||||
* Found a TLB in the range.
|
||||
* Change cache attribute in tlb2 word.
|
||||
*/
|
||||
tlb_word2_value =
|
||||
TLB_WORD2_U0_DISABLE | TLB_WORD2_U1_DISABLE |
|
||||
TLB_WORD2_U2_DISABLE | TLB_WORD2_U3_DISABLE |
|
||||
TLB_WORD2_W_DISABLE | tlb_word2_i_value |
|
||||
TLB_WORD2_M_DISABLE | TLB_WORD2_G_DISABLE |
|
||||
TLB_WORD2_E_DISABLE | TLB_WORD2_UX_ENABLE |
|
||||
TLB_WORD2_UW_ENABLE | TLB_WORD2_UR_ENABLE |
|
||||
TLB_WORD2_SX_ENABLE | TLB_WORD2_SW_ENABLE |
|
||||
TLB_WORD2_SR_ENABLE;
|
||||
|
||||
/*
|
||||
* Now either flush or invalidate the dcache
|
||||
*/
|
||||
if (tlb_word2_i_value)
|
||||
flush_dcache();
|
||||
else
|
||||
invalidate_dcache();
|
||||
|
||||
mttlb3(i, tlb_word2_value);
|
||||
asm("iccci 0,0");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Execute an ISYNC instruction so that the new TLB entry takes effect */
|
||||
asm("isync");
|
||||
}
|
||||
|
||||
static int add_tlb_entry(u64 phys_addr,
|
||||
u32 virt_addr,
|
||||
u32 tlb_word0_size_value,
|
||||
u32 tlb_word2_i_value)
|
||||
{
|
||||
int i;
|
||||
unsigned long tlb_word0_value;
|
||||
unsigned long tlb_word1_value;
|
||||
unsigned long tlb_word2_value;
|
||||
|
||||
/* First, find the index of a TLB entry not being used */
|
||||
for (i=0; i<PPC4XX_TLB_SIZE; i++) {
|
||||
tlb_word0_value = mftlb1(i);
|
||||
if ((tlb_word0_value & TLB_WORD0_V_MASK) == TLB_WORD0_V_DISABLE)
|
||||
break;
|
||||
}
|
||||
if (i >= PPC4XX_TLB_SIZE)
|
||||
return -1;
|
||||
|
||||
/* Second, create the TLB entry */
|
||||
tlb_word0_value = TLB_WORD0_EPN_ENCODE(virt_addr) | TLB_WORD0_V_ENABLE |
|
||||
TLB_WORD0_TS_0 | tlb_word0_size_value;
|
||||
tlb_word1_value = TLB_WORD1_RPN_ENCODE((u32)phys_addr) |
|
||||
TLB_WORD1_ERPN_ENCODE(phys_addr >> 32);
|
||||
tlb_word2_value = TLB_WORD2_U0_DISABLE | TLB_WORD2_U1_DISABLE |
|
||||
TLB_WORD2_U2_DISABLE | TLB_WORD2_U3_DISABLE |
|
||||
TLB_WORD2_W_DISABLE | tlb_word2_i_value |
|
||||
TLB_WORD2_M_DISABLE | TLB_WORD2_G_DISABLE |
|
||||
TLB_WORD2_E_DISABLE | TLB_WORD2_UX_ENABLE |
|
||||
TLB_WORD2_UW_ENABLE | TLB_WORD2_UR_ENABLE |
|
||||
TLB_WORD2_SX_ENABLE | TLB_WORD2_SW_ENABLE |
|
||||
TLB_WORD2_SR_ENABLE;
|
||||
|
||||
/* Wait for all memory accesses to complete */
|
||||
sync();
|
||||
|
||||
/* Third, add the TLB entries */
|
||||
mttlb1(i, tlb_word0_value);
|
||||
mttlb2(i, tlb_word1_value);
|
||||
mttlb3(i, tlb_word2_value);
|
||||
|
||||
/* Execute an ISYNC instruction so that the new TLB entry takes effect */
|
||||
asm("isync");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void program_tlb_addr(u64 phys_addr,
|
||||
u32 virt_addr,
|
||||
u32 mem_size,
|
||||
u32 tlb_word2_i_value)
|
||||
{
|
||||
int rc;
|
||||
int tlb_i;
|
||||
|
||||
tlb_i = tlb_word2_i_value;
|
||||
while (mem_size != 0) {
|
||||
rc = 0;
|
||||
/* Add the TLB entries in to map the region. */
|
||||
if (((phys_addr & TLB_256MB_ALIGN_MASK) == phys_addr) &&
|
||||
(mem_size >= TLB_256MB_SIZE)) {
|
||||
/* Add a 256MB TLB entry */
|
||||
if ((rc = add_tlb_entry(phys_addr, virt_addr,
|
||||
TLB_WORD0_SIZE_256MB, tlb_i)) == 0) {
|
||||
mem_size -= TLB_256MB_SIZE;
|
||||
phys_addr += TLB_256MB_SIZE;
|
||||
virt_addr += TLB_256MB_SIZE;
|
||||
}
|
||||
} else if (((phys_addr & TLB_16MB_ALIGN_MASK) == phys_addr) &&
|
||||
(mem_size >= TLB_16MB_SIZE)) {
|
||||
/* Add a 16MB TLB entry */
|
||||
if ((rc = add_tlb_entry(phys_addr, virt_addr,
|
||||
TLB_WORD0_SIZE_16MB, tlb_i)) == 0) {
|
||||
mem_size -= TLB_16MB_SIZE;
|
||||
phys_addr += TLB_16MB_SIZE;
|
||||
virt_addr += TLB_16MB_SIZE;
|
||||
}
|
||||
} else if (((phys_addr & TLB_1MB_ALIGN_MASK) == phys_addr) &&
|
||||
(mem_size >= TLB_1MB_SIZE)) {
|
||||
/* Add a 1MB TLB entry */
|
||||
if ((rc = add_tlb_entry(phys_addr, virt_addr,
|
||||
TLB_WORD0_SIZE_1MB, tlb_i)) == 0) {
|
||||
mem_size -= TLB_1MB_SIZE;
|
||||
phys_addr += TLB_1MB_SIZE;
|
||||
virt_addr += TLB_1MB_SIZE;
|
||||
}
|
||||
} else if (((phys_addr & TLB_256KB_ALIGN_MASK) == phys_addr) &&
|
||||
(mem_size >= TLB_256KB_SIZE)) {
|
||||
/* Add a 256KB TLB entry */
|
||||
if ((rc = add_tlb_entry(phys_addr, virt_addr,
|
||||
TLB_WORD0_SIZE_256KB, tlb_i)) == 0) {
|
||||
mem_size -= TLB_256KB_SIZE;
|
||||
phys_addr += TLB_256KB_SIZE;
|
||||
virt_addr += TLB_256KB_SIZE;
|
||||
}
|
||||
} else if (((phys_addr & TLB_64KB_ALIGN_MASK) == phys_addr) &&
|
||||
(mem_size >= TLB_64KB_SIZE)) {
|
||||
/* Add a 64KB TLB entry */
|
||||
if ((rc = add_tlb_entry(phys_addr, virt_addr,
|
||||
TLB_WORD0_SIZE_64KB, tlb_i)) == 0) {
|
||||
mem_size -= TLB_64KB_SIZE;
|
||||
phys_addr += TLB_64KB_SIZE;
|
||||
virt_addr += TLB_64KB_SIZE;
|
||||
}
|
||||
} else if (((phys_addr & TLB_16KB_ALIGN_MASK) == phys_addr) &&
|
||||
(mem_size >= TLB_16KB_SIZE)) {
|
||||
/* Add a 16KB TLB entry */
|
||||
if ((rc = add_tlb_entry(phys_addr, virt_addr,
|
||||
TLB_WORD0_SIZE_16KB, tlb_i)) == 0) {
|
||||
mem_size -= TLB_16KB_SIZE;
|
||||
phys_addr += TLB_16KB_SIZE;
|
||||
virt_addr += TLB_16KB_SIZE;
|
||||
}
|
||||
} else if (((phys_addr & TLB_4KB_ALIGN_MASK) == phys_addr) &&
|
||||
(mem_size >= TLB_4KB_SIZE)) {
|
||||
/* Add a 4KB TLB entry */
|
||||
if ((rc = add_tlb_entry(phys_addr, virt_addr,
|
||||
TLB_WORD0_SIZE_4KB, tlb_i)) == 0) {
|
||||
mem_size -= TLB_4KB_SIZE;
|
||||
phys_addr += TLB_4KB_SIZE;
|
||||
virt_addr += TLB_4KB_SIZE;
|
||||
}
|
||||
} else if (((phys_addr & TLB_1KB_ALIGN_MASK) == phys_addr) &&
|
||||
(mem_size >= TLB_1KB_SIZE)) {
|
||||
/* Add a 1KB TLB entry */
|
||||
if ((rc = add_tlb_entry(phys_addr, virt_addr,
|
||||
TLB_WORD0_SIZE_1KB, tlb_i)) == 0) {
|
||||
mem_size -= TLB_1KB_SIZE;
|
||||
phys_addr += TLB_1KB_SIZE;
|
||||
virt_addr += TLB_1KB_SIZE;
|
||||
}
|
||||
} else {
|
||||
printf("ERROR: no TLB size exists for the base address 0x%llx.\n",
|
||||
phys_addr);
|
||||
}
|
||||
|
||||
if (rc != 0)
|
||||
printf("ERROR: no TLB entries available for the base addr 0x%llx.\n",
|
||||
phys_addr);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Program one (or multiple) TLB entries for one memory region
|
||||
*
|
||||
* Common usage for boards with SDRAM DIMM modules to dynamically
|
||||
* configure the TLB's for the SDRAM
|
||||
*/
|
||||
void program_tlb(u64 phys_addr, u32 virt_addr, u32 size, u32 tlb_word2_i_value)
|
||||
{
|
||||
region_t region_array;
|
||||
|
||||
region_array.base = phys_addr;
|
||||
region_array.size = size;
|
||||
region_array.tlb_word2_i_value = tlb_word2_i_value; /* en-/disable cache */
|
||||
|
||||
/* Call the routine to add in the tlb entries for the memory regions */
|
||||
program_tlb_addr(region_array.base, virt_addr, region_array.size,
|
||||
region_array.tlb_word2_i_value);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_440 */
|
||||
392
u-boot/arch/powerpc/cpu/ppc4xx/traps.c
Normal file
392
u-boot/arch/powerpc/cpu/ppc4xx/traps.c
Normal file
@@ -0,0 +1,392 @@
|
||||
/*
|
||||
* linux/arch/powerpc/kernel/traps.c
|
||||
*
|
||||
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
|
||||
*
|
||||
* Modified by Cort Dougan (cort@cs.nmt.edu)
|
||||
* and Paul Mackerras (paulus@cs.anu.edu.au)
|
||||
*
|
||||
* (C) Copyright 2000
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file handles the architecture-dependent parts of hardware exceptions
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <kgdb.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/* Returns 0 if exception not found and fixup otherwise. */
|
||||
extern unsigned long search_exception_table(unsigned long);
|
||||
|
||||
/* THIS NEEDS CHANGING to use the board info structure.
|
||||
*/
|
||||
#define END_OF_MEM (gd->bd->bi_memstart + gd->bd->bi_memsize)
|
||||
|
||||
static __inline__ unsigned long get_esr(void)
|
||||
{
|
||||
unsigned long val;
|
||||
|
||||
#if defined(CONFIG_440)
|
||||
asm volatile("mfspr %0, 0x03e" : "=r" (val) :);
|
||||
#else
|
||||
asm volatile("mfesr %0" : "=r" (val) :);
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
#define ESR_MCI 0x80000000
|
||||
#define ESR_PIL 0x08000000
|
||||
#define ESR_PPR 0x04000000
|
||||
#define ESR_PTR 0x02000000
|
||||
#define ESR_DST 0x00800000
|
||||
#define ESR_DIZ 0x00400000
|
||||
#define ESR_U0F 0x00008000
|
||||
|
||||
#if defined(CONFIG_CMD_BEDBUG)
|
||||
extern void do_bedbug_breakpoint(struct pt_regs *);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Trap & Exception support
|
||||
*/
|
||||
|
||||
static void print_backtrace(unsigned long *sp)
|
||||
{
|
||||
int cnt = 0;
|
||||
unsigned long i;
|
||||
|
||||
printf("Call backtrace: ");
|
||||
while (sp) {
|
||||
if ((uint)sp > END_OF_MEM)
|
||||
break;
|
||||
|
||||
i = sp[1];
|
||||
if (cnt++ % 7 == 0)
|
||||
printf("\n");
|
||||
printf("%08lX ", i);
|
||||
if (cnt > 32) break;
|
||||
sp = (unsigned long *)*sp;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void show_regs(struct pt_regs *regs)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DEAR: %08lX\n",
|
||||
regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
|
||||
printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
|
||||
regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
|
||||
regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
|
||||
regs->msr&MSR_IR ? 1 : 0,
|
||||
regs->msr&MSR_DR ? 1 : 0);
|
||||
|
||||
printf("\n");
|
||||
for (i = 0; i < 32; i++) {
|
||||
if ((i % 8) == 0) {
|
||||
printf("GPR%02d: ", i);
|
||||
}
|
||||
|
||||
printf("%08lX ", regs->gpr[i]);
|
||||
if ((i % 8) == 7) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void _exception(int signr, struct pt_regs *regs)
|
||||
{
|
||||
show_regs(regs);
|
||||
print_backtrace((unsigned long *)regs->gpr[1]);
|
||||
panic("Exception");
|
||||
}
|
||||
|
||||
void MachineCheckException(struct pt_regs *regs)
|
||||
{
|
||||
unsigned long fixup, val;
|
||||
#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
|
||||
u32 value2;
|
||||
int corr_ecc = 0;
|
||||
int uncorr_ecc = 0;
|
||||
#endif
|
||||
|
||||
if ((fixup = search_exception_table(regs->nip)) != 0) {
|
||||
regs->nip = fixup;
|
||||
val = mfspr(MCSR);
|
||||
/* Clear MCSR */
|
||||
mtspr(SPRN_MCSR, val);
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_CMD_KGDB)
|
||||
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
|
||||
return;
|
||||
#endif
|
||||
|
||||
printf("Machine Check Exception.\n");
|
||||
printf("Caused by (from msr): ");
|
||||
printf("regs %p ", regs);
|
||||
|
||||
val = get_esr();
|
||||
|
||||
#if !defined(CONFIG_440) && !defined(CONFIG_405EX)
|
||||
if (val& ESR_IMCP) {
|
||||
printf("Instruction");
|
||||
mtspr(ESR, val & ~ESR_IMCP);
|
||||
} else {
|
||||
printf("Data");
|
||||
}
|
||||
printf(" machine check.\n");
|
||||
|
||||
#elif defined(CONFIG_440) || defined(CONFIG_405EX)
|
||||
if (val& ESR_IMCP){
|
||||
printf("Instruction Synchronous Machine Check exception\n");
|
||||
mtspr(SPRN_ESR, val & ~ESR_IMCP);
|
||||
} else {
|
||||
val = mfspr(MCSR);
|
||||
if (val & MCSR_IB)
|
||||
printf("Instruction Read PLB Error\n");
|
||||
#if defined(CONFIG_440)
|
||||
if (val & MCSR_DRB)
|
||||
printf("Data Read PLB Error\n");
|
||||
if (val & MCSR_DWB)
|
||||
printf("Data Write PLB Error\n");
|
||||
#else
|
||||
if (val & MCSR_DB)
|
||||
printf("Data PLB Error\n");
|
||||
#endif
|
||||
if (val & MCSR_TLBP)
|
||||
printf("TLB Parity Error\n");
|
||||
if (val & MCSR_ICP){
|
||||
/*flush_instruction_cache(); */
|
||||
printf("I-Cache Parity Error\n");
|
||||
}
|
||||
if (val & MCSR_DCSP)
|
||||
printf("D-Cache Search Parity Error\n");
|
||||
if (val & MCSR_DCFP)
|
||||
printf("D-Cache Flush Parity Error\n");
|
||||
if (val & MCSR_IMPE)
|
||||
printf("Machine Check exception is imprecise\n");
|
||||
|
||||
/* Clear MCSR */
|
||||
mtspr(SPRN_MCSR, val);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_DDR_ECC) && defined(CONFIG_SDRAM_PPC4xx_IBM_DDR2)
|
||||
/*
|
||||
* Read and print ECC status register/info:
|
||||
* The faulting address is only known upon uncorrectable ECC
|
||||
* errors.
|
||||
*/
|
||||
mfsdram(SDRAM_ECCES, val);
|
||||
if (val & SDRAM_ECCES_CE)
|
||||
printf("ECC: Correctable error\n");
|
||||
if (val & SDRAM_ECCES_UE) {
|
||||
printf("ECC: Uncorrectable error at 0x%02x%08x\n",
|
||||
mfdcr(SDRAM_ERRADDULL), mfdcr(SDRAM_ERRADDLLL));
|
||||
}
|
||||
#endif /* CONFIG_DDR_ECC ... */
|
||||
|
||||
#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
|
||||
mfsdram(DDR0_00, val) ;
|
||||
printf("DDR0: DDR0_00 %lx\n", val);
|
||||
val = (val >> 16) & 0xff;
|
||||
if (val & 0x80)
|
||||
printf("DDR0: At least one interrupt active\n");
|
||||
if (val & 0x40)
|
||||
printf("DDR0: DRAM initialization complete.\n");
|
||||
if (val & 0x20) {
|
||||
printf("DDR0: Multiple uncorrectable ECC events.\n");
|
||||
uncorr_ecc = 1;
|
||||
}
|
||||
if (val & 0x10) {
|
||||
printf("DDR0: Single uncorrectable ECC event.\n");
|
||||
uncorr_ecc = 1;
|
||||
}
|
||||
if (val & 0x08) {
|
||||
printf("DDR0: Multiple correctable ECC events.\n");
|
||||
corr_ecc = 1;
|
||||
}
|
||||
if (val & 0x04) {
|
||||
printf("DDR0: Single correctable ECC event.\n");
|
||||
corr_ecc = 1;
|
||||
}
|
||||
if (val & 0x02)
|
||||
printf("Multiple accesses outside the defined"
|
||||
" physical memory space detected\n");
|
||||
if (val & 0x01)
|
||||
printf("DDR0: Single access outside the defined"
|
||||
" physical memory space detected.\n");
|
||||
|
||||
mfsdram(DDR0_01, val);
|
||||
val = (val >> 8) & 0x7;
|
||||
switch (val ) {
|
||||
case 0:
|
||||
printf("DDR0: Write Out-of-Range command\n");
|
||||
break;
|
||||
case 1:
|
||||
printf("DDR0: Read Out-of-Range command\n");
|
||||
break;
|
||||
case 2:
|
||||
printf("DDR0: Masked write Out-of-Range command\n");
|
||||
break;
|
||||
case 4:
|
||||
printf("DDR0: Wrap write Out-of-Range command\n");
|
||||
break;
|
||||
case 5:
|
||||
printf("DDR0: Wrap read Out-of-Range command\n");
|
||||
break;
|
||||
default:
|
||||
mfsdram(DDR0_01, value2);
|
||||
printf("DDR0: No DDR0 error know 0x%lx %x\n", val, value2);
|
||||
}
|
||||
mfsdram(DDR0_23, val);
|
||||
if (((val >> 16) & 0xff) && corr_ecc)
|
||||
printf("DDR0: Syndrome for correctable ECC event 0x%lx\n",
|
||||
(val >> 16) & 0xff);
|
||||
mfsdram(DDR0_23, val);
|
||||
if (((val >> 8) & 0xff) && uncorr_ecc)
|
||||
printf("DDR0: Syndrome for uncorrectable ECC event 0x%lx\n",
|
||||
(val >> 8) & 0xff);
|
||||
mfsdram(DDR0_33, val);
|
||||
if (val)
|
||||
printf("DDR0: Address of command that caused an "
|
||||
"Out-of-Range interrupt %lx\n", val);
|
||||
mfsdram(DDR0_34, val);
|
||||
if (val && uncorr_ecc)
|
||||
printf("DDR0: Address of uncorrectable ECC event %lx\n", val);
|
||||
mfsdram(DDR0_35, val);
|
||||
if (val && uncorr_ecc)
|
||||
printf("DDR0: Address of uncorrectable ECC event %lx\n", val);
|
||||
mfsdram(DDR0_36, val);
|
||||
if (val && uncorr_ecc)
|
||||
printf("DDR0: Data of uncorrectable ECC event 0x%08lx\n", val);
|
||||
mfsdram(DDR0_37, val);
|
||||
if (val && uncorr_ecc)
|
||||
printf("DDR0: Data of uncorrectable ECC event 0x%08lx\n", val);
|
||||
mfsdram(DDR0_38, val);
|
||||
if (val && corr_ecc)
|
||||
printf("DDR0: Address of correctable ECC event %lx\n", val);
|
||||
mfsdram(DDR0_39, val);
|
||||
if (val && corr_ecc)
|
||||
printf("DDR0: Address of correctable ECC event %lx\n", val);
|
||||
mfsdram(DDR0_40, val);
|
||||
if (val && corr_ecc)
|
||||
printf("DDR0: Data of correctable ECC event 0x%08lx\n", val);
|
||||
mfsdram(DDR0_41, val);
|
||||
if (val && corr_ecc)
|
||||
printf("DDR0: Data of correctable ECC event 0x%08lx\n", val);
|
||||
#endif /* CONFIG_440EPX */
|
||||
#endif /* CONFIG_440 */
|
||||
show_regs(regs);
|
||||
print_backtrace((unsigned long *)regs->gpr[1]);
|
||||
panic("machine check");
|
||||
}
|
||||
|
||||
void AlignmentException(struct pt_regs *regs)
|
||||
{
|
||||
#if defined(CONFIG_CMD_KGDB)
|
||||
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
|
||||
return;
|
||||
#endif
|
||||
|
||||
show_regs(regs);
|
||||
print_backtrace((unsigned long *)regs->gpr[1]);
|
||||
panic("Alignment Exception");
|
||||
}
|
||||
|
||||
void ProgramCheckException(struct pt_regs *regs)
|
||||
{
|
||||
long esr_val;
|
||||
|
||||
#if defined(CONFIG_CMD_KGDB)
|
||||
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
|
||||
return;
|
||||
#endif
|
||||
|
||||
show_regs(regs);
|
||||
|
||||
esr_val = get_esr();
|
||||
if( esr_val & ESR_PIL )
|
||||
printf( "** Illegal Instruction **\n" );
|
||||
else if( esr_val & ESR_PPR )
|
||||
printf( "** Privileged Instruction **\n" );
|
||||
else if( esr_val & ESR_PTR )
|
||||
printf( "** Trap Instruction **\n" );
|
||||
|
||||
print_backtrace((unsigned long *)regs->gpr[1]);
|
||||
panic("Program Check Exception");
|
||||
}
|
||||
|
||||
void DecrementerPITException(struct pt_regs *regs)
|
||||
{
|
||||
/*
|
||||
* Reset PIT interrupt
|
||||
*/
|
||||
mtspr(SPRN_TSR, 0x08000000);
|
||||
|
||||
/*
|
||||
* Call timer_interrupt routine in interrupts.c
|
||||
*/
|
||||
timer_interrupt(NULL);
|
||||
}
|
||||
|
||||
|
||||
void UnknownException(struct pt_regs *regs)
|
||||
{
|
||||
#if defined(CONFIG_CMD_KGDB)
|
||||
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
|
||||
return;
|
||||
#endif
|
||||
|
||||
printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
|
||||
regs->nip, regs->msr, regs->trap);
|
||||
_exception(0, regs);
|
||||
}
|
||||
|
||||
void DebugException(struct pt_regs *regs)
|
||||
{
|
||||
printf("Debugger trap at @ %lx\n", regs->nip );
|
||||
show_regs(regs);
|
||||
#if defined(CONFIG_CMD_BEDBUG)
|
||||
do_bedbug_breakpoint( regs );
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Probe an address by reading. If not present, return -1, otherwise
|
||||
* return 0.
|
||||
*/
|
||||
int
|
||||
addr_probe(uint *addr)
|
||||
{
|
||||
#if 0
|
||||
int retval;
|
||||
|
||||
__asm__ __volatile__( \
|
||||
"1: lwz %0,0(%1)\n" \
|
||||
" eieio\n" \
|
||||
" li %0,0\n" \
|
||||
"2:\n" \
|
||||
".section .fixup,\"ax\"\n" \
|
||||
"3: li %0,-1\n" \
|
||||
" b 2b\n" \
|
||||
".section __ex_table,\"a\"\n" \
|
||||
" .align 2\n" \
|
||||
" .long 1b,3b\n" \
|
||||
".text" \
|
||||
: "=r" (retval) : "r"(addr));
|
||||
|
||||
return (retval);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
61
u-boot/arch/powerpc/cpu/ppc4xx/u-boot-spl.lds
Normal file
61
u-boot/arch/powerpc/cpu/ppc4xx/u-boot-spl.lds
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2012-2013 Stefan Roese <sr@denx.de>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
MEMORY
|
||||
{
|
||||
sdram : ORIGIN = CONFIG_SPL_BSS_START_ADDR,
|
||||
LENGTH = CONFIG_SPL_BSS_MAX_SIZE
|
||||
flash : ORIGIN = CONFIG_SPL_TEXT_BASE,
|
||||
LENGTH = CONFIG_SYS_SPL_MAX_LEN
|
||||
}
|
||||
|
||||
OUTPUT_ARCH(powerpc)
|
||||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
#ifdef CONFIG_440
|
||||
.bootpg 0xfffff000 :
|
||||
{
|
||||
arch/powerpc/cpu/ppc4xx/start.o (.bootpg)
|
||||
|
||||
/*
|
||||
* PPC440 board need a board specific object with the
|
||||
* TLB definitions. This needs to get included right after
|
||||
* start.o, since the first shadow TLB only covers 4k
|
||||
* of address space.
|
||||
*/
|
||||
CONFIG_BOARDDIR/init.o (.bootpg)
|
||||
} > flash
|
||||
#endif
|
||||
|
||||
.resetvec 0xFFFFFFFC :
|
||||
{
|
||||
KEEP(*(.resetvec))
|
||||
} > flash
|
||||
|
||||
.text :
|
||||
{
|
||||
__start = .;
|
||||
arch/powerpc/cpu/ppc4xx/start.o (.text)
|
||||
CONFIG_BOARDDIR/init.o (.text)
|
||||
*(.text*)
|
||||
} > flash
|
||||
|
||||
. = ALIGN(4);
|
||||
.data : { *(SORT_BY_ALIGNMENT(.data*)) } > flash
|
||||
|
||||
. = ALIGN(4);
|
||||
.rodata : { *(SORT_BY_ALIGNMENT(.rodata*)) } > flash
|
||||
|
||||
.bss :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
__bss_start = .;
|
||||
*(.bss*)
|
||||
. = ALIGN(4);
|
||||
__bss_end = .;
|
||||
} > sdram
|
||||
}
|
||||
136
u-boot/arch/powerpc/cpu/ppc4xx/u-boot.lds
Normal file
136
u-boot/arch/powerpc/cpu/ppc4xx/u-boot.lds
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright 2007-2009 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include "config.h" /* CONFIG_BOARDDIR */
|
||||
|
||||
#ifndef RESET_VECTOR_ADDRESS
|
||||
#ifdef CONFIG_RESET_VECTOR_ADDRESS
|
||||
#define RESET_VECTOR_ADDRESS CONFIG_RESET_VECTOR_ADDRESS
|
||||
#else
|
||||
#define RESET_VECTOR_ADDRESS 0xfffffffc
|
||||
#endif
|
||||
#endif
|
||||
|
||||
OUTPUT_ARCH(powerpc)
|
||||
|
||||
PHDRS
|
||||
{
|
||||
text PT_LOAD;
|
||||
bss PT_LOAD;
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/* Read-only sections, merged into text segment: */
|
||||
. = + SIZEOF_HEADERS;
|
||||
.text :
|
||||
{
|
||||
*(.text*)
|
||||
} :text
|
||||
_etext = .;
|
||||
PROVIDE (etext = .);
|
||||
.rodata :
|
||||
{
|
||||
*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
|
||||
} :text
|
||||
|
||||
/* Read-write section, merged into data segment: */
|
||||
. = (. + 0x00FF) & 0xFFFFFF00;
|
||||
_erotext = .;
|
||||
PROVIDE (erotext = .);
|
||||
.reloc :
|
||||
{
|
||||
_GOT2_TABLE_ = .;
|
||||
KEEP(*(.got2))
|
||||
KEEP(*(.got))
|
||||
_FIXUP_TABLE_ = .;
|
||||
KEEP(*(.fixup))
|
||||
}
|
||||
__got2_entries = ((_GLOBAL_OFFSET_TABLE_ - _GOT2_TABLE_) >> 2) - 1;
|
||||
__fixup_entries = (. - _FIXUP_TABLE_) >> 2;
|
||||
|
||||
.data :
|
||||
{
|
||||
*(.data*)
|
||||
*(.sdata*)
|
||||
}
|
||||
_edata = .;
|
||||
PROVIDE (edata = .);
|
||||
|
||||
. = .;
|
||||
|
||||
. = ALIGN(4);
|
||||
.u_boot_list : {
|
||||
KEEP(*(SORT(.u_boot_list*)));
|
||||
}
|
||||
|
||||
. = .;
|
||||
__start___ex_table = .;
|
||||
__ex_table : { *(__ex_table) }
|
||||
__stop___ex_table = .;
|
||||
|
||||
. = ALIGN(256);
|
||||
__init_begin = .;
|
||||
.text.init : { *(.text.init) }
|
||||
.data.init : {
|
||||
*(.data.init)
|
||||
. = ALIGN(256);
|
||||
LONG(0) LONG(0) /* Extend u-boot.bin to here */
|
||||
}
|
||||
__init_end = .;
|
||||
_end = .;
|
||||
|
||||
#ifndef CONFIG_SPL
|
||||
#ifdef CONFIG_440
|
||||
.bootpg RESET_VECTOR_ADDRESS - 0xffc :
|
||||
{
|
||||
arch/powerpc/cpu/ppc4xx/start.o (.bootpg)
|
||||
|
||||
/*
|
||||
* PPC440 board need a board specific object with the
|
||||
* TLB definitions. This needs to get included right after
|
||||
* start.o, since the first shadow TLB only covers 4k
|
||||
* of address space.
|
||||
*/
|
||||
#ifdef CONFIG_INIT_TLB
|
||||
CONFIG_INIT_TLB (.bootpg)
|
||||
#else
|
||||
CONFIG_BOARDDIR/init.o (.bootpg)
|
||||
#endif
|
||||
} :text = 0xffff
|
||||
#endif
|
||||
|
||||
.resetvec RESET_VECTOR_ADDRESS :
|
||||
{
|
||||
KEEP(*(.resetvec))
|
||||
} :text = 0xffff
|
||||
|
||||
. = RESET_VECTOR_ADDRESS + 0x4;
|
||||
|
||||
/*
|
||||
* Make sure that the bss segment isn't linked at 0x0, otherwise its
|
||||
* address won't be updated during relocation fixups. Note that
|
||||
* this is a temporary fix. Code to dynamically the fixup the bss
|
||||
* location will be added in the future. When the bss relocation
|
||||
* fixup code is present this workaround should be removed.
|
||||
*/
|
||||
#if (RESET_VECTOR_ADDRESS == 0xfffffffc)
|
||||
. |= 0x10;
|
||||
#endif
|
||||
#endif /* CONFIG_SPL */
|
||||
|
||||
__bss_start = .;
|
||||
.bss (NOLOAD) :
|
||||
{
|
||||
*(.bss*)
|
||||
*(.sbss*)
|
||||
*(COMMON)
|
||||
} :bss
|
||||
|
||||
. = ALIGN(4);
|
||||
__bss_end = . ;
|
||||
PROVIDE (end = .);
|
||||
}
|
||||
164
u-boot/arch/powerpc/cpu/ppc4xx/uic.c
Normal file
164
u-boot/arch/powerpc/cpu/ppc4xx/uic.c
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* (C) Copyright 2000-2002
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*
|
||||
* (C) Copyright 2002 (440 port)
|
||||
* Scott McNutt, Artesyn Communication Producs, smcnutt@artsyncp.com
|
||||
*
|
||||
* (C) Copyright 2003 (440GX port)
|
||||
* Travis B. Sawyer, Sandburst Corporation, tsawyer@sandburst.com
|
||||
*
|
||||
* (C) Copyright 2008 (PPC440X05 port for Virtex 5 FX)
|
||||
* Ricardo Ribalda-Universidad Autonoma de Madrid-ricardo.ribalda@gmail.com
|
||||
* Work supported by Qtechnology (htpp://qtec.com)
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <watchdog.h>
|
||||
#include <command.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/interrupt.h>
|
||||
#include <asm/ppc4xx.h>
|
||||
#include <ppc_asm.tmpl>
|
||||
#include <commproc.h>
|
||||
|
||||
#if (UIC_MAX > 3)
|
||||
#define UICB0_ALL (UIC_MASK(VECNUM_UIC1CI) | UIC_MASK(VECNUM_UIC1NCI) | \
|
||||
UIC_MASK(VECNUM_UIC2CI) | UIC_MASK(VECNUM_UIC2NCI) | \
|
||||
UIC_MASK(VECNUM_UIC3CI) | UIC_MASK(VECNUM_UIC3NCI))
|
||||
#elif (UIC_MAX > 2)
|
||||
#define UICB0_ALL (UIC_MASK(VECNUM_UIC1CI) | UIC_MASK(VECNUM_UIC1NCI) | \
|
||||
UIC_MASK(VECNUM_UIC2CI) | UIC_MASK(VECNUM_UIC2NCI))
|
||||
#elif (UIC_MAX > 1)
|
||||
#define UICB0_ALL (UIC_MASK(VECNUM_UIC1CI) | UIC_MASK(VECNUM_UIC1NCI))
|
||||
#else
|
||||
#define UICB0_ALL 0
|
||||
#endif
|
||||
|
||||
u32 get_dcr(u16);
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
void pic_enable(void)
|
||||
{
|
||||
#if (UIC_MAX > 1)
|
||||
/* Install the UIC1 handlers */
|
||||
irq_install_handler(VECNUM_UIC1NCI, (void *)(void *)external_interrupt, 0);
|
||||
irq_install_handler(VECNUM_UIC1CI, (void *)(void *)external_interrupt, 0);
|
||||
#endif
|
||||
#if (UIC_MAX > 2)
|
||||
irq_install_handler(VECNUM_UIC2NCI, (void *)(void *)external_interrupt, 0);
|
||||
irq_install_handler(VECNUM_UIC2CI, (void *)(void *)external_interrupt, 0);
|
||||
#endif
|
||||
#if (UIC_MAX > 3)
|
||||
irq_install_handler(VECNUM_UIC3NCI, (void *)(void *)external_interrupt, 0);
|
||||
irq_install_handler(VECNUM_UIC3CI, (void *)(void *)external_interrupt, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Handler for UIC interrupt */
|
||||
static void uic_interrupt(u32 uic_base, int vec_base)
|
||||
{
|
||||
u32 uic_msr;
|
||||
u32 msr_shift;
|
||||
int vec;
|
||||
|
||||
/*
|
||||
* Read masked interrupt status register to determine interrupt source
|
||||
*/
|
||||
uic_msr = get_dcr(uic_base + UIC_MSR);
|
||||
msr_shift = uic_msr;
|
||||
vec = vec_base;
|
||||
|
||||
while (msr_shift != 0) {
|
||||
if (msr_shift & 0x80000000)
|
||||
interrupt_run_handler(vec);
|
||||
/*
|
||||
* Shift msr to next position and increment vector
|
||||
*/
|
||||
msr_shift <<= 1;
|
||||
vec++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle external interrupts
|
||||
*/
|
||||
void external_interrupt(struct pt_regs *regs)
|
||||
{
|
||||
u32 uic_msr;
|
||||
|
||||
/*
|
||||
* Read masked interrupt status register to determine interrupt source
|
||||
*/
|
||||
uic_msr = mfdcr(UIC0MSR);
|
||||
|
||||
#if (UIC_MAX > 1)
|
||||
if ((UIC_MASK(VECNUM_UIC1CI) & uic_msr) ||
|
||||
(UIC_MASK(VECNUM_UIC1NCI) & uic_msr))
|
||||
uic_interrupt(UIC1_DCR_BASE, 32);
|
||||
#endif
|
||||
|
||||
#if (UIC_MAX > 2)
|
||||
if ((UIC_MASK(VECNUM_UIC2CI) & uic_msr) ||
|
||||
(UIC_MASK(VECNUM_UIC2NCI) & uic_msr))
|
||||
uic_interrupt(UIC2_DCR_BASE, 64);
|
||||
#endif
|
||||
|
||||
#if (UIC_MAX > 3)
|
||||
if ((UIC_MASK(VECNUM_UIC3CI) & uic_msr) ||
|
||||
(UIC_MASK(VECNUM_UIC3NCI) & uic_msr))
|
||||
uic_interrupt(UIC3_DCR_BASE, 96);
|
||||
#endif
|
||||
|
||||
mtdcr(UIC0SR, (uic_msr & UICB0_ALL));
|
||||
|
||||
if (uic_msr & ~(UICB0_ALL))
|
||||
uic_interrupt(UIC0_DCR_BASE, 0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void pic_irq_ack(unsigned int vec)
|
||||
{
|
||||
if ((vec >= 0) && (vec < 32))
|
||||
mtdcr(UIC0SR, UIC_MASK(vec));
|
||||
else if ((vec >= 32) && (vec < 64))
|
||||
mtdcr(UIC1SR, UIC_MASK(vec));
|
||||
else if ((vec >= 64) && (vec < 96))
|
||||
mtdcr(UIC2SR, UIC_MASK(vec));
|
||||
else if (vec >= 96)
|
||||
mtdcr(UIC3SR, UIC_MASK(vec));
|
||||
}
|
||||
|
||||
/*
|
||||
* Install and free a interrupt handler.
|
||||
*/
|
||||
void pic_irq_enable(unsigned int vec)
|
||||
{
|
||||
|
||||
if ((vec >= 0) && (vec < 32))
|
||||
mtdcr(UIC0ER, mfdcr(UIC0ER) | UIC_MASK(vec));
|
||||
else if ((vec >= 32) && (vec < 64))
|
||||
mtdcr(UIC1ER, mfdcr(UIC1ER) | UIC_MASK(vec));
|
||||
else if ((vec >= 64) && (vec < 96))
|
||||
mtdcr(UIC2ER, mfdcr(UIC2ER) | UIC_MASK(vec));
|
||||
else if (vec >= 96)
|
||||
mtdcr(UIC3ER, mfdcr(UIC3ER) | UIC_MASK(vec));
|
||||
|
||||
debug("Install interrupt vector %d\n", vec);
|
||||
}
|
||||
|
||||
void pic_irq_disable(unsigned int vec)
|
||||
{
|
||||
if ((vec >= 0) && (vec < 32))
|
||||
mtdcr(UIC0ER, mfdcr(UIC0ER) & ~UIC_MASK(vec));
|
||||
else if ((vec >= 32) && (vec < 64))
|
||||
mtdcr(UIC1ER, mfdcr(UIC1ER) & ~UIC_MASK(vec));
|
||||
else if ((vec >= 64) && (vec < 96))
|
||||
mtdcr(UIC2ER, mfdcr(UIC2ER) & ~UIC_MASK(vec));
|
||||
else if (vec >= 96)
|
||||
mtdcr(UIC3ER, mfdcr(UIC3ER) & ~UIC_MASK(vec));
|
||||
}
|
||||
45
u-boot/arch/powerpc/cpu/ppc4xx/usb.c
Normal file
45
u-boot/arch/powerpc/cpu/ppc4xx/usb.c
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* (C) Copyright 2007
|
||||
* Markus Klotzbuecher, DENX Software Engineering <mk@denx.de>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
|
||||
#if defined(CONFIG_USB_OHCI_NEW) && defined(CONFIG_SYS_USB_OHCI_CPU_INIT)
|
||||
|
||||
#ifdef CONFIG_4xx_DCACHE
|
||||
#include <asm/mmu.h>
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
#endif
|
||||
|
||||
int usb_cpu_init(void)
|
||||
{
|
||||
#ifdef CONFIG_4xx_DCACHE
|
||||
/* disable cache */
|
||||
change_tlb(gd->bd->bi_memstart, gd->bd->bi_memsize, TLB_WORD2_I_ENABLE);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_cpu_stop(void)
|
||||
{
|
||||
#ifdef CONFIG_4xx_DCACHE
|
||||
/* enable cache */
|
||||
change_tlb(gd->bd->bi_memstart, gd->bd->bi_memsize, 0);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_cpu_init_fail(void)
|
||||
{
|
||||
#ifdef CONFIG_4xx_DCACHE
|
||||
/* enable cache */
|
||||
change_tlb(gd->bd->bi_memstart, gd->bd->bi_memsize, 0);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* defined(CONFIG_USB_OHCI) && defined(CONFIG_SYS_USB_OHCI_CPU_INIT) */
|
||||
1523
u-boot/arch/powerpc/cpu/ppc4xx/usb_ohci.c
Normal file
1523
u-boot/arch/powerpc/cpu/ppc4xx/usb_ohci.c
Normal file
File diff suppressed because it is too large
Load Diff
410
u-boot/arch/powerpc/cpu/ppc4xx/usb_ohci.h
Normal file
410
u-boot/arch/powerpc/cpu/ppc4xx/usb_ohci.h
Normal file
@@ -0,0 +1,410 @@
|
||||
/*
|
||||
* URB OHCI HCD (Host Controller Driver) for USB.
|
||||
*
|
||||
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
|
||||
* (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
|
||||
*
|
||||
* usb-ohci.h
|
||||
*/
|
||||
|
||||
static int cc_to_error[16] = {
|
||||
|
||||
/* mapping of the OHCI CC status to error codes */
|
||||
/* No Error */ 0,
|
||||
/* CRC Error */ USB_ST_CRC_ERR,
|
||||
/* Bit Stuff */ USB_ST_BIT_ERR,
|
||||
/* Data Togg */ USB_ST_CRC_ERR,
|
||||
/* Stall */ USB_ST_STALLED,
|
||||
/* DevNotResp */ -1,
|
||||
/* PIDCheck */ USB_ST_BIT_ERR,
|
||||
/* UnExpPID */ USB_ST_BIT_ERR,
|
||||
/* DataOver */ USB_ST_BUF_ERR,
|
||||
/* DataUnder */ USB_ST_BUF_ERR,
|
||||
/* reservd */ -1,
|
||||
/* reservd */ -1,
|
||||
/* BufferOver */ USB_ST_BUF_ERR,
|
||||
/* BuffUnder */ USB_ST_BUF_ERR,
|
||||
/* Not Access */ -1,
|
||||
/* Not Access */ -1
|
||||
};
|
||||
|
||||
/* ED States */
|
||||
|
||||
#define ED_NEW 0x00
|
||||
#define ED_UNLINK 0x01
|
||||
#define ED_OPER 0x02
|
||||
#define ED_DEL 0x04
|
||||
#define ED_URB_DEL 0x08
|
||||
|
||||
/* usb_ohci_ed */
|
||||
struct ed {
|
||||
__u32 hwINFO;
|
||||
__u32 hwTailP;
|
||||
__u32 hwHeadP;
|
||||
__u32 hwNextED;
|
||||
|
||||
struct ed *ed_prev;
|
||||
__u8 int_period;
|
||||
__u8 int_branch;
|
||||
__u8 int_load;
|
||||
__u8 int_interval;
|
||||
__u8 state;
|
||||
__u8 type;
|
||||
__u16 last_iso;
|
||||
struct ed *ed_rm_list;
|
||||
|
||||
struct usb_device *usb_dev;
|
||||
__u32 unused[3];
|
||||
} __attribute__((aligned(16)));
|
||||
typedef struct ed ed_t;
|
||||
|
||||
/* TD info field */
|
||||
#define TD_CC 0xf0000000
|
||||
#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f)
|
||||
#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28)
|
||||
#define TD_EC 0x0C000000
|
||||
#define TD_T 0x03000000
|
||||
#define TD_T_DATA0 0x02000000
|
||||
#define TD_T_DATA1 0x03000000
|
||||
#define TD_T_TOGGLE 0x00000000
|
||||
#define TD_R 0x00040000
|
||||
#define TD_DI 0x00E00000
|
||||
#define TD_DI_SET(X) (((X) & 0x07)<< 21)
|
||||
#define TD_DP 0x00180000
|
||||
#define TD_DP_SETUP 0x00000000
|
||||
#define TD_DP_IN 0x00100000
|
||||
#define TD_DP_OUT 0x00080000
|
||||
|
||||
#define TD_ISO 0x00010000
|
||||
#define TD_DEL 0x00020000
|
||||
|
||||
/* CC Codes */
|
||||
#define TD_CC_NOERROR 0x00
|
||||
#define TD_CC_CRC 0x01
|
||||
#define TD_CC_BITSTUFFING 0x02
|
||||
#define TD_CC_DATATOGGLEM 0x03
|
||||
#define TD_CC_STALL 0x04
|
||||
#define TD_DEVNOTRESP 0x05
|
||||
#define TD_PIDCHECKFAIL 0x06
|
||||
#define TD_UNEXPECTEDPID 0x07
|
||||
#define TD_DATAOVERRUN 0x08
|
||||
#define TD_DATAUNDERRUN 0x09
|
||||
#define TD_BUFFEROVERRUN 0x0C
|
||||
#define TD_BUFFERUNDERRUN 0x0D
|
||||
#define TD_NOTACCESSED 0x0F
|
||||
|
||||
#define MAXPSW 1
|
||||
|
||||
struct td {
|
||||
__u32 hwINFO;
|
||||
__u32 hwCBP; /* Current Buffer Pointer */
|
||||
__u32 hwNextTD; /* Next TD Pointer */
|
||||
__u32 hwBE; /* Memory Buffer End Pointer */
|
||||
|
||||
__u16 hwPSW[MAXPSW];
|
||||
__u8 unused;
|
||||
__u8 index;
|
||||
struct ed *ed;
|
||||
struct td *next_dl_td;
|
||||
struct usb_device *usb_dev;
|
||||
int transfer_len;
|
||||
__u32 data;
|
||||
|
||||
__u32 unused2[2];
|
||||
} __attribute__((aligned(32)));
|
||||
typedef struct td td_t;
|
||||
|
||||
#define OHCI_ED_SKIP (1 << 14)
|
||||
|
||||
/*
|
||||
* The HCCA (Host Controller Communications Area) is a 256 byte
|
||||
* structure defined in the OHCI spec. that the host controller is
|
||||
* told the base address of. It must be 256-byte aligned.
|
||||
*/
|
||||
|
||||
#define NUM_INTS 32 /* part of the OHCI standard */
|
||||
struct ohci_hcca {
|
||||
__u32 int_table[NUM_INTS]; /* Interrupt ED table */
|
||||
#if defined(CONFIG_MPC5200)
|
||||
__u16 pad1; /* set to 0 on each frame_no change */
|
||||
__u16 frame_no; /* current frame number */
|
||||
#else
|
||||
__u16 frame_no; /* current frame number */
|
||||
__u16 pad1; /* set to 0 on each frame_no change */
|
||||
#endif
|
||||
__u32 done_head; /* info returned for an interrupt */
|
||||
u8 reserved_for_hc[116];
|
||||
} __attribute__((aligned(256)));
|
||||
|
||||
/*
|
||||
* Maximum number of root hub ports.
|
||||
*/
|
||||
#define MAX_ROOT_PORTS 15 /* maximum OHCI root hub ports */
|
||||
|
||||
/*
|
||||
* This is the structure of the OHCI controller's memory mapped I/O
|
||||
* region. This is Memory Mapped I/O. You must use the readl() and
|
||||
* writel() macros defined in asm/io.h to access these!!
|
||||
*/
|
||||
struct ohci_regs {
|
||||
/* control and status registers */
|
||||
__u32 revision;
|
||||
__u32 control;
|
||||
__u32 cmdstatus;
|
||||
__u32 intrstatus;
|
||||
__u32 intrenable;
|
||||
__u32 intrdisable;
|
||||
/* memory pointers */
|
||||
__u32 hcca;
|
||||
__u32 ed_periodcurrent;
|
||||
__u32 ed_controlhead;
|
||||
__u32 ed_controlcurrent;
|
||||
__u32 ed_bulkhead;
|
||||
__u32 ed_bulkcurrent;
|
||||
__u32 donehead;
|
||||
/* frame counters */
|
||||
__u32 fminterval;
|
||||
__u32 fmremaining;
|
||||
__u32 fmnumber;
|
||||
__u32 periodicstart;
|
||||
__u32 lsthresh;
|
||||
/* Root hub ports */
|
||||
struct ohci_roothub_regs {
|
||||
__u32 a;
|
||||
__u32 b;
|
||||
__u32 status;
|
||||
__u32 portstatus[MAX_ROOT_PORTS];
|
||||
} roothub;
|
||||
} __attribute__((aligned(32)));
|
||||
|
||||
/* OHCI CONTROL AND STATUS REGISTER MASKS */
|
||||
|
||||
/*
|
||||
* HcControl (control) register masks
|
||||
*/
|
||||
#define OHCI_CTRL_CBSR (3 << 0) /* control/bulk service ratio */
|
||||
#define OHCI_CTRL_PLE (1 << 2) /* periodic list enable */
|
||||
#define OHCI_CTRL_IE (1 << 3) /* isochronous enable */
|
||||
#define OHCI_CTRL_CLE (1 << 4) /* control list enable */
|
||||
#define OHCI_CTRL_BLE (1 << 5) /* bulk list enable */
|
||||
#define OHCI_CTRL_HCFS (3 << 6) /* host controller functional state */
|
||||
#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */
|
||||
#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */
|
||||
#define OHCI_CTRL_RWE (1 << 10) /* remote wakeup enable */
|
||||
|
||||
/* pre-shifted values for HCFS */
|
||||
# define OHCI_USB_RESET (0 << 6)
|
||||
# define OHCI_USB_RESUME (1 << 6)
|
||||
# define OHCI_USB_OPER (2 << 6)
|
||||
# define OHCI_USB_SUSPEND (3 << 6)
|
||||
|
||||
/*
|
||||
* HcCommandStatus (cmdstatus) register masks
|
||||
*/
|
||||
#define OHCI_HCR (1 << 0) /* host controller reset */
|
||||
#define OHCI_CLF (1 << 1) /* control list filled */
|
||||
#define OHCI_BLF (1 << 2) /* bulk list filled */
|
||||
#define OHCI_OCR (1 << 3) /* ownership change request */
|
||||
#define OHCI_SOC (3 << 16) /* scheduling overrun count */
|
||||
|
||||
/*
|
||||
* masks used with interrupt registers:
|
||||
* HcInterruptStatus (intrstatus)
|
||||
* HcInterruptEnable (intrenable)
|
||||
* HcInterruptDisable (intrdisable)
|
||||
*/
|
||||
#define OHCI_INTR_SO (1 << 0) /* scheduling overrun */
|
||||
#define OHCI_INTR_WDH (1 << 1) /* writeback of done_head */
|
||||
#define OHCI_INTR_SF (1 << 2) /* start frame */
|
||||
#define OHCI_INTR_RD (1 << 3) /* resume detect */
|
||||
#define OHCI_INTR_UE (1 << 4) /* unrecoverable error */
|
||||
#define OHCI_INTR_FNO (1 << 5) /* frame number overflow */
|
||||
#define OHCI_INTR_RHSC (1 << 6) /* root hub status change */
|
||||
#define OHCI_INTR_OC (1 << 30) /* ownership change */
|
||||
#define OHCI_INTR_MIE (1 << 31) /* master interrupt enable */
|
||||
|
||||
/* Virtual Root HUB */
|
||||
struct virt_root_hub {
|
||||
int devnum; /* Address of Root Hub endpoint */
|
||||
void *dev; /* was urb */
|
||||
void *int_addr;
|
||||
int send;
|
||||
int interval;
|
||||
};
|
||||
|
||||
/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */
|
||||
|
||||
/* destination of request */
|
||||
#define RH_INTERFACE 0x01
|
||||
#define RH_ENDPOINT 0x02
|
||||
#define RH_OTHER 0x03
|
||||
|
||||
#define RH_CLASS 0x20
|
||||
#define RH_VENDOR 0x40
|
||||
|
||||
/* Requests: bRequest << 8 | bmRequestType */
|
||||
#define RH_GET_STATUS 0x0080
|
||||
#define RH_CLEAR_FEATURE 0x0100
|
||||
#define RH_SET_FEATURE 0x0300
|
||||
#define RH_SET_ADDRESS 0x0500
|
||||
#define RH_GET_DESCRIPTOR 0x0680
|
||||
#define RH_SET_DESCRIPTOR 0x0700
|
||||
#define RH_GET_CONFIGURATION 0x0880
|
||||
#define RH_SET_CONFIGURATION 0x0900
|
||||
#define RH_GET_STATE 0x0280
|
||||
#define RH_GET_INTERFACE 0x0A80
|
||||
#define RH_SET_INTERFACE 0x0B00
|
||||
#define RH_SYNC_FRAME 0x0C80
|
||||
/* Our Vendor Specific Request */
|
||||
#define RH_SET_EP 0x2000
|
||||
|
||||
/* Hub port features */
|
||||
#define RH_PORT_CONNECTION 0x00
|
||||
#define RH_PORT_ENABLE 0x01
|
||||
#define RH_PORT_SUSPEND 0x02
|
||||
#define RH_PORT_OVER_CURRENT 0x03
|
||||
#define RH_PORT_RESET 0x04
|
||||
#define RH_PORT_POWER 0x08
|
||||
#define RH_PORT_LOW_SPEED 0x09
|
||||
|
||||
#define RH_C_PORT_CONNECTION 0x10
|
||||
#define RH_C_PORT_ENABLE 0x11
|
||||
#define RH_C_PORT_SUSPEND 0x12
|
||||
#define RH_C_PORT_OVER_CURRENT 0x13
|
||||
#define RH_C_PORT_RESET 0x14
|
||||
|
||||
/* Hub features */
|
||||
#define RH_C_HUB_LOCAL_POWER 0x00
|
||||
#define RH_C_HUB_OVER_CURRENT 0x01
|
||||
|
||||
#define RH_DEVICE_REMOTE_WAKEUP 0x00
|
||||
#define RH_ENDPOINT_STALL 0x01
|
||||
|
||||
#define RH_ACK 0x01
|
||||
#define RH_REQ_ERR -1
|
||||
#define RH_NACK 0x00
|
||||
|
||||
/* OHCI ROOT HUB REGISTER MASKS */
|
||||
|
||||
/* roothub.portstatus [i] bits */
|
||||
#define RH_PS_CCS 0x00000001 /* current connect status */
|
||||
#define RH_PS_PES 0x00000002 /* port enable status */
|
||||
#define RH_PS_PSS 0x00000004 /* port suspend status */
|
||||
#define RH_PS_POCI 0x00000008 /* port over current indicator */
|
||||
#define RH_PS_PRS 0x00000010 /* port reset status */
|
||||
#define RH_PS_PPS 0x00000100 /* port power status */
|
||||
#define RH_PS_LSDA 0x00000200 /* low speed device attached */
|
||||
#define RH_PS_CSC 0x00010000 /* connect status change */
|
||||
#define RH_PS_PESC 0x00020000 /* port enable status change */
|
||||
#define RH_PS_PSSC 0x00040000 /* port suspend status change */
|
||||
#define RH_PS_OCIC 0x00080000 /* over current indicator change */
|
||||
#define RH_PS_PRSC 0x00100000 /* port reset status change */
|
||||
|
||||
/* roothub.status bits */
|
||||
#define RH_HS_LPS 0x00000001 /* local power status */
|
||||
#define RH_HS_OCI 0x00000002 /* over current indicator */
|
||||
#define RH_HS_DRWE 0x00008000 /* device remote wakeup enable */
|
||||
#define RH_HS_LPSC 0x00010000 /* local power status change */
|
||||
#define RH_HS_OCIC 0x00020000 /* over current indicator change */
|
||||
#define RH_HS_CRWE 0x80000000 /* clear remote wakeup enable */
|
||||
|
||||
/* roothub.b masks */
|
||||
#define RH_B_DR 0x0000ffff /* device removable flags */
|
||||
#define RH_B_PPCM 0xffff0000 /* port power control mask */
|
||||
|
||||
/* roothub.a masks */
|
||||
#define RH_A_NDP (0xff << 0) /* number of downstream ports */
|
||||
#define RH_A_PSM (1 << 8) /* power switching mode */
|
||||
#define RH_A_NPS (1 << 9) /* no power switching */
|
||||
#define RH_A_DT (1 << 10) /* device type (mbz) */
|
||||
#define RH_A_OCPM (1 << 11) /* over current protection mode */
|
||||
#define RH_A_NOCP (1 << 12) /* no over current protection */
|
||||
#define RH_A_POTPGT (0xff << 24) /* power on to power good time */
|
||||
|
||||
/* urb */
|
||||
#define N_URB_TD 48
|
||||
typedef struct {
|
||||
ed_t *ed;
|
||||
__u16 length; /* number of tds associated with this request */
|
||||
__u16 td_cnt; /* number of tds already serviced */
|
||||
int state;
|
||||
unsigned long pipe;
|
||||
int actual_length;
|
||||
td_t *td[N_URB_TD]; /* list pointer to all corresponding TDs associated with this request */
|
||||
} urb_priv_t;
|
||||
#define URB_DEL 1
|
||||
|
||||
/*
|
||||
* This is the full ohci controller description
|
||||
*
|
||||
* Note how the "proper" USB information is just
|
||||
* a subset of what the full implementation needs. (Linus)
|
||||
*/
|
||||
|
||||
typedef struct ohci {
|
||||
struct ohci_hcca *hcca; /* hcca */
|
||||
/*dma_addr_t hcca_dma; */
|
||||
|
||||
int irq;
|
||||
int disabled; /* e.g. got a UE, we're hung */
|
||||
int sleeping;
|
||||
unsigned long flags; /* for HC bugs */
|
||||
|
||||
struct ohci_regs *regs; /* OHCI controller's memory */
|
||||
|
||||
ed_t *ed_rm_list[2]; /* lists of all endpoints to be removed */
|
||||
ed_t *ed_bulktail; /* last endpoint of bulk list */
|
||||
ed_t *ed_controltail; /* last endpoint of control list */
|
||||
int intrstatus;
|
||||
__u32 hc_control; /* copy of the hc control reg */
|
||||
struct usb_device *dev[32];
|
||||
struct virt_root_hub rh;
|
||||
|
||||
const char *slot_name;
|
||||
} ohci_t;
|
||||
|
||||
#define NUM_EDS 8 /* num of preallocated endpoint descriptors */
|
||||
|
||||
struct ohci_device {
|
||||
ed_t ed[NUM_EDS];
|
||||
int ed_cnt;
|
||||
};
|
||||
|
||||
/* hcd */
|
||||
/* endpoint */
|
||||
static int ep_link(ohci_t * ohci, ed_t * ed);
|
||||
static int ep_unlink(ohci_t * ohci, ed_t * ed);
|
||||
static ed_t *ep_add_ed(struct usb_device *usb_dev, unsigned long pipe);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* we need more TDs than EDs */
|
||||
#define NUM_TD 64
|
||||
|
||||
/* +1 so we can align the storage */
|
||||
td_t gtd[NUM_TD + 1];
|
||||
/* pointers to aligned storage */
|
||||
td_t *ptd;
|
||||
|
||||
/* TDs ... */
|
||||
static inline struct td *td_alloc(struct usb_device *usb_dev)
|
||||
{
|
||||
int i;
|
||||
struct td *td;
|
||||
|
||||
td = NULL;
|
||||
for (i = 0; i < NUM_TD; i++) {
|
||||
if (ptd[i].usb_dev == NULL) {
|
||||
td = &ptd[i];
|
||||
td->usb_dev = usb_dev;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return td;
|
||||
}
|
||||
|
||||
static inline void ed_free(struct ed *ed)
|
||||
{
|
||||
ed->usb_dev = NULL;
|
||||
}
|
||||
89
u-boot/arch/powerpc/cpu/ppc4xx/xilinx_irq.c
Normal file
89
u-boot/arch/powerpc/cpu/ppc4xx/xilinx_irq.c
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* (C) Copyright 2008
|
||||
* Ricado Ribalda-Universidad Autonoma de Madrid-ricardo.ribalda@gmail.com
|
||||
* This work has been supported by: QTechnology http://qtec.com/
|
||||
* Based on interrupts.c Wolfgang Denk-DENX Software Engineering-wd@denx.de
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <watchdog.h>
|
||||
#include <command.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/interrupt.h>
|
||||
#include <asm/ppc4xx.h>
|
||||
#include <ppc_asm.tmpl>
|
||||
#include <commproc.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/xilinx_irq.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
void pic_enable(void)
|
||||
{
|
||||
debug("Xilinx PIC at 0x%8x\n", intc);
|
||||
|
||||
/*
|
||||
* Disable all external interrupts until they are
|
||||
* explicitly requested.
|
||||
*/
|
||||
out_be32((u32 *) IER, 0);
|
||||
|
||||
/* Acknowledge any pending interrupts just in case. */
|
||||
out_be32((u32 *) IAR, 0xffffffff);
|
||||
|
||||
/* Turn on the Master Enable. */
|
||||
out_be32((u32 *) MER, 0x3UL);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int xilinx_pic_irq_get(void)
|
||||
{
|
||||
u32 irq;
|
||||
irq = in_be32((u32 *) IVR);
|
||||
|
||||
/* If no interrupt is pending then all bits of the IVR are set to 1. As
|
||||
* the IVR is as many bits wide as numbers of inputs are available.
|
||||
* Therefore, if all bits of the IVR are set to one, its content will
|
||||
* be bigger than XPAR_INTC_MAX_NUM_INTR_INPUTS.
|
||||
*/
|
||||
if (irq >= XPAR_INTC_MAX_NUM_INTR_INPUTS)
|
||||
irq = -1; /* report no pending interrupt. */
|
||||
|
||||
debug("get_irq: %d\n", irq);
|
||||
return (irq);
|
||||
}
|
||||
|
||||
void pic_irq_enable(unsigned int irq)
|
||||
{
|
||||
u32 mask = IRQ_MASK(irq);
|
||||
debug("enable: %d\n", irq);
|
||||
out_be32((u32 *) SIE, mask);
|
||||
}
|
||||
|
||||
void pic_irq_disable(unsigned int irq)
|
||||
{
|
||||
u32 mask = IRQ_MASK(irq);
|
||||
debug("disable: %d\n", irq);
|
||||
out_be32((u32 *) CIE, mask);
|
||||
}
|
||||
|
||||
void pic_irq_ack(unsigned int irq)
|
||||
{
|
||||
u32 mask = IRQ_MASK(irq);
|
||||
debug("ack: %d\n", irq);
|
||||
out_be32((u32 *) IAR, mask);
|
||||
}
|
||||
|
||||
void external_interrupt(struct pt_regs *regs)
|
||||
{
|
||||
int irq;
|
||||
|
||||
irq = xilinx_pic_irq_get();
|
||||
if (irq < 0)
|
||||
return;
|
||||
|
||||
interrupt_run_handler(irq);
|
||||
|
||||
return;
|
||||
}
|
||||
Reference in New Issue
Block a user