GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)

This commit is contained in:
lai
2026-09-06 03:52:57 +08:00
commit b1928b41c0
21813 changed files with 4413081 additions and 0 deletions
@@ -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);
}