diff options
author | Angelos Mouzakitis <a.mouzakitis@virtualopensystems.com> | 2023-10-10 14:33:42 +0000 |
---|---|---|
committer | Angelos Mouzakitis <a.mouzakitis@virtualopensystems.com> | 2023-10-10 14:33:42 +0000 |
commit | af1a266670d040d2f4083ff309d732d648afba2a (patch) | |
tree | 2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/u-boot/arch/powerpc/cpu/mpc8xx | |
parent | e02cda008591317b1625707ff8e115a4841aa889 (diff) |
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/u-boot/arch/powerpc/cpu/mpc8xx')
-rw-r--r-- | roms/u-boot/arch/powerpc/cpu/mpc8xx/Kconfig | 175 | ||||
-rw-r--r-- | roms/u-boot/arch/powerpc/cpu/mpc8xx/Makefile | 14 | ||||
-rw-r--r-- | roms/u-boot/arch/powerpc/cpu/mpc8xx/cache.c | 49 | ||||
-rw-r--r-- | roms/u-boot/arch/powerpc/cpu/mpc8xx/config.mk | 6 | ||||
-rw-r--r-- | roms/u-boot/arch/powerpc/cpu/mpc8xx/cpu.c | 287 | ||||
-rw-r--r-- | roms/u-boot/arch/powerpc/cpu/mpc8xx/cpu_init.c | 192 | ||||
-rw-r--r-- | roms/u-boot/arch/powerpc/cpu/mpc8xx/fdt.c | 30 | ||||
-rw-r--r-- | roms/u-boot/arch/powerpc/cpu/mpc8xx/immap.c | 406 | ||||
-rw-r--r-- | roms/u-boot/arch/powerpc/cpu/mpc8xx/interrupts.c | 252 | ||||
-rw-r--r-- | roms/u-boot/arch/powerpc/cpu/mpc8xx/speed.c | 44 | ||||
-rw-r--r-- | roms/u-boot/arch/powerpc/cpu/mpc8xx/start.S | 542 | ||||
-rw-r--r-- | roms/u-boot/arch/powerpc/cpu/mpc8xx/traps.c | 157 |
12 files changed, 2154 insertions, 0 deletions
diff --git a/roms/u-boot/arch/powerpc/cpu/mpc8xx/Kconfig b/roms/u-boot/arch/powerpc/cpu/mpc8xx/Kconfig new file mode 100644 index 000000000..f11231737 --- /dev/null +++ b/roms/u-boot/arch/powerpc/cpu/mpc8xx/Kconfig @@ -0,0 +1,175 @@ +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 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 diff --git a/roms/u-boot/arch/powerpc/cpu/mpc8xx/Makefile b/roms/u-boot/arch/powerpc/cpu/mpc8xx/Makefile new file mode 100644 index 000000000..8918a2628 --- /dev/null +++ b/roms/u-boot/arch/powerpc/cpu/mpc8xx/Makefile @@ -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 diff --git a/roms/u-boot/arch/powerpc/cpu/mpc8xx/cache.c b/roms/u-boot/arch/powerpc/cpu/mpc8xx/cache.c new file mode 100644 index 000000000..41559009c --- /dev/null +++ b/roms/u-boot/arch/powerpc/cpu/mpc8xx/cache.c @@ -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); +} diff --git a/roms/u-boot/arch/powerpc/cpu/mpc8xx/config.mk b/roms/u-boot/arch/powerpc/cpu/mpc8xx/config.mk new file mode 100644 index 000000000..00b7ed50a --- /dev/null +++ b/roms/u-boot/arch/powerpc/cpu/mpc8xx/config.mk @@ -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 diff --git a/roms/u-boot/arch/powerpc/cpu/mpc8xx/cpu.c b/roms/u-boot/arch/powerpc/cpu/mpc8xx/cpu.c new file mode 100644 index 000000000..893aecef2 --- /dev/null +++ b/roms/u-boot/arch/powerpc/cpu/mpc8xx/cpu.c @@ -0,0 +1,287 @@ +// 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 <net.h> +#include <time.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 <asm/global_data.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(struct cmd_tbl *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(struct bd_info *bis) +{ +#if defined(CONFIG_MPC8XX_FEC) + fec_initialize(bis); +#endif + return 0; +} diff --git a/roms/u-boot/arch/powerpc/cpu/mpc8xx/cpu_init.c b/roms/u-boot/arch/powerpc/cpu/mpc8xx/cpu_init.c new file mode 100644 index 000000000..c8d06b050 --- /dev/null +++ b/roms/u-boot/arch/powerpc/cpu/mpc8xx/cpu_init.c @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + */ + +#include <common.h> +#include <init.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; +} diff --git a/roms/u-boot/arch/powerpc/cpu/mpc8xx/fdt.c b/roms/u-boot/arch/powerpc/cpu/mpc8xx/fdt.c new file mode 100644 index 000000000..b4a26efe3 --- /dev/null +++ b/roms/u-boot/arch/powerpc/cpu/mpc8xx/fdt.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2008 (C) Bryan O'Donoghue + * + * Code copied & edited from Freescale mpc85xx stuff. + */ + +#include <common.h> +#include <time.h> +#include <asm/global_data.h> +#include <linux/libfdt.h> +#include <fdt_support.h> + +DECLARE_GLOBAL_DATA_PTR; + +void ft_cpu_setup(void *blob, struct bd_info *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)gd->ram_base, (u64)gd->ram_size); +} diff --git a/roms/u-boot/arch/powerpc/cpu/mpc8xx/immap.c b/roms/u-boot/arch/powerpc/cpu/mpc8xx/immap.c new file mode 100644 index 000000000..40793c26e --- /dev/null +++ b/roms/u-boot/arch/powerpc/cpu/mpc8xx/immap.c @@ -0,0 +1,406 @@ +// 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/global_data.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(struct cmd_tbl *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(struct cmd_tbl *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(struct cmd_tbl *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(struct cmd_tbl *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(struct cmd_tbl *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(struct cmd_tbl *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", + "" +); diff --git a/roms/u-boot/arch/powerpc/cpu/mpc8xx/interrupts.c b/roms/u-boot/arch/powerpc/cpu/mpc8xx/interrupts.c new file mode 100644 index 000000000..eef1951f2 --- /dev/null +++ b/roms/u-boot/arch/powerpc/cpu/mpc8xx/interrupts.c @@ -0,0 +1,252 @@ +// 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 <time.h> +#include <asm/cpm_8xx.h> +#include <asm/processor.h> +#include <asm/io.h> +#include <asm/ptrace.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); +} + +/************************************************************************/ diff --git a/roms/u-boot/arch/powerpc/cpu/mpc8xx/speed.c b/roms/u-boot/arch/powerpc/cpu/mpc8xx/speed.c new file mode 100644 index 000000000..ad3d3f910 --- /dev/null +++ b/roms/u-boot/arch/powerpc/cpu/mpc8xx/speed.c @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2000-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + */ + +#include <common.h> +#include <clock_legacy.h> +#include <mpc8xx.h> +#include <asm/global_data.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; +} diff --git a/roms/u-boot/arch/powerpc/cpu/mpc8xx/start.S b/roms/u-boot/arch/powerpc/cpu/mpc8xx/start.S new file mode 100644 index 000000000..ed735cdee --- /dev/null +++ b/roms/u-boot/arch/powerpc/cpu/mpc8xx/start.S @@ -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 diff --git a/roms/u-boot/arch/powerpc/cpu/mpc8xx/traps.c b/roms/u-boot/arch/powerpc/cpu/mpc8xx/traps.c new file mode 100644 index 000000000..56794b08a --- /dev/null +++ b/roms/u-boot/arch/powerpc/cpu/mpc8xx/traps.c @@ -0,0 +1,157 @@ +// 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 <asm/ptrace.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"); +} + +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); +} |