diff options
34 files changed, 5418 insertions, 26 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index cd350deaa7..4e41455861 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -319,7 +319,7 @@ S: Maintained F: arch/powerpc/ POWERPC MPC8XX -M: Wolfgang Denk <wd@denx.de> +M: Christophe Leroy <christophe.leroy@c-s.fr> S: Maintained T: git git://git.denx.de/u-boot-mpc8xx.git F: arch/powerpc/cpu/mpc8xx/ @@ -324,6 +324,9 @@ The following options need to be configured: multiple fs option at one time for marvell soc family +- 8xx CPU Options: (if using an MPC8xx CPU) + CONFIG_8xx_GCLK_FREQ - CPU clock + - 85xx CPU Options: CONFIG_SYS_PPC64 @@ -687,10 +690,29 @@ The following options need to be configured: Define this variable to enable hw flow control in serial driver. Current user of this option is drivers/serial/nsl16550.c driver +- Console Interface: + Depending on board, define exactly one serial port + (CONFIG_8xx_CONS_SMC1 or CONFIG_8xx_CONS_SMC2), + or switch off the serial console by defining + CONFIG_8xx_CONS_NONE + + Note: if CONFIG_8xx_CONS_NONE is defined, the serial + port routines must be defined elsewhere + (i.e. serial_init(), serial_getc(), ...) + - Console Baudrate: CONFIG_BAUDRATE - in bps Select one of the baudrates listed in CONFIG_SYS_BAUDRATE_TABLE, see below. + CONFIG_SYS_BRGCLK_PRESCALE, baudrate prescale + +- Console Rx buffer length + With CONFIG_SYS_SMC_RXBUFLEN it is possible to define + the maximum receive buffer length for the SMC. + This option is actual only for 8xx possible. + If using CONFIG_SYS_SMC_RXBUFLEN also CONFIG_SYS_MAXIDLE + must be defined, to setup the maximum idle timeout for + the SMC. - Autoboot Command: CONFIG_BOOTCOMMAND @@ -856,7 +878,7 @@ The following options need to be configured: (configuration option CONFIG_CMD_CACHE) unless you know what you (and your U-Boot users) are doing. Data cache cannot be enabled on systems like the - 8260 (where accesses to the IMMR region must be + 8xx (where accesses to the IMMR region must be uncached), and it cannot be disabled on all other systems where we (mis-) use the data cache to hold an initial stack and some data. @@ -919,9 +941,11 @@ The following options need to be configured: CONFIG_WATCHDOG If this variable is defined, it enables watchdog support for the SoC. There must be support in the SoC - specific code for a watchdog. When supported for a - specific SoC is available, then no further board specific - code should be needed to use it. + specific code for a watchdog. For the 8xx + CPUs, the SIU Watchdog feature is enabled in the SYPCR + register. When supported for a specific SoC is + available, then no further board specific code should + be needed to use it. CONFIG_HW_WATCHDOG When using a watchdog circuitry external to the used @@ -3932,7 +3956,7 @@ Low Level (hardware related) configuration options: - CONFIG_SYS_IMMR: Physical address of the Internal Memory. DO NOT CHANGE unless you know exactly what you're - doing! (11-4) [82xx systems only] + doing! (11-4) [MPC8xx systems only] - CONFIG_SYS_INIT_RAM_ADDR: @@ -3945,6 +3969,7 @@ Low Level (hardware related) configuration options: sequences. U-Boot uses the following memory types: + - MPC8xx: IMMR (internal memory of the CPU) - CONFIG_SYS_GBL_DATA_OFFSET: @@ -3964,6 +3989,16 @@ Low Level (hardware related) configuration options: point to an otherwise UNUSED address space between the top of RAM and the start of the PCI space. +- CONFIG_SYS_SIUMCR: SIU Module Configuration (11-6) + +- CONFIG_SYS_SYPCR: System Protection Control (11-9) + +- CONFIG_SYS_TBSCR: Time Base Status and Control (11-26) + +- CONFIG_SYS_PISCR: Periodic Interrupt Status and Control (11-31) + +- CONFIG_SYS_PLPRCR: PLL, Low-Power, and Reset Control Register (15-30) + - CONFIG_SYS_SCCR: System Clock and reset Control Register (15-27) - CONFIG_SYS_OR_TIMING_SDRAM: @@ -3972,6 +4007,8 @@ Low Level (hardware related) configuration options: - CONFIG_SYS_MAMR_PTA: periodic timer for refresh +- CONFIG_SYS_DER: Debug Event Register (37-47) + - FLASH_BASE0_PRELIM, FLASH_BASE1_PRELIM, CONFIG_SYS_REMAP_OR_AM, CONFIG_SYS_PRELIM_OR_AM, CONFIG_SYS_OR_TIMING_FLASH, CONFIG_SYS_OR0_REMAP, CONFIG_SYS_OR0_PRELIM, CONFIG_SYS_BR0_PRELIM, CONFIG_SYS_OR1_REMAP, CONFIG_SYS_OR1_PRELIM, @@ -4057,6 +4094,21 @@ Low Level (hardware related) configuration options: Only for 83xx systems. If specified, then DDR should be configured using CS0 and CS1 instead of CS2 and CS3. +- CONFIG_ETHER_ON_FEC[12] + Define to enable FEC[12] on a 8xx series processor. + +- CONFIG_FEC[12]_PHY + Define to the hardcoded PHY address which corresponds + to the given FEC; i. e. + #define CONFIG_FEC1_PHY 4 + means that the PHY with address 4 is connected to FEC1 + + When set to -1, means to probe for first available. + +- CONFIG_FEC[12]_PHY_NORXERR + The PHY does not have a RXERR line (RMII only). + (so program the FEC to ignore it). + - CONFIG_RMII Enable RMII mode for all FECs. Note that this is a global option, we can't diff --git a/api/api_platform-powerpc.c b/api/api_platform-powerpc.c index d1b54ea4e1..9e9bc63b2f 100644 --- a/api/api_platform-powerpc.c +++ b/api/api_platform-powerpc.c @@ -30,7 +30,7 @@ int platform_sys_info(struct sys_info *si) si->clk_bus = gd->bus_clk; si->clk_cpu = gd->cpu_clk; -#if defined(CONFIG_E500) || defined(CONFIG_MPC86xx) +#if defined(CONFIG_8xx) || defined(CONFIG_E500) || defined(CONFIG_MPC86xx) #define bi_bar bi_immr_base #elif defined(CONFIG_MPC83xx) #define bi_bar bi_immrbar diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index c3dba8955d..a7558d59b2 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -29,10 +29,16 @@ config MPC86xx select SYS_FSL_DDR select SYS_FSL_DDR_BE +config 8xx + bool "MPC8xx" + endchoice +source "arch/powerpc/lib/Kconfig" + source "arch/powerpc/cpu/mpc83xx/Kconfig" source "arch/powerpc/cpu/mpc85xx/Kconfig" source "arch/powerpc/cpu/mpc86xx/Kconfig" +source "arch/powerpc/cpu/mpc8xx/Kconfig" endmenu diff --git a/arch/powerpc/cpu/mpc8xx/Kconfig b/arch/powerpc/cpu/mpc8xx/Kconfig new file mode 100644 index 0000000000..a425cba8aa --- /dev/null +++ b/arch/powerpc/cpu/mpc8xx/Kconfig @@ -0,0 +1,13 @@ +menu "mpc8xx CPU" + depends on 8xx + +config SYS_CPU + default "mpc8xx" + +choice + prompt "Target select" + optional + +endchoice + +endmenu diff --git a/arch/powerpc/cpu/mpc8xx/Makefile b/arch/powerpc/cpu/mpc8xx/Makefile new file mode 100644 index 0000000000..5dd801d76e --- /dev/null +++ b/arch/powerpc/cpu/mpc8xx/Makefile @@ -0,0 +1,17 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +extra-y += start.o +extra-y += traps.o +obj-y += cpu.o +obj-y += cpu_init.o +obj-y += fec.o +obj-$(CONFIG_OF_LIBFDT) += fdt.o +obj-y += interrupts.o +obj-y += serial.o +obj-y += speed.o +obj-y += spi.o diff --git a/arch/powerpc/cpu/mpc8xx/config.mk b/arch/powerpc/cpu/mpc8xx/config.mk new file mode 100644 index 0000000000..485e43d2de --- /dev/null +++ b/arch/powerpc/cpu/mpc8xx/config.mk @@ -0,0 +1,8 @@ +# +# (C) Copyright 2000-2010 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +PLATFORM_CPPFLAGS += -mstring -mcpu=860 -msoft-float diff --git a/arch/powerpc/cpu/mpc8xx/cpu.c b/arch/powerpc/cpu/mpc8xx/cpu.c new file mode 100644 index 0000000000..80b9596813 --- /dev/null +++ b/arch/powerpc/cpu/mpc8xx/cpu.c @@ -0,0 +1,331 @@ +/* + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * 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 <watchdog.h> +#include <command.h> +#include <mpc8xx.h> +#include <commproc.h> +#include <netdev.h> +#include <asm/cache.h> +#include <linux/compiler.h> +#include <asm/io.h> + +#if defined(CONFIG_OF_LIBFDT) +#include <libfdt.h> +#include <fdt_support.h> +#endif + +DECLARE_GLOBAL_DATA_PTR; + +static char *cpu_warning = "\n " \ + "*** Warning: CPU Core has Silicon Bugs -- Check the Errata ***"; + +static int check_CPU (long clock, uint pvr, uint immr) +{ + char *id_str = + NULL; + volatile immap_t *immap = (immap_t *) (immr & 0xFFFF0000); + uint k, m; + char buf[32]; + char pre = 'X'; + char *mid = "xx"; + char *suf; + + /* the highest 16 bits should be 0x0050 for a 860 */ + + if ((pvr >> 16) != 0x0050) + return -1; + + k = (immr << 16) | + immap->im_cpm.cp_dparam16[PROFF_REVNUM / sizeof(u16)]; + m = 0; + suf = ""; + + /* + * 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 */ + suf = "A"; + /* fall through */ + case 0x08000003: /* Rev. 0.3 */ + pre = 'M'; m = 1; + if (id_str == NULL) + id_str = + "PC866x"; /* Unknown chip from MPC866 family */ + break; + case 0x09000000: pre = 'M'; mid = suf = ""; m = 1; + if (id_str == NULL) + id_str = "PC885"; /* 870/875/880/885 */ + break; + + default: suf = NULL; break; + } + + if (id_str == NULL) + id_str = "PC86x"; /* Unknown 86x chip */ + if (suf) + printf ("%c%s%sZPnn%s", pre, id_str, mid, suf); + else + printf ("unknown M%s (0x%08x)", id_str, k); + + 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)? */ + + immap->im_cpm.cp_fec.fec_addr_low = 0x12345678; + if (immap->im_cpm.cp_fec.fec_addr_low == 0x12345678) { + printf (" FEC present"); + } + + if (!m) { + puts (cpu_warning); + } + + putc ('\n'); + + return 0; +} + +/* ------------------------------------------------------------------------- */ + +int checkcpu (void) +{ + ulong clock = gd->cpu_clk; + uint immr = get_immr (0); /* Return full IMMR contents */ + uint pvr = get_pvr (); + + puts ("CPU: "); + + return check_CPU (clock, pvr, immr); +} + +/* ------------------------------------------------------------------------- */ +/* L1 i-cache */ + +int checkicache (void) +{ + volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR; + volatile memctl8xx_t *memctl = &immap->im_memctl; + u32 cacheon = rd_ic_cst () & IDC_ENABLED; + + u32 k = memctl->memc_br0 & ~0x00007fff; /* probe in flash memoryarea */ + 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 */ + +int checkdcache (void) +{ + volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR; + volatile memctl8xx_t *memctl = &immap->im_memctl; + u32 cacheon = rd_dc_cst () & IDC_ENABLED; + + u32 k = memctl->memc_br0 & ~0x00007fff; /* probe in flash memoryarea */ + 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; +}; + +/* ------------------------------------------------------------------------- */ + +void upmconfig (uint upm, uint * table, uint size) +{ + uint i; + uint addr = 0; + volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR; + volatile memctl8xx_t *memctl = &immap->im_memctl; + + for (i = 0; i < size; i++) { + memctl->memc_mdr = table[i]; /* (16-15) */ + 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; + + volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR; + + immap->im_clkrst.car_plprcr |= PLPRCR_CSR; /* Checkstop Reset enable */ + + /* 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) +{ + uint immr = get_immr (0); /* Return full IMMR contents */ + volatile immap_t *immap = (volatile immap_t *)(immr & 0xFFFF0000); + ulong oscclk, factor, pll; + + if (immap->im_clkrst.car_sccr & SCCR_TBS) { + return (gd->cpu_clk / 16); + } + + pll = 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 ((immap->im_clkrst.car_sccr & SCCR_RTSEL) == 0 || factor > 2) { + return (oscclk / 4); + } + return (oscclk / 16); +} + +/* ------------------------------------------------------------------------- */ + +#if defined(CONFIG_WATCHDOG) +void watchdog_reset (void) +{ + int re_enable = disable_interrupts (); + + reset_8xx_watchdog ((immap_t *) CONFIG_SYS_IMMR); + if (re_enable) + enable_interrupts (); +} +#endif /* CONFIG_WATCHDOG */ + +#if defined(CONFIG_WATCHDOG) + +void reset_8xx_watchdog (volatile immap_t * immr) +{ + /* + * All other boards use the MPC8xx Internal Watchdog + */ + immr->im_siu_conf.sc_swsr = 0x556c; /* write magic1 */ + immr->im_siu_conf.sc_swsr = 0xaa39; /* write magic2 */ +} +#endif /* CONFIG_WATCHDOG */ + +/* + * Initializes on-chip ethernet controllers. + * to override, implement board_eth_init() + */ +int cpu_eth_init(bd_t *bis) +{ +#if defined(FEC_ENET) + fec_initialize(bis); +#endif + return 0; +} diff --git a/arch/powerpc/cpu/mpc8xx/cpu_init.c b/arch/powerpc/cpu/mpc8xx/cpu_init.c new file mode 100644 index 0000000000..0f935aff9e --- /dev/null +++ b/arch/powerpc/cpu/mpc8xx/cpu_init.c @@ -0,0 +1,180 @@ +/* + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <watchdog.h> + +#include <mpc8xx.h> +#include <commproc.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 (volatile immap_t * immr) +{ + volatile memctl8xx_t *memctl = &immr->im_memctl; +# ifdef CONFIG_SYS_PLPRCR + ulong mfmask; +# endif + ulong reg; + + /* SYPCR - contains watchdog control (11-9) */ + + immr->im_siu_conf.sc_sypcr = CONFIG_SYS_SYPCR; + +#if defined(CONFIG_WATCHDOG) + reset_8xx_watchdog (immr); +#endif /* CONFIG_WATCHDOG */ + + /* SIUMCR - contains debug pin configuration (11-6) */ + immr->im_siu_conf.sc_siumcr |= CONFIG_SYS_SIUMCR; + /* initialize timebase status and control register (11-26) */ + /* unlock TBSCRK */ + + immr->im_sitk.sitk_tbscrk = KAPWR_KEY; + immr->im_sit.sit_tbscr = CONFIG_SYS_TBSCR; + + /* initialize the PIT (11-31) */ + + immr->im_sitk.sitk_piscrk = KAPWR_KEY; + immr->im_sit.sit_piscr = CONFIG_SYS_PISCR; + + /* System integration timers. Don't change EBDF! (15-27) */ + + immr->im_clkrstk.cark_sccrk = KAPWR_KEY; + reg = immr->im_clkrst.car_sccr; + reg &= SCCR_MASK; + reg |= CONFIG_SYS_SCCR; + immr->im_clkrst.car_sccr = reg; + + /* PLL (CPU clock) settings (15-30) */ + + 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 + mfmask = PLPRCR_MFACT_MSK; + + if ((CONFIG_SYS_PLPRCR & mfmask) != 0) + reg = CONFIG_SYS_PLPRCR; /* reset control bits */ + else { + reg = immr->im_clkrst.car_plprcr; + reg &= mfmask; /* isolate MF-related fields */ + reg |= CONFIG_SYS_PLPRCR; /* reset control bits */ + } + immr->im_clkrst.car_plprcr = reg; +#endif + + /* + * Memory Controller: + */ + + /* perform BR0 reset that MPC850 Rev. A can't guarantee */ + reg = memctl->memc_br0; + reg &= BR_PS_MSK; /* Clear everything except Port Size bits */ + reg |= BR_V; /* then add just the "Bank Valid" bit */ + memctl->memc_br0 = reg; + + /* 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) + memctl->memc_or0 = CONFIG_SYS_OR0_REMAP; +#endif +#if defined(CONFIG_SYS_OR1_REMAP) + memctl->memc_or1 = CONFIG_SYS_OR1_REMAP; +#endif +#if defined(CONFIG_SYS_OR5_REMAP) + memctl->memc_or5 = CONFIG_SYS_OR5_REMAP; +#endif + + /* now restrict to preliminary range */ + memctl->memc_br0 = CONFIG_SYS_BR0_PRELIM; + memctl->memc_or0 = CONFIG_SYS_OR0_PRELIM; + +#if (defined(CONFIG_SYS_OR1_PRELIM) && defined(CONFIG_SYS_BR1_PRELIM)) + memctl->memc_or1 = CONFIG_SYS_OR1_PRELIM; + memctl->memc_br1 = CONFIG_SYS_BR1_PRELIM; +#endif + +#if defined(CONFIG_SYS_OR2_PRELIM) && defined(CONFIG_SYS_BR2_PRELIM) + memctl->memc_or2 = CONFIG_SYS_OR2_PRELIM; + memctl->memc_br2 = CONFIG_SYS_BR2_PRELIM; +#endif + +#if defined(CONFIG_SYS_OR3_PRELIM) && defined(CONFIG_SYS_BR3_PRELIM) + memctl->memc_or3 = CONFIG_SYS_OR3_PRELIM; + memctl->memc_br3 = CONFIG_SYS_BR3_PRELIM; +#endif + +#if defined(CONFIG_SYS_OR4_PRELIM) && defined(CONFIG_SYS_BR4_PRELIM) + memctl->memc_or4 = CONFIG_SYS_OR4_PRELIM; + memctl->memc_br4 = CONFIG_SYS_BR4_PRELIM; +#endif + +#if defined(CONFIG_SYS_OR5_PRELIM) && defined(CONFIG_SYS_BR5_PRELIM) + memctl->memc_or5 = CONFIG_SYS_OR5_PRELIM; + memctl->memc_br5 = CONFIG_SYS_BR5_PRELIM; +#endif + +#if defined(CONFIG_SYS_OR6_PRELIM) && defined(CONFIG_SYS_BR6_PRELIM) + memctl->memc_or6 = CONFIG_SYS_OR6_PRELIM; + memctl->memc_br6 = CONFIG_SYS_BR6_PRELIM; +#endif + +#if defined(CONFIG_SYS_OR7_PRELIM) && defined(CONFIG_SYS_BR7_PRELIM) + memctl->memc_or7 = CONFIG_SYS_OR7_PRELIM; + memctl->memc_br7 = CONFIG_SYS_BR7_PRELIM; +#endif + + /* + * Reset CPM + */ + immr->im_cpm.cp_cpcr = CPM_CR_RST | CPM_CR_FLG; + do { /* Spin until command processed */ + __asm__ ("eieio"); + } while (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/arch/powerpc/cpu/mpc8xx/fdt.c b/arch/powerpc/cpu/mpc8xx/fdt.c new file mode 100644 index 0000000000..34d36478d3 --- /dev/null +++ b/arch/powerpc/cpu/mpc8xx/fdt.c @@ -0,0 +1,27 @@ +/* + * Copyright 2008 (C) Bryan O'Donoghue + * + * Code copied & edited from Freescale mpc85xx stuff. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <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,cpm-brg", "clock-frequency", + gd->arch.brg_clk, 1); + + fdt_fixup_memory(blob, (u64)bd->bi_memstart, (u64)bd->bi_memsize); +} diff --git a/arch/powerpc/cpu/mpc8xx/fec.c b/arch/powerpc/cpu/mpc8xx/fec.c new file mode 100644 index 0000000000..7aa526d7ec --- /dev/null +++ b/arch/powerpc/cpu/mpc8xx/fec.c @@ -0,0 +1,847 @@ +/* + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <command.h> +#include <commproc.h> +#include <malloc.h> +#include <net.h> + +#include <phy.h> + +DECLARE_GLOBAL_DATA_PTR; + +#if defined(CONFIG_CMD_NET) && \ + (defined(FEC_ENET) || defined(CONFIG_ETHER_ON_FEC1) || defined(CONFIG_ETHER_ON_FEC2)) + +/* compatibility test, if only FEC_ENET defined assume ETHER on FEC1 */ +#if defined(FEC_ENET) && !defined(CONFIG_ETHER_ON_FEC1) && !defined(CONFIG_ETHER_ON_FEC2) +#define CONFIG_ETHER_ON_FEC1 1 +#endif + +/* define WANT_MII when MII support is required */ +#if defined(CONFIG_SYS_DISCOVER_PHY) || defined(CONFIG_FEC1_PHY) || defined(CONFIG_FEC2_PHY) +#define WANT_MII +#else +#undef WANT_MII +#endif + +#if defined(WANT_MII) +#include <miiphy.h> + +#if !(defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) +#error "CONFIG_MII has to be defined!" +#endif + +#endif + +#if defined(CONFIG_RMII) && !defined(WANT_MII) +#error RMII support is unusable without a working PHY. +#endif + +#ifdef CONFIG_SYS_DISCOVER_PHY +static int mii_discover_phy(struct eth_device *dev); +#endif + +int fec8xx_miiphy_read(struct mii_dev *bus, int addr, int devad, int reg); +int fec8xx_miiphy_write(struct mii_dev *bus, int addr, int devad, int reg, + u16 value); + +static struct ether_fcc_info_s +{ + int ether_index; + int fecp_offset; + int phy_addr; + int actual_phy_addr; + int initialized; +} + ether_fcc_info[] = { +#if defined(CONFIG_ETHER_ON_FEC1) + { + 0, + offsetof(immap_t, im_cpm.cp_fec1), +#if defined(CONFIG_FEC1_PHY) + CONFIG_FEC1_PHY, +#else + -1, /* discover */ +#endif + -1, + 0, + + }, +#endif +#if defined(CONFIG_ETHER_ON_FEC2) + { + 1, + offsetof(immap_t, im_cpm.cp_fec2), +#if defined(CONFIG_FEC2_PHY) + CONFIG_FEC2_PHY, +#else + -1, +#endif + -1, + 0, + }, +#endif +}; + +/* Ethernet Transmit and Receive Buffers */ +#define DBUF_LENGTH 1520 + +#define TX_BUF_CNT 2 + +#define TOUT_LOOP 100 + +#define PKT_MAXBUF_SIZE 1518 +#define PKT_MINBUF_SIZE 64 +#define PKT_MAXBLR_SIZE 1520 + +#ifdef __GNUC__ +static char txbuf[DBUF_LENGTH] __attribute__ ((aligned(8))); +#else +#error txbuf must be aligned. +#endif + +static uint rxIdx; /* index of the current RX buffer */ +static uint txIdx; /* index of the current TX buffer */ + +/* + * FEC Ethernet Tx and Rx buffer descriptors allocated at the + * immr->udata_bd address on Dual-Port RAM + * Provide for Double Buffering + */ + +typedef volatile struct CommonBufferDescriptor { + cbd_t rxbd[PKTBUFSRX]; /* Rx BD */ + cbd_t txbd[TX_BUF_CNT]; /* Tx BD */ +} RTXBD; + +static RTXBD *rtx = NULL; + +static int fec_send(struct eth_device *dev, void *packet, int length); +static int fec_recv(struct eth_device* dev); +static int fec_init(struct eth_device* dev, bd_t * bd); +static void fec_halt(struct eth_device* dev); +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) +static void __mii_init(void); +#endif + +int fec_initialize(bd_t *bis) +{ + struct eth_device* dev; + struct ether_fcc_info_s *efis; + int i; + + for (i = 0; i < ARRAY_SIZE(ether_fcc_info); i++) { + + dev = malloc(sizeof(*dev)); + if (dev == NULL) + hang(); + + memset(dev, 0, sizeof(*dev)); + + /* for FEC1 make sure that the name of the interface is the same + as the old one for compatibility reasons */ + if (i == 0) { + strcpy(dev->name, "FEC"); + } else { + sprintf (dev->name, "FEC%d", + ether_fcc_info[i].ether_index + 1); + } + + efis = ðer_fcc_info[i]; + + /* + * reset actual phy addr + */ + efis->actual_phy_addr = -1; + + dev->priv = efis; + dev->init = fec_init; + dev->halt = fec_halt; + dev->send = fec_send; + dev->recv = fec_recv; + + eth_register(dev); + +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) + int retval; + struct mii_dev *mdiodev = mdio_alloc(); + if (!mdiodev) + return -ENOMEM; + strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN); + mdiodev->read = fec8xx_miiphy_read; + mdiodev->write = fec8xx_miiphy_write; + + retval = mdio_register(mdiodev); + if (retval < 0) + return retval; +#endif + } + return 1; +} + +static int fec_send(struct eth_device *dev, void *packet, int length) +{ + int j, rc; + struct ether_fcc_info_s *efis = dev->priv; + volatile fec_t *fecp = (volatile fec_t *)(CONFIG_SYS_IMMR + efis->fecp_offset); + + /* section 16.9.23.3 + * Wait for ready + */ + j = 0; + while ((rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY) && (j<TOUT_LOOP)) { + udelay(1); + j++; + } + if (j>=TOUT_LOOP) { + printf("TX not ready\n"); + } + + rtx->txbd[txIdx].cbd_bufaddr = (uint)packet; + rtx->txbd[txIdx].cbd_datlen = length; + rtx->txbd[txIdx].cbd_sc |= BD_ENET_TX_READY | BD_ENET_TX_LAST; + __asm__ ("eieio"); + + /* Activate transmit Buffer Descriptor polling */ + fecp->fec_x_des_active = 0x01000000; /* Descriptor polling active */ + + j = 0; + while ((rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY) && (j<TOUT_LOOP)) { + udelay(1); + j++; + } + if (j>=TOUT_LOOP) { + printf("TX timeout\n"); + } + /* return only status bits */; + rc = (rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_STATS); + + txIdx = (txIdx + 1) % TX_BUF_CNT; + + return rc; +} + +static int fec_recv (struct eth_device *dev) +{ + struct ether_fcc_info_s *efis = dev->priv; + volatile fec_t *fecp = + (volatile fec_t *) (CONFIG_SYS_IMMR + efis->fecp_offset); + int length; + + for (;;) { + /* section 16.9.23.2 */ + if (rtx->rxbd[rxIdx].cbd_sc & BD_ENET_RX_EMPTY) { + length = -1; + break; /* nothing received - leave for() loop */ + } + + length = rtx->rxbd[rxIdx].cbd_datlen; + + if (rtx->rxbd[rxIdx].cbd_sc & 0x003f) { + } else { + uchar *rx = net_rx_packets[rxIdx]; + + length -= 4; + +#if defined(CONFIG_CMD_CDP) + if ((rx[0] & 1) != 0 && + memcmp((uchar *)rx, net_bcast_ethaddr, 6) != 0 && + !is_cdp_packet((uchar *)rx)) + rx = NULL; +#endif + /* + * Pass the packet up to the protocol layers. + */ + if (rx != NULL) + net_process_received_packet(rx, length); + } + + /* Give the buffer back to the FEC. */ + rtx->rxbd[rxIdx].cbd_datlen = 0; + + /* wrap around buffer index when necessary */ + if ((rxIdx + 1) >= PKTBUFSRX) { + rtx->rxbd[PKTBUFSRX - 1].cbd_sc = + (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY); + rxIdx = 0; + } else { + rtx->rxbd[rxIdx].cbd_sc = BD_ENET_RX_EMPTY; + rxIdx++; + } + + __asm__ ("eieio"); + + /* Try to fill Buffer Descriptors */ + fecp->fec_r_des_active = 0x01000000; /* Descriptor polling active */ + } + + return length; +} + +/************************************************************** + * + * FEC Ethernet Initialization Routine + * + *************************************************************/ + +#define FEC_ECNTRL_PINMUX 0x00000004 +#define FEC_ECNTRL_ETHER_EN 0x00000002 +#define FEC_ECNTRL_RESET 0x00000001 + +#define FEC_RCNTRL_BC_REJ 0x00000010 +#define FEC_RCNTRL_PROM 0x00000008 +#define FEC_RCNTRL_MII_MODE 0x00000004 +#define FEC_RCNTRL_DRT 0x00000002 +#define FEC_RCNTRL_LOOP 0x00000001 + +#define FEC_TCNTRL_FDEN 0x00000004 +#define FEC_TCNTRL_HBC 0x00000002 +#define FEC_TCNTRL_GTS 0x00000001 + +#define FEC_RESET_DELAY 50 + +#if defined(CONFIG_RMII) + +static inline void fec_10Mbps(struct eth_device *dev) +{ + struct ether_fcc_info_s *efis = dev->priv; + int fecidx = efis->ether_index; + uint mask = (fecidx == 0) ? 0x0000010 : 0x0000008; + + if ((unsigned int)fecidx >= 2) + hang(); + + ((volatile immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_cptr |= mask; +} + +static inline void fec_100Mbps(struct eth_device *dev) +{ + struct ether_fcc_info_s *efis = dev->priv; + int fecidx = efis->ether_index; + uint mask = (fecidx == 0) ? 0x0000010 : 0x0000008; + + if ((unsigned int)fecidx >= 2) + hang(); + + ((volatile immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_cptr &= ~mask; +} + +#endif + +static inline void fec_full_duplex(struct eth_device *dev) +{ + struct ether_fcc_info_s *efis = dev->priv; + volatile fec_t *fecp = (volatile fec_t *)(CONFIG_SYS_IMMR + efis->fecp_offset); + + fecp->fec_r_cntrl &= ~FEC_RCNTRL_DRT; + fecp->fec_x_cntrl |= FEC_TCNTRL_FDEN; /* FD enable */ +} + +static inline void fec_half_duplex(struct eth_device *dev) +{ + struct ether_fcc_info_s *efis = dev->priv; + volatile fec_t *fecp = (volatile fec_t *)(CONFIG_SYS_IMMR + efis->fecp_offset); + + fecp->fec_r_cntrl |= FEC_RCNTRL_DRT; + fecp->fec_x_cntrl &= ~FEC_TCNTRL_FDEN; /* FD disable */ +} + +static void fec_pin_init(int fecidx) +{ + bd_t *bd = gd->bd; + volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR; + + /* + * Set MII speed to 2.5 MHz or slightly below. + * + * According to the MPC860T (Rev. D) Fast ethernet controller user + * manual (6.2.14), + * the MII management interface clock must be less than or equal + * to 2.5 MHz. + * This MDC frequency is equal to system clock / (2 * MII_SPEED). + * Then MII_SPEED = system_clock / 2 * 2,5 MHz. + * + * All MII configuration is done via FEC1 registers: + */ + immr->im_cpm.cp_fec1.fec_mii_speed = ((bd->bi_intfreq + 4999999) / 5000000) << 1; + +#if defined(CONFIG_MPC885_FAMILY) && defined(WANT_MII) + /* use MDC for MII */ + immr->im_ioport.iop_pdpar |= 0x0080; + immr->im_ioport.iop_pddir &= ~0x0080; +#endif + + if (fecidx == 0) { +#if defined(CONFIG_ETHER_ON_FEC1) + +#if defined(CONFIG_MPC885_FAMILY) /* MPC87x/88x have got 2 FECs and different pinout */ + +#if !defined(CONFIG_RMII) + + immr->im_ioport.iop_papar |= 0xf830; + immr->im_ioport.iop_padir |= 0x0830; + immr->im_ioport.iop_padir &= ~0xf000; + + immr->im_cpm.cp_pbpar |= 0x00001001; + immr->im_cpm.cp_pbdir &= ~0x00001001; + + immr->im_ioport.iop_pcpar |= 0x000c; + immr->im_ioport.iop_pcdir &= ~0x000c; + + immr->im_cpm.cp_pepar |= 0x00000003; + immr->im_cpm.cp_pedir |= 0x00000003; + immr->im_cpm.cp_peso &= ~0x00000003; + + immr->im_cpm.cp_cptr &= ~0x00000100; + +#else + +#if !defined(CONFIG_FEC1_PHY_NORXERR) + immr->im_ioport.iop_papar |= 0x1000; + immr->im_ioport.iop_padir &= ~0x1000; +#endif + immr->im_ioport.iop_papar |= 0xe810; + immr->im_ioport.iop_padir |= 0x0810; + immr->im_ioport.iop_padir &= ~0xe000; + + immr->im_cpm.cp_pbpar |= 0x00000001; + immr->im_cpm.cp_pbdir &= ~0x00000001; + + immr->im_cpm.cp_cptr |= 0x00000100; + immr->im_cpm.cp_cptr &= ~0x00000050; + +#endif /* !CONFIG_RMII */ + +#else + /* + * Configure all of port D for MII. + */ + immr->im_ioport.iop_pdpar = 0x1fff; + + immr->im_ioport.iop_pddir = 0x1fff; /* Rev. D and later */ +#endif + +#endif /* CONFIG_ETHER_ON_FEC1 */ + } else if (fecidx == 1) { + +#if defined(CONFIG_ETHER_ON_FEC2) + +#if defined(CONFIG_MPC885_FAMILY) /* MPC87x/88x have got 2 FECs and different pinout */ + +#if !defined(CONFIG_RMII) + immr->im_cpm.cp_pepar |= 0x0003fffc; + immr->im_cpm.cp_pedir |= 0x0003fffc; + immr->im_cpm.cp_peso &= ~0x000087fc; + immr->im_cpm.cp_peso |= 0x00037800; + + immr->im_cpm.cp_cptr &= ~0x00000080; +#else + +#if !defined(CONFIG_FEC2_PHY_NORXERR) + immr->im_cpm.cp_pepar |= 0x00000010; + immr->im_cpm.cp_pedir |= 0x00000010; + immr->im_cpm.cp_peso &= ~0x00000010; +#endif + immr->im_cpm.cp_pepar |= 0x00039620; + immr->im_cpm.cp_pedir |= 0x00039620; + immr->im_cpm.cp_peso |= 0x00031000; + immr->im_cpm.cp_peso &= ~0x00008620; + + immr->im_cpm.cp_cptr |= 0x00000080; + immr->im_cpm.cp_cptr &= ~0x00000028; +#endif /* CONFIG_RMII */ + +#endif /* CONFIG_MPC885_FAMILY */ + +#endif /* CONFIG_ETHER_ON_FEC2 */ + + } +} + +static int fec_reset(volatile fec_t *fecp) +{ + int i; + + /* Whack a reset. + * A delay is required between a reset of the FEC block and + * initialization of other FEC registers because the reset takes + * some time to complete. If you don't delay, subsequent writes + * to FEC registers might get killed by the reset routine which is + * still in progress. + */ + + fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET; + for (i = 0; + (fecp->fec_ecntrl & FEC_ECNTRL_RESET) && (i < FEC_RESET_DELAY); + ++i) { + udelay (1); + } + if (i == FEC_RESET_DELAY) + return -1; + + return 0; +} + +static int fec_init (struct eth_device *dev, bd_t * bd) +{ + struct ether_fcc_info_s *efis = dev->priv; + volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR; + volatile fec_t *fecp = + (volatile fec_t *) (CONFIG_SYS_IMMR + efis->fecp_offset); + int i; + +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) + /* the MII interface is connected to FEC1 + * so for the miiphy_xxx function to work we must + * call mii_init since fec_halt messes the thing up + */ + if (efis->ether_index != 0) + __mii_init(); +#endif + + if (fec_reset(fecp) < 0) + printf ("FEC_RESET_DELAY timeout\n"); + + /* We use strictly polling mode only + */ + fecp->fec_imask = 0; + + /* Clear any pending interrupt + */ + fecp->fec_ievent = 0xffc0; + + /* No need to set the IVEC register */ + + /* Set station address + */ +#define ea dev->enetaddr + fecp->fec_addr_low = (ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]); + fecp->fec_addr_high = (ea[4] << 8) | (ea[5]); +#undef ea + +#if defined(CONFIG_CMD_CDP) + /* + * Turn on multicast address hash table + */ + fecp->fec_hash_table_high = 0xffffffff; + fecp->fec_hash_table_low = 0xffffffff; +#else + /* Clear multicast address hash table + */ + fecp->fec_hash_table_high = 0; + fecp->fec_hash_table_low = 0; +#endif + + /* Set maximum receive buffer size. + */ + fecp->fec_r_buff_size = PKT_MAXBLR_SIZE; + + /* Set maximum frame length + */ + fecp->fec_r_hash = PKT_MAXBUF_SIZE; + + /* + * Setup Buffers and Buffer Desriptors + */ + rxIdx = 0; + txIdx = 0; + + if (!rtx) + rtx = (RTXBD *)(immr->im_cpm.cp_dpmem + CPM_FEC_BASE); + /* + * Setup Receiver Buffer Descriptors (13.14.24.18) + * Settings: + * Empty, Wrap + */ + for (i = 0; i < PKTBUFSRX; i++) { + rtx->rxbd[i].cbd_sc = BD_ENET_RX_EMPTY; + rtx->rxbd[i].cbd_datlen = 0; /* Reset */ + rtx->rxbd[i].cbd_bufaddr = (uint) net_rx_packets[i]; + } + rtx->rxbd[PKTBUFSRX - 1].cbd_sc |= BD_ENET_RX_WRAP; + + /* + * Setup Ethernet Transmitter Buffer Descriptors (13.14.24.19) + * Settings: + * Last, Tx CRC + */ + for (i = 0; i < TX_BUF_CNT; i++) { + rtx->txbd[i].cbd_sc = BD_ENET_TX_LAST | BD_ENET_TX_TC; + rtx->txbd[i].cbd_datlen = 0; /* Reset */ + rtx->txbd[i].cbd_bufaddr = (uint) (&txbuf[0]); + } + rtx->txbd[TX_BUF_CNT - 1].cbd_sc |= BD_ENET_TX_WRAP; + + /* Set receive and transmit descriptor base + */ + fecp->fec_r_des_start = (unsigned int) (&rtx->rxbd[0]); + fecp->fec_x_des_start = (unsigned int) (&rtx->txbd[0]); + + /* Enable MII mode + */ + /* Half duplex mode */ + fecp->fec_r_cntrl = FEC_RCNTRL_MII_MODE | FEC_RCNTRL_DRT; + fecp->fec_x_cntrl = 0; + + /* Enable big endian and don't care about SDMA FC. + */ + fecp->fec_fun_code = 0x78000000; + + /* + * Setup the pin configuration of the FEC + */ + fec_pin_init (efis->ether_index); + + rxIdx = 0; + txIdx = 0; + + /* + * Now enable the transmit and receive processing + */ + fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN; + + if (efis->phy_addr == -1) { +#ifdef CONFIG_SYS_DISCOVER_PHY + /* + * wait for the PHY to wake up after reset + */ + efis->actual_phy_addr = mii_discover_phy (dev); + + if (efis->actual_phy_addr == -1) { + printf ("Unable to discover phy!\n"); + return -1; + } +#else + efis->actual_phy_addr = -1; +#endif + } else { + efis->actual_phy_addr = efis->phy_addr; + } + +#if defined(CONFIG_MII) && defined(CONFIG_RMII) + /* + * adapt the RMII speed to the speed of the phy + */ + if (miiphy_speed (dev->name, efis->actual_phy_addr) == _100BASET) { + fec_100Mbps (dev); + } else { + fec_10Mbps (dev); + } +#endif + +#if defined(CONFIG_MII) + /* + * adapt to the half/full speed settings + */ + if (miiphy_duplex (dev->name, efis->actual_phy_addr) == FULL) { + fec_full_duplex (dev); + } else { + fec_half_duplex (dev); + } +#endif + + /* And last, try to fill Rx Buffer Descriptors */ + fecp->fec_r_des_active = 0x01000000; /* Descriptor polling active */ + + efis->initialized = 1; + + return 0; +} + + +static void fec_halt(struct eth_device* dev) +{ + struct ether_fcc_info_s *efis = dev->priv; + volatile fec_t *fecp = (volatile fec_t *)(CONFIG_SYS_IMMR + efis->fecp_offset); + int i; + + /* avoid halt if initialized; mii gets stuck otherwise */ + if (!efis->initialized) + return; + + /* Whack a reset. + * A delay is required between a reset of the FEC block and + * initialization of other FEC registers because the reset takes + * some time to complete. If you don't delay, subsequent writes + * to FEC registers might get killed by the reset routine which is + * still in progress. + */ + + fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET; + for (i = 0; + (fecp->fec_ecntrl & FEC_ECNTRL_RESET) && (i < FEC_RESET_DELAY); + ++i) { + udelay (1); + } + if (i == FEC_RESET_DELAY) { + printf ("FEC_RESET_DELAY timeout\n"); + return; + } + + efis->initialized = 0; +} + +#if defined(CONFIG_SYS_DISCOVER_PHY) || defined(CONFIG_MII) || defined(CONFIG_CMD_MII) + +/* Make MII read/write commands for the FEC. +*/ + +#define mk_mii_read(ADDR, REG) (0x60020000 | ((ADDR << 23) | \ + (REG & 0x1f) << 18)) + +#define mk_mii_write(ADDR, REG, VAL) (0x50020000 | ((ADDR << 23) | \ + (REG & 0x1f) << 18) | \ + (VAL & 0xffff)) + +/* Interrupt events/masks. +*/ +#define FEC_ENET_HBERR ((uint)0x80000000) /* Heartbeat error */ +#define FEC_ENET_BABR ((uint)0x40000000) /* Babbling receiver */ +#define FEC_ENET_BABT ((uint)0x20000000) /* Babbling transmitter */ +#define FEC_ENET_GRA ((uint)0x10000000) /* Graceful stop complete */ +#define FEC_ENET_TXF ((uint)0x08000000) /* Full frame transmitted */ +#define FEC_ENET_TXB ((uint)0x04000000) /* A buffer was transmitted */ +#define FEC_ENET_RXF ((uint)0x02000000) /* Full frame received */ +#define FEC_ENET_RXB ((uint)0x01000000) /* A buffer was received */ +#define FEC_ENET_MII ((uint)0x00800000) /* MII interrupt */ +#define FEC_ENET_EBERR ((uint)0x00400000) /* SDMA bus error */ + +/* send command to phy using mii, wait for result */ +static uint +mii_send(uint mii_cmd) +{ + uint mii_reply; + volatile fec_t *ep; + int cnt; + + ep = &(((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_fec); + + ep->fec_mii_data = mii_cmd; /* command to phy */ + + /* wait for mii complete */ + cnt = 0; + while (!(ep->fec_ievent & FEC_ENET_MII)) { + if (++cnt > 1000) { + printf("mii_send STUCK!\n"); + break; + } + } + mii_reply = ep->fec_mii_data; /* result from phy */ + ep->fec_ievent = FEC_ENET_MII; /* clear MII complete */ + return (mii_reply & 0xffff); /* data read from phy */ +} +#endif + +#if defined(CONFIG_SYS_DISCOVER_PHY) +static int mii_discover_phy(struct eth_device *dev) +{ +#define MAX_PHY_PASSES 11 + uint phyno; + int pass; + uint phytype; + int phyaddr; + + phyaddr = -1; /* didn't find a PHY yet */ + for (pass = 1; pass <= MAX_PHY_PASSES && phyaddr < 0; ++pass) { + if (pass > 1) { + /* PHY may need more time to recover from reset. + * The LXT970 needs 50ms typical, no maximum is + * specified, so wait 10ms before try again. + * With 11 passes this gives it 100ms to wake up. + */ + udelay(10000); /* wait 10ms */ + } + for (phyno = 0; phyno < 32 && phyaddr < 0; ++phyno) { + phytype = mii_send(mk_mii_read(phyno, MII_PHYSID2)); + if (phytype != 0xffff) { + phyaddr = phyno; + phytype |= mii_send(mk_mii_read(phyno, + MII_PHYSID1)) << 16; + } + } + } + if (phyaddr < 0) { + printf("No PHY device found.\n"); + } + return phyaddr; +} +#endif /* CONFIG_SYS_DISCOVER_PHY */ + +#if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) && !defined(CONFIG_BITBANGMII) + +/**************************************************************************** + * mii_init -- Initialize the MII via FEC 1 for MII command without ethernet + * This function is a subset of eth_init + **************************************************************************** + */ +static void __mii_init(void) +{ + volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR; + volatile fec_t *fecp = &(immr->im_cpm.cp_fec); + + if (fec_reset(fecp) < 0) + printf ("FEC_RESET_DELAY timeout\n"); + + /* We use strictly polling mode only + */ + fecp->fec_imask = 0; + + /* Clear any pending interrupt + */ + fecp->fec_ievent = 0xffc0; + + /* Now enable the transmit and receive processing + */ + fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN; +} + +void mii_init (void) +{ + int i; + + __mii_init(); + + /* Setup the pin configuration of the FEC(s) + */ + for (i = 0; i < ARRAY_SIZE(ether_fcc_info); i++) + fec_pin_init(ether_fcc_info[i].ether_index); +} + +/***************************************************************************** + * Read and write a MII PHY register, routines used by MII Utilities + * + * FIXME: These routines are expected to return 0 on success, but mii_send + * does _not_ return an error code. Maybe 0xFFFF means error, i.e. + * no PHY connected... + * For now always return 0. + * FIXME: These routines only work after calling eth_init() at least once! + * Otherwise they hang in mii_send() !!! Sorry! + *****************************************************************************/ + +int fec8xx_miiphy_read(struct mii_dev *bus, int addr, int devad, int reg) +{ + unsigned short value = 0; + short rdreg; /* register working value */ + + rdreg = mii_send(mk_mii_read(addr, reg)); + + value = rdreg; + return value; +} + +int fec8xx_miiphy_write(struct mii_dev *bus, int addr, int devad, int reg, + u16 value) +{ + (void)mii_send(mk_mii_write(addr, reg, value)); + + return 0; +} +#endif + +#endif diff --git a/arch/powerpc/cpu/mpc8xx/interrupts.c b/arch/powerpc/cpu/mpc8xx/interrupts.c new file mode 100644 index 0000000000..f090ad9ecb --- /dev/null +++ b/arch/powerpc/cpu/mpc8xx/interrupts.c @@ -0,0 +1,259 @@ +/* + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <mpc8xx.h> +#include <mpc8xx_irq.h> +#include <asm/processor.h> +#include <commproc.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); + +/************************************************************************/ + +int interrupt_init_cpu (unsigned *decrementer_count) +{ + volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR; + + *decrementer_count = get_tbclk () / CONFIG_SYS_HZ; + + /* disable all interrupts */ + immr->im_siu_conf.sc_simask = 0; + + /* Configure CPM interrupts */ + cpm_interrupt_init (); + + return (0); +} + +/************************************************************************/ + +/* + * Handle external interrupts + */ +void external_interrupt (struct pt_regs *regs) +{ + volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR; + int irq; + ulong simask, newmask; + ulong vec, v_bit; + + /* + * read the SIVEC register and shift the bits down + * to get the irq number + */ + vec = immr->im_siu_conf.sc_sivec; + irq = vec >> 26; + v_bit = 0x80000000UL >> irq; + + /* + * Read Interrupt Mask Register and Mask Interrupts + */ + simask = immr->im_siu_conf.sc_simask; + newmask = simask & (~(0xFFFF0000 >> irq)); + immr->im_siu_conf.sc_simask = newmask; + + if (!(irq & 0x1)) { /* External Interrupt ? */ + ulong siel; + + /* + * Read Interrupt Edge/Level Register + */ + siel = immr->im_siu_conf.sc_siel; + + if (siel & v_bit) { /* edge triggered interrupt ? */ + /* + * Rewrite SIPEND Register to clear interrupt + */ + 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 + */ + immr->im_siu_conf.sc_simask = simask; +} + +/************************************************************************/ + +/* + * CPM interrupt handler + */ +static void cpm_interrupt (void *regs) +{ + volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR; + uint vec; + + /* + * Get the vector by setting the ACK bit + * and then reading the register. + */ + immr->im_cpic.cpic_civr = 1; + vec = immr->im_cpic.cpic_civr; + vec >>= 11; + + if (cpm_vecs[vec].handler != NULL) { + (*cpm_vecs[vec].handler) (cpm_vecs[vec].arg); + } else { + 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. + */ + 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) +{ + volatile immap_t *immr = (immap_t *) 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; + 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; + immr->im_siu_conf.sc_simask |= 1 << (31 - vec); + } +} + +void irq_free_handler (int vec) +{ + volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR; + + if ((vec & CPMVEC_OFFSET) != 0) { + /* CPM interrupt */ + vec &= 0xffff; + immr->im_cpic.cpic_cimr &= ~(1 << vec); + cpm_vecs[vec].handler = NULL; + cpm_vecs[vec].arg = NULL; + } else { + /* SIU interrupt */ + 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) +{ + volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR; + + /* + * Initialize the CPM interrupt controller. + */ + + immr->im_cpic.cpic_cicr = + (CICR_SCD_SCC4 | + CICR_SCC_SCC3 | + CICR_SCB_SCC2 | + CICR_SCA_SCC1) | ((CPM_INTERRUPT / 2) << 13) | CICR_HP_MASK; + + immr->im_cpic.cpic_cimr = 0; + + /* + * Install the error handler. + */ + irq_install_handler (CPMVEC_ERROR, cpm_error_interrupt, NULL); + + 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) +{ + volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR; + + /* Reset Timer Expired and Timers Interrupt Status */ + 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. + */ + immr->im_clkrst.car_plprcr = immr->im_clkrst.car_plprcr; +} + +/************************************************************************/ diff --git a/arch/powerpc/cpu/mpc8xx/serial.c b/arch/powerpc/cpu/mpc8xx/serial.c new file mode 100644 index 0000000000..d4f1a41a1a --- /dev/null +++ b/arch/powerpc/cpu/mpc8xx/serial.c @@ -0,0 +1,301 @@ +/* + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <commproc.h> +#include <command.h> +#include <serial.h> +#include <watchdog.h> +#include <linux/compiler.h> + +DECLARE_GLOBAL_DATA_PTR; + +#if !defined(CONFIG_8xx_CONS_NONE) /* No Console at all */ + +#if defined(CONFIG_8xx_CONS_SMC1) /* Console on SMC1 */ +#define SMC_INDEX 0 +#define PROFF_SMC PROFF_SMC1 +#define CPM_CR_CH_SMC CPM_CR_CH_SMC1 + +#elif defined(CONFIG_8xx_CONS_SMC2) /* Console on SMC2 */ +#define SMC_INDEX 1 +#define PROFF_SMC PROFF_SMC2 +#define CPM_CR_CH_SMC CPM_CR_CH_SMC2 + +#endif /* CONFIG_8xx_CONS_SMCx */ + +#if !defined(CONFIG_SYS_SMC_RXBUFLEN) +#define CONFIG_SYS_SMC_RXBUFLEN 1 +#define CONFIG_SYS_MAXIDLE 0 +#else +#if !defined(CONFIG_SYS_MAXIDLE) +#error "you must define CONFIG_SYS_MAXIDLE" +#endif +#endif + +typedef volatile struct serialbuffer { + cbd_t rxbd; /* Rx BD */ + cbd_t txbd; /* Tx BD */ + uint rxindex; /* index for next character to read */ + volatile uchar rxbuf[CONFIG_SYS_SMC_RXBUFLEN];/* rx buffers */ + volatile uchar txbuf; /* tx buffers */ +} serialbuffer_t; + +static void serial_setdivisor(volatile cpm8xx_t *cp) +{ + int divisor=(gd->cpu_clk + 8*gd->baudrate)/16/gd->baudrate; + + if(divisor/16>0x1000) { + /* bad divisor, assume 50MHz clock and 9600 baud */ + divisor=(50*1000*1000 + 8*9600)/16/9600; + } + +#ifdef CONFIG_SYS_BRGCLK_PRESCALE + divisor /= CONFIG_SYS_BRGCLK_PRESCALE; +#endif + + if(divisor<=0x1000) { + cp->cp_brgc1=((divisor-1)<<1) | CPM_BRG_EN; + } else { + cp->cp_brgc1=((divisor/16-1)<<1) | CPM_BRG_EN | CPM_BRG_DIV16; + } +} + +/* + * Minimal serial functions needed to use one of the SMC ports + * as serial console interface. + */ + +static void smc_setbrg (void) +{ + volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR; + volatile cpm8xx_t *cp = &(im->im_cpm); + + /* Set up the baud rate generator. + * See 8xx_io/commproc.c for details. + * + * Wire BRG1 to SMCx + */ + + cp->cp_simode = 0x00000000; + + serial_setdivisor(cp); +} + +static int smc_init (void) +{ + volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR; + volatile smc_t *sp; + volatile smc_uart_t *up; + volatile cpm8xx_t *cp = &(im->im_cpm); + uint dpaddr; + volatile serialbuffer_t *rtx; + + /* initialize pointers to SMC */ + + sp = (smc_t *) &(cp->cp_smc[SMC_INDEX]); + up = (smc_uart_t *) &cp->cp_dparam[PROFF_SMC]; + /* Disable relocation */ + up->smc_rpbase = 0; + + /* Disable transmitter/receiver. */ + sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); + + /* Enable SDMA. */ + im->im_siu_conf.sc_sdcr = 1; + + /* clear error conditions */ +#ifdef CONFIG_SYS_SDSR + im->im_sdma.sdma_sdsr = CONFIG_SYS_SDSR; +#else + im->im_sdma.sdma_sdsr = 0x83; +#endif + + /* clear SDMA interrupt mask */ +#ifdef CONFIG_SYS_SDMR + im->im_sdma.sdma_sdmr = CONFIG_SYS_SDMR; +#else + im->im_sdma.sdma_sdmr = 0x00; +#endif + +#if defined(CONFIG_8xx_CONS_SMC1) + /* Use Port B for SMC1 instead of other functions. */ + cp->cp_pbpar |= 0x000000c0; + cp->cp_pbdir &= ~0x000000c0; + cp->cp_pbodr &= ~0x000000c0; +#else /* CONFIG_8xx_CONS_SMC2 */ + /* Use Port B for SMC2 instead of other functions. + */ + cp->cp_pbpar |= 0x00000c00; + cp->cp_pbdir &= ~0x00000c00; + cp->cp_pbodr &= ~0x00000c00; +#endif + + /* Set the physical address of the host memory buffers in + * the buffer descriptors. + */ + dpaddr = CPM_SERIAL_BASE; + + rtx = (serialbuffer_t *)&cp->cp_dpmem[dpaddr]; + /* Allocate space for two buffer descriptors in the DP ram. + * For now, this address seems OK, but it may have to + * change with newer versions of the firmware. + * damm: allocating space after the two buffers for rx/tx data + */ + + rtx->rxbd.cbd_bufaddr = (uint) &rtx->rxbuf; + rtx->rxbd.cbd_sc = 0; + + rtx->txbd.cbd_bufaddr = (uint) &rtx->txbuf; + rtx->txbd.cbd_sc = 0; + + /* Set up the uart parameters in the parameter ram. */ + up->smc_rbase = dpaddr; + up->smc_tbase = dpaddr+sizeof(cbd_t); + up->smc_rfcr = SMC_EB; + up->smc_tfcr = SMC_EB; + + /* Set UART mode, 8 bit, no parity, one stop. + * Enable receive and transmit. + */ + sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; + + /* Mask all interrupts and remove anything pending. + */ + sp->smc_smcm = 0; + sp->smc_smce = 0xff; + + /* Set up the baud rate generator */ + smc_setbrg (); + + /* Make the first buffer the only buffer. */ + rtx->txbd.cbd_sc |= BD_SC_WRAP; + rtx->rxbd.cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP; + + /* single/multi character receive. */ + up->smc_mrblr = CONFIG_SYS_SMC_RXBUFLEN; + up->smc_maxidl = CONFIG_SYS_MAXIDLE; + rtx->rxindex = 0; + + /* Initialize Tx/Rx parameters. */ + while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */ + ; + + cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC, CPM_CR_INIT_TRX) | CPM_CR_FLG; + + while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */ + ; + + /* Enable transmitter/receiver. */ + sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; + + return (0); +} + +static void +smc_putc(const char c) +{ + volatile smc_uart_t *up; + volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR; + volatile cpm8xx_t *cpmp = &(im->im_cpm); + volatile serialbuffer_t *rtx; + + if (c == '\n') + smc_putc ('\r'); + + up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC]; + + rtx = (serialbuffer_t *)&cpmp->cp_dpmem[up->smc_rbase]; + + /* Wait for last character to go. */ + rtx->txbuf = c; + rtx->txbd.cbd_datlen = 1; + rtx->txbd.cbd_sc |= BD_SC_READY; + __asm__("eieio"); + + while (rtx->txbd.cbd_sc & BD_SC_READY) { + WATCHDOG_RESET (); + __asm__("eieio"); + } +} + +static void +smc_puts (const char *s) +{ + while (*s) { + smc_putc (*s++); + } +} + +static int +smc_getc(void) +{ + volatile smc_uart_t *up; + volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR; + volatile cpm8xx_t *cpmp = &(im->im_cpm); + volatile serialbuffer_t *rtx; + unsigned char c; + + up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC]; + rtx = (serialbuffer_t *)&cpmp->cp_dpmem[up->smc_rbase]; + + /* Wait for character to show up. */ + while (rtx->rxbd.cbd_sc & BD_SC_EMPTY) + WATCHDOG_RESET (); + + /* the characters are read one by one, + * use the rxindex to know the next char to deliver + */ + c = *(unsigned char *) (rtx->rxbd.cbd_bufaddr+rtx->rxindex); + rtx->rxindex++; + + /* check if all char are readout, then make prepare for next receive */ + if (rtx->rxindex >= rtx->rxbd.cbd_datlen) { + rtx->rxindex = 0; + rtx->rxbd.cbd_sc |= BD_SC_EMPTY; + } + return(c); +} + +static int +smc_tstc(void) +{ + volatile smc_uart_t *up; + volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR; + volatile cpm8xx_t *cpmp = &(im->im_cpm); + volatile serialbuffer_t *rtx; + + up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC]; + + rtx = (serialbuffer_t *)&cpmp->cp_dpmem[up->smc_rbase]; + + return !(rtx->rxbd.cbd_sc & BD_SC_EMPTY); +} + +struct serial_device serial_smc_device = +{ + .name = "serial_smc", + .start = smc_init, + .stop = NULL, + .setbrg = smc_setbrg, + .getc = smc_getc, + .tstc = smc_tstc, + .putc = smc_putc, + .puts = smc_puts, +}; + +__weak struct serial_device *default_serial_console(void) +{ + return &serial_smc_device; +} + +void mpc8xx_serial_initialize(void) +{ + serial_register(&serial_smc_device); +} + +#endif /* CONFIG_8xx_CONS_NONE */ diff --git a/arch/powerpc/cpu/mpc8xx/speed.c b/arch/powerpc/cpu/mpc8xx/speed.c new file mode 100644 index 0000000000..751c089a6d --- /dev/null +++ b/arch/powerpc/cpu/mpc8xx/speed.c @@ -0,0 +1,62 @@ +/* + * (C) Copyright 2000-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <mpc8xx.h> +#include <asm/processor.h> + +DECLARE_GLOBAL_DATA_PTR; + +void get_brgclk(uint sccr) +{ + uint divider = 0; + + switch((sccr&SCCR_DFBRG11)>>11){ + case 0: + divider = 1; + break; + case 1: + divider = 4; + break; + case 2: + divider = 16; + break; + case 3: + divider = 64; + break; + } + gd->arch.brg_clk = gd->cpu_clk/divider; +} + +/* + * get_clocks() fills in gd->cpu_clock depending on CONFIG_8xx_GCLK_FREQ + */ +int get_clocks (void) +{ + uint immr = get_immr (0); /* Return full IMMR contents */ + volatile immap_t *immap = (immap_t *) (immr & 0xFFFF0000); + uint sccr = immap->im_clkrst.car_sccr; + /* + * 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; + } + + get_brgclk(sccr); + + return (0); +} diff --git a/arch/powerpc/cpu/mpc8xx/spi.c b/arch/powerpc/cpu/mpc8xx/spi.c new file mode 100644 index 0000000000..c7863ecd09 --- /dev/null +++ b/arch/powerpc/cpu/mpc8xx/spi.c @@ -0,0 +1,368 @@ +/* + * Copyright (c) 2001 Navin Boppuri / Prashant Patel + * <nboppuri@trinetcommunication.com>, + * <pmpatel@trinetcommunication.com> + * Copyright (c) 2001 Gerd Mennchen <Gerd.Mennchen@icn.siemens.de> + * Copyright (c) 2001 Wolfgang Denk, DENX Software Engineering, <wd@denx.de>. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * MPC8xx CPM SPI interface. + * + * Parts of this code are probably not portable and/or specific to + * the board which I used for the tests. Please send fixes/complaints + * to wd@denx.de + * + */ + +#include <common.h> +#include <mpc8xx.h> +#include <commproc.h> +#include <linux/ctype.h> +#include <malloc.h> +#include <post.h> +#include <serial.h> + +#ifdef CONFIG_SPI + +#define SPI_EEPROM_WREN 0x06 +#define SPI_EEPROM_RDSR 0x05 +#define SPI_EEPROM_READ 0x03 +#define SPI_EEPROM_WRITE 0x02 + +/* --------------------------------------------------------------- + * Offset for initial SPI buffers in DPRAM: + * We need a 520 byte scratch DPRAM area to use at an early stage. + * It is used between the two initialization calls (spi_init_f() + * and spi_init_r()). + * The value 0xb00 makes it far enough from the start of the data + * area (as well as from the stack pointer). + * --------------------------------------------------------------- */ +#ifndef CONFIG_SYS_SPI_INIT_OFFSET +#define CONFIG_SYS_SPI_INIT_OFFSET 0xB00 +#endif + +/* ------------------- + * Function prototypes + * ------------------- */ +void spi_init (void); + +ssize_t spi_read (uchar *, int, uchar *, int); +ssize_t spi_write (uchar *, int, uchar *, int); +ssize_t spi_xfer (size_t); + +/* ------------------- + * Variables + * ------------------- */ + +#define MAX_BUFFER 0x104 + +/* ---------------------------------------------------------------------- + * Initially we place the RX and TX buffers at a fixed location in DPRAM! + * ---------------------------------------------------------------------- */ +static uchar *rxbuf = + (uchar *)&((cpm8xx_t *)&((immap_t *)CONFIG_SYS_IMMR)->im_cpm)->cp_dpmem + [CONFIG_SYS_SPI_INIT_OFFSET]; +static uchar *txbuf = + (uchar *)&((cpm8xx_t *)&((immap_t *)CONFIG_SYS_IMMR)->im_cpm)->cp_dpmem + [CONFIG_SYS_SPI_INIT_OFFSET+MAX_BUFFER]; + +/* ************************************************************************** + * + * Function: spi_init_f + * + * Description: Init SPI-Controller (ROM part) + * + * return: --- + * + * *********************************************************************** */ +void spi_init_f (void) +{ + unsigned int dpaddr; + + volatile spi_t *spi; + volatile immap_t *immr; + volatile cpm8xx_t *cp; + volatile cbd_t *tbdf, *rbdf; + + immr = (immap_t *) CONFIG_SYS_IMMR; + cp = (cpm8xx_t *) &immr->im_cpm; + + spi = (spi_t *)&cp->cp_dparam[PROFF_SPI]; + /* Disable relocation */ + spi->spi_rpbase = 0; + +/* 1 */ + /* ------------------------------------------------ + * Initialize Port B SPI pins -> page 34-8 MPC860UM + * (we are only in Master Mode !) + * ------------------------------------------------ */ + + /* -------------------------------------------- + * GPIO or per. Function + * PBPAR[28] = 1 [0x00000008] -> PERI: (SPIMISO) + * PBPAR[29] = 1 [0x00000004] -> PERI: (SPIMOSI) + * PBPAR[30] = 1 [0x00000002] -> PERI: (SPICLK) + * PBPAR[31] = 0 [0x00000001] -> GPIO: (CS for PCUE/CCM-EEPROM) + * -------------------------------------------- */ + cp->cp_pbpar |= 0x0000000E; /* set bits */ + cp->cp_pbpar &= ~0x00000001; /* reset bit */ + + /* ---------------------------------------------- + * In/Out or per. Function 0/1 + * PBDIR[28] = 1 [0x00000008] -> PERI1: SPIMISO + * PBDIR[29] = 1 [0x00000004] -> PERI1: SPIMOSI + * PBDIR[30] = 1 [0x00000002] -> PERI1: SPICLK + * PBDIR[31] = 1 [0x00000001] -> GPIO OUT: CS for PCUE/CCM-EEPROM + * ---------------------------------------------- */ + cp->cp_pbdir |= 0x0000000F; + + /* ---------------------------------------------- + * open drain or active output + * PBODR[28] = 1 [0x00000008] -> open drain: SPIMISO + * PBODR[29] = 0 [0x00000004] -> active output SPIMOSI + * PBODR[30] = 0 [0x00000002] -> active output: SPICLK + * PBODR[31] = 0 [0x00000001] -> active output: GPIO OUT: CS for PCUE/CCM + * ---------------------------------------------- */ + + cp->cp_pbodr |= 0x00000008; + cp->cp_pbodr &= ~0x00000007; + + /* Initialize the parameter ram. + * We need to make sure many things are initialized to zero + */ + spi->spi_rstate = 0; + spi->spi_rdp = 0; + spi->spi_rbptr = 0; + spi->spi_rbc = 0; + spi->spi_rxtmp = 0; + spi->spi_tstate = 0; + spi->spi_tdp = 0; + spi->spi_tbptr = 0; + spi->spi_tbc = 0; + spi->spi_txtmp = 0; + + dpaddr = CPM_SPI_BASE; + +/* 3 */ + /* Set up the SPI parameters in the parameter ram */ + spi->spi_rbase = dpaddr; + spi->spi_tbase = dpaddr + sizeof (cbd_t); + + /***********IMPORTANT******************/ + + /* + * Setting transmit and receive buffer descriptor pointers + * initially to rbase and tbase. Only the microcode patches + * documentation talks about initializing this pointer. This + * is missing from the sample I2C driver. If you dont + * initialize these pointers, the kernel hangs. + */ + spi->spi_rbptr = spi->spi_rbase; + spi->spi_tbptr = spi->spi_tbase; + +/* 4 */ + /* Init SPI Tx + Rx Parameters */ + while (cp->cp_cpcr & CPM_CR_FLG) + ; + cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SPI, CPM_CR_INIT_TRX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG) + ; + +/* 5 */ + /* Set SDMA configuration register */ + immr->im_siu_conf.sc_sdcr = 0x0001; + +/* 6 */ + /* Set to big endian. */ + spi->spi_tfcr = SMC_EB; + spi->spi_rfcr = SMC_EB; + +/* 7 */ + /* Set maximum receive size. */ + spi->spi_mrblr = MAX_BUFFER; + +/* 8 + 9 */ + /* tx and rx buffer descriptors */ + tbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_tbase]; + rbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_rbase]; + + tbdf->cbd_sc &= ~BD_SC_READY; + rbdf->cbd_sc &= ~BD_SC_EMPTY; + + /* Set the bd's rx and tx buffer address pointers */ + rbdf->cbd_bufaddr = (ulong) rxbuf; + tbdf->cbd_bufaddr = (ulong) txbuf; + +/* 10 + 11 */ + cp->cp_spim = 0; /* Mask all SPI events */ + cp->cp_spie = SPI_EMASK; /* Clear all SPI events */ + + return; +} + +/* ************************************************************************** + * + * Function: spi_init_r + * + * Description: Init SPI-Controller (RAM part) - + * The malloc engine is ready and we can move our buffers to + * normal RAM + * + * return: --- + * + * *********************************************************************** */ +void spi_init_r (void) +{ + volatile cpm8xx_t *cp; + volatile spi_t *spi; + volatile immap_t *immr; + volatile cbd_t *tbdf, *rbdf; + + immr = (immap_t *) CONFIG_SYS_IMMR; + cp = (cpm8xx_t *) &immr->im_cpm; + + spi = (spi_t *)&cp->cp_dparam[PROFF_SPI]; + /* Disable relocation */ + spi->spi_rpbase = 0; + + /* tx and rx buffer descriptors */ + tbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_tbase]; + rbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_rbase]; + + /* Allocate memory for RX and TX buffers */ + rxbuf = (uchar *) malloc (MAX_BUFFER); + txbuf = (uchar *) malloc (MAX_BUFFER); + + rbdf->cbd_bufaddr = (ulong) rxbuf; + tbdf->cbd_bufaddr = (ulong) txbuf; + + return; +} + +/**************************************************************************** + * Function: spi_write + **************************************************************************** */ +ssize_t spi_write (uchar *addr, int alen, uchar *buffer, int len) +{ + int i; + + memset(rxbuf, 0, MAX_BUFFER); + memset(txbuf, 0, MAX_BUFFER); + *txbuf = SPI_EEPROM_WREN; /* write enable */ + spi_xfer(1); + memcpy(txbuf, addr, alen); + *txbuf = SPI_EEPROM_WRITE; /* WRITE memory array */ + memcpy(alen + txbuf, buffer, len); + spi_xfer(alen + len); + /* ignore received data */ + for (i = 0; i < 1000; i++) { + *txbuf = SPI_EEPROM_RDSR; /* read status */ + txbuf[1] = 0; + spi_xfer(2); + if (!(rxbuf[1] & 1)) { + break; + } + udelay(1000); + } + if (i >= 1000) { + printf ("*** spi_write: Time out while writing!\n"); + } + + return len; +} + +/**************************************************************************** + * Function: spi_read + **************************************************************************** */ +ssize_t spi_read (uchar *addr, int alen, uchar *buffer, int len) +{ + memset(rxbuf, 0, MAX_BUFFER); + memset(txbuf, 0, MAX_BUFFER); + memcpy(txbuf, addr, alen); + *txbuf = SPI_EEPROM_READ; /* READ memory array */ + + /* + * There is a bug in 860T (?) that cuts the last byte of input + * if we're reading into DPRAM. The solution we choose here is + * to always read len+1 bytes (we have one extra byte at the + * end of the buffer). + */ + spi_xfer(alen + len + 1); + memcpy(buffer, alen + rxbuf, len); + + return len; +} + +/**************************************************************************** + * Function: spi_xfer + **************************************************************************** */ +ssize_t spi_xfer (size_t count) +{ + volatile immap_t *immr; + volatile cpm8xx_t *cp; + volatile spi_t *spi; + cbd_t *tbdf, *rbdf; + ushort loop; + int tm; + + immr = (immap_t *) CONFIG_SYS_IMMR; + cp = (cpm8xx_t *) &immr->im_cpm; + + spi = (spi_t *)&cp->cp_dparam[PROFF_SPI]; + /* Disable relocation */ + spi->spi_rpbase = 0; + + tbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_tbase]; + rbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_rbase]; + + /* Set CS for device */ + cp->cp_pbdat &= ~0x0001; + + /* Setting tx bd status and data length */ + tbdf->cbd_sc = BD_SC_READY | BD_SC_LAST | BD_SC_WRAP; + tbdf->cbd_datlen = count; + + /* Setting rx bd status and data length */ + rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP; + rbdf->cbd_datlen = 0; /* rx length has no significance */ + + loop = cp->cp_spmode & SPMODE_LOOP; + cp->cp_spmode = /*SPMODE_DIV16 |*/ /* BRG/16 mode not used here */ + loop | + SPMODE_REV | + SPMODE_MSTR | + SPMODE_EN | + SPMODE_LEN(8) | /* 8 Bits per char */ + SPMODE_PM(0x8) ; /* medium speed */ + cp->cp_spim = 0; /* Mask all SPI events */ + cp->cp_spie = SPI_EMASK; /* Clear all SPI events */ + + /* start spi transfer */ + cp->cp_spcom |= SPI_STR; /* Start transmit */ + + /* -------------------------------- + * Wait for SPI transmit to get out + * or time out (1 second = 1000 ms) + * -------------------------------- */ + for (tm=0; tm<1000; ++tm) { + if (cp->cp_spie & SPI_TXB) { /* Tx Buffer Empty */ + break; + } + if ((tbdf->cbd_sc & BD_SC_READY) == 0) { + break; + } + udelay (1000); + } + if (tm >= 1000) { + printf ("*** spi_xfer: Time out while xferring to/from SPI!\n"); + } + + /* Clear CS for device */ + cp->cp_pbdat |= 0x0001; + + return count; +} +#endif /* CONFIG_SPI */ diff --git a/arch/powerpc/cpu/mpc8xx/start.S b/arch/powerpc/cpu/mpc8xx/start.S new file mode 100644 index 0000000000..b00696fc75 --- /dev/null +++ b/arch/powerpc/cpu/mpc8xx/start.S @@ -0,0 +1,636 @@ +/* + * 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> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* 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 */ + /*----------------------------------------------------------------------*/ + + lis r3, CONFIG_SYS_IMMR@h /* pass IMMR as arg1 to C routine */ + ori r1, r3, CONFIG_SYS_INIT_SP_OFFSET /* set up the stack in internal DPRAM */ + /* Note: R0 is still 0 here */ + stwu r0, -4(r1) /* clear final stack frame so that */ + stwu r0, -4(r1) /* stack backtraces terminate cleanly */ + + /* + * 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 + + /* let the C-code set up the rest */ + /* */ + /* Be careful to keep code relocatable ! */ + /*----------------------------------------------------------------------*/ + + GET_GOT /* initialize GOT access */ + + /* r3: IMMR */ + 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 + +/* Cache functions. +*/ + .globl icache_enable +icache_enable: + SYNC + lis r3, IDC_INVALL@h + mtspr IC_CST, r3 + lis r3, IDC_ENABLE@h + mtspr IC_CST, r3 + blr + + .globl icache_disable +icache_disable: + SYNC + lis r3, IDC_DISABLE@h + mtspr IC_CST, r3 + blr + + .globl icache_status +icache_status: + mfspr r3, IC_CST + srwi r3, r3, 31 /* >>31 => select bit 0 */ + blr + + .globl dcache_enable +dcache_enable: + lis r3, 0x0400 /* Set cache mode with MMU off */ + mtspr MD_CTR, r3 + + lis r3, IDC_INVALL@h + mtspr DC_CST, r3 + lis r3, IDC_ENABLE@h + mtspr DC_CST, r3 + blr + + .globl dcache_disable +dcache_disable: + SYNC + lis r3, IDC_DISABLE@h + mtspr DC_CST, r3 + lis r3, IDC_INVALL@h + mtspr DC_CST, r3 + blr + + .globl dcache_status +dcache_status: + mfspr r3, DC_CST + srwi r3, r3, 31 /* >>31 => select bit 0 */ + blr + + .globl dc_read +dc_read: + mtspr DC_ADR, r3 + mfspr r3, DC_DAT + blr + +/* + * unsigned int get_immr (unsigned int mask) + * + * return (mask ? (IMMR & mask) : IMMR); + */ + .globl get_immr +get_immr: + mr r4,r3 /* save mask */ + mfspr r3, IMMR /* IMMR */ + cmpwi 0,r4,0 /* mask != 0 ? */ + beq 4f + and r3,r3,r4 /* IMMR & mask */ +4: + blr + + .globl get_pvr +get_pvr: + mfspr r3, PVR + blr + + + .globl wr_ic_cst +wr_ic_cst: + mtspr IC_CST, r3 + blr + + .globl rd_ic_cst +rd_ic_cst: + mfspr r3, IC_CST + blr + + .globl wr_ic_adr +wr_ic_adr: + mtspr IC_ADR, r3 + blr + + + .globl wr_dc_cst +wr_dc_cst: + mtspr DC_CST, r3 + blr + + .globl rd_dc_cst +rd_dc_cst: + mfspr r3, DC_CST + blr + + .globl wr_dc_adr +wr_dc_adr: + mtspr DC_ADR, r3 + blr + +/*------------------------------------------------------------------------------*/ + +/* + * 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/arch/powerpc/cpu/mpc8xx/traps.c b/arch/powerpc/cpu/mpc8xx/traps.c new file mode 100644 index 0000000000..ec283d83fa --- /dev/null +++ b/arch/powerpc/cpu/mpc8xx/traps.c @@ -0,0 +1,168 @@ +/* + * linux/arch/powerpc/kernel/traps.c + * + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Modified by Cort Dougan (cort@cs.nmt.edu) + * and Paul Mackerras (paulus@cs.anu.edu.au) + * + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * This file handles the architecture-dependent parts of hardware exceptions + */ + +#include <common.h> +#include <command.h> +#include <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; + + /* 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 = search_exception_table(regs->nip)) != 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); +} + +/* Probe an address by reading. If not present, return -1, otherwise + * return 0. + */ +int addr_probe(uint *addr) +{ + return 0; +} diff --git a/arch/powerpc/include/asm/8xx_immap.h b/arch/powerpc/include/asm/8xx_immap.h new file mode 100644 index 0000000000..3999a02b9c --- /dev/null +++ b/arch/powerpc/include/asm/8xx_immap.h @@ -0,0 +1,468 @@ +/* + * MPC8xx Internal Memory Map + * Copyright (c) 1997 Dan Malek (dmalek@jlc.net) + * + * The I/O on the MPC860 is comprised of blocks of special registers + * and the dual port ram for the Communication Processor Module. + * Within this space are functional units such as the SIU, memory + * controller, system timers, and other control functions. It is + * a combination that I found difficult to separate into logical + * functional files.....but anyone else is welcome to try. -- Dan + */ +#ifndef __IMMAP_8XX__ +#define __IMMAP_8XX__ + +/* System configuration registers. +*/ +typedef struct sys_conf { + uint sc_siumcr; + uint sc_sypcr; + uint sc_swt; + char res1[2]; + ushort sc_swsr; + uint sc_sipend; + uint sc_simask; + uint sc_siel; + uint sc_sivec; + uint sc_tesr; + char res2[0xc]; + uint sc_sdcr; + char res3[0x4c]; +} sysconf8xx_t; + +/* PCMCIA configuration registers. +*/ +typedef struct pcmcia_conf { + uint pcmc_pbr0; + uint pcmc_por0; + uint pcmc_pbr1; + uint pcmc_por1; + uint pcmc_pbr2; + uint pcmc_por2; + uint pcmc_pbr3; + uint pcmc_por3; + uint pcmc_pbr4; + uint pcmc_por4; + uint pcmc_pbr5; + uint pcmc_por5; + uint pcmc_pbr6; + uint pcmc_por6; + uint pcmc_pbr7; + uint pcmc_por7; + char res1[0x20]; + uint pcmc_pgcra; + uint pcmc_pgcrb; + uint pcmc_pscr; + char res2[4]; + uint pcmc_pipr; + char res3[4]; + uint pcmc_per; + char res4[4]; +} pcmconf8xx_t; + +/* Memory controller registers. +*/ +typedef struct mem_ctlr { + uint memc_br0; + uint memc_or0; + uint memc_br1; + uint memc_or1; + uint memc_br2; + uint memc_or2; + uint memc_br3; + uint memc_or3; + uint memc_br4; + uint memc_or4; + uint memc_br5; + uint memc_or5; + uint memc_br6; + uint memc_or6; + uint memc_br7; + uint memc_or7; + char res1[0x24]; + uint memc_mar; + uint memc_mcr; + char res2[4]; + uint memc_mamr; + uint memc_mbmr; + ushort memc_mstat; + ushort memc_mptpr; + uint memc_mdr; + char res3[0x80]; +} memctl8xx_t; + +/* System Integration Timers. +*/ +typedef struct sys_int_timers { + ushort sit_tbscr; + char res0[0x02]; + uint sit_tbreff0; + uint sit_tbreff1; + char res1[0x14]; + ushort sit_rtcsc; + char res2[0x02]; + uint sit_rtc; + uint sit_rtsec; + uint sit_rtcal; + char res3[0x10]; + ushort sit_piscr; + char res4[2]; + uint sit_pitc; + uint sit_pitr; + char res5[0x34]; +} sit8xx_t; + +#define TBSCR_TBIRQ_MASK ((ushort)0xff00) +#define TBSCR_REFA ((ushort)0x0080) +#define TBSCR_REFB ((ushort)0x0040) +#define TBSCR_REFAE ((ushort)0x0008) +#define TBSCR_REFBE ((ushort)0x0004) +#define TBSCR_TBF ((ushort)0x0002) +#define TBSCR_TBE ((ushort)0x0001) + +#define RTCSC_RTCIRQ_MASK ((ushort)0xff00) +#define RTCSC_SEC ((ushort)0x0080) +#define RTCSC_ALR ((ushort)0x0040) +#define RTCSC_38K ((ushort)0x0010) +#define RTCSC_SIE ((ushort)0x0008) +#define RTCSC_ALE ((ushort)0x0004) +#define RTCSC_RTF ((ushort)0x0002) +#define RTCSC_RTE ((ushort)0x0001) + +#define PISCR_PIRQ_MASK ((ushort)0xff00) +#define PISCR_PS ((ushort)0x0080) +#define PISCR_PIE ((ushort)0x0004) +#define PISCR_PTF ((ushort)0x0002) +#define PISCR_PTE ((ushort)0x0001) + +/* Clocks and Reset. +*/ +typedef struct clk_and_reset { + uint car_sccr; + uint car_plprcr; + uint car_rsr; + char res[0x74]; /* Reserved area */ +} car8xx_t; + +/* System Integration Timers keys. +*/ +typedef struct sitk { + uint sitk_tbscrk; + uint sitk_tbreff0k; + uint sitk_tbreff1k; + uint sitk_tbk; + char res1[0x10]; + uint sitk_rtcsck; + uint sitk_rtck; + uint sitk_rtseck; + uint sitk_rtcalk; + char res2[0x10]; + uint sitk_piscrk; + uint sitk_pitck; + char res3[0x38]; +} sitk8xx_t; + +/* Clocks and reset keys. +*/ +typedef struct cark { + uint cark_sccrk; + uint cark_plprcrk; + uint cark_rsrk; + char res[0x474]; +} cark8xx_t; + +/* The key to unlock registers maintained by keep-alive power. +*/ +#define KAPWR_KEY ((unsigned int)0x55ccaa33) + +/* I2C +*/ +typedef struct i2c { + u_char i2c_i2mod; + char res1[3]; + u_char i2c_i2add; + char res2[3]; + u_char i2c_i2brg; + char res3[3]; + u_char i2c_i2com; + char res4[3]; + u_char i2c_i2cer; + char res5[3]; + u_char i2c_i2cmr; + char res6[0x8b]; +} i2c8xx_t; + +/* DMA control/status registers. +*/ +typedef struct sdma_csr { + char res1[4]; + uint sdma_sdar; + u_char sdma_sdsr; + char res3[3]; + u_char sdma_sdmr; + char res4[3]; + u_char sdma_idsr1; + char res5[3]; + u_char sdma_idmr1; + char res6[3]; + u_char sdma_idsr2; + char res7[3]; + u_char sdma_idmr2; + char res8[0x13]; +} sdma8xx_t; + +/* Communication Processor Module Interrupt Controller. +*/ +typedef struct cpm_ic { + ushort cpic_civr; + char res[0xe]; + uint cpic_cicr; + uint cpic_cipr; + uint cpic_cimr; + uint cpic_cisr; +} cpic8xx_t; + +/* Input/Output Port control/status registers. +*/ +typedef struct io_port { + ushort iop_padir; + ushort iop_papar; + ushort iop_paodr; + ushort iop_padat; + char res1[8]; + ushort iop_pcdir; + ushort iop_pcpar; + ushort iop_pcso; + ushort iop_pcdat; + ushort iop_pcint; + char res2[6]; + ushort iop_pddir; + ushort iop_pdpar; + char res3[2]; + ushort iop_pddat; + uint utmode; + char res4[4]; +} iop8xx_t; + +/* Communication Processor Module Timers +*/ +typedef struct cpm_timers { + ushort cpmt_tgcr; + char res1[0xe]; + ushort cpmt_tmr1; + ushort cpmt_tmr2; + ushort cpmt_trr1; + ushort cpmt_trr2; + ushort cpmt_tcr1; + ushort cpmt_tcr2; + ushort cpmt_tcn1; + ushort cpmt_tcn2; + ushort cpmt_tmr3; + ushort cpmt_tmr4; + ushort cpmt_trr3; + ushort cpmt_trr4; + ushort cpmt_tcr3; + ushort cpmt_tcr4; + ushort cpmt_tcn3; + ushort cpmt_tcn4; + ushort cpmt_ter1; + ushort cpmt_ter2; + ushort cpmt_ter3; + ushort cpmt_ter4; + char res2[8]; +} cpmtimer8xx_t; + +/* Finally, the Communication Processor stuff..... +*/ +typedef struct scc { /* Serial communication channels */ + uint scc_gsmrl; + uint scc_gsmrh; + ushort scc_psmr; + char res1[2]; + ushort scc_todr; + ushort scc_dsr; + ushort scc_scce; + char res2[2]; + ushort scc_sccm; + char res3; + u_char scc_sccs; + char res4[8]; +} scc_t; + +typedef struct smc { /* Serial management channels */ + char res1[2]; + ushort smc_smcmr; + char res2[2]; + u_char smc_smce; + char res3[3]; + u_char smc_smcm; + char res4[5]; +} smc_t; + +/* MPC860T Fast Ethernet Controller. It isn't part of the CPM, but + * it fits within the address space. + */ + +typedef struct fec { + uint fec_addr_low; /* lower 32 bits of station address */ + ushort fec_addr_high; /* upper 16 bits of station address */ + ushort res1; /* reserved */ + uint fec_hash_table_high; /* upper 32-bits of hash table */ + uint fec_hash_table_low; /* lower 32-bits of hash table */ + uint fec_r_des_start; /* beginning of Rx descriptor ring */ + uint fec_x_des_start; /* beginning of Tx descriptor ring */ + uint fec_r_buff_size; /* Rx buffer size */ + uint res2[9]; /* reserved */ + uint fec_ecntrl; /* ethernet control register */ + uint fec_ievent; /* interrupt event register */ + uint fec_imask; /* interrupt mask register */ + uint fec_ivec; /* interrupt level and vector status */ + uint fec_r_des_active; /* Rx ring updated flag */ + uint fec_x_des_active; /* Tx ring updated flag */ + uint res3[10]; /* reserved */ + uint fec_mii_data; /* MII data register */ + uint fec_mii_speed; /* MII speed control register */ + uint res4[17]; /* reserved */ + uint fec_r_bound; /* end of RAM (read-only) */ + uint fec_r_fstart; /* Rx FIFO start address */ + uint res5[6]; /* reserved */ + uint fec_x_fstart; /* Tx FIFO start address */ + uint res6[17]; /* reserved */ + uint fec_fun_code; /* fec SDMA function code */ + uint res7[3]; /* reserved */ + uint fec_r_cntrl; /* Rx control register */ + uint fec_r_hash; /* Rx hash register */ + uint res8[14]; /* reserved */ + uint fec_x_cntrl; /* Tx control register */ + uint res9[0x1e]; /* reserved */ +} fec_t; + +typedef struct comm_proc { + /* General control and status registers. + */ + ushort cp_cpcr; + u_char res1[2]; + ushort cp_rccr; + u_char res2; + u_char cp_rmds; + u_char res3[4]; + ushort cp_cpmcr1; + ushort cp_cpmcr2; + ushort cp_cpmcr3; + ushort cp_cpmcr4; + u_char res4[2]; + ushort cp_rter; + u_char res5[2]; + ushort cp_rtmr; + u_char res6[0x14]; + + /* Baud rate generators. + */ + uint cp_brgc1; + uint cp_brgc2; + uint cp_brgc3; + uint cp_brgc4; + + /* Serial Communication Channels. + */ + scc_t cp_scc[4]; + + /* Serial Management Channels. + */ + smc_t cp_smc[2]; + + /* Serial Peripheral Interface. + */ + ushort cp_spmode; + u_char res7[4]; + u_char cp_spie; + u_char res8[3]; + u_char cp_spim; + u_char res9[2]; + u_char cp_spcom; + u_char res10[2]; + + /* Parallel Interface Port. + */ + u_char res11[2]; + ushort cp_pipc; + u_char res12[2]; + ushort cp_ptpr; + uint cp_pbdir; + uint cp_pbpar; + u_char res13[2]; + ushort cp_pbodr; + uint cp_pbdat; + + /* Port E - MPC87x/88x only. + */ + uint cp_pedir; + uint cp_pepar; + uint cp_peso; + uint cp_peodr; + uint cp_pedat; + + /* Communications Processor Timing Register - + Contains RMII Timing for the FECs on MPC87x/88x only. + */ + uint cp_cptr; + + /* Serial Interface and Time Slot Assignment. + */ + uint cp_simode; + u_char cp_sigmr; + u_char res15; + u_char cp_sistr; + u_char cp_sicmr; + u_char res16[4]; + uint cp_sicr; + uint cp_sirp; + u_char res17[0xc]; + + u_char res19[0x100]; + u_char cp_siram[0x200]; + + /* The fast ethernet controller is not really part of the CPM, + * but it resides in the address space. + */ + fec_t cp_fec; + char res18[0xE00]; + + /* The MPC885 family has a second FEC here */ + fec_t cp_fec2; +#define cp_fec1 cp_fec /* consistency macro */ + + /* Dual Ported RAM follows. + * There are many different formats for this memory area + * depending upon the devices used and options chosen. + * Some processors don't have all of it populated. + */ + u_char cp_dpmem[0x1C00]; /* BD / Data / ucode */ + + /* Parameter RAM */ + union { + u_char cp_dparam[0x400]; + u16 cp_dparam16[0x200]; + }; +} cpm8xx_t; + +/* Internal memory map. +*/ +typedef struct immap { + sysconf8xx_t im_siu_conf; /* SIU Configuration */ + pcmconf8xx_t im_pcmcia; /* PCMCIA Configuration */ + memctl8xx_t im_memctl; /* Memory Controller */ + sit8xx_t im_sit; /* System integration timers */ + car8xx_t im_clkrst; /* Clocks and reset */ + sitk8xx_t im_sitk; /* Sys int timer keys */ + cark8xx_t im_clkrstk; /* Clocks and reset keys */ + char res[96]; + i2c8xx_t im_i2c; /* I2C control/status */ + sdma8xx_t im_sdma; /* SDMA control/status */ + cpic8xx_t im_cpic; /* CPM Interrupt Controller */ + iop8xx_t im_ioport; /* IO Port control/status */ + cpmtimer8xx_t im_cpmtimer; /* CPM timers */ + cpm8xx_t im_cpm; /* Communication processor */ +} immap_t; + +#endif /* __IMMAP_8XX__ */ diff --git a/arch/powerpc/include/asm/cache.h b/arch/powerpc/include/asm/cache.h index 20c52fcddc..d3a83910b6 100644 --- a/arch/powerpc/include/asm/cache.h +++ b/arch/powerpc/include/asm/cache.h @@ -7,7 +7,9 @@ #include <asm/processor.h> /* bytes per L1 cache line */ -#if defined(CONFIG_PPC64BRIDGE) +#if defined(CONFIG_8xx) +#define L1_CACHE_SHIFT 4 +#elif defined(CONFIG_PPC64BRIDGE) #define L1_CACHE_SHIFT 7 #elif defined(CONFIG_E500MC) #define L1_CACHE_SHIFT 6 @@ -70,4 +72,41 @@ void disable_cpc_sram(void); #define L2CACHE_NONE 0x03 /* NONE */ #define L2CACHE_PARITY 0x08 /* Mask for L2 Cache Parity Protected bit */ +#ifdef CONFIG_8xx +/* Cache control on the MPC8xx is provided through some additional + * special purpose registers. + */ +#define IC_CST 560 /* Instruction cache control/status */ +#define IC_ADR 561 /* Address needed for some commands */ +#define IC_DAT 562 /* Read-only data register */ +#define DC_CST 568 /* Data cache control/status */ +#define DC_ADR 569 /* Address needed for some commands */ +#define DC_DAT 570 /* Read-only data register */ + +/* Commands. Only the first few are available to the instruction cache. +*/ +#define IDC_ENABLE 0x02000000 /* Cache enable */ +#define IDC_DISABLE 0x04000000 /* Cache disable */ +#define IDC_LDLCK 0x06000000 /* Load and lock */ +#define IDC_UNLINE 0x08000000 /* Unlock line */ +#define IDC_UNALL 0x0a000000 /* Unlock all */ +#define IDC_INVALL 0x0c000000 /* Invalidate all */ + +#define DC_FLINE 0x0e000000 /* Flush data cache line */ +#define DC_SFWT 0x01000000 /* Set forced writethrough mode */ +#define DC_CFWT 0x03000000 /* Clear forced writethrough mode */ +#define DC_SLES 0x05000000 /* Set little endian swap mode */ +#define DC_CLES 0x07000000 /* Clear little endian swap mode */ + +/* Status. +*/ +#define IDC_ENABLED 0x80000000 /* Cache is enabled */ +#define IDC_CERR1 0x00200000 /* Cache error 1 */ +#define IDC_CERR2 0x00100000 /* Cache error 2 */ +#define IDC_CERR3 0x00080000 /* Cache error 3 */ + +#define DC_DFWT 0x40000000 /* Data cache is forced write through */ +#define DC_LES 0x20000000 /* Caches are little endian mode */ +#endif /* CONFIG_8xx */ + #endif diff --git a/arch/powerpc/include/asm/global_data.h b/arch/powerpc/include/asm/global_data.h index 1c4a82ca99..35a02b61a4 100644 --- a/arch/powerpc/include/asm/global_data.h +++ b/arch/powerpc/include/asm/global_data.h @@ -19,6 +19,9 @@ struct arch_global_data { u8 sdhc_adapter; #endif #endif +#if defined(CONFIG_8xx) + unsigned long brg_clk; +#endif #if defined(CONFIG_CPM2) /* There are many clocks on the MPC8260 - see page 9-5 */ unsigned long vco_out; diff --git a/arch/powerpc/include/asm/iopin_8xx.h b/arch/powerpc/include/asm/iopin_8xx.h new file mode 100644 index 0000000000..8db0fa2a1c --- /dev/null +++ b/arch/powerpc/include/asm/iopin_8xx.h @@ -0,0 +1,379 @@ +/* + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * MPC8xx I/O port pin manipulation functions + * Roughly based on iopin_8260.h + */ + +#ifndef _ASM_IOPIN_8XX_H_ +#define _ASM_IOPIN_8XX_H_ + +#include <linux/types.h> +#include <asm/8xx_immap.h> + +#ifdef __KERNEL__ + +typedef struct { + u_char port:2; /* port number (A=0, B=1, C=2, D=3) */ + u_char pin:5; /* port pin (0-31) */ + u_char flag:1; /* for whatever */ +} iopin_t; + +#define IOPIN_PORTA 0 +#define IOPIN_PORTB 1 +#define IOPIN_PORTC 2 +#define IOPIN_PORTD 3 + +static __inline__ void +iopin_set_high(iopin_t *iopin) +{ + if (iopin->port == IOPIN_PORTA) { + volatile ushort *datp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_padat; + *datp |= (1 << (15 - iopin->pin)); + } else if (iopin->port == IOPIN_PORTB) { + volatile uint *datp = &((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pbdat; + *datp |= (1 << (31 - iopin->pin)); + } else if (iopin->port == IOPIN_PORTC) { + volatile ushort *datp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcdat; + *datp |= (1 << (15 - iopin->pin)); + } else if (iopin->port == IOPIN_PORTD) { + volatile ushort *datp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pddat; + *datp |= (1 << (15 - iopin->pin)); + } +} + +static __inline__ void +iopin_set_low(iopin_t *iopin) +{ + if (iopin->port == IOPIN_PORTA) { + volatile ushort *datp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_padat; + *datp &= ~(1 << (15 - iopin->pin)); + } else if (iopin->port == IOPIN_PORTB) { + volatile uint *datp = &((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pbdat; + *datp &= ~(1 << (31 - iopin->pin)); + } else if (iopin->port == IOPIN_PORTC) { + volatile ushort *datp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcdat; + *datp &= ~(1 << (15 - iopin->pin)); + } else if (iopin->port == IOPIN_PORTD) { + volatile ushort *datp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pddat; + *datp &= ~(1 << (15 - iopin->pin)); + } +} + +static __inline__ uint +iopin_is_high(iopin_t *iopin) +{ + if (iopin->port == IOPIN_PORTA) { + volatile ushort *datp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_padat; + return (*datp >> (15 - iopin->pin)) & 1; + } else if (iopin->port == IOPIN_PORTB) { + volatile uint *datp = &((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pbdat; + return (*datp >> (31 - iopin->pin)) & 1; + } else if (iopin->port == IOPIN_PORTC) { + volatile ushort *datp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcdat; + return (*datp >> (15 - iopin->pin)) & 1; + } else if (iopin->port == IOPIN_PORTD) { + volatile ushort *datp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pddat; + return (*datp >> (15 - iopin->pin)) & 1; + } + return 0; +} + +static __inline__ uint +iopin_is_low(iopin_t *iopin) +{ + if (iopin->port == IOPIN_PORTA) { + volatile ushort *datp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_padat; + return ((*datp >> (15 - iopin->pin)) & 1) ^ 1; + } else if (iopin->port == IOPIN_PORTB) { + volatile uint *datp = &((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pbdat; + return ((*datp >> (31 - iopin->pin)) & 1) ^ 1; + } else if (iopin->port == IOPIN_PORTC) { + volatile ushort *datp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcdat; + return ((*datp >> (15 - iopin->pin)) & 1) ^ 1; + } else if (iopin->port == IOPIN_PORTD) { + volatile ushort *datp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pddat; + return ((*datp >> (15 - iopin->pin)) & 1) ^ 1; + } + return 0; +} + +static __inline__ void +iopin_set_out(iopin_t *iopin) +{ + if (iopin->port == IOPIN_PORTA) { + volatile ushort *dirp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_padir; + *dirp |= (1 << (15 - iopin->pin)); + } else if (iopin->port == IOPIN_PORTB) { + volatile uint *dirp = &((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pbdir; + *dirp |= (1 << (31 - iopin->pin)); + } else if (iopin->port == IOPIN_PORTC) { + volatile ushort *dirp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcdir; + *dirp |= (1 << (15 - iopin->pin)); + } else if (iopin->port == IOPIN_PORTD) { + volatile ushort *dirp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pddir; + *dirp |= (1 << (15 - iopin->pin)); + } +} + +static __inline__ void +iopin_set_in(iopin_t *iopin) +{ + if (iopin->port == IOPIN_PORTA) { + volatile ushort *dirp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_padir; + *dirp &= ~(1 << (15 - iopin->pin)); + } else if (iopin->port == IOPIN_PORTB) { + volatile uint *dirp = &((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pbdir; + *dirp &= ~(1 << (31 - iopin->pin)); + } else if (iopin->port == IOPIN_PORTC) { + volatile ushort *dirp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcdir; + *dirp &= ~(1 << (15 - iopin->pin)); + } else if (iopin->port == IOPIN_PORTD) { + volatile ushort *dirp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pddir; + *dirp &= ~(1 << (15 - iopin->pin)); + } +} + +static __inline__ uint +iopin_is_out(iopin_t *iopin) +{ + if (iopin->port == IOPIN_PORTA) { + volatile ushort *dirp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_padir; + return (*dirp >> (15 - iopin->pin)) & 1; + } else if (iopin->port == IOPIN_PORTB) { + volatile uint *dirp = &((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pbdir; + return (*dirp >> (31 - iopin->pin)) & 1; + } else if (iopin->port == IOPIN_PORTC) { + volatile ushort *dirp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcdir; + return (*dirp >> (15 - iopin->pin)) & 1; + } else if (iopin->port == IOPIN_PORTD) { + volatile ushort *dirp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pddir; + return (*dirp >> (15 - iopin->pin)) & 1; + } + return 0; +} + +static __inline__ uint +iopin_is_in(iopin_t *iopin) +{ + if (iopin->port == IOPIN_PORTA) { + volatile ushort *dirp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_padir; + return ((*dirp >> (15 - iopin->pin)) & 1) ^ 1; + } else if (iopin->port == IOPIN_PORTB) { + volatile uint *dirp = &((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pbdir; + return ((*dirp >> (31 - iopin->pin)) & 1) ^ 1; + } else if (iopin->port == IOPIN_PORTC) { + volatile ushort *dirp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcdir; + return ((*dirp >> (15 - iopin->pin)) & 1) ^ 1; + } else if (iopin->port == IOPIN_PORTD) { + volatile ushort *dirp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pddir; + return ((*dirp >> (15 - iopin->pin)) & 1) ^ 1; + } + return 0; +} + +static __inline__ void +iopin_set_odr(iopin_t *iopin) +{ + if (iopin->port == IOPIN_PORTA) { + volatile ushort *odrp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_paodr; + *odrp |= (1 << (15 - iopin->pin)); + } else if (iopin->port == IOPIN_PORTB) { + volatile ushort *odrp = &((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pbodr; + *odrp |= (1 << (31 - iopin->pin)); + } +} + +static __inline__ void +iopin_set_act(iopin_t *iopin) +{ + if (iopin->port == IOPIN_PORTA) { + volatile ushort *odrp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_paodr; + *odrp &= ~(1 << (15 - iopin->pin)); + } else if (iopin->port == IOPIN_PORTB) { + volatile ushort *odrp = &((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pbodr; + *odrp &= ~(1 << (31 - iopin->pin)); + } +} + +static __inline__ uint +iopin_is_odr(iopin_t *iopin) +{ + if (iopin->port == IOPIN_PORTA) { + volatile ushort *odrp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_paodr; + return (*odrp >> (15 - iopin->pin)) & 1; + } else if (iopin->port == IOPIN_PORTB) { + volatile ushort *odrp = &((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pbodr; + return (*odrp >> (31 - iopin->pin)) & 1; + } + return 0; +} + +static __inline__ uint +iopin_is_act(iopin_t *iopin) +{ + if (iopin->port == IOPIN_PORTA) { + volatile ushort *odrp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_paodr; + return ((*odrp >> (15 - iopin->pin)) & 1) ^ 1; + } else if (iopin->port == IOPIN_PORTB) { + volatile ushort *odrp = &((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pbodr; + return ((*odrp >> (31 - iopin->pin)) & 1) ^ 1; + } + return 0; +} + +static __inline__ void +iopin_set_ded(iopin_t *iopin) +{ + if (iopin->port == IOPIN_PORTA) { + volatile ushort *parp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_papar; + *parp |= (1 << (15 - iopin->pin)); + } else if (iopin->port == IOPIN_PORTB) { + volatile uint *parp = &((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pbpar; + *parp |= (1 << (31 - iopin->pin)); + } else if (iopin->port == IOPIN_PORTC) { + volatile ushort *parp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcpar; + *parp |= (1 << (15 - iopin->pin)); + } else if (iopin->port == IOPIN_PORTD) { + volatile ushort *parp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pdpar; + *parp |= (1 << (15 - iopin->pin)); + } +} + +static __inline__ void +iopin_set_gen(iopin_t *iopin) +{ + if (iopin->port == IOPIN_PORTA) { + volatile ushort *parp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_papar; + *parp &= ~(1 << (15 - iopin->pin)); + } else if (iopin->port == IOPIN_PORTB) { + volatile uint *parp = &((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pbpar; + *parp &= ~(1 << (31 - iopin->pin)); + } else if (iopin->port == IOPIN_PORTC) { + volatile ushort *parp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcpar; + *parp &= ~(1 << (15 - iopin->pin)); + } else if (iopin->port == IOPIN_PORTD) { + volatile ushort *parp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pdpar; + *parp &= ~(1 << (15 - iopin->pin)); + } +} + +static __inline__ uint +iopin_is_ded(iopin_t *iopin) +{ + if (iopin->port == IOPIN_PORTA) { + volatile ushort *parp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_papar; + return (*parp >> (15 - iopin->pin)) & 1; + } else if (iopin->port == IOPIN_PORTB) { + volatile uint *parp = &((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pbpar; + return (*parp >> (31 - iopin->pin)) & 1; + } else if (iopin->port == IOPIN_PORTC) { + volatile ushort *parp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcpar; + return (*parp >> (15 - iopin->pin)) & 1; + } else if (iopin->port == IOPIN_PORTD) { + volatile ushort *parp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pdpar; + return (*parp >> (15 - iopin->pin)) & 1; + } + return 0; +} + +static __inline__ uint +iopin_is_gen(iopin_t *iopin) +{ + if (iopin->port == IOPIN_PORTA) { + volatile ushort *parp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_papar; + return ((*parp >> (15 - iopin->pin)) & 1) ^ 1; + } else if (iopin->port == IOPIN_PORTB) { + volatile uint *parp = &((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pbpar; + return ((*parp >> (31 - iopin->pin)) & 1) ^ 1; + } else if (iopin->port == IOPIN_PORTC) { + volatile ushort *parp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcpar; + return ((*parp >> (15 - iopin->pin)) & 1) ^ 1; + } else if (iopin->port == IOPIN_PORTD) { + volatile ushort *parp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pdpar; + return ((*parp >> (15 - iopin->pin)) & 1) ^ 1; + } + return 0; +} + +static __inline__ void +iopin_set_opt2(iopin_t *iopin) +{ + if (iopin->port == IOPIN_PORTC) { + volatile ushort *sorp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcso; + *sorp |= (1 << (15 - iopin->pin)); + } +} + +static __inline__ void +iopin_set_opt1(iopin_t *iopin) +{ + if (iopin->port == IOPIN_PORTC) { + volatile ushort *sorp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcso; + *sorp &= ~(1 << (15 - iopin->pin)); + } +} + +static __inline__ uint +iopin_is_opt2(iopin_t *iopin) +{ + if (iopin->port == IOPIN_PORTC) { + volatile ushort *sorp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcso; + return (*sorp >> (15 - iopin->pin)) & 1; + } + return 0; +} + +static __inline__ uint +iopin_is_opt1(iopin_t *iopin) +{ + if (iopin->port == IOPIN_PORTC) { + volatile ushort *sorp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcso; + return ((*sorp >> (15 - iopin->pin)) & 1) ^ 1; + } + return 0; +} + +static __inline__ void +iopin_set_falledge(iopin_t *iopin) +{ + if (iopin->port == IOPIN_PORTC) { + volatile ushort *intp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcint; + *intp |= (1 << (15 - iopin->pin)); + } +} + +static __inline__ void +iopin_set_anyedge(iopin_t *iopin) +{ + if (iopin->port == IOPIN_PORTC) { + volatile ushort *intp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcint; + *intp &= ~(1 << (15 - iopin->pin)); + } +} + +static __inline__ uint +iopin_is_falledge(iopin_t *iopin) +{ + if (iopin->port == IOPIN_PORTC) { + volatile ushort *intp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcint; + return (*intp >> (15 - iopin->pin)) & 1; + } + return 0; +} + +static __inline__ uint +iopin_is_anyedge(iopin_t *iopin) +{ + if (iopin->port == IOPIN_PORTC) { + volatile ushort *intp = &((immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcint; + return ((*intp >> (15 - iopin->pin)) & 1) ^ 1; + } + return 0; +} + +#endif /* __KERNEL__ */ + +#endif /* _ASM_IOPIN_8XX_H_ */ diff --git a/arch/powerpc/include/asm/ppc.h b/arch/powerpc/include/asm/ppc.h index aa6c304d2d..9a8afe1132 100644 --- a/arch/powerpc/include/asm/ppc.h +++ b/arch/powerpc/include/asm/ppc.h @@ -13,6 +13,14 @@ #ifndef __ASSEMBLY__ +#if defined(CONFIG_8xx) +#include <asm/8xx_immap.h> +#if defined(CONFIG_MPC866) +# define CONFIG_MPC866_FAMILY 1 +#elif defined(CONFIG_MPC885) +# define CONFIG_MPC885_FAMILY 1 +#endif +#endif #ifdef CONFIG_MPC86xx #include <mpc86xx.h> #include <asm/immap_86xx.h> @@ -35,6 +43,9 @@ #include <asm/arch/immap_lsch2.h> #endif +#if defined(CONFIG_8xx) +uint get_immr(uint); +#endif uint get_pvr(void); uint get_svr(void); uint rd_ic_cst(void); diff --git a/arch/powerpc/lib/Kconfig b/arch/powerpc/lib/Kconfig new file mode 100644 index 0000000000..7c8ea971c3 --- /dev/null +++ b/arch/powerpc/lib/Kconfig @@ -0,0 +1,7 @@ +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 diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index 9a3043abf8..4aa41836a2 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_BAT_RW) += bat_rw.o obj-$(CONFIG_CMD_BOOTM) += bootm.o obj-y += cache.o obj-y += extable.o +obj-$(CONFIG_CMD_IMMAP) += immap.o obj-y += interrupts.o obj-$(CONFIG_CMD_KGDB) += kgdb.o obj-y += stack.o diff --git a/arch/powerpc/lib/immap.c b/arch/powerpc/lib/immap.c new file mode 100644 index 0000000000..1beed1fa40 --- /dev/null +++ b/arch/powerpc/lib/immap.c @@ -0,0 +1,397 @@ +/* + * (C) Copyright 2000-2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * MPC8xx Internal Memory Map Functions + */ + +#include <common.h> +#include <command.h> + +#if defined(CONFIG_8xx) + +#include <asm/8xx_immap.h> +#include <commproc.h> +#include <asm/iopin_8xx.h> + +DECLARE_GLOBAL_DATA_PTR; + +int +do_siuinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR; + + volatile sysconf8xx_t *sc = &immap->im_siu_conf; + + printf ("SIUMCR= %08x SYPCR = %08x\n", sc->sc_siumcr, sc->sc_sypcr); + printf ("SWT = %08x\n", sc->sc_swt); + printf ("SIPEND= %08x SIMASK= %08x\n", sc->sc_sipend, sc->sc_simask); + printf ("SIEL = %08x SIVEC = %08x\n", sc->sc_siel, sc->sc_sivec); + printf ("TESR = %08x SDCR = %08x\n", sc->sc_tesr, sc->sc_sdcr); + return 0; +} + +int +do_memcinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR; + + volatile memctl8xx_t *memctl = &immap->im_memctl; + int nbanks = 8; + volatile uint *p = &memctl->memc_br0; + int i; + + for (i = 0; i < nbanks; i++, p += 2) { + if (i < 10) { + printf ("BR%d = %08x OR%d = %08x\n", + i, p[0], i, p[1]); + } else { + printf ("BR%d = %08x OR%d = %08x\n", + i, p[0], i, p[1]); + } + } + + printf ("MAR = %08x", memctl->memc_mar); + printf (" MCR = %08x\n", memctl->memc_mcr); + printf ("MAMR = %08x MBMR = %08x", + memctl->memc_mamr, memctl->memc_mbmr); + printf ("\nMSTAT = %04x\n", memctl->memc_mstat); + printf ("MPTPR = %04x MDR = %08x\n", + memctl->memc_mptpr, memctl->memc_mdr); + return 0; +} + +int +do_carinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR; + + volatile car8xx_t *car = &immap->im_clkrst; + + printf ("SCCR = %08x\n", car->car_sccr); + printf ("PLPRCR= %08x\n", car->car_plprcr); + printf ("RSR = %08x\n", 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 + +int +do_iopinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR; + + volatile iop8xx_t *iop = &immap->im_ioport; + volatile ushort *l, *r; + volatile uint *R; + + counter = 0; + header (); + + /* + * Ports A & B + */ + + l = &iop->iop_padir; + R = &immap->im_cpm.cp_pbdir; + binary ("PA_DIR", *l++, PA_NBITS); + binary ("PB_DIR", *R++, PB_NBITS); + binary ("PA_PAR", *l++, PA_NBITS); + binary ("PB_PAR", *R++, PB_NBITS); + binary ("PA_ODR", *l++, PA_NB_ODR); + binary ("PB_ODR", *R++, PB_NB_ODR); + binary ("PA_DAT", *l++, PA_NBITS); + binary ("PB_DAT", *R++, PB_NBITS); + + header (); + + /* + * Ports C & D + */ + + l = &iop->iop_pcdir; + r = &iop->iop_pddir; + binary ("PC_DIR", *l++, PC_NBITS); + binary ("PD_DIR", *r++, PD_NBITS); + binary ("PC_PAR", *l++, PC_NBITS); + binary ("PD_PAR", *r++, PD_NBITS); + binary ("PC_SO ", *l++, PC_NBITS); + binary (" ", 0, 0); + r++; + binary ("PC_DAT", *l++, PC_NBITS); + binary ("PD_DAT", *r++, PD_NBITS); + binary ("PC_INT", *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 + */ +int +do_iopset (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + uint rcode = 0; + iopin_t iopin; + static uint port = 0; + static uint pin = 0; + static uint value = 0; + 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'); +} + +int +do_brginfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR; + + volatile cpm8xx_t *cp = &immap->im_cpm; + volatile uint *p = &cp->cp_brgc1; + int i = 1; + + while (i <= 4) + prbrg (i++, *p++); + + return 0; +} + +/***************************************************/ + +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", + "" +); +#endif diff --git a/arch/powerpc/lib/time.c b/arch/powerpc/lib/time.c index 3a5ad4d8d2..4cbb65eb68 100644 --- a/arch/powerpc/lib/time.c +++ b/arch/powerpc/lib/time.c @@ -64,10 +64,21 @@ int timer_init(void) { unsigned long temp; +#if defined(CONFIG_8xx) + volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR; + + /* unlock */ + immap->im_sitk.sitk_tbk = KAPWR_KEY; +#endif + /* reset */ asm volatile("li %0,0 ; mttbu %0 ; mttbl %0;" : "=&r"(temp) ); +#if defined(CONFIG_8xx) + /* enable */ + immap->im_sit.sit_tbscr |= TBSCR_TBE; +#endif return (0); } /* ------------------------------------------------------------------------- */ diff --git a/cmd/bdinfo.c b/cmd/bdinfo.c index 401a694712..8971697e60 100644 --- a/cmd/bdinfo.c +++ b/cmd/bdinfo.c @@ -180,7 +180,7 @@ int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) print_bi_flash(bd); print_num("sramstart", bd->bi_sramstart); print_num("sramsize", bd->bi_sramsize); -#if defined(CONFIG_E500) +#if defined(CONFIG_8xx) || defined(CONFIG_E500) print_num("immr_base", bd->bi_immr_base); #endif print_num("bootflags", bd->bi_bootflags); diff --git a/cmd/reginfo.c b/cmd/reginfo.c index 8e4bec8c4b..850f28cabc 100644 --- a/cmd/reginfo.c +++ b/cmd/reginfo.c @@ -7,7 +7,9 @@ #include <common.h> #include <command.h> -#if defined(CONFIG_MPC86xx) +#if defined(CONFIG_8xx) +#include <mpc8xx.h> +#elif defined(CONFIG_MPC86xx) extern void mpc86xx_reginfo(void); #elif defined(CONFIG_MPC85xx) extern void mpc85xx_reginfo(void); @@ -16,7 +18,60 @@ extern void mpc85xx_reginfo(void); static int do_reginfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { -#if defined(CONFIG_MPC86xx) +#if defined(CONFIG_8xx) + volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR; + volatile memctl8xx_t *memctl = &immap->im_memctl; + volatile sysconf8xx_t *sysconf = &immap->im_siu_conf; + volatile sit8xx_t *timers = &immap->im_sit; + + /* Hopefully more PowerPC knowledgable people will add code to display + * other useful registers + */ + + printf ("\nSystem Configuration registers\n" + + "\tIMMR\t0x%08X\n", get_immr(0)); + + printf("\tSIUMCR\t0x%08X", sysconf->sc_siumcr); + printf("\tSYPCR\t0x%08X\n",sysconf->sc_sypcr); + + printf("\tSWT\t0x%08X", sysconf->sc_swt); + printf("\tSWSR\t0x%04X\n", sysconf->sc_swsr); + + printf("\tSIPEND\t0x%08X\tSIMASK\t0x%08X\n", + sysconf->sc_sipend, sysconf->sc_simask); + printf("\tSIEL\t0x%08X\tSIVEC\t0x%08X\n", + sysconf->sc_siel, sysconf->sc_sivec); + printf("\tTESR\t0x%08X\tSDCR\t0x%08X\n", + sysconf->sc_tesr, sysconf->sc_sdcr); + + printf ("Memory Controller Registers\n" + + "\tBR0\t0x%08X\tOR0\t0x%08X \n", memctl->memc_br0, memctl->memc_or0); + printf("\tBR1\t0x%08X\tOR1\t0x%08X \n", memctl->memc_br1, memctl->memc_or1); + printf("\tBR2\t0x%08X\tOR2\t0x%08X \n", memctl->memc_br2, memctl->memc_or2); + printf("\tBR3\t0x%08X\tOR3\t0x%08X \n", memctl->memc_br3, memctl->memc_or3); + printf("\tBR4\t0x%08X\tOR4\t0x%08X \n", memctl->memc_br4, memctl->memc_or4); + printf("\tBR5\t0x%08X\tOR5\t0x%08X \n", memctl->memc_br5, memctl->memc_or5); + printf("\tBR6\t0x%08X\tOR6\t0x%08X \n", memctl->memc_br6, memctl->memc_or6); + printf("\tBR7\t0x%08X\tOR7\t0x%08X \n", memctl->memc_br7, memctl->memc_or7); + printf ("\n" + "\tmamr\t0x%08X\tmbmr\t0x%08X \n", + memctl->memc_mamr, memctl->memc_mbmr ); + printf("\tmstat\t0x%08X\tmptpr\t0x%08X \n", + memctl->memc_mstat, memctl->memc_mptpr ); + printf("\tmdr\t0x%08X \n", memctl->memc_mdr); + + printf ("\nSystem Integration Timers\n" + "\tTBSCR\t0x%08X\tRTCSC\t0x%08X \n", + timers->sit_tbscr, timers->sit_rtcsc); + printf("\tPISCR\t0x%08X \n", timers->sit_piscr); + + /* + * May be some CPM info here? + */ + +#elif defined(CONFIG_MPC86xx) mpc86xx_reginfo(); #elif defined(CONFIG_MPC85xx) diff --git a/include/asm-generic/u-boot.h b/include/asm-generic/u-boot.h index 789592992e..d3049d81f5 100644 --- a/include/asm-generic/u-boot.h +++ b/include/asm-generic/u-boot.h @@ -37,7 +37,7 @@ typedef struct bd_info { unsigned long bi_dsp_freq; /* dsp core frequency */ unsigned long bi_ddr_freq; /* ddr frequency */ #endif -#if defined(CONFIG_E500) || defined(CONFIG_MPC86xx) +#if defined(CONFIG_8xx) || defined(CONFIG_E500) || defined(CONFIG_MPC86xx) unsigned long bi_immr_base; /* base of IMMR register */ #endif #if defined(CONFIG_M68K) diff --git a/include/commproc.h b/include/commproc.h new file mode 100644 index 0000000000..5518cb325d --- /dev/null +++ b/include/commproc.h @@ -0,0 +1,687 @@ +/* + * MPC8xx Communication Processor Module. + * Copyright (c) 1997 Dan Malek (dmalek@jlc.net) + * + * (C) Copyright 2000-2006 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This file contains structures and information for the communication + * processor channels. Some CPM control and status is available + * throught the MPC8xx internal memory map. See immap.h for details. + * This file only contains what I need for the moment, not the total + * CPM capabilities. I (or someone else) will add definitions as they + * are needed. -- Dan + * + */ +#ifndef __CPM_8XX__ +#define __CPM_8XX__ + +#include <asm/8xx_immap.h> + +/* CPM Command register. +*/ +#define CPM_CR_RST ((ushort)0x8000) +#define CPM_CR_OPCODE ((ushort)0x0f00) +#define CPM_CR_CHAN ((ushort)0x00f0) +#define CPM_CR_FLG ((ushort)0x0001) + +/* Some commands (there are more...later) +*/ +#define CPM_CR_INIT_TRX ((ushort)0x0000) +#define CPM_CR_INIT_RX ((ushort)0x0001) +#define CPM_CR_INIT_TX ((ushort)0x0002) +#define CPM_CR_HUNT_MODE ((ushort)0x0003) +#define CPM_CR_STOP_TX ((ushort)0x0004) +#define CPM_CR_RESTART_TX ((ushort)0x0006) +#define CPM_CR_SET_GADDR ((ushort)0x0008) + +/* Channel numbers. +*/ +#define CPM_CR_CH_SCC1 ((ushort)0x0000) +#define CPM_CR_CH_I2C ((ushort)0x0001) /* I2C and IDMA1 */ +#define CPM_CR_CH_SCC2 ((ushort)0x0004) +#define CPM_CR_CH_SPI ((ushort)0x0005) /* SPI/IDMA2/Timers */ +#define CPM_CR_CH_SCC3 ((ushort)0x0008) +#define CPM_CR_CH_SMC1 ((ushort)0x0009) /* SMC1 / DSP1 */ +#define CPM_CR_CH_SCC4 ((ushort)0x000c) +#define CPM_CR_CH_SMC2 ((ushort)0x000d) /* SMC2 / DSP2 */ + +#define mk_cr_cmd(CH, CMD) ((CMD << 8) | (CH << 4)) + +/* + * DPRAM defines and allocation functions + */ +#define CPM_SERIAL_BASE 0x0800 +#define CPM_I2C_BASE 0x0820 +#define CPM_SPI_BASE 0x0840 +#define CPM_FEC_BASE 0x0860 +#define CPM_SERIAL2_BASE 0x08E0 +#define CPM_SCC_BASE 0x0900 +#define CPM_POST_BASE 0x0980 +#define CPM_WLKBD_BASE 0x0a00 + +#define BD_IIC_START ((uint) 0x0400) /* <- please use CPM_I2C_BASE !! */ + +/* Export the base address of the communication processor registers + * and dual port ram. + */ +extern cpm8xx_t *cpmp; /* Pointer to comm processor */ + +/* Buffer descriptors used by many of the CPM protocols. +*/ +typedef struct cpm_buf_desc { + ushort cbd_sc; /* Status and Control */ + ushort cbd_datlen; /* Data length in buffer */ + uint cbd_bufaddr; /* Buffer address in host memory */ +} cbd_t; + +#define BD_SC_EMPTY ((ushort)0x8000) /* Receive is empty */ +#define BD_SC_READY ((ushort)0x8000) /* Transmit is ready */ +#define BD_SC_WRAP ((ushort)0x2000) /* Last buffer descriptor */ +#define BD_SC_INTRPT ((ushort)0x1000) /* Interrupt on change */ +#define BD_SC_LAST ((ushort)0x0800) /* Last buffer in frame */ +#define BD_SC_TC ((ushort)0x0400) /* Transmit CRC */ +#define BD_SC_CM ((ushort)0x0200) /* Continous mode */ +#define BD_SC_ID ((ushort)0x0100) /* Rec'd too many idles */ +#define BD_SC_P ((ushort)0x0100) /* xmt preamble */ +#define BD_SC_BR ((ushort)0x0020) /* Break received */ +#define BD_SC_FR ((ushort)0x0010) /* Framing error */ +#define BD_SC_PR ((ushort)0x0008) /* Parity error */ +#define BD_SC_OV ((ushort)0x0002) /* Overrun */ +#define BD_SC_CD ((ushort)0x0001) /* Carrier Detect lost */ + +/* Parameter RAM offsets. +*/ +#define PROFF_SCC1 ((uint)0x0000) +#define PROFF_IIC ((uint)0x0080) +#define PROFF_REVNUM ((uint)0x00b0) +#define PROFF_SCC2 ((uint)0x0100) +#define PROFF_SPI ((uint)0x0180) +#define PROFF_SCC3 ((uint)0x0200) +#define PROFF_SMC1 ((uint)0x0280) +#define PROFF_SCC4 ((uint)0x0300) +#define PROFF_SMC2 ((uint)0x0380) + +/* Define enough so I can at least use the serial port as a UART. + */ +typedef struct smc_uart { + ushort smc_rbase; /* Rx Buffer descriptor base address */ + ushort smc_tbase; /* Tx Buffer descriptor base address */ + u_char smc_rfcr; /* Rx function code */ + u_char smc_tfcr; /* Tx function code */ + ushort smc_mrblr; /* Max receive buffer length */ + uint smc_rstate; /* Internal */ + uint smc_idp; /* Internal */ + ushort smc_rbptr; /* Internal */ + ushort smc_ibc; /* Internal */ + uint smc_rxtmp; /* Internal */ + uint smc_tstate; /* Internal */ + uint smc_tdp; /* Internal */ + ushort smc_tbptr; /* Internal */ + ushort smc_tbc; /* Internal */ + uint smc_txtmp; /* Internal */ + ushort smc_maxidl; /* Maximum idle characters */ + ushort smc_tmpidl; /* Temporary idle counter */ + ushort smc_brklen; /* Last received break length */ + ushort smc_brkec; /* rcv'd break condition counter */ + ushort smc_brkcr; /* xmt break count register */ + ushort smc_rmask; /* Temporary bit mask */ + u_char res1[8]; + ushort smc_rpbase; /* Relocation pointer */ +} smc_uart_t; + +/* Function code bits. +*/ +#define SMC_EB ((u_char)0x10) /* Set big endian byte order */ + +/* SMC uart mode register. +*/ +#define SMCMR_REN ((ushort)0x0001) +#define SMCMR_TEN ((ushort)0x0002) +#define SMCMR_DM ((ushort)0x000c) +#define SMCMR_SM_GCI ((ushort)0x0000) +#define SMCMR_SM_UART ((ushort)0x0020) +#define SMCMR_SM_TRANS ((ushort)0x0030) +#define SMCMR_SM_MASK ((ushort)0x0030) +#define SMCMR_PM_EVEN ((ushort)0x0100) /* Even parity, else odd */ +#define SMCMR_REVD SMCMR_PM_EVEN +#define SMCMR_PEN ((ushort)0x0200) /* Parity enable */ +#define SMCMR_BS SMCMR_PEN +#define SMCMR_SL ((ushort)0x0400) /* Two stops, else one */ +#define SMCR_CLEN_MASK ((ushort)0x7800) /* Character length */ +#define smcr_mk_clen(C) (((C) << 11) & SMCR_CLEN_MASK) + +/* SMC2 as Centronics parallel printer. It is half duplex, in that + * it can only receive or transmit. The parameter ram values for + * each direction are either unique or properly overlap, so we can + * include them in one structure. + */ +typedef struct smc_centronics { + ushort scent_rbase; + ushort scent_tbase; + u_char scent_cfcr; + u_char scent_smask; + ushort scent_mrblr; + uint scent_rstate; + uint scent_r_ptr; + ushort scent_rbptr; + ushort scent_r_cnt; + uint scent_rtemp; + uint scent_tstate; + uint scent_t_ptr; + ushort scent_tbptr; + ushort scent_t_cnt; + uint scent_ttemp; + ushort scent_max_sl; + ushort scent_sl_cnt; + ushort scent_character1; + ushort scent_character2; + ushort scent_character3; + ushort scent_character4; + ushort scent_character5; + ushort scent_character6; + ushort scent_character7; + ushort scent_character8; + ushort scent_rccm; + ushort scent_rccr; +} smc_cent_t; + +/* Centronics Status Mask Register. +*/ +#define SMC_CENT_F ((u_char)0x08) +#define SMC_CENT_PE ((u_char)0x04) +#define SMC_CENT_S ((u_char)0x02) + +/* SMC Event and Mask register. +*/ +#define SMCM_BRKE ((unsigned char)0x40) /* When in UART Mode */ +#define SMCM_BRK ((unsigned char)0x10) /* When in UART Mode */ +#define SMCM_TXE ((unsigned char)0x10) /* When in Transparent Mode */ +#define SMCM_BSY ((unsigned char)0x04) +#define SMCM_TX ((unsigned char)0x02) +#define SMCM_RX ((unsigned char)0x01) + +/* Baud rate generators. +*/ +#define CPM_BRG_RST ((uint)0x00020000) +#define CPM_BRG_EN ((uint)0x00010000) +#define CPM_BRG_EXTC_INT ((uint)0x00000000) +#define CPM_BRG_EXTC_CLK2 ((uint)0x00004000) +#define CPM_BRG_EXTC_CLK6 ((uint)0x00008000) +#define CPM_BRG_ATB ((uint)0x00002000) +#define CPM_BRG_CD_MASK ((uint)0x00001ffe) +#define CPM_BRG_DIV16 ((uint)0x00000001) + +/* SI Clock Route Register +*/ +#define SICR_RCLK_SCC1_BRG1 ((uint)0x00000000) +#define SICR_TCLK_SCC1_BRG1 ((uint)0x00000000) +#define SICR_RCLK_SCC2_BRG2 ((uint)0x00000800) +#define SICR_TCLK_SCC2_BRG2 ((uint)0x00000100) +#define SICR_RCLK_SCC3_BRG3 ((uint)0x00100000) +#define SICR_TCLK_SCC3_BRG3 ((uint)0x00020000) +#define SICR_RCLK_SCC4_BRG4 ((uint)0x18000000) +#define SICR_TCLK_SCC4_BRG4 ((uint)0x03000000) + +/* SCCs. +*/ +#define SCC_GSMRH_IRP ((uint)0x00040000) +#define SCC_GSMRH_GDE ((uint)0x00010000) +#define SCC_GSMRH_TCRC_CCITT ((uint)0x00008000) +#define SCC_GSMRH_TCRC_BISYNC ((uint)0x00004000) +#define SCC_GSMRH_TCRC_HDLC ((uint)0x00000000) +#define SCC_GSMRH_REVD ((uint)0x00002000) +#define SCC_GSMRH_TRX ((uint)0x00001000) +#define SCC_GSMRH_TTX ((uint)0x00000800) +#define SCC_GSMRH_CDP ((uint)0x00000400) +#define SCC_GSMRH_CTSP ((uint)0x00000200) +#define SCC_GSMRH_CDS ((uint)0x00000100) +#define SCC_GSMRH_CTSS ((uint)0x00000080) +#define SCC_GSMRH_TFL ((uint)0x00000040) +#define SCC_GSMRH_RFW ((uint)0x00000020) +#define SCC_GSMRH_TXSY ((uint)0x00000010) +#define SCC_GSMRH_SYNL16 ((uint)0x0000000c) +#define SCC_GSMRH_SYNL8 ((uint)0x00000008) +#define SCC_GSMRH_SYNL4 ((uint)0x00000004) +#define SCC_GSMRH_RTSM ((uint)0x00000002) +#define SCC_GSMRH_RSYN ((uint)0x00000001) + +#define SCC_GSMRL_SIR ((uint)0x80000000) /* SCC2 only */ +#define SCC_GSMRL_EDGE_NONE ((uint)0x60000000) +#define SCC_GSMRL_EDGE_NEG ((uint)0x40000000) +#define SCC_GSMRL_EDGE_POS ((uint)0x20000000) +#define SCC_GSMRL_EDGE_BOTH ((uint)0x00000000) +#define SCC_GSMRL_TCI ((uint)0x10000000) +#define SCC_GSMRL_TSNC_3 ((uint)0x0c000000) +#define SCC_GSMRL_TSNC_4 ((uint)0x08000000) +#define SCC_GSMRL_TSNC_14 ((uint)0x04000000) +#define SCC_GSMRL_TSNC_INF ((uint)0x00000000) +#define SCC_GSMRL_RINV ((uint)0x02000000) +#define SCC_GSMRL_TINV ((uint)0x01000000) +#define SCC_GSMRL_TPL_128 ((uint)0x00c00000) +#define SCC_GSMRL_TPL_64 ((uint)0x00a00000) +#define SCC_GSMRL_TPL_48 ((uint)0x00800000) +#define SCC_GSMRL_TPL_32 ((uint)0x00600000) +#define SCC_GSMRL_TPL_16 ((uint)0x00400000) +#define SCC_GSMRL_TPL_8 ((uint)0x00200000) +#define SCC_GSMRL_TPL_NONE ((uint)0x00000000) +#define SCC_GSMRL_TPP_ALL1 ((uint)0x00180000) +#define SCC_GSMRL_TPP_01 ((uint)0x00100000) +#define SCC_GSMRL_TPP_10 ((uint)0x00080000) +#define SCC_GSMRL_TPP_ZEROS ((uint)0x00000000) +#define SCC_GSMRL_TEND ((uint)0x00040000) +#define SCC_GSMRL_TDCR_32 ((uint)0x00030000) +#define SCC_GSMRL_TDCR_16 ((uint)0x00020000) +#define SCC_GSMRL_TDCR_8 ((uint)0x00010000) +#define SCC_GSMRL_TDCR_1 ((uint)0x00000000) +#define SCC_GSMRL_RDCR_32 ((uint)0x0000c000) +#define SCC_GSMRL_RDCR_16 ((uint)0x00008000) +#define SCC_GSMRL_RDCR_8 ((uint)0x00004000) +#define SCC_GSMRL_RDCR_1 ((uint)0x00000000) +#define SCC_GSMRL_RENC_DFMAN ((uint)0x00003000) +#define SCC_GSMRL_RENC_MANCH ((uint)0x00002000) +#define SCC_GSMRL_RENC_FM0 ((uint)0x00001000) +#define SCC_GSMRL_RENC_NRZI ((uint)0x00000800) +#define SCC_GSMRL_RENC_NRZ ((uint)0x00000000) +#define SCC_GSMRL_TENC_DFMAN ((uint)0x00000600) +#define SCC_GSMRL_TENC_MANCH ((uint)0x00000400) +#define SCC_GSMRL_TENC_FM0 ((uint)0x00000200) +#define SCC_GSMRL_TENC_NRZI ((uint)0x00000100) +#define SCC_GSMRL_TENC_NRZ ((uint)0x00000000) +#define SCC_GSMRL_DIAG_LE ((uint)0x000000c0) /* Loop and echo */ +#define SCC_GSMRL_DIAG_ECHO ((uint)0x00000080) +#define SCC_GSMRL_DIAG_LOOP ((uint)0x00000040) +#define SCC_GSMRL_DIAG_NORM ((uint)0x00000000) +#define SCC_GSMRL_ENR ((uint)0x00000020) +#define SCC_GSMRL_ENT ((uint)0x00000010) +#define SCC_GSMRL_MODE_ENET ((uint)0x0000000c) +#define SCC_GSMRL_MODE_DDCMP ((uint)0x00000009) +#define SCC_GSMRL_MODE_BISYNC ((uint)0x00000008) +#define SCC_GSMRL_MODE_V14 ((uint)0x00000007) +#define SCC_GSMRL_MODE_AHDLC ((uint)0x00000006) +#define SCC_GSMRL_MODE_PROFIBUS ((uint)0x00000005) +#define SCC_GSMRL_MODE_UART ((uint)0x00000004) +#define SCC_GSMRL_MODE_SS7 ((uint)0x00000003) +#define SCC_GSMRL_MODE_ATALK ((uint)0x00000002) +#define SCC_GSMRL_MODE_HDLC ((uint)0x00000000) + +#define SCC_TODR_TOD ((ushort)0x8000) + +/* SCC Event and Mask register. +*/ +#define SCCM_TXE ((unsigned char)0x10) +#define SCCM_BSY ((unsigned char)0x04) +#define SCCM_TX ((unsigned char)0x02) +#define SCCM_RX ((unsigned char)0x01) + +typedef struct scc_param { + ushort scc_rbase; /* Rx Buffer descriptor base address */ + ushort scc_tbase; /* Tx Buffer descriptor base address */ + u_char scc_rfcr; /* Rx function code */ + u_char scc_tfcr; /* Tx function code */ + ushort scc_mrblr; /* Max receive buffer length */ + uint scc_rstate; /* Internal */ + uint scc_idp; /* Internal */ + ushort scc_rbptr; /* Internal */ + ushort scc_ibc; /* Internal */ + uint scc_rxtmp; /* Internal */ + uint scc_tstate; /* Internal */ + uint scc_tdp; /* Internal */ + ushort scc_tbptr; /* Internal */ + ushort scc_tbc; /* Internal */ + uint scc_txtmp; /* Internal */ + uint scc_rcrc; /* Internal */ + uint scc_tcrc; /* Internal */ +} sccp_t; + +/* Function code bits. +*/ +#define SCC_EB ((u_char)0x10) /* Set big endian byte order */ + +/* CPM Ethernet through SCCx. + */ +typedef struct scc_enet { + sccp_t sen_genscc; + uint sen_cpres; /* Preset CRC */ + uint sen_cmask; /* Constant mask for CRC */ + uint sen_crcec; /* CRC Error counter */ + uint sen_alec; /* alignment error counter */ + uint sen_disfc; /* discard frame counter */ + ushort sen_pads; /* Tx short frame pad character */ + ushort sen_retlim; /* Retry limit threshold */ + ushort sen_retcnt; /* Retry limit counter */ + ushort sen_maxflr; /* maximum frame length register */ + ushort sen_minflr; /* minimum frame length register */ + ushort sen_maxd1; /* maximum DMA1 length */ + ushort sen_maxd2; /* maximum DMA2 length */ + ushort sen_maxd; /* Rx max DMA */ + ushort sen_dmacnt; /* Rx DMA counter */ + ushort sen_maxb; /* Max BD byte count */ + ushort sen_gaddr1; /* Group address filter */ + ushort sen_gaddr2; + ushort sen_gaddr3; + ushort sen_gaddr4; + uint sen_tbuf0data0; /* Save area 0 - current frame */ + uint sen_tbuf0data1; /* Save area 1 - current frame */ + uint sen_tbuf0rba; /* Internal */ + uint sen_tbuf0crc; /* Internal */ + ushort sen_tbuf0bcnt; /* Internal */ + ushort sen_paddrh; /* physical address (MSB) */ + ushort sen_paddrm; + ushort sen_paddrl; /* physical address (LSB) */ + ushort sen_pper; /* persistence */ + ushort sen_rfbdptr; /* Rx first BD pointer */ + ushort sen_tfbdptr; /* Tx first BD pointer */ + ushort sen_tlbdptr; /* Tx last BD pointer */ + uint sen_tbuf1data0; /* Save area 0 - current frame */ + uint sen_tbuf1data1; /* Save area 1 - current frame */ + uint sen_tbuf1rba; /* Internal */ + uint sen_tbuf1crc; /* Internal */ + ushort sen_tbuf1bcnt; /* Internal */ + ushort sen_txlen; /* Tx Frame length counter */ + ushort sen_iaddr1; /* Individual address filter */ + ushort sen_iaddr2; + ushort sen_iaddr3; + ushort sen_iaddr4; + ushort sen_boffcnt; /* Backoff counter */ + + /* NOTE: Some versions of the manual have the following items + * incorrectly documented. Below is the proper order. + */ + ushort sen_taddrh; /* temp address (MSB) */ + ushort sen_taddrm; + ushort sen_taddrl; /* temp address (LSB) */ +} scc_enet_t; + +/*********************************************************************/ + +/* SCC Event register as used by Ethernet. +*/ +#define SCCE_ENET_GRA ((ushort)0x0080) /* Graceful stop complete */ +#define SCCE_ENET_TXE ((ushort)0x0010) /* Transmit Error */ +#define SCCE_ENET_RXF ((ushort)0x0008) /* Full frame received */ +#define SCCE_ENET_BSY ((ushort)0x0004) /* All incoming buffers full */ +#define SCCE_ENET_TXB ((ushort)0x0002) /* A buffer was transmitted */ +#define SCCE_ENET_RXB ((ushort)0x0001) /* A buffer was received */ + +/* SCC Mode Register (PSMR) as used by Ethernet. +*/ +#define SCC_PSMR_HBC ((ushort)0x8000) /* Enable heartbeat */ +#define SCC_PSMR_FC ((ushort)0x4000) /* Force collision */ +#define SCC_PSMR_RSH ((ushort)0x2000) /* Receive short frames */ +#define SCC_PSMR_IAM ((ushort)0x1000) /* Check individual hash */ +#define SCC_PSMR_ENCRC ((ushort)0x0800) /* Ethernet CRC mode */ +#define SCC_PSMR_PRO ((ushort)0x0200) /* Promiscuous mode */ +#define SCC_PSMR_BRO ((ushort)0x0100) /* Catch broadcast pkts */ +#define SCC_PSMR_SBT ((ushort)0x0080) /* Special backoff timer */ +#define SCC_PSMR_LPB ((ushort)0x0040) /* Set Loopback mode */ +#define SCC_PSMR_SIP ((ushort)0x0020) /* Sample Input Pins */ +#define SCC_PSMR_LCW ((ushort)0x0010) /* Late collision window */ +#define SCC_PSMR_NIB22 ((ushort)0x000a) /* Start frame search */ +#define SCC_PSMR_FDE ((ushort)0x0001) /* Full duplex enable */ + +/* Buffer descriptor control/status used by Ethernet receive. +*/ +#define BD_ENET_RX_EMPTY ((ushort)0x8000) +#define BD_ENET_RX_WRAP ((ushort)0x2000) +#define BD_ENET_RX_INTR ((ushort)0x1000) +#define BD_ENET_RX_LAST ((ushort)0x0800) +#define BD_ENET_RX_FIRST ((ushort)0x0400) +#define BD_ENET_RX_MISS ((ushort)0x0100) +#define BD_ENET_RX_LG ((ushort)0x0020) +#define BD_ENET_RX_NO ((ushort)0x0010) +#define BD_ENET_RX_SH ((ushort)0x0008) +#define BD_ENET_RX_CR ((ushort)0x0004) +#define BD_ENET_RX_OV ((ushort)0x0002) +#define BD_ENET_RX_CL ((ushort)0x0001) +#define BD_ENET_RX_STATS ((ushort)0x013f) /* All status bits */ + +/* Buffer descriptor control/status used by Ethernet transmit. +*/ +#define BD_ENET_TX_READY ((ushort)0x8000) +#define BD_ENET_TX_PAD ((ushort)0x4000) +#define BD_ENET_TX_WRAP ((ushort)0x2000) +#define BD_ENET_TX_INTR ((ushort)0x1000) +#define BD_ENET_TX_LAST ((ushort)0x0800) +#define BD_ENET_TX_TC ((ushort)0x0400) +#define BD_ENET_TX_DEF ((ushort)0x0200) +#define BD_ENET_TX_HB ((ushort)0x0100) +#define BD_ENET_TX_LC ((ushort)0x0080) +#define BD_ENET_TX_RL ((ushort)0x0040) +#define BD_ENET_TX_RCMASK ((ushort)0x003c) +#define BD_ENET_TX_UN ((ushort)0x0002) +#define BD_ENET_TX_CSL ((ushort)0x0001) +#define BD_ENET_TX_STATS ((ushort)0x03ff) /* All status bits */ + +/* SCC as UART +*/ +typedef struct scc_uart { + sccp_t scc_genscc; + uint scc_res1; /* Reserved */ + uint scc_res2; /* Reserved */ + ushort scc_maxidl; /* Maximum idle chars */ + ushort scc_idlc; /* temp idle counter */ + ushort scc_brkcr; /* Break count register */ + ushort scc_parec; /* receive parity error counter */ + ushort scc_frmec; /* receive framing error counter */ + ushort scc_nosec; /* receive noise counter */ + ushort scc_brkec; /* receive break condition counter */ + ushort scc_brkln; /* last received break length */ + ushort scc_uaddr1; /* UART address character 1 */ + ushort scc_uaddr2; /* UART address character 2 */ + ushort scc_rtemp; /* Temp storage */ + ushort scc_toseq; /* Transmit out of sequence char */ + ushort scc_char1; /* control character 1 */ + ushort scc_char2; /* control character 2 */ + ushort scc_char3; /* control character 3 */ + ushort scc_char4; /* control character 4 */ + ushort scc_char5; /* control character 5 */ + ushort scc_char6; /* control character 6 */ + ushort scc_char7; /* control character 7 */ + ushort scc_char8; /* control character 8 */ + ushort scc_rccm; /* receive control character mask */ + ushort scc_rccr; /* receive control character register */ + ushort scc_rlbc; /* receive last break character */ +} scc_uart_t; + +/* SCC Event and Mask registers when it is used as a UART. +*/ +#define UART_SCCM_GLR ((ushort)0x1000) +#define UART_SCCM_GLT ((ushort)0x0800) +#define UART_SCCM_AB ((ushort)0x0200) +#define UART_SCCM_IDL ((ushort)0x0100) +#define UART_SCCM_GRA ((ushort)0x0080) +#define UART_SCCM_BRKE ((ushort)0x0040) +#define UART_SCCM_BRKS ((ushort)0x0020) +#define UART_SCCM_CCR ((ushort)0x0008) +#define UART_SCCM_BSY ((ushort)0x0004) +#define UART_SCCM_TX ((ushort)0x0002) +#define UART_SCCM_RX ((ushort)0x0001) + +/* The SCC PSMR when used as a UART. +*/ +#define SCU_PSMR_FLC ((ushort)0x8000) +#define SCU_PSMR_SL ((ushort)0x4000) +#define SCU_PSMR_CL ((ushort)0x3000) +#define SCU_PSMR_UM ((ushort)0x0c00) +#define SCU_PSMR_FRZ ((ushort)0x0200) +#define SCU_PSMR_RZS ((ushort)0x0100) +#define SCU_PSMR_SYN ((ushort)0x0080) +#define SCU_PSMR_DRT ((ushort)0x0040) +#define SCU_PSMR_PEN ((ushort)0x0010) +#define SCU_PSMR_RPM ((ushort)0x000c) +#define SCU_PSMR_REVP ((ushort)0x0008) +#define SCU_PSMR_TPM ((ushort)0x0003) +#define SCU_PSMR_TEVP ((ushort)0x0003) + +/* CPM Transparent mode SCC. + */ +typedef struct scc_trans { + sccp_t st_genscc; + uint st_cpres; /* Preset CRC */ + uint st_cmask; /* Constant mask for CRC */ +} scc_trans_t; + +#define BD_SCC_TX_LAST ((ushort)0x0800) + +/* IIC parameter RAM. +*/ +typedef struct iic { + ushort iic_rbase; /* Rx Buffer descriptor base address */ + ushort iic_tbase; /* Tx Buffer descriptor base address */ + u_char iic_rfcr; /* Rx function code */ + u_char iic_tfcr; /* Tx function code */ + ushort iic_mrblr; /* Max receive buffer length */ + uint iic_rstate; /* Internal */ + uint iic_rdp; /* Internal */ + ushort iic_rbptr; /* Internal */ + ushort iic_rbc; /* Internal */ + uint iic_rxtmp; /* Internal */ + uint iic_tstate; /* Internal */ + uint iic_tdp; /* Internal */ + ushort iic_tbptr; /* Internal */ + ushort iic_tbc; /* Internal */ + uint iic_txtmp; /* Internal */ + uint iic_res; /* reserved */ + ushort iic_rpbase; /* Relocation pointer */ + ushort iic_res2; /* reserved */ +} iic_t; + +/* SPI parameter RAM. +*/ +typedef struct spi { + ushort spi_rbase; /* Rx Buffer descriptor base address */ + ushort spi_tbase; /* Tx Buffer descriptor base address */ + u_char spi_rfcr; /* Rx function code */ + u_char spi_tfcr; /* Tx function code */ + ushort spi_mrblr; /* Max receive buffer length */ + uint spi_rstate; /* Internal */ + uint spi_rdp; /* Internal */ + ushort spi_rbptr; /* Internal */ + ushort spi_rbc; /* Internal */ + uint spi_rxtmp; /* Internal */ + uint spi_tstate; /* Internal */ + uint spi_tdp; /* Internal */ + ushort spi_tbptr; /* Internal */ + ushort spi_tbc; /* Internal */ + uint spi_txtmp; /* Internal */ + uint spi_res; + ushort spi_rpbase; /* Relocation pointer */ + ushort spi_res2; +} spi_t; + +/* SPI Mode register. +*/ +#define SPMODE_LOOP ((ushort)0x4000) /* Loopback */ +#define SPMODE_CI ((ushort)0x2000) /* Clock Invert */ +#define SPMODE_CP ((ushort)0x1000) /* Clock Phase */ +#define SPMODE_DIV16 ((ushort)0x0800) /* BRG/16 mode */ +#define SPMODE_REV ((ushort)0x0400) /* Reversed Data */ +#define SPMODE_MSTR ((ushort)0x0200) /* SPI Master */ +#define SPMODE_EN ((ushort)0x0100) /* Enable */ +#define SPMODE_LENMSK ((ushort)0x00f0) /* character length */ +#define SPMODE_PMMSK ((ushort)0x000f) /* prescale modulus */ + +#define SPMODE_LEN(x) ((((x)-1)&0xF)<<4) +#define SPMODE_PM(x) ((x) &0xF) + +/* HDLC parameter RAM. +*/ + +typedef struct hdlc_pram_s { + /* + * SCC parameter RAM + */ + ushort rbase; /* Rx Buffer descriptor base address */ + ushort tbase; /* Tx Buffer descriptor base address */ + uchar rfcr; /* Rx function code */ + uchar tfcr; /* Tx function code */ + ushort mrblr; /* Rx buffer length */ + ulong rstate; /* Rx internal state */ + ulong rptr; /* Rx internal data pointer */ + ushort rbptr; /* rb BD Pointer */ + ushort rcount; /* Rx internal byte count */ + ulong rtemp; /* Rx temp */ + ulong tstate; /* Tx internal state */ + ulong tptr; /* Tx internal data pointer */ + ushort tbptr; /* Tx BD pointer */ + ushort tcount; /* Tx byte count */ + ulong ttemp; /* Tx temp */ + ulong rcrc; /* temp receive CRC */ + ulong tcrc; /* temp transmit CRC */ + /* + * HDLC specific parameter RAM + */ + uchar res[4]; /* reserved */ + ulong c_mask; /* CRC constant */ + ulong c_pres; /* CRC preset */ + ushort disfc; /* discarded frame counter */ + ushort crcec; /* CRC error counter */ + ushort abtsc; /* abort sequence counter */ + ushort nmarc; /* nonmatching address rx cnt */ + ushort retrc; /* frame retransmission cnt */ + ushort mflr; /* maximum frame length reg */ + ushort max_cnt; /* maximum length counter */ + ushort rfthr; /* received frames threshold */ + ushort rfcnt; /* received frames count */ + ushort hmask; /* user defined frm addr mask */ + ushort haddr1; /* user defined frm address 1 */ + ushort haddr2; /* user defined frm address 2 */ + ushort haddr3; /* user defined frm address 3 */ + ushort haddr4; /* user defined frm address 4 */ + ushort tmp; /* temp */ + ushort tmp_mb; /* temp */ +} hdlc_pram_t; + +/* CPM interrupts. There are nearly 32 interrupts generated by CPM + * channels or devices. All of these are presented to the PPC core + * as a single interrupt. The CPM interrupt handler dispatches its + * own handlers, in a similar fashion to the PPC core handler. We + * use the table as defined in the manuals (i.e. no special high + * priority and SCC1 == SCCa, etc...). + */ +#define CPMVEC_NR 32 +#define CPMVEC_OFFSET 0x00010000 +#define CPMVEC_PIO_PC15 ((ushort)0x1f | CPMVEC_OFFSET) +#define CPMVEC_SCC1 ((ushort)0x1e | CPMVEC_OFFSET) +#define CPMVEC_SCC2 ((ushort)0x1d | CPMVEC_OFFSET) +#define CPMVEC_SCC3 ((ushort)0x1c | CPMVEC_OFFSET) +#define CPMVEC_SCC4 ((ushort)0x1b | CPMVEC_OFFSET) +#define CPMVEC_PIO_PC14 ((ushort)0x1a | CPMVEC_OFFSET) +#define CPMVEC_TIMER1 ((ushort)0x19 | CPMVEC_OFFSET) +#define CPMVEC_PIO_PC13 ((ushort)0x18 | CPMVEC_OFFSET) +#define CPMVEC_PIO_PC12 ((ushort)0x17 | CPMVEC_OFFSET) +#define CPMVEC_SDMA_CB_ERR ((ushort)0x16 | CPMVEC_OFFSET) +#define CPMVEC_IDMA1 ((ushort)0x15 | CPMVEC_OFFSET) +#define CPMVEC_IDMA2 ((ushort)0x14 | CPMVEC_OFFSET) +#define CPMVEC_TIMER2 ((ushort)0x12 | CPMVEC_OFFSET) +#define CPMVEC_RISCTIMER ((ushort)0x11 | CPMVEC_OFFSET) +#define CPMVEC_I2C ((ushort)0x10 | CPMVEC_OFFSET) +#define CPMVEC_PIO_PC11 ((ushort)0x0f | CPMVEC_OFFSET) +#define CPMVEC_PIO_PC10 ((ushort)0x0e | CPMVEC_OFFSET) +#define CPMVEC_TIMER3 ((ushort)0x0c | CPMVEC_OFFSET) +#define CPMVEC_PIO_PC9 ((ushort)0x0b | CPMVEC_OFFSET) +#define CPMVEC_PIO_PC8 ((ushort)0x0a | CPMVEC_OFFSET) +#define CPMVEC_PIO_PC7 ((ushort)0x09 | CPMVEC_OFFSET) +#define CPMVEC_TIMER4 ((ushort)0x07 | CPMVEC_OFFSET) +#define CPMVEC_PIO_PC6 ((ushort)0x06 | CPMVEC_OFFSET) +#define CPMVEC_SPI ((ushort)0x05 | CPMVEC_OFFSET) +#define CPMVEC_SMC1 ((ushort)0x04 | CPMVEC_OFFSET) +#define CPMVEC_SMC2 ((ushort)0x03 | CPMVEC_OFFSET) +#define CPMVEC_PIO_PC5 ((ushort)0x02 | CPMVEC_OFFSET) +#define CPMVEC_PIO_PC4 ((ushort)0x01 | CPMVEC_OFFSET) +#define CPMVEC_ERROR ((ushort)0x00 | CPMVEC_OFFSET) + +extern void irq_install_handler(int vec, void (*handler)(void *), void *dev_id); + +/* CPM interrupt configuration vector. +*/ +#define CICR_SCD_SCC4 ((uint)0x00c00000) /* SCC4 @ SCCd */ +#define CICR_SCC_SCC3 ((uint)0x00200000) /* SCC3 @ SCCc */ +#define CICR_SCB_SCC2 ((uint)0x00040000) /* SCC2 @ SCCb */ +#define CICR_SCA_SCC1 ((uint)0x00000000) /* SCC1 @ SCCa */ +#define CICR_IRL_MASK ((uint)0x0000e000) /* Core interrrupt */ +#define CICR_HP_MASK ((uint)0x00001f00) /* Hi-pri int. */ +#define CICR_IEN ((uint)0x00000080) /* Int. enable */ +#define CICR_SPS ((uint)0x00000001) /* SCC Spread */ +#endif /* __CPM_8XX__ */ diff --git a/include/mpc8xx.h b/include/mpc8xx.h index 33a2cd8057..fc081ab756 100644 --- a/include/mpc8xx.h +++ b/include/mpc8xx.h @@ -145,20 +145,6 @@ PLPRCR_MFI_MSK | \ PLPRCR_PDF_MSK) -/* Older chips (MPC860/862 et al) defines */ -#define PLPRCR_MF_MSK 0xFFF00000 /* Multiplication factor bits */ -#define PLPRCR_MF_SHIFT 20 /* Multiplication factor shift value */ - -#define PLPRCR_SPLSS 0x00008000 /* SPLL Lock Status Sticky bit */ -#define PLPRCR_TMIST 0x00001000 /* Timers Interrupt Status */ - -#define PLPRCR_LPM_MSK 0x00000300 /* Low Power Mode mask */ -#define PLPRCR_LPM_NORMAL 0x00000000 /* normal power management mode */ -#define PLPRCR_LPM_DOZE 0x00000100 /* doze power management mode */ -#define PLPRCR_LPM_SLEEP 0x00000200 /* sleep power management mode */ -#define PLPRCR_LPM_DEEP_SLEEP 0x00000300 /* deep sleep power mgt mode */ -#define PLPRCR_LPM_DOWN 0x00000300 /* down power management mode */ - /* Common defines */ #define PLPRCR_TEXPS 0x00004000 /* TEXP Status */ #define PLPRCR_CSRC 0x00000400 /* Clock Source */ diff --git a/include/ppc_asm.tmpl b/include/ppc_asm.tmpl index ce71ee9bc9..18783340d9 100644 --- a/include/ppc_asm.tmpl +++ b/include/ppc_asm.tmpl @@ -81,6 +81,52 @@ #define r30 30 #define r31 31 +#if defined(CONFIG_8xx) + +/* Some special registers */ + +#define ICR 148 /* Interrupt Cause Register (37-44) */ +#define DER 149 +#define COUNTA 150 /* Breakpoint Counter (37-44) */ +#define COUNTB 151 /* Breakpoint Counter (37-44) */ +#define LCTRL1 156 /* Load/Store Support (37-40) */ +#define LCTRL2 157 /* Load/Store Support (37-41) */ +#define ICTRL 158 + +#endif /* CONFIG_8xx */ + + +#if defined(CONFIG_8xx) + +/* Registers in the processor's internal memory map that we use. +*/ +#define SYPCR 0x00000004 +#define BR0 0x00000100 +#define OR0 0x00000104 +#define BR1 0x00000108 +#define OR1 0x0000010c +#define BR2 0x00000110 +#define OR2 0x00000114 +#define BR3 0x00000118 +#define OR3 0x0000011c +#define BR4 0x00000120 +#define OR4 0x00000124 + +#define MAR 0x00000164 +#define MCR 0x00000168 +#define MAMR 0x00000170 +#define MBMR 0x00000174 +#define MSTAT 0x00000178 +#define MPTPR 0x0000017a +#define MDR 0x0000017c + +#define TBSCR 0x00000200 +#define TBREFF0 0x00000204 + +#define PLPRCR 0x00000284 + +#endif + #define curptr r2 #define SYNC \ diff --git a/include/watchdog.h b/include/watchdog.h index 52f4c506b0..a3a2eeaf1b 100644 --- a/include/watchdog.h +++ b/include/watchdog.h @@ -72,6 +72,11 @@ int init_func_watchdog_reset(void); * Prototypes from $(CPU)/cpu.c. */ +/* MPC 8xx */ +#if defined(CONFIG_8xx) && !defined(__ASSEMBLY__) + void reset_8xx_watchdog(volatile immap_t *immr); +#endif + #if defined(CONFIG_HW_WATCHDOG) && !defined(__ASSEMBLY__) void hw_watchdog_init(void); #endif diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt index 54eee53572..8a4d3f8fe0 100644 --- a/scripts/config_whitelist.txt +++ b/scripts/config_whitelist.txt @@ -12,6 +12,10 @@ CONFIG_83XX_GENERIC_PCIE_REGISTER_HOSES CONFIG_83XX_PCICLK CONFIG_83XX_PCI_STREAMING CONFIG_88F5182 +CONFIG_8xx_CONS_NONE +CONFIG_8xx_CONS_SMC1 +CONFIG_8xx_CONS_SMC2 +CONFIG_8xx_GCLK_FREQ CONFIG_A003399_NOR_WORKAROUND CONFIG_A008044_WORKAROUND CONFIG_ACX517AKN @@ -701,6 +705,8 @@ CONFIG_ETHER_ON_FCC CONFIG_ETHER_ON_FCC1 CONFIG_ETHER_ON_FCC2 CONFIG_ETHER_ON_FCC3 +CONFIG_ETHER_ON_FEC1 +CONFIG_ETHER_ON_FEC2 CONFIG_ETHPRIME CONFIG_ETH_BUFSIZE CONFIG_ETH_RXSIZE @@ -756,6 +762,8 @@ CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN CONFIG_FEATURE_SH_EXTRA_QUIET CONFIG_FEATURE_SH_FANCY_PROMPT CONFIG_FEATURE_SH_STANDALONE_SHELL +CONFIG_FEC1_PHY +CONFIG_FEC2_PHY CONFIG_FEC_ENET_DEV CONFIG_FEC_FIXED_SPEED CONFIG_FEC_MXC_25M_REF_CLK @@ -1525,6 +1533,10 @@ CONFIG_MPC83XX_PCI2 CONFIG_MPC85XX_FEC CONFIG_MPC85XX_FEC_NAME CONFIG_MPC85XX_PCI2 +CONFIG_MPC866 +CONFIG_MPC866_FAMILY +CONFIG_MPC885 +CONFIG_MPC885_FAMILY CONFIG_MPC8XXX_SPI CONFIG_MPC8xxx_DISABLE_BPTR CONFIG_MPLL_FREQ @@ -2503,6 +2515,7 @@ CONFIG_SYS_BR6_64M CONFIG_SYS_BR6_8M CONFIG_SYS_BR6_PRELIM CONFIG_SYS_BR7_PRELIM +CONFIG_SYS_BRGCLK_PRESCALE CONFIG_SYS_BUSCLK CONFIG_SYS_CACHELINE_SHIFT CONFIG_SYS_CACHE_ACR0 @@ -2904,6 +2917,7 @@ CONFIG_SYS_DEBUG_SERVER_FW_IN_NOR CONFIG_SYS_DEFAULT_LPDDR2_TIMINGS CONFIG_SYS_DEFAULT_VIDEO_MODE CONFIG_SYS_DEF_EEPROM_ADDR +CONFIG_SYS_DER CONFIG_SYS_DEVICE_NULLDEV CONFIG_SYS_DFU_DATA_BUF_SIZE CONFIG_SYS_DFU_MAX_FILE_SIZE @@ -4469,6 +4483,7 @@ CONFIG_SYS_PIOC_PPUDR_VAL CONFIG_SYS_PIOD_PDR_VAL1 CONFIG_SYS_PIOD_PPUDR_VAL CONFIG_SYS_PIO_MODE +CONFIG_SYS_PISCR CONFIG_SYS_PIT_BASE CONFIG_SYS_PIT_PRESCALE CONFIG_SYS_PIXIS_VBOOT_ENABLE @@ -4486,6 +4501,7 @@ CONFIG_SYS_PLL_BYPASS CONFIG_SYS_PLL_FDR CONFIG_SYS_PLL_ODR CONFIG_SYS_PLL_SETTLING_TIME +CONFIG_SYS_PLPRCR CONFIG_SYS_PLUG_BASE CONFIG_SYS_PMAN CONFIG_SYS_PMC_BASE @@ -4641,6 +4657,7 @@ CONFIG_SYS_SDIO_BASE0 CONFIG_SYS_SDIO_BASE1 CONFIG_SYS_SDIO_BASE2 CONFIG_SYS_SDIO_BASE3 +CONFIG_SYS_SDMR CONFIG_SYS_SDRAM CONFIG_SYS_SDRAM1 CONFIG_SYS_SDRAM_BASE @@ -4686,6 +4703,7 @@ CONFIG_SYS_SDRC_MR_VAL5 CONFIG_SYS_SDRC_TR_VAL CONFIG_SYS_SDRC_TR_VAL1 CONFIG_SYS_SDRC_TR_VAL2 +CONFIG_SYS_SDSR CONFIG_SYS_SD_VOLTAGE CONFIG_SYS_SEC_MON_ADDR CONFIG_SYS_SEC_MON_OFFSET @@ -4712,12 +4730,14 @@ CONFIG_SYS_SH_SDHI_NR_CHANNEL CONFIG_SYS_SICRH CONFIG_SYS_SICRL CONFIG_SYS_SIL1178_I2C +CONFIG_SYS_SIUMCR CONFIG_SYS_SJA1000_BASE CONFIG_SYS_SMC0_CYCLE0_VAL CONFIG_SYS_SMC0_MODE0_VAL CONFIG_SYS_SMC0_PULSE0_VAL CONFIG_SYS_SMC0_SETUP0_VAL CONFIG_SYS_SMC_CSR0_VAL +CONFIG_SYS_SMC_RXBUFLEN CONFIG_SYS_SMI_BASE CONFIG_SYS_SPANSION_BASE CONFIG_SYS_SPANSION_BOOT @@ -4782,9 +4802,11 @@ CONFIG_SYS_STATUS_OK CONFIG_SYS_STMICRO_BOOT CONFIG_SYS_SUPPORT_64BIT_DATA CONFIG_SYS_SXCNFG_VAL +CONFIG_SYS_SYPCR CONFIG_SYS_SYSTEMACE_BASE CONFIG_SYS_SYSTEMACE_WIDTH CONFIG_SYS_TBIPA_VALUE +CONFIG_SYS_TBSCR CONFIG_SYS_TCLK CONFIG_SYS_TEXT_ADDR CONFIG_SYS_TEXT_BASE_NOR |