GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
menu "mpc8xx CPU"
|
||||
depends on MPC8xx
|
||||
|
||||
config SYS_CPU
|
||||
default "mpc8xx"
|
||||
|
||||
choice
|
||||
prompt "Target select"
|
||||
optional
|
||||
|
||||
config TARGET_MCR3000
|
||||
bool "Support MCR3000 board from CSSI"
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "CPU select"
|
||||
default MPC866
|
||||
|
||||
config MPC866
|
||||
bool "MPC866"
|
||||
|
||||
config MPC885
|
||||
bool "MPC885"
|
||||
|
||||
endchoice
|
||||
|
||||
#config MPC8xx_WATCHDOG
|
||||
# bool "Watchdog"
|
||||
# select HW_WATCHDOG
|
||||
|
||||
config 8xx_GCLK_FREQ
|
||||
int "CPU GCLK Frequency"
|
||||
|
||||
comment "Specific commands"
|
||||
|
||||
config CMD_IMMAP
|
||||
bool "Enable various commands to dump IMMR information"
|
||||
help
|
||||
This enables various commands such as:
|
||||
|
||||
siuinfo - print System Interface Unit (SIU) registers
|
||||
memcinfo - print Memory Controller registers
|
||||
|
||||
comment "Configuration Registers"
|
||||
|
||||
config SYS_SIUMCR
|
||||
hex "SIUMCR register"
|
||||
help
|
||||
SIU Module Configuration (11-6)
|
||||
|
||||
config SYS_SYPCR
|
||||
hex "SYPCR register"
|
||||
help
|
||||
System Protection Control (11-9)
|
||||
|
||||
config SYS_TBSCR
|
||||
hex "TBSCR register"
|
||||
help
|
||||
Time Base Status and Control (11-26)
|
||||
|
||||
config SYS_PISCR
|
||||
hex "PISCR register"
|
||||
help
|
||||
Periodic Interrupt Status and Control (11-31)
|
||||
|
||||
config SYS_PLPRCR_BOOL
|
||||
bool "Customise PLPRCR"
|
||||
|
||||
config SYS_PLPRCR
|
||||
hex "PLPRCR register"
|
||||
depends on SYS_PLPRCR_BOOL
|
||||
help
|
||||
PLL, Low-Power, and Reset Control Register (15-30)
|
||||
|
||||
config SYS_SCCR
|
||||
hex "SCCR register"
|
||||
help
|
||||
System Clock and reset Control Register (15-27)
|
||||
|
||||
config SYS_SCCR_MASK
|
||||
hex "MASK for setting SCCR register"
|
||||
|
||||
config SYS_DER
|
||||
hex "DER register"
|
||||
help
|
||||
Debug Event Register (37-47)
|
||||
|
||||
comment "Memory mapping"
|
||||
|
||||
config SYS_BR0_PRELIM
|
||||
hex "Preliminary value for BR0"
|
||||
|
||||
config SYS_OR0_PRELIM
|
||||
hex "Preliminary value for OR0"
|
||||
|
||||
config SYS_BR1_PRELIM_BOOL
|
||||
bool "Define Bank 1"
|
||||
|
||||
config SYS_BR1_PRELIM
|
||||
hex "Preliminary value for BR1"
|
||||
depends on SYS_BR1_PRELIM_BOOL
|
||||
|
||||
config SYS_OR1_PRELIM
|
||||
hex "Preliminary value for OR1"
|
||||
depends on SYS_BR1_PRELIM_BOOL
|
||||
|
||||
config SYS_BR2_PRELIM_BOOL
|
||||
bool "Define Bank 2"
|
||||
|
||||
config SYS_BR2_PRELIM
|
||||
hex "Preliminary value for BR2"
|
||||
depends on SYS_BR2_PRELIM_BOOL
|
||||
|
||||
config SYS_OR2_PRELIM
|
||||
hex "Preliminary value for OR2"
|
||||
depends on SYS_BR2_PRELIM_BOOL
|
||||
|
||||
config SYS_BR3_PRELIM_BOOL
|
||||
bool "Define Bank 3"
|
||||
|
||||
config SYS_BR3_PRELIM
|
||||
hex "Preliminary value for BR3"
|
||||
depends on SYS_BR3_PRELIM_BOOL
|
||||
|
||||
config SYS_OR3_PRELIM
|
||||
hex "Preliminary value for OR3"
|
||||
depends on SYS_BR3_PRELIM_BOOL
|
||||
|
||||
config SYS_BR4_PRELIM_BOOL
|
||||
bool "Define Bank 4"
|
||||
|
||||
config SYS_BR4_PRELIM
|
||||
hex "Preliminary value for BR4"
|
||||
depends on SYS_BR4_PRELIM_BOOL
|
||||
|
||||
config SYS_OR4_PRELIM
|
||||
hex "Preliminary value for OR4"
|
||||
depends on SYS_BR4_PRELIM_BOOL
|
||||
|
||||
config SYS_BR5_PRELIM_BOOL
|
||||
bool "Define Bank 5"
|
||||
|
||||
config SYS_BR5_PRELIM
|
||||
hex "Preliminary value for BR5"
|
||||
depends on SYS_BR5_PRELIM_BOOL
|
||||
|
||||
config SYS_OR5_PRELIM
|
||||
hex "Preliminary value for OR5"
|
||||
depends on SYS_BR5_PRELIM_BOOL
|
||||
|
||||
config SYS_BR6_PRELIM_BOOL
|
||||
bool "Define Bank 6"
|
||||
|
||||
config SYS_BR6_PRELIM
|
||||
hex "Preliminary value for BR6"
|
||||
depends on SYS_BR6_PRELIM_BOOL
|
||||
|
||||
config SYS_OR6_PRELIM
|
||||
hex "Preliminary value for OR6"
|
||||
depends on SYS_BR6_PRELIM_BOOL
|
||||
|
||||
config SYS_BR7_PRELIM_BOOL
|
||||
bool "Define Bank 7"
|
||||
|
||||
config SYS_BR7_PRELIM
|
||||
hex "Preliminary value for BR7"
|
||||
depends on SYS_BR7_PRELIM_BOOL
|
||||
|
||||
config SYS_OR7_PRELIM
|
||||
hex "Preliminary value for OR7"
|
||||
depends on SYS_BR7_PRELIM_BOOL
|
||||
|
||||
config SYS_IMMR
|
||||
hex "Value for IMMR"
|
||||
|
||||
source "board/cssi/MCR3000/Kconfig"
|
||||
|
||||
endmenu
|
||||
@@ -0,0 +1,14 @@
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# (C) Copyright 2000-2006
|
||||
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
|
||||
extra-y += start.o
|
||||
extra-y += traps.o
|
||||
obj-y += cpu.o
|
||||
obj-y += cpu_init.o
|
||||
obj-$(CONFIG_OF_LIBFDT) += fdt.o
|
||||
obj-$(CONFIG_CMD_IMMAP) += immap.o
|
||||
obj-y += interrupts.o
|
||||
obj-y += speed.o
|
||||
obj-y += cache.o
|
||||
@@ -0,0 +1,49 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2017
|
||||
* Christophe Leroy, CS Systemes d'Information, christophe.leroy@c-s.fr
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <cpu_func.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/ppc.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/mmu.h>
|
||||
|
||||
int icache_status(void)
|
||||
{
|
||||
return !!(mfspr(IC_CST) & IDC_ENABLED);
|
||||
}
|
||||
|
||||
void icache_enable(void)
|
||||
{
|
||||
sync();
|
||||
mtspr(IC_CST, IDC_INVALL);
|
||||
mtspr(IC_CST, IDC_ENABLE);
|
||||
}
|
||||
|
||||
void icache_disable(void)
|
||||
{
|
||||
sync();
|
||||
mtspr(IC_CST, IDC_DISABLE);
|
||||
}
|
||||
|
||||
int dcache_status(void)
|
||||
{
|
||||
return !!(mfspr(IC_CST) & IDC_ENABLED);
|
||||
}
|
||||
|
||||
void dcache_enable(void)
|
||||
{
|
||||
mtspr(MD_CTR, MD_RESETVAL); /* Set cache mode with MMU off */
|
||||
mtspr(DC_CST, IDC_INVALL);
|
||||
mtspr(DC_CST, IDC_ENABLE);
|
||||
}
|
||||
|
||||
void dcache_disable(void)
|
||||
{
|
||||
sync();
|
||||
mtspr(DC_CST, IDC_DISABLE);
|
||||
mtspr(DC_CST, IDC_INVALL);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# (C) Copyright 2000-2010
|
||||
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
|
||||
PLATFORM_CPPFLAGS += -mstring -mcpu=860 -msoft-float
|
||||
@@ -0,0 +1,284 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2000-2002
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*/
|
||||
|
||||
/*
|
||||
* m8xx.c
|
||||
*
|
||||
* 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 <cpu_func.h>
|
||||
#include <vsprintf.h>
|
||||
#include <watchdog.h>
|
||||
#include <command.h>
|
||||
#include <mpc8xx.h>
|
||||
#include <netdev.h>
|
||||
#include <asm/cache.h>
|
||||
#include <asm/cpm_8xx.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#if defined(CONFIG_OF_LIBFDT)
|
||||
#include <linux/libfdt.h>
|
||||
#include <fdt_support.h>
|
||||
#endif
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* L1 i-cache */
|
||||
|
||||
int checkicache(void)
|
||||
{
|
||||
immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR;
|
||||
memctl8xx_t __iomem *memctl = &immap->im_memctl;
|
||||
u32 cacheon = rd_ic_cst() & IDC_ENABLED;
|
||||
/* probe in flash memoryarea */
|
||||
u32 k = in_be32(&memctl->memc_br0) & ~0x00007fff;
|
||||
u32 m;
|
||||
u32 lines = -1;
|
||||
|
||||
wr_ic_cst(IDC_UNALL);
|
||||
wr_ic_cst(IDC_INVALL);
|
||||
wr_ic_cst(IDC_DISABLE);
|
||||
__asm__ volatile ("isync");
|
||||
|
||||
while (!((m = rd_ic_cst()) & IDC_CERR2)) {
|
||||
wr_ic_adr(k);
|
||||
wr_ic_cst(IDC_LDLCK);
|
||||
__asm__ volatile ("isync");
|
||||
|
||||
lines++;
|
||||
k += 0x10; /* the number of bytes in a cacheline */
|
||||
}
|
||||
|
||||
wr_ic_cst(IDC_UNALL);
|
||||
wr_ic_cst(IDC_INVALL);
|
||||
|
||||
if (cacheon)
|
||||
wr_ic_cst(IDC_ENABLE);
|
||||
else
|
||||
wr_ic_cst(IDC_DISABLE);
|
||||
|
||||
__asm__ volatile ("isync");
|
||||
|
||||
return lines << 4;
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* L1 d-cache */
|
||||
/* call with cache disabled */
|
||||
|
||||
static int checkdcache(void)
|
||||
{
|
||||
immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR;
|
||||
memctl8xx_t __iomem *memctl = &immap->im_memctl;
|
||||
u32 cacheon = rd_dc_cst() & IDC_ENABLED;
|
||||
/* probe in flash memoryarea */
|
||||
u32 k = in_be32(&memctl->memc_br0) & ~0x00007fff;
|
||||
u32 m;
|
||||
u32 lines = -1;
|
||||
|
||||
wr_dc_cst(IDC_UNALL);
|
||||
wr_dc_cst(IDC_INVALL);
|
||||
wr_dc_cst(IDC_DISABLE);
|
||||
|
||||
while (!((m = rd_dc_cst()) & IDC_CERR2)) {
|
||||
wr_dc_adr(k);
|
||||
wr_dc_cst(IDC_LDLCK);
|
||||
lines++;
|
||||
k += 0x10; /* the number of bytes in a cacheline */
|
||||
}
|
||||
|
||||
wr_dc_cst(IDC_UNALL);
|
||||
wr_dc_cst(IDC_INVALL);
|
||||
|
||||
if (cacheon)
|
||||
wr_dc_cst(IDC_ENABLE);
|
||||
else
|
||||
wr_dc_cst(IDC_DISABLE);
|
||||
|
||||
return lines << 4;
|
||||
};
|
||||
|
||||
static int check_CPU(long clock, uint pvr, uint immr)
|
||||
{
|
||||
immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR;
|
||||
uint k;
|
||||
char buf[32];
|
||||
|
||||
/* the highest 16 bits should be 0x0050 for a 860 */
|
||||
|
||||
if (PVR_VER(pvr) != PVR_VER(PVR_8xx))
|
||||
return -1;
|
||||
|
||||
k = (immr << 16) |
|
||||
in_be16(&immap->im_cpm.cp_dparam16[PROFF_REVNUM / sizeof(u16)]);
|
||||
|
||||
/*
|
||||
* Some boards use sockets so different CPUs can be used.
|
||||
* We have to check chip version in run time.
|
||||
*/
|
||||
switch (k) {
|
||||
/* MPC866P/MPC866T/MPC859T/MPC859DSL/MPC852T */
|
||||
case 0x08010004: /* Rev. A.0 */
|
||||
printf("MPC866xxxZPnnA");
|
||||
break;
|
||||
case 0x08000003: /* Rev. 0.3 */
|
||||
printf("MPC866xxxZPnn");
|
||||
break;
|
||||
case 0x09000000: /* 870/875/880/885 */
|
||||
puts("MPC885ZPnn");
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("unknown MPC86x (0x%08x)", k);
|
||||
break;
|
||||
}
|
||||
|
||||
printf(" at %s MHz: ", strmhz(buf, clock));
|
||||
|
||||
print_size(checkicache(), " I-Cache ");
|
||||
print_size(checkdcache(), " D-Cache");
|
||||
|
||||
/* do we have a FEC (860T/P or 852/859/866/885)? */
|
||||
|
||||
out_be32(&immap->im_cpm.cp_fec.fec_addr_low, 0x12345678);
|
||||
if (in_be32(&immap->im_cpm.cp_fec.fec_addr_low) == 0x12345678)
|
||||
printf(" FEC present");
|
||||
|
||||
putc('\n');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
int checkcpu(void)
|
||||
{
|
||||
ulong clock = gd->cpu_clk;
|
||||
uint immr = get_immr(); /* Return full IMMR contents */
|
||||
uint pvr = get_pvr();
|
||||
|
||||
puts("CPU: ");
|
||||
|
||||
return check_CPU(clock, pvr, immr);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
void upmconfig(uint upm, uint *table, uint size)
|
||||
{
|
||||
uint i;
|
||||
uint addr = 0;
|
||||
immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR;
|
||||
memctl8xx_t __iomem *memctl = &immap->im_memctl;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
out_be32(&memctl->memc_mdr, table[i]); /* (16-15) */
|
||||
out_be32(&memctl->memc_mcr, addr | upm); /* (16-16) */
|
||||
addr++;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
ulong msr, addr;
|
||||
|
||||
immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR;
|
||||
|
||||
/* Checkstop Reset enable */
|
||||
setbits_be32(&immap->im_clkrst.car_plprcr, PLPRCR_CSR);
|
||||
|
||||
/* Interrupts and MMU off */
|
||||
__asm__ volatile ("mtspr 81, 0");
|
||||
__asm__ volatile ("mfmsr %0" : "=r" (msr));
|
||||
|
||||
msr &= ~0x1030;
|
||||
__asm__ volatile ("mtmsr %0" : : "r" (msr));
|
||||
|
||||
/*
|
||||
* Trying to execute the next instruction at a non-existing address
|
||||
* should cause a machine check, resulting in reset
|
||||
*/
|
||||
#ifdef CONFIG_SYS_RESET_ADDRESS
|
||||
addr = CONFIG_SYS_RESET_ADDRESS;
|
||||
#else
|
||||
/*
|
||||
* note: when CONFIG_SYS_MONITOR_BASE points to a RAM address,
|
||||
* CONFIG_SYS_MONITOR_BASE - sizeof (ulong) is usually a valid address.
|
||||
* Better pick an address known to be invalid on your system and assign
|
||||
* it to CONFIG_SYS_RESET_ADDRESS.
|
||||
* "(ulong)-1" used to be a good choice for many systems...
|
||||
*/
|
||||
addr = CONFIG_SYS_MONITOR_BASE - sizeof(ulong);
|
||||
#endif
|
||||
((void (*)(void)) addr)();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Get timebase clock frequency (like cpu_clk in Hz)
|
||||
*
|
||||
* See sections 14.2 and 14.6 of the User's Manual
|
||||
*/
|
||||
unsigned long get_tbclk(void)
|
||||
{
|
||||
immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR;
|
||||
ulong oscclk, factor, pll;
|
||||
|
||||
if (in_be32(&immap->im_clkrst.car_sccr) & SCCR_TBS)
|
||||
return gd->cpu_clk / 16;
|
||||
|
||||
pll = in_be32(&immap->im_clkrst.car_plprcr);
|
||||
|
||||
#define PLPRCR_val(a) ((pll & PLPRCR_ ## a ## _MSK) >> PLPRCR_ ## a ## _SHIFT)
|
||||
|
||||
/*
|
||||
* For newer PQ1 chips (MPC866/87x/88x families), PLL multiplication
|
||||
* factor is calculated as follows:
|
||||
*
|
||||
* MFN
|
||||
* MFI + -------
|
||||
* MFD + 1
|
||||
* factor = -----------------
|
||||
* (PDF + 1) * 2^S
|
||||
*
|
||||
*/
|
||||
factor = (PLPRCR_val(MFI) + PLPRCR_val(MFN) / (PLPRCR_val(MFD) + 1)) /
|
||||
(PLPRCR_val(PDF) + 1) / (1 << PLPRCR_val(S));
|
||||
|
||||
oscclk = gd->cpu_clk / factor;
|
||||
|
||||
if ((in_be32(&immap->im_clkrst.car_sccr) & SCCR_RTSEL) == 0 ||
|
||||
factor > 2)
|
||||
return oscclk / 4;
|
||||
|
||||
return oscclk / 16;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initializes on-chip ethernet controllers.
|
||||
* to override, implement board_eth_init()
|
||||
*/
|
||||
int cpu_eth_init(bd_t *bis)
|
||||
{
|
||||
#if defined(CONFIG_MPC8XX_FEC)
|
||||
fec_initialize(bis);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2000-2002
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <watchdog.h>
|
||||
|
||||
#include <mpc8xx.h>
|
||||
#include <asm/cpm_8xx.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/*
|
||||
* Breath some life into the CPU...
|
||||
*
|
||||
* Set up the memory map,
|
||||
* initialize a bunch of registers,
|
||||
* initialize the UPM's
|
||||
*/
|
||||
void cpu_init_f(immap_t __iomem *immr)
|
||||
{
|
||||
memctl8xx_t __iomem *memctl = &immr->im_memctl;
|
||||
ulong reg;
|
||||
|
||||
/* SYPCR - contains watchdog control (11-9) */
|
||||
|
||||
#ifndef CONFIG_HW_WATCHDOG
|
||||
/* deactivate watchdog if not enabled in config */
|
||||
out_be32(&immr->im_siu_conf.sc_sypcr, CONFIG_SYS_SYPCR & ~SYPCR_SWE);
|
||||
#endif
|
||||
|
||||
WATCHDOG_RESET();
|
||||
|
||||
/* SIUMCR - contains debug pin configuration (11-6) */
|
||||
setbits_be32(&immr->im_siu_conf.sc_siumcr, CONFIG_SYS_SIUMCR);
|
||||
/* initialize timebase status and control register (11-26) */
|
||||
/* unlock TBSCRK */
|
||||
|
||||
out_be32(&immr->im_sitk.sitk_tbscrk, KAPWR_KEY);
|
||||
out_be16(&immr->im_sit.sit_tbscr, CONFIG_SYS_TBSCR | TBSCR_TBE);
|
||||
|
||||
/* Unlock timebase register */
|
||||
out_be32(&immr->im_sitk.sitk_tbk, KAPWR_KEY);
|
||||
|
||||
/* initialize the PIT (11-31) */
|
||||
|
||||
out_be32(&immr->im_sitk.sitk_piscrk, KAPWR_KEY);
|
||||
out_be16(&immr->im_sit.sit_piscr, CONFIG_SYS_PISCR);
|
||||
|
||||
/* System integration timers. Don't change EBDF! (15-27) */
|
||||
|
||||
out_be32(&immr->im_clkrstk.cark_sccrk, KAPWR_KEY);
|
||||
clrsetbits_be32(&immr->im_clkrst.car_sccr, ~CONFIG_SYS_SCCR_MASK,
|
||||
CONFIG_SYS_SCCR);
|
||||
|
||||
/*
|
||||
* MPC866/885 ERRATA GLL2
|
||||
* Description:
|
||||
* In 1:2:1 mode, when HRESET is detected at the positive edge of
|
||||
* EXTCLK, then there will be a loss of phase between
|
||||
* EXTCLK and CLKOUT.
|
||||
*
|
||||
* Workaround:
|
||||
* Reprogram the SCCR:
|
||||
* 1. Write 1'b00 to SCCR[EBDF].
|
||||
* 2. Write 1'b01 to SCCR[EBDF].
|
||||
* 3. Rewrite the desired value to the PLPRCR register.
|
||||
*/
|
||||
reg = in_be32(&immr->im_clkrst.car_sccr);
|
||||
/* Are we in mode 1:2:1 ? */
|
||||
if ((reg & SCCR_EBDF11) == SCCR_EBDF01) {
|
||||
clrbits_be32(&immr->im_clkrst.car_sccr, SCCR_EBDF11);
|
||||
setbits_be32(&immr->im_clkrst.car_sccr, SCCR_EBDF01);
|
||||
}
|
||||
|
||||
/* PLL (CPU clock) settings (15-30) */
|
||||
|
||||
out_be32(&immr->im_clkrstk.cark_plprcrk, KAPWR_KEY);
|
||||
|
||||
/* If CONFIG_SYS_PLPRCR (set in the various *_config.h files) tries to
|
||||
* set the MF field, then just copy CONFIG_SYS_PLPRCR over car_plprcr,
|
||||
* otherwise OR in CONFIG_SYS_PLPRCR so we do not change the current MF
|
||||
* field value.
|
||||
*
|
||||
* For newer (starting MPC866) chips PLPRCR layout is different.
|
||||
*/
|
||||
#ifdef CONFIG_SYS_PLPRCR
|
||||
if ((CONFIG_SYS_PLPRCR & PLPRCR_MFACT_MSK) != 0) /* reset control bits*/
|
||||
out_be32(&immr->im_clkrst.car_plprcr, CONFIG_SYS_PLPRCR);
|
||||
else /* isolate MF-related fields and reset control bits */
|
||||
clrsetbits_be32(&immr->im_clkrst.car_plprcr, ~PLPRCR_MFACT_MSK,
|
||||
CONFIG_SYS_PLPRCR);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Memory Controller:
|
||||
*/
|
||||
|
||||
/* Clear everything except Port Size bits & add the "Bank Valid" bit */
|
||||
clrsetbits_be32(&memctl->memc_br0, ~BR_PS_MSK, BR_V);
|
||||
|
||||
/* Map banks 0 (and maybe 1) to the FLASH banks 0 (and 1) at
|
||||
* preliminary addresses - these have to be modified later
|
||||
* when FLASH size has been determined
|
||||
*
|
||||
* Depending on the size of the memory region defined by
|
||||
* CONFIG_SYS_OR0_REMAP some boards (wide address mask) allow to map the
|
||||
* CONFIG_SYS_MONITOR_BASE, while others (narrower address mask) can't
|
||||
* map CONFIG_SYS_MONITOR_BASE.
|
||||
*
|
||||
* For example, for CONFIG_IVMS8, the CONFIG_SYS_MONITOR_BASE is
|
||||
* 0xff000000, but CONFIG_SYS_OR0_REMAP's address mask is 0xfff80000.
|
||||
*
|
||||
* If BR0 wasn't loaded with address base 0xff000000, then BR0's
|
||||
* base address remains as 0x00000000. However, the address mask
|
||||
* have been narrowed to 512Kb, so CONFIG_SYS_MONITOR_BASE wasn't mapped
|
||||
* into the Bank0.
|
||||
*
|
||||
* This is why CONFIG_IVMS8 and similar boards must load BR0 with
|
||||
* CONFIG_SYS_BR0_PRELIM in advance.
|
||||
*
|
||||
* [Thanks to Michael Liao for this explanation.
|
||||
* I owe him a free beer. - wd]
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_SYS_OR0_REMAP)
|
||||
out_be32(&memctl->memc_or0, CONFIG_SYS_OR0_REMAP);
|
||||
#endif
|
||||
#if defined(CONFIG_SYS_OR1_REMAP)
|
||||
out_be32(&memctl->memc_or1, CONFIG_SYS_OR1_REMAP);
|
||||
#endif
|
||||
#if defined(CONFIG_SYS_OR5_REMAP)
|
||||
out_be32(&memctl->memc_or5, CONFIG_SYS_OR5_REMAP);
|
||||
#endif
|
||||
|
||||
/* now restrict to preliminary range */
|
||||
out_be32(&memctl->memc_br0, CONFIG_SYS_BR0_PRELIM);
|
||||
out_be32(&memctl->memc_or0, CONFIG_SYS_OR0_PRELIM);
|
||||
|
||||
#if (defined(CONFIG_SYS_OR1_PRELIM) && defined(CONFIG_SYS_BR1_PRELIM))
|
||||
out_be32(&memctl->memc_or1, CONFIG_SYS_OR1_PRELIM);
|
||||
out_be32(&memctl->memc_br1, CONFIG_SYS_BR1_PRELIM);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SYS_OR2_PRELIM) && defined(CONFIG_SYS_BR2_PRELIM)
|
||||
out_be32(&memctl->memc_or2, CONFIG_SYS_OR2_PRELIM);
|
||||
out_be32(&memctl->memc_br2, CONFIG_SYS_BR2_PRELIM);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SYS_OR3_PRELIM) && defined(CONFIG_SYS_BR3_PRELIM)
|
||||
out_be32(&memctl->memc_or3, CONFIG_SYS_OR3_PRELIM);
|
||||
out_be32(&memctl->memc_br3, CONFIG_SYS_BR3_PRELIM);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SYS_OR4_PRELIM) && defined(CONFIG_SYS_BR4_PRELIM)
|
||||
out_be32(&memctl->memc_or4, CONFIG_SYS_OR4_PRELIM);
|
||||
out_be32(&memctl->memc_br4, CONFIG_SYS_BR4_PRELIM);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SYS_OR5_PRELIM) && defined(CONFIG_SYS_BR5_PRELIM)
|
||||
out_be32(&memctl->memc_or5, CONFIG_SYS_OR5_PRELIM);
|
||||
out_be32(&memctl->memc_br5, CONFIG_SYS_BR5_PRELIM);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SYS_OR6_PRELIM) && defined(CONFIG_SYS_BR6_PRELIM)
|
||||
out_be32(&memctl->memc_or6, CONFIG_SYS_OR6_PRELIM);
|
||||
out_be32(&memctl->memc_br6, CONFIG_SYS_BR6_PRELIM);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SYS_OR7_PRELIM) && defined(CONFIG_SYS_BR7_PRELIM)
|
||||
out_be32(&memctl->memc_or7, CONFIG_SYS_OR7_PRELIM);
|
||||
out_be32(&memctl->memc_br7, CONFIG_SYS_BR7_PRELIM);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Reset CPM
|
||||
*/
|
||||
out_be16(&immr->im_cpm.cp_cpcr, CPM_CR_RST | CPM_CR_FLG);
|
||||
/* Spin until command processed */
|
||||
while (in_be16(&immr->im_cpm.cp_cpcr) & CPM_CR_FLG)
|
||||
;
|
||||
}
|
||||
|
||||
/*
|
||||
* initialize higher level parts of CPU like timers
|
||||
*/
|
||||
int cpu_init_r(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2008 (C) Bryan O'Donoghue
|
||||
*
|
||||
* Code copied & edited from Freescale mpc85xx stuff.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <linux/libfdt.h>
|
||||
#include <fdt_support.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
void ft_cpu_setup(void *blob, bd_t *bd)
|
||||
{
|
||||
do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
|
||||
"timebase-frequency", get_tbclk(), 1);
|
||||
do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
|
||||
"bus-frequency", bd->bi_busfreq, 1);
|
||||
do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
|
||||
"clock-frequency", bd->bi_intfreq, 1);
|
||||
do_fixup_by_compat_u32(blob, "fsl,pq1-soc", "clock-frequency",
|
||||
bd->bi_intfreq, 1);
|
||||
do_fixup_by_compat_u32(blob, "fsl,cpm-brg", "clock-frequency",
|
||||
gd->arch.brg_clk, 1);
|
||||
|
||||
fdt_fixup_memory(blob, (u64)bd->bi_memstart, (u64)bd->bi_memsize);
|
||||
}
|
||||
@@ -0,0 +1,400 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2000-2003
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*/
|
||||
|
||||
/*
|
||||
* MPC8xx Internal Memory Map Functions
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
|
||||
#include <asm/immap_8xx.h>
|
||||
#include <asm/cpm_8xx.h>
|
||||
#include <asm/iopin_8xx.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
static int do_siuinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR;
|
||||
sysconf8xx_t __iomem *sc = &immap->im_siu_conf;
|
||||
|
||||
printf("SIUMCR= %08x SYPCR = %08x\n",
|
||||
in_be32(&sc->sc_siumcr), in_be32(&sc->sc_sypcr));
|
||||
printf("SWT = %08x\n", in_be32(&sc->sc_swt));
|
||||
printf("SIPEND= %08x SIMASK= %08x\n",
|
||||
in_be32(&sc->sc_sipend), in_be32(&sc->sc_simask));
|
||||
printf("SIEL = %08x SIVEC = %08x\n",
|
||||
in_be32(&sc->sc_siel), in_be32(&sc->sc_sivec));
|
||||
printf("TESR = %08x SDCR = %08x\n",
|
||||
in_be32(&sc->sc_tesr), in_be32(&sc->sc_sdcr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_memcinfo(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR;
|
||||
memctl8xx_t __iomem *memctl = &immap->im_memctl;
|
||||
int nbanks = 8;
|
||||
uint __iomem *p = &memctl->memc_br0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nbanks; i++, p += 2)
|
||||
printf("BR%-2d = %08x OR%-2d = %08x\n",
|
||||
i, in_be32(p), i, in_be32(p + 1));
|
||||
|
||||
printf("MAR = %08x", in_be32(&memctl->memc_mar));
|
||||
printf(" MCR = %08x\n", in_be32(&memctl->memc_mcr));
|
||||
printf("MAMR = %08x MBMR = %08x",
|
||||
in_be32(&memctl->memc_mamr), in_be32(&memctl->memc_mbmr));
|
||||
printf("\nMSTAT = %04x\n", in_be16(&memctl->memc_mstat));
|
||||
printf("MPTPR = %04x MDR = %08x\n",
|
||||
in_be16(&memctl->memc_mptpr), in_be32(&memctl->memc_mdr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_carinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR;
|
||||
car8xx_t __iomem *car = &immap->im_clkrst;
|
||||
|
||||
printf("SCCR = %08x\n", in_be32(&car->car_sccr));
|
||||
printf("PLPRCR= %08x\n", in_be32(&car->car_plprcr));
|
||||
printf("RSR = %08x\n", in_be32(&car->car_rsr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int counter;
|
||||
|
||||
static void header(void)
|
||||
{
|
||||
char *data = "\
|
||||
-------------------------------- --------------------------------\
|
||||
00000000001111111111222222222233 00000000001111111111222222222233\
|
||||
01234567890123456789012345678901 01234567890123456789012345678901\
|
||||
-------------------------------- --------------------------------\
|
||||
";
|
||||
int i;
|
||||
|
||||
if (counter % 2)
|
||||
putc('\n');
|
||||
counter = 0;
|
||||
|
||||
for (i = 0; i < 4; i++, data += 79)
|
||||
printf("%.79s\n", data);
|
||||
}
|
||||
|
||||
static void binary(char *label, uint value, int nbits)
|
||||
{
|
||||
uint mask = 1 << (nbits - 1);
|
||||
int i, second = (counter++ % 2);
|
||||
|
||||
if (second)
|
||||
putc(' ');
|
||||
puts(label);
|
||||
for (i = 32 + 1; i != nbits; i--)
|
||||
putc(' ');
|
||||
|
||||
while (mask != 0) {
|
||||
if (value & mask)
|
||||
putc('1');
|
||||
else
|
||||
putc('0');
|
||||
mask >>= 1;
|
||||
}
|
||||
|
||||
if (second)
|
||||
putc('\n');
|
||||
}
|
||||
|
||||
#define PA_NBITS 16
|
||||
#define PA_NB_ODR 8
|
||||
#define PB_NBITS 18
|
||||
#define PB_NB_ODR 16
|
||||
#define PC_NBITS 12
|
||||
#define PD_NBITS 13
|
||||
|
||||
static int do_iopinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR;
|
||||
iop8xx_t __iomem *iop = &immap->im_ioport;
|
||||
ushort __iomem *l, *r;
|
||||
uint __iomem *R;
|
||||
|
||||
counter = 0;
|
||||
header();
|
||||
|
||||
/*
|
||||
* Ports A & B
|
||||
*/
|
||||
|
||||
l = &iop->iop_padir;
|
||||
R = &immap->im_cpm.cp_pbdir;
|
||||
binary("PA_DIR", in_be16(l++), PA_NBITS);
|
||||
binary("PB_DIR", in_be32(R++), PB_NBITS);
|
||||
binary("PA_PAR", in_be16(l++), PA_NBITS);
|
||||
binary("PB_PAR", in_be32(R++), PB_NBITS);
|
||||
binary("PA_ODR", in_be16(l++), PA_NB_ODR);
|
||||
binary("PB_ODR", in_be32(R++), PB_NB_ODR);
|
||||
binary("PA_DAT", in_be16(l++), PA_NBITS);
|
||||
binary("PB_DAT", in_be32(R++), PB_NBITS);
|
||||
|
||||
header();
|
||||
|
||||
/*
|
||||
* Ports C & D
|
||||
*/
|
||||
|
||||
l = &iop->iop_pcdir;
|
||||
r = &iop->iop_pddir;
|
||||
binary("PC_DIR", in_be16(l++), PC_NBITS);
|
||||
binary("PD_DIR", in_be16(r++), PD_NBITS);
|
||||
binary("PC_PAR", in_be16(l++), PC_NBITS);
|
||||
binary("PD_PAR", in_be16(r++), PD_NBITS);
|
||||
binary("PC_SO ", in_be16(l++), PC_NBITS);
|
||||
binary(" ", 0, 0);
|
||||
r++;
|
||||
binary("PC_DAT", in_be16(l++), PC_NBITS);
|
||||
binary("PD_DAT", in_be16(r++), PD_NBITS);
|
||||
binary("PC_INT", in_be16(l++), PC_NBITS);
|
||||
|
||||
header();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* set the io pins
|
||||
* this needs a clean up for smaller tighter code
|
||||
* use *uint and set the address based on cmd + port
|
||||
*/
|
||||
static int do_iopset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
uint rcode = 0;
|
||||
iopin_t iopin;
|
||||
static uint port;
|
||||
static uint pin;
|
||||
static uint value;
|
||||
static enum {
|
||||
DIR,
|
||||
PAR,
|
||||
SOR,
|
||||
ODR,
|
||||
DAT,
|
||||
INT
|
||||
} cmd = DAT;
|
||||
|
||||
if (argc != 5) {
|
||||
puts("iopset PORT PIN CMD VALUE\n");
|
||||
return 1;
|
||||
}
|
||||
port = argv[1][0] - 'A';
|
||||
if (port > 3)
|
||||
port -= 0x20;
|
||||
if (port > 3)
|
||||
rcode = 1;
|
||||
pin = simple_strtol(argv[2], NULL, 10);
|
||||
if (pin > 31)
|
||||
rcode = 1;
|
||||
|
||||
|
||||
switch (argv[3][0]) {
|
||||
case 'd':
|
||||
if (argv[3][1] == 'a')
|
||||
cmd = DAT;
|
||||
else if (argv[3][1] == 'i')
|
||||
cmd = DIR;
|
||||
else
|
||||
rcode = 1;
|
||||
break;
|
||||
case 'p':
|
||||
cmd = PAR;
|
||||
break;
|
||||
case 'o':
|
||||
cmd = ODR;
|
||||
break;
|
||||
case 's':
|
||||
cmd = SOR;
|
||||
break;
|
||||
case 'i':
|
||||
cmd = INT;
|
||||
break;
|
||||
default:
|
||||
printf("iopset: unknown command %s\n", argv[3]);
|
||||
rcode = 1;
|
||||
}
|
||||
if (argv[4][0] == '1')
|
||||
value = 1;
|
||||
else if (argv[4][0] == '0')
|
||||
value = 0;
|
||||
else
|
||||
rcode = 1;
|
||||
if (rcode == 0) {
|
||||
iopin.port = port;
|
||||
iopin.pin = pin;
|
||||
iopin.flag = 0;
|
||||
switch (cmd) {
|
||||
case DIR:
|
||||
if (value)
|
||||
iopin_set_out(&iopin);
|
||||
else
|
||||
iopin_set_in(&iopin);
|
||||
break;
|
||||
case PAR:
|
||||
if (value)
|
||||
iopin_set_ded(&iopin);
|
||||
else
|
||||
iopin_set_gen(&iopin);
|
||||
break;
|
||||
case SOR:
|
||||
if (value)
|
||||
iopin_set_opt2(&iopin);
|
||||
else
|
||||
iopin_set_opt1(&iopin);
|
||||
break;
|
||||
case ODR:
|
||||
if (value)
|
||||
iopin_set_odr(&iopin);
|
||||
else
|
||||
iopin_set_act(&iopin);
|
||||
break;
|
||||
case DAT:
|
||||
if (value)
|
||||
iopin_set_high(&iopin);
|
||||
else
|
||||
iopin_set_low(&iopin);
|
||||
break;
|
||||
case INT:
|
||||
if (value)
|
||||
iopin_set_falledge(&iopin);
|
||||
else
|
||||
iopin_set_anyedge(&iopin);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rcode;
|
||||
}
|
||||
|
||||
static void prbrg(int n, uint val)
|
||||
{
|
||||
uint extc = (val >> 14) & 3;
|
||||
uint cd = (val & CPM_BRG_CD_MASK) >> 1;
|
||||
uint div16 = (val & CPM_BRG_DIV16) != 0;
|
||||
|
||||
ulong clock = gd->cpu_clk;
|
||||
|
||||
printf("BRG%d:", n);
|
||||
|
||||
if (val & CPM_BRG_RST)
|
||||
puts(" RESET");
|
||||
else
|
||||
puts(" ");
|
||||
|
||||
if (val & CPM_BRG_EN)
|
||||
puts(" ENABLED");
|
||||
else
|
||||
puts(" DISABLED");
|
||||
|
||||
printf(" EXTC=%d", extc);
|
||||
|
||||
if (val & CPM_BRG_ATB)
|
||||
puts(" ATB");
|
||||
else
|
||||
puts(" ");
|
||||
|
||||
printf(" DIVIDER=%4d", cd);
|
||||
if (extc == 0 && cd != 0) {
|
||||
uint baudrate;
|
||||
|
||||
if (div16)
|
||||
baudrate = (clock / 16) / (cd + 1);
|
||||
else
|
||||
baudrate = clock / (cd + 1);
|
||||
|
||||
printf("=%6d bps", baudrate);
|
||||
} else {
|
||||
puts(" ");
|
||||
}
|
||||
|
||||
if (val & CPM_BRG_DIV16)
|
||||
puts(" DIV16");
|
||||
else
|
||||
puts(" ");
|
||||
|
||||
putc('\n');
|
||||
}
|
||||
|
||||
static int do_brginfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR;
|
||||
cpm8xx_t __iomem *cp = &immap->im_cpm;
|
||||
uint __iomem *p = &cp->cp_brgc1;
|
||||
int i = 1;
|
||||
|
||||
while (i <= 4)
|
||||
prbrg(i++, in_be32(p++));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CMD_REGINFO
|
||||
void print_reginfo(void)
|
||||
{
|
||||
immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR;
|
||||
sit8xx_t __iomem *timers = &immap->im_sit;
|
||||
|
||||
printf("\nSystem Configuration registers\n"
|
||||
"\tIMMR\t0x%08X\n", get_immr());
|
||||
do_siuinfo(NULL, 0, 0, NULL);
|
||||
|
||||
printf("Memory Controller Registers\n");
|
||||
do_memcinfo(NULL, 0, 0, NULL);
|
||||
|
||||
printf("\nSystem Integration Timers\n");
|
||||
printf("\tTBSCR\t0x%04X\tRTCSC\t0x%04X\n",
|
||||
in_be16(&timers->sit_tbscr), in_be16(&timers->sit_rtcsc));
|
||||
printf("\tPISCR\t0x%04X\n", in_be16(&timers->sit_piscr));
|
||||
}
|
||||
#endif
|
||||
|
||||
/***************************************************/
|
||||
|
||||
U_BOOT_CMD(
|
||||
siuinfo, 1, 1, do_siuinfo,
|
||||
"print System Interface Unit (SIU) registers",
|
||||
""
|
||||
);
|
||||
|
||||
U_BOOT_CMD(
|
||||
memcinfo, 1, 1, do_memcinfo,
|
||||
"print Memory Controller registers",
|
||||
""
|
||||
);
|
||||
|
||||
U_BOOT_CMD(
|
||||
carinfo, 1, 1, do_carinfo,
|
||||
"print Clocks and Reset registers",
|
||||
""
|
||||
);
|
||||
|
||||
U_BOOT_CMD(
|
||||
iopinfo, 1, 1, do_iopinfo,
|
||||
"print I/O Port registers",
|
||||
""
|
||||
);
|
||||
|
||||
U_BOOT_CMD(
|
||||
iopset, 5, 0, do_iopset,
|
||||
"set I/O Port registers",
|
||||
"PORT PIN CMD VALUE\nPORT: A-D, PIN: 0-31, CMD: [dat|dir|odr|sor], VALUE: 0|1"
|
||||
);
|
||||
|
||||
U_BOOT_CMD(
|
||||
brginfo, 1, 1, do_brginfo,
|
||||
"print Baud Rate Generator (BRG) registers",
|
||||
""
|
||||
);
|
||||
@@ -0,0 +1,250 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2000-2002
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <irq_func.h>
|
||||
#include <mpc8xx.h>
|
||||
#include <mpc8xx_irq.h>
|
||||
#include <asm/cpm_8xx.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
/*
|
||||
* CPM interrupt vector functions.
|
||||
*/
|
||||
struct interrupt_action {
|
||||
interrupt_handler_t *handler;
|
||||
void *arg;
|
||||
};
|
||||
|
||||
static struct interrupt_action cpm_vecs[CPMVEC_NR];
|
||||
static struct interrupt_action irq_vecs[NR_IRQS];
|
||||
|
||||
static void cpm_interrupt_init(void);
|
||||
static void cpm_interrupt(void *regs);
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
void interrupt_init_cpu(unsigned *decrementer_count)
|
||||
{
|
||||
immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR;
|
||||
|
||||
*decrementer_count = get_tbclk() / CONFIG_SYS_HZ;
|
||||
|
||||
/* disable all interrupts */
|
||||
out_be32(&immr->im_siu_conf.sc_simask, 0);
|
||||
|
||||
/* Configure CPM interrupts */
|
||||
cpm_interrupt_init();
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
/*
|
||||
* Handle external interrupts
|
||||
*/
|
||||
void external_interrupt(struct pt_regs *regs)
|
||||
{
|
||||
immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR;
|
||||
int irq;
|
||||
ulong simask;
|
||||
ulong vec, v_bit;
|
||||
|
||||
/*
|
||||
* read the SIVEC register and shift the bits down
|
||||
* to get the irq number
|
||||
*/
|
||||
vec = in_be32(&immr->im_siu_conf.sc_sivec);
|
||||
irq = vec >> 26;
|
||||
v_bit = 0x80000000UL >> irq;
|
||||
|
||||
/*
|
||||
* Read Interrupt Mask Register and Mask Interrupts
|
||||
*/
|
||||
simask = in_be32(&immr->im_siu_conf.sc_simask);
|
||||
clrbits_be32(&immr->im_siu_conf.sc_simask, 0xFFFF0000 >> irq);
|
||||
|
||||
if (!(irq & 0x1)) { /* External Interrupt ? */
|
||||
ulong siel;
|
||||
|
||||
/*
|
||||
* Read Interrupt Edge/Level Register
|
||||
*/
|
||||
siel = in_be32(&immr->im_siu_conf.sc_siel);
|
||||
|
||||
if (siel & v_bit) { /* edge triggered interrupt ? */
|
||||
/*
|
||||
* Rewrite SIPEND Register to clear interrupt
|
||||
*/
|
||||
out_be32(&immr->im_siu_conf.sc_sipend, v_bit);
|
||||
}
|
||||
}
|
||||
|
||||
if (irq_vecs[irq].handler != NULL) {
|
||||
irq_vecs[irq].handler(irq_vecs[irq].arg);
|
||||
} else {
|
||||
printf("\nBogus External Interrupt IRQ %d Vector %ld\n",
|
||||
irq, vec);
|
||||
/* turn off the bogus interrupt to avoid it from now */
|
||||
simask &= ~v_bit;
|
||||
}
|
||||
/*
|
||||
* Re-Enable old Interrupt Mask
|
||||
*/
|
||||
out_be32(&immr->im_siu_conf.sc_simask, simask);
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
/*
|
||||
* CPM interrupt handler
|
||||
*/
|
||||
static void cpm_interrupt(void *regs)
|
||||
{
|
||||
immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR;
|
||||
uint vec;
|
||||
|
||||
/*
|
||||
* Get the vector by setting the ACK bit
|
||||
* and then reading the register.
|
||||
*/
|
||||
out_be16(&immr->im_cpic.cpic_civr, 1);
|
||||
vec = in_be16(&immr->im_cpic.cpic_civr);
|
||||
vec >>= 11;
|
||||
|
||||
if (cpm_vecs[vec].handler != NULL) {
|
||||
(*cpm_vecs[vec].handler) (cpm_vecs[vec].arg);
|
||||
} else {
|
||||
clrbits_be32(&immr->im_cpic.cpic_cimr, 1 << vec);
|
||||
printf("Masking bogus CPM interrupt vector 0x%x\n", vec);
|
||||
}
|
||||
/*
|
||||
* After servicing the interrupt,
|
||||
* we have to remove the status indicator.
|
||||
*/
|
||||
setbits_be32(&immr->im_cpic.cpic_cisr, 1 << vec);
|
||||
}
|
||||
|
||||
/*
|
||||
* The CPM can generate the error interrupt when there is a race
|
||||
* condition between generating and masking interrupts. All we have
|
||||
* to do is ACK it and return. This is a no-op function so we don't
|
||||
* need any special tests in the interrupt handler.
|
||||
*/
|
||||
static void cpm_error_interrupt(void *dummy)
|
||||
{
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
/*
|
||||
* Install and free an interrupt handler
|
||||
*/
|
||||
void irq_install_handler(int vec, interrupt_handler_t *handler, void *arg)
|
||||
{
|
||||
immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR;
|
||||
|
||||
if ((vec & CPMVEC_OFFSET) != 0) {
|
||||
/* CPM interrupt */
|
||||
vec &= 0xffff;
|
||||
if (cpm_vecs[vec].handler != NULL)
|
||||
printf("CPM interrupt 0x%x replacing 0x%x\n",
|
||||
(uint)handler, (uint)cpm_vecs[vec].handler);
|
||||
cpm_vecs[vec].handler = handler;
|
||||
cpm_vecs[vec].arg = arg;
|
||||
setbits_be32(&immr->im_cpic.cpic_cimr, 1 << vec);
|
||||
} else {
|
||||
/* SIU interrupt */
|
||||
if (irq_vecs[vec].handler != NULL)
|
||||
printf("SIU interrupt %d 0x%x replacing 0x%x\n",
|
||||
vec, (uint)handler, (uint)cpm_vecs[vec].handler);
|
||||
irq_vecs[vec].handler = handler;
|
||||
irq_vecs[vec].arg = arg;
|
||||
setbits_be32(&immr->im_siu_conf.sc_simask, 1 << (31 - vec));
|
||||
}
|
||||
}
|
||||
|
||||
void irq_free_handler(int vec)
|
||||
{
|
||||
immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR;
|
||||
|
||||
if ((vec & CPMVEC_OFFSET) != 0) {
|
||||
/* CPM interrupt */
|
||||
vec &= 0xffff;
|
||||
clrbits_be32(&immr->im_cpic.cpic_cimr, 1 << vec);
|
||||
cpm_vecs[vec].handler = NULL;
|
||||
cpm_vecs[vec].arg = NULL;
|
||||
} else {
|
||||
/* SIU interrupt */
|
||||
clrbits_be32(&immr->im_siu_conf.sc_simask, 1 << (31 - vec));
|
||||
irq_vecs[vec].handler = NULL;
|
||||
irq_vecs[vec].arg = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
static void cpm_interrupt_init(void)
|
||||
{
|
||||
immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR;
|
||||
uint cicr;
|
||||
|
||||
/*
|
||||
* Initialize the CPM interrupt controller.
|
||||
*/
|
||||
|
||||
cicr = CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1 |
|
||||
((CPM_INTERRUPT / 2) << 13) | CICR_HP_MASK;
|
||||
|
||||
out_be32(&immr->im_cpic.cpic_cicr, cicr);
|
||||
out_be32(&immr->im_cpic.cpic_cimr, 0);
|
||||
|
||||
/*
|
||||
* Install the error handler.
|
||||
*/
|
||||
irq_install_handler(CPMVEC_ERROR, cpm_error_interrupt, NULL);
|
||||
|
||||
setbits_be32(&immr->im_cpic.cpic_cicr, CICR_IEN);
|
||||
|
||||
/*
|
||||
* Install the cpm interrupt handler
|
||||
*/
|
||||
irq_install_handler(CPM_INTERRUPT, cpm_interrupt, NULL);
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
/*
|
||||
* timer_interrupt - gets called when the decrementer overflows,
|
||||
* with interrupts disabled.
|
||||
* Trivial implementation - no need to be really accurate.
|
||||
*/
|
||||
void timer_interrupt_cpu(struct pt_regs *regs)
|
||||
{
|
||||
immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR;
|
||||
|
||||
/* Reset Timer Expired and Timers Interrupt Status */
|
||||
out_be32(&immr->im_clkrstk.cark_plprcrk, KAPWR_KEY);
|
||||
__asm__ ("nop");
|
||||
/*
|
||||
Clear TEXPS (and TMIST on older chips). SPLSS (on older
|
||||
chips) is cleared too.
|
||||
|
||||
Bitwise OR is a read-modify-write operation so ALL bits
|
||||
which are cleared by writing `1' would be cleared by
|
||||
operations like
|
||||
|
||||
immr->im_clkrst.car_plprcr |= PLPRCR_TEXPS;
|
||||
|
||||
The same can be achieved by simple writing of the PLPRCR
|
||||
to itself. If a bit value should be preserved, read the
|
||||
register, ZERO the bit and write, not OR, the result back.
|
||||
*/
|
||||
setbits_be32(&immr->im_clkrst.car_plprcr, 0);
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
@@ -0,0 +1,42 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2000-2004
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <mpc8xx.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/*
|
||||
* get_clocks() fills in gd->cpu_clock depending on CONFIG_8xx_GCLK_FREQ
|
||||
*/
|
||||
int get_clocks(void)
|
||||
{
|
||||
immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR;
|
||||
uint sccr = in_be32(&immap->im_clkrst.car_sccr);
|
||||
uint divider = 1 << (((sccr & SCCR_DFBRG11) >> 11) * 2);
|
||||
|
||||
/*
|
||||
* If for some reason measuring the gclk frequency won't
|
||||
* work, we return the hardwired value.
|
||||
* (For example, the cogent CMA286-60 CPU module has no
|
||||
* separate oscillator for PITRTCLK)
|
||||
*/
|
||||
gd->cpu_clk = CONFIG_8xx_GCLK_FREQ;
|
||||
|
||||
if ((sccr & SCCR_EBDF11) == 0) {
|
||||
/* No Bus Divider active */
|
||||
gd->bus_clk = gd->cpu_clk;
|
||||
} else {
|
||||
/* The MPC8xx has only one BDF: half clock speed */
|
||||
gd->bus_clk = gd->cpu_clk / 2;
|
||||
}
|
||||
|
||||
gd->arch.brg_clk = gd->cpu_clk / divider;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,542 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright (C) 1998 Dan Malek <dmalek@jlc.net>
|
||||
* Copyright (C) 1999 Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
|
||||
* Copyright (C) 2000,2001,2002 Wolfgang Denk <wd@denx.de>
|
||||
*/
|
||||
|
||||
/* U-Boot - Startup Code for PowerPC based Embedded Boards
|
||||
*
|
||||
*
|
||||
* The processor starts at 0x00000100 and the code is executed
|
||||
* from flash. The code is organized to be at an other address
|
||||
* in memory, but as long we don't jump around before relocating,
|
||||
* board_init lies at a quite high address and when the cpu has
|
||||
* jumped there, everything is ok.
|
||||
* This works because the cpu gives the FLASH (CS0) the whole
|
||||
* address space at startup, and board_init lies as a echo of
|
||||
* the flash somewhere up there in the memory map.
|
||||
*
|
||||
* board_init will change CS0 to be positioned at the correct
|
||||
* address and (s)dram will be positioned at address 0
|
||||
*/
|
||||
#include <asm-offsets.h>
|
||||
#include <config.h>
|
||||
#include <mpc8xx.h>
|
||||
#include <version.h>
|
||||
|
||||
#include <ppc_asm.tmpl>
|
||||
#include <ppc_defs.h>
|
||||
|
||||
#include <asm/cache.h>
|
||||
#include <asm/mmu.h>
|
||||
#include <asm/u-boot.h>
|
||||
|
||||
/* We don't want the MMU yet.
|
||||
*/
|
||||
#undef MSR_KERNEL
|
||||
#define MSR_KERNEL ( MSR_ME | MSR_RI ) /* Machine Check and Recoverable Interr. */
|
||||
|
||||
/*
|
||||
* Set up GOT: Global Offset Table
|
||||
*
|
||||
* Use r12 to access the GOT
|
||||
*/
|
||||
START_GOT
|
||||
GOT_ENTRY(_GOT2_TABLE_)
|
||||
GOT_ENTRY(_FIXUP_TABLE_)
|
||||
|
||||
GOT_ENTRY(_start)
|
||||
GOT_ENTRY(_start_of_vectors)
|
||||
GOT_ENTRY(_end_of_vectors)
|
||||
GOT_ENTRY(transfer_to_handler)
|
||||
|
||||
GOT_ENTRY(__init_end)
|
||||
GOT_ENTRY(__bss_end)
|
||||
GOT_ENTRY(__bss_start)
|
||||
END_GOT
|
||||
|
||||
/*
|
||||
* r3 - 1st arg to board_init(): IMMP pointer
|
||||
* r4 - 2nd arg to board_init(): boot flag
|
||||
*/
|
||||
.text
|
||||
.long 0x27051956 /* U-Boot Magic Number */
|
||||
.globl version_string
|
||||
version_string:
|
||||
.ascii U_BOOT_VERSION_STRING, "\0"
|
||||
|
||||
. = EXC_OFF_SYS_RESET
|
||||
.globl _start
|
||||
_start:
|
||||
lis r3, CONFIG_SYS_IMMR@h /* position IMMR */
|
||||
mtspr 638, r3
|
||||
|
||||
/* Initialize machine status; enable machine check interrupt */
|
||||
/*----------------------------------------------------------------------*/
|
||||
li r3, MSR_KERNEL /* Set ME, RI flags */
|
||||
mtmsr r3
|
||||
mtspr SRR1, r3 /* Make SRR1 match MSR */
|
||||
|
||||
mfspr r3, ICR /* clear Interrupt Cause Register */
|
||||
|
||||
/* Initialize debug port registers */
|
||||
/*----------------------------------------------------------------------*/
|
||||
xor r0, r0, r0 /* Clear R0 */
|
||||
mtspr LCTRL1, r0 /* Initialize debug port regs */
|
||||
mtspr LCTRL2, r0
|
||||
mtspr COUNTA, r0
|
||||
mtspr COUNTB, r0
|
||||
|
||||
/* Reset the caches */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
mfspr r3, IC_CST /* Clear error bits */
|
||||
mfspr r3, DC_CST
|
||||
|
||||
lis r3, IDC_UNALL@h /* Unlock all */
|
||||
mtspr IC_CST, r3
|
||||
mtspr DC_CST, r3
|
||||
|
||||
lis r3, IDC_INVALL@h /* Invalidate all */
|
||||
mtspr IC_CST, r3
|
||||
mtspr DC_CST, r3
|
||||
|
||||
lis r3, IDC_DISABLE@h /* Disable data cache */
|
||||
mtspr DC_CST, r3
|
||||
|
||||
lis r3, IDC_ENABLE@h /* Enable instruction cache */
|
||||
mtspr IC_CST, r3
|
||||
|
||||
/* invalidate all tlb's */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
tlbia
|
||||
isync
|
||||
|
||||
/*
|
||||
* Calculate absolute address in FLASH and jump there
|
||||
*----------------------------------------------------------------------*/
|
||||
|
||||
lis r3, CONFIG_SYS_MONITOR_BASE@h
|
||||
ori r3, r3, CONFIG_SYS_MONITOR_BASE@l
|
||||
addi r3, r3, in_flash - _start + EXC_OFF_SYS_RESET
|
||||
mtlr r3
|
||||
blr
|
||||
|
||||
in_flash:
|
||||
|
||||
/* initialize some SPRs that are hard to access from C */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Disable serialized ifetch and show cycles
|
||||
* (i.e. set processor to normal mode).
|
||||
* This is also a silicon bug workaround, see errata
|
||||
*/
|
||||
|
||||
li r2, 0x0007
|
||||
mtspr ICTRL, r2
|
||||
|
||||
/* Set up debug mode entry */
|
||||
|
||||
lis r2, CONFIG_SYS_DER@h
|
||||
ori r2, r2, CONFIG_SYS_DER@l
|
||||
mtspr DER, r2
|
||||
|
||||
/* set up the stack on top of internal DPRAM */
|
||||
lis r3, (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_RAM_SIZE)@h
|
||||
ori r3, r3, (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_RAM_SIZE)@l
|
||||
stw r0, -4(r3)
|
||||
stw r0, -8(r3)
|
||||
addi r1, r3, -8
|
||||
|
||||
bl board_init_f_alloc_reserve
|
||||
addi r1, r3, -8
|
||||
|
||||
/* Zeroise the CPM dpram */
|
||||
lis r4, CONFIG_SYS_IMMR@h
|
||||
ori r4, r4, (0x2000 - 4)
|
||||
li r0, (0x2000 / 4)
|
||||
mtctr r0
|
||||
li r0, 0
|
||||
1: stwu r0, 4(r4)
|
||||
bdnz 1b
|
||||
|
||||
bl board_init_f_init_reserve
|
||||
|
||||
/* let the C-code set up the rest */
|
||||
/* */
|
||||
/* Be careful to keep code relocatable ! */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
GET_GOT /* initialize GOT access */
|
||||
|
||||
lis r3, CONFIG_SYS_IMMR@h
|
||||
bl cpu_init_f /* run low-level CPU init code (from Flash) */
|
||||
|
||||
bl board_init_f /* run 1st part of board init code (from Flash) */
|
||||
|
||||
/* NOTREACHED - board_init_f() does not return */
|
||||
|
||||
|
||||
.globl _start_of_vectors
|
||||
_start_of_vectors:
|
||||
|
||||
/* Machine check */
|
||||
STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
|
||||
|
||||
/* Data Storage exception. "Never" generated on the 860. */
|
||||
STD_EXCEPTION(0x300, DataStorage, UnknownException)
|
||||
|
||||
/* Instruction Storage exception. "Never" generated on the 860. */
|
||||
STD_EXCEPTION(0x400, InstStorage, UnknownException)
|
||||
|
||||
/* External Interrupt exception. */
|
||||
STD_EXCEPTION(0x500, ExtInterrupt, external_interrupt)
|
||||
|
||||
/* Alignment exception. */
|
||||
. = 0x600
|
||||
Alignment:
|
||||
EXCEPTION_PROLOG(SRR0, SRR1)
|
||||
mfspr r4,DAR
|
||||
stw r4,_DAR(r21)
|
||||
mfspr r5,DSISR
|
||||
stw r5,_DSISR(r21)
|
||||
addi r3,r1,STACK_FRAME_OVERHEAD
|
||||
EXC_XFER_TEMPLATE(Alignment, AlignmentException, MSR_KERNEL, COPY_EE)
|
||||
|
||||
/* Program check exception */
|
||||
. = 0x700
|
||||
ProgramCheck:
|
||||
EXCEPTION_PROLOG(SRR0, SRR1)
|
||||
addi r3,r1,STACK_FRAME_OVERHEAD
|
||||
EXC_XFER_TEMPLATE(ProgramCheck, ProgramCheckException,
|
||||
MSR_KERNEL, COPY_EE)
|
||||
|
||||
/* No FPU on MPC8xx. This exception is not supposed to happen.
|
||||
*/
|
||||
STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
|
||||
|
||||
/* I guess we could implement decrementer, and may have
|
||||
* to someday for timekeeping.
|
||||
*/
|
||||
STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
|
||||
STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
|
||||
STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
|
||||
STD_EXCEPTION(0xc00, SystemCall, UnknownException)
|
||||
STD_EXCEPTION(0xd00, SingleStep, UnknownException)
|
||||
|
||||
STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
|
||||
STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
|
||||
|
||||
/* On the MPC8xx, this is a software emulation interrupt. It occurs
|
||||
* for all unimplemented and illegal instructions.
|
||||
*/
|
||||
STD_EXCEPTION(0x1000, SoftEmu, SoftEmuException)
|
||||
|
||||
STD_EXCEPTION(0x1100, InstructionTLBMiss, UnknownException)
|
||||
STD_EXCEPTION(0x1200, DataTLBMiss, UnknownException)
|
||||
STD_EXCEPTION(0x1300, InstructionTLBError, UnknownException)
|
||||
STD_EXCEPTION(0x1400, DataTLBError, UnknownException)
|
||||
|
||||
STD_EXCEPTION(0x1500, Reserved5, UnknownException)
|
||||
STD_EXCEPTION(0x1600, Reserved6, UnknownException)
|
||||
STD_EXCEPTION(0x1700, Reserved7, UnknownException)
|
||||
STD_EXCEPTION(0x1800, Reserved8, UnknownException)
|
||||
STD_EXCEPTION(0x1900, Reserved9, UnknownException)
|
||||
STD_EXCEPTION(0x1a00, ReservedA, UnknownException)
|
||||
STD_EXCEPTION(0x1b00, ReservedB, UnknownException)
|
||||
|
||||
STD_EXCEPTION(0x1c00, DataBreakpoint, UnknownException)
|
||||
STD_EXCEPTION(0x1d00, InstructionBreakpoint, DebugException)
|
||||
STD_EXCEPTION(0x1e00, PeripheralBreakpoint, UnknownException)
|
||||
STD_EXCEPTION(0x1f00, DevPortBreakpoint, UnknownException)
|
||||
|
||||
|
||||
.globl _end_of_vectors
|
||||
_end_of_vectors:
|
||||
|
||||
|
||||
. = 0x2000
|
||||
|
||||
/*
|
||||
* This code finishes saving the registers to the exception frame
|
||||
* and jumps to the appropriate handler for the exception.
|
||||
* Register r21 is pointer into trap frame, r1 has new stack pointer.
|
||||
*/
|
||||
.globl transfer_to_handler
|
||||
transfer_to_handler:
|
||||
stw r22,_NIP(r21)
|
||||
lis r22,MSR_POW@h
|
||||
andc r23,r23,r22
|
||||
stw r23,_MSR(r21)
|
||||
SAVE_GPR(7, r21)
|
||||
SAVE_4GPRS(8, r21)
|
||||
SAVE_8GPRS(12, r21)
|
||||
SAVE_8GPRS(24, r21)
|
||||
mflr r23
|
||||
andi. r24,r23,0x3f00 /* get vector offset */
|
||||
stw r24,TRAP(r21)
|
||||
li r22,0
|
||||
stw r22,RESULT(r21)
|
||||
mtspr SPRG2,r22 /* r1 is now kernel sp */
|
||||
lwz r24,0(r23) /* virtual address of handler */
|
||||
lwz r23,4(r23) /* where to go when done */
|
||||
mtspr SRR0,r24
|
||||
mtspr SRR1,r20
|
||||
mtlr r23
|
||||
SYNC
|
||||
rfi /* jump to handler, enable MMU */
|
||||
|
||||
int_return:
|
||||
mfmsr r28 /* Disable interrupts */
|
||||
li r4,0
|
||||
ori r4,r4,MSR_EE
|
||||
andc r28,r28,r4
|
||||
SYNC /* Some chip revs need this... */
|
||||
mtmsr r28
|
||||
SYNC
|
||||
lwz r2,_CTR(r1)
|
||||
lwz r0,_LINK(r1)
|
||||
mtctr r2
|
||||
mtlr r0
|
||||
lwz r2,_XER(r1)
|
||||
lwz r0,_CCR(r1)
|
||||
mtspr XER,r2
|
||||
mtcrf 0xFF,r0
|
||||
REST_10GPRS(3, r1)
|
||||
REST_10GPRS(13, r1)
|
||||
REST_8GPRS(23, r1)
|
||||
REST_GPR(31, r1)
|
||||
lwz r2,_NIP(r1) /* Restore environment */
|
||||
lwz r0,_MSR(r1)
|
||||
mtspr SRR0,r2
|
||||
mtspr SRR1,r0
|
||||
lwz r0,GPR0(r1)
|
||||
lwz r2,GPR2(r1)
|
||||
lwz r1,GPR1(r1)
|
||||
SYNC
|
||||
rfi
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* void relocate_code (addr_sp, gd, addr_moni)
|
||||
*
|
||||
* This "function" does not return, instead it continues in RAM
|
||||
* after relocating the monitor code.
|
||||
*
|
||||
* r3 = dest
|
||||
* r4 = src
|
||||
* r5 = length in bytes
|
||||
* r6 = cachelinesize
|
||||
*/
|
||||
.globl relocate_code
|
||||
relocate_code:
|
||||
mr r1, r3 /* Set new stack pointer */
|
||||
mr r9, r4 /* Save copy of Global Data pointer */
|
||||
mr r10, r5 /* Save copy of Destination Address */
|
||||
|
||||
GET_GOT
|
||||
mr r3, r5 /* Destination Address */
|
||||
lis r4, CONFIG_SYS_MONITOR_BASE@h /* Source Address */
|
||||
ori r4, r4, CONFIG_SYS_MONITOR_BASE@l
|
||||
lwz r5, GOT(__init_end)
|
||||
sub r5, r5, r4
|
||||
li r6, CONFIG_SYS_CACHELINE_SIZE /* Cache Line Size */
|
||||
|
||||
/*
|
||||
* Fix GOT pointer:
|
||||
*
|
||||
* New GOT-PTR = (old GOT-PTR - CONFIG_SYS_MONITOR_BASE) + Destination Address
|
||||
*
|
||||
* Offset:
|
||||
*/
|
||||
sub r15, r10, r4
|
||||
|
||||
/* First our own GOT */
|
||||
add r12, r12, r15
|
||||
/* then the one used by the C code */
|
||||
add r30, r30, r15
|
||||
|
||||
/*
|
||||
* Now relocate code
|
||||
*/
|
||||
|
||||
cmplw cr1,r3,r4
|
||||
addi r0,r5,3
|
||||
srwi. r0,r0,2
|
||||
beq cr1,4f /* In place copy is not necessary */
|
||||
beq 7f /* Protect against 0 count */
|
||||
mtctr r0
|
||||
bge cr1,2f
|
||||
|
||||
la r8,-4(r4)
|
||||
la r7,-4(r3)
|
||||
1: lwzu r0,4(r8)
|
||||
stwu r0,4(r7)
|
||||
bdnz 1b
|
||||
b 4f
|
||||
|
||||
2: slwi r0,r0,2
|
||||
add r8,r4,r0
|
||||
add r7,r3,r0
|
||||
3: lwzu r0,-4(r8)
|
||||
stwu r0,-4(r7)
|
||||
bdnz 3b
|
||||
|
||||
/*
|
||||
* Now flush the cache: note that we must start from a cache aligned
|
||||
* address. Otherwise we might miss one cache line.
|
||||
*/
|
||||
4: cmpwi r6,0
|
||||
add r5,r3,r5
|
||||
beq 7f /* Always flush prefetch queue in any case */
|
||||
subi r0,r6,1
|
||||
andc r3,r3,r0
|
||||
mr r4,r3
|
||||
5: dcbst 0,r4
|
||||
add r4,r4,r6
|
||||
cmplw r4,r5
|
||||
blt 5b
|
||||
sync /* Wait for all dcbst to complete on bus */
|
||||
mr r4,r3
|
||||
6: icbi 0,r4
|
||||
add r4,r4,r6
|
||||
cmplw r4,r5
|
||||
blt 6b
|
||||
7: sync /* Wait for all icbi to complete on bus */
|
||||
isync
|
||||
|
||||
/*
|
||||
* We are done. Do not return, instead branch to second part of board
|
||||
* initialization, now running from RAM.
|
||||
*/
|
||||
|
||||
addi r0, r10, in_ram - _start + EXC_OFF_SYS_RESET
|
||||
mtlr r0
|
||||
blr
|
||||
|
||||
in_ram:
|
||||
|
||||
/*
|
||||
* Relocation Function, r12 point to got2+0x8000
|
||||
*
|
||||
* Adjust got2 pointers, no need to check for 0, this code
|
||||
* already puts a few entries in the table.
|
||||
*/
|
||||
li r0,__got2_entries@sectoff@l
|
||||
la r3,GOT(_GOT2_TABLE_)
|
||||
lwz r11,GOT(_GOT2_TABLE_)
|
||||
mtctr r0
|
||||
sub r11,r3,r11
|
||||
addi r3,r3,-4
|
||||
1: lwzu r0,4(r3)
|
||||
cmpwi r0,0
|
||||
beq- 2f
|
||||
add r0,r0,r11
|
||||
stw r0,0(r3)
|
||||
2: bdnz 1b
|
||||
|
||||
/*
|
||||
* Now adjust the fixups and the pointers to the fixups
|
||||
* in case we need to move ourselves again.
|
||||
*/
|
||||
li r0,__fixup_entries@sectoff@l
|
||||
lwz r3,GOT(_FIXUP_TABLE_)
|
||||
cmpwi r0,0
|
||||
mtctr r0
|
||||
addi r3,r3,-4
|
||||
beq 4f
|
||||
3: lwzu r4,4(r3)
|
||||
lwzux r0,r4,r11
|
||||
cmpwi r0,0
|
||||
add r0,r0,r11
|
||||
stw r4,0(r3)
|
||||
beq- 5f
|
||||
stw r0,0(r4)
|
||||
5: bdnz 3b
|
||||
4:
|
||||
clear_bss:
|
||||
/*
|
||||
* Now clear BSS segment
|
||||
*/
|
||||
lwz r3,GOT(__bss_start)
|
||||
lwz r4,GOT(__bss_end)
|
||||
|
||||
cmplw 0, r3, r4
|
||||
beq 6f
|
||||
|
||||
li r0, 0
|
||||
5:
|
||||
stw r0, 0(r3)
|
||||
addi r3, r3, 4
|
||||
cmplw 0, r3, r4
|
||||
bne 5b
|
||||
6:
|
||||
|
||||
mr r3, r9 /* Global Data pointer */
|
||||
mr r4, r10 /* Destination Address */
|
||||
bl board_init_r
|
||||
|
||||
/*
|
||||
* Copy exception vector code to low memory
|
||||
*
|
||||
* r3: dest_addr
|
||||
* r7: source address, r8: end address, r9: target address
|
||||
*/
|
||||
.globl trap_init
|
||||
trap_init:
|
||||
mflr r4 /* save link register */
|
||||
GET_GOT
|
||||
lwz r7, GOT(_start)
|
||||
lwz r8, GOT(_end_of_vectors)
|
||||
|
||||
li r9, 0x100 /* reset vector always at 0x100 */
|
||||
|
||||
cmplw 0, r7, r8
|
||||
bgelr /* return if r7>=r8 - just in case */
|
||||
1:
|
||||
lwz r0, 0(r7)
|
||||
stw r0, 0(r9)
|
||||
addi r7, r7, 4
|
||||
addi r9, r9, 4
|
||||
cmplw 0, r7, r8
|
||||
bne 1b
|
||||
|
||||
/*
|
||||
* relocate `hdlr' and `int_return' entries
|
||||
*/
|
||||
li r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET
|
||||
li r8, Alignment - _start + EXC_OFF_SYS_RESET
|
||||
2:
|
||||
bl trap_reloc
|
||||
addi r7, r7, 0x100 /* next exception vector */
|
||||
cmplw 0, r7, r8
|
||||
blt 2b
|
||||
|
||||
li r7, .L_Alignment - _start + EXC_OFF_SYS_RESET
|
||||
bl trap_reloc
|
||||
|
||||
li r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET
|
||||
bl trap_reloc
|
||||
|
||||
li r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET
|
||||
li r8, SystemCall - _start + EXC_OFF_SYS_RESET
|
||||
3:
|
||||
bl trap_reloc
|
||||
addi r7, r7, 0x100 /* next exception vector */
|
||||
cmplw 0, r7, r8
|
||||
blt 3b
|
||||
|
||||
li r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET
|
||||
li r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET
|
||||
4:
|
||||
bl trap_reloc
|
||||
addi r7, r7, 0x100 /* next exception vector */
|
||||
cmplw 0, r7, r8
|
||||
blt 4b
|
||||
|
||||
mtlr r4 /* restore link register */
|
||||
blr
|
||||
@@ -0,0 +1,156 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file handles the architecture-dependent parts of hardware exceptions
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
/* 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 0x02000000
|
||||
|
||||
/*
|
||||
* 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");
|
||||
}
|
||||
|
||||
static void show_regs(struct pt_regs *regs)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %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 in kernel pc %lx signal %d", regs->nip, signr);
|
||||
}
|
||||
|
||||
void MachineCheckException(struct pt_regs *regs)
|
||||
{
|
||||
unsigned long fixup = search_exception_table(regs->nip);
|
||||
|
||||
/* Probing PCI using config cycles cause this exception
|
||||
* when a device is not present. Catch it and return to
|
||||
* the PCI exception handler.
|
||||
*/
|
||||
if (fixup != 0) {
|
||||
regs->nip = fixup;
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Machine check in kernel mode.\n");
|
||||
printf("Caused by (from msr): ");
|
||||
printf("regs %p ", regs);
|
||||
switch (regs->msr & 0x000F0000) {
|
||||
case (0x80000000 >> 12):
|
||||
printf("Machine check signal - probably due to mm fault\n"
|
||||
"with mmu off\n");
|
||||
break;
|
||||
case (0x80000000 >> 13):
|
||||
printf("Transfer error ack signal\n");
|
||||
break;
|
||||
case (0x80000000 >> 14):
|
||||
printf("Data parity signal\n");
|
||||
break;
|
||||
case (0x80000000 >> 15):
|
||||
printf("Address parity signal\n");
|
||||
break;
|
||||
default:
|
||||
printf("Unknown values in msr\n");
|
||||
}
|
||||
show_regs(regs);
|
||||
print_backtrace((unsigned long *)regs->gpr[1]);
|
||||
panic("machine check");
|
||||
}
|
||||
|
||||
void AlignmentException(struct pt_regs *regs)
|
||||
{
|
||||
show_regs(regs);
|
||||
print_backtrace((unsigned long *)regs->gpr[1]);
|
||||
panic("Alignment Exception");
|
||||
}
|
||||
|
||||
void ProgramCheckException(struct pt_regs *regs)
|
||||
{
|
||||
show_regs(regs);
|
||||
print_backtrace((unsigned long *)regs->gpr[1]);
|
||||
panic("Program Check Exception");
|
||||
}
|
||||
|
||||
void SoftEmuException(struct pt_regs *regs)
|
||||
{
|
||||
show_regs(regs);
|
||||
print_backtrace((unsigned long *)regs->gpr[1]);
|
||||
panic("Software Emulation Exception");
|
||||
}
|
||||
|
||||
|
||||
void UnknownException(struct pt_regs *regs)
|
||||
{
|
||||
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);
|
||||
}
|
||||
Reference in New Issue
Block a user