u-boot/arch/powerpc/cpu/mpc8xx/cpu.c

332 lines
7.5 KiB
C
Raw Normal View History

powerpc: Partialy restore core of mpc8xx CS Systemes d'Information (CSSI) manufactures 8xx boards for critical communication systems. Those boards have been running U-Boot since 2010 and will have to be maintained until at least 2027. commit 5b8e76c35ec312a3f73126bd1a2d2c0965b98a9f ("powerpc, 8xx: remove support for 8xx") orphaned those boards by removing support for the mpc8xx CPU. This commit partially restores support for the 8xx, with the following limitations: - Restores support for MPC866 and MPC885 only - Does not restore IDE, PCMCIA, I2C, USB - Does not restore examples - Does not restore POST - Does not restore Ethernet on SCC - Does not restore console on SCC - Does not restore bedbug and kgdb support As the 866 and 885 do not support the following features, they are not restored either: - VIDEO / LCD - RTC clock The CPM uCODE patch is not restored either, because: - 866 and 885 already have support for I2C and SPI relocation without a uCODE patch - relocation of SMC, I2C or SPI is only needed for using SCCs for Ethernet or QMC The dynamic setup/calculation of clocks is removed, we expect the target being use with the clock and PLPRCR register defined in the configuration. All the clock settings for 8xx prior to 866 is removed as well as we now only support 866 and 885. This code is mature and addresses mature boards. Therefore all code enclosed in '#if 0/#endif' and '#if XX_DEBUG/#endif' is unneeded. The following files are not restored by this patch: - arch/powerpc/cpu/mpc8xx/bedbug_860.c - arch/powerpc/cpu/mpc8xx/fec.h - arch/powerpc/cpu/mpc8xx/kgdb.S - arch/powerpc/cpu/mpc8xx/plprcr_write.S - arch/powerpc/cpu/mpc8xx/scc.c - arch/powerpc/cpu/mpc8xx/upatch.c - arch/powerpc/cpu/mpc8xx/video.c - arch/powerpc/include/asm/status_led.h - arch/powerpc/lib/ide.c - arch/powerpc/lib/ide.h - doc/README.MPC866 - drivers/pcmcia/mpc8xx_pcmcia.c - drivers/rtc/mpc8xx.c - drivers/usb/gadget/mpc8xx_udc.c - drivers/video/mpc8xx_lcd.c - examples/standalone/test_burst.c - examples/standalone/test_burst.h - examples/standalone/test_burst_lib.S - examples/standalone/timer.c - include/mpc823_lcd.h - include/usb/mpc8xx_udc.h - post/cpu/mpc8xx/Makefile - post/cpu/mpc8xx/cache.c - post/cpu/mpc8xx/cache_8xx.S - post/cpu/mpc8xx/ether.c - post/cpu/mpc8xx/spr.c - post/cpu/mpc8xx/uart.c - post/cpu/mpc8xx/usb.c - post/cpu/mpc8xx/watchdog.c Some of the restored files are not located in a proper location. In order to keep traceability of the changes, they will be moved to their correct location and moved to Kconfig in a followup patch. This patch also declares CSSI as point of contact for the update of the 8xx platform, as those boards are the only ones still being maintained on the 8xx area. A later patch will add those boards to the tree. Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
2017-07-06 08:23:22 +00:00
/*
* (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;
}