diff options
Diffstat (limited to 'cpu/mpc824x')
| -rw-r--r-- | cpu/mpc824x/drivers/epic/epic1.c | 513 | ||||
| -rw-r--r-- | cpu/mpc824x/traps.c | 205 | 
2 files changed, 718 insertions, 0 deletions
| diff --git a/cpu/mpc824x/drivers/epic/epic1.c b/cpu/mpc824x/drivers/epic/epic1.c new file mode 100644 index 000000000..362e12970 --- /dev/null +++ b/cpu/mpc824x/drivers/epic/epic1.c @@ -0,0 +1,513 @@ +/************************************************** + * + * copyright @ motorola, 1999 + * + *************************************************/ +#include <mpc824x.h> +#include <common.h> +#include "epic.h" + + +#define PRINT(format, args...) printf(format , ## args) + +typedef void (*VOIDFUNCPTR)  (void);  /* ptr to function returning void */ +struct SrcVecTable SrcVecTable[MAXVEC] = /* Addr/Vector cross-reference tbl */ +    { +    { EPIC_EX_INT0_VEC_REG,  "External Direct/Serial Source 0"}, +    { EPIC_EX_INT1_VEC_REG,  "External Direct/Serial Source 1"}, +    { EPIC_EX_INT2_VEC_REG,  "External Direct/Serial Source 2"}, +    { EPIC_EX_INT3_VEC_REG,  "External Direct/Serial Source 3"}, +    { EPIC_EX_INT4_VEC_REG,  "External Direct/Serial Source 4"}, + +    { EPIC_SR_INT5_VEC_REG,  "External Serial Source 5"}, +    { EPIC_SR_INT6_VEC_REG,  "External Serial Source 6"}, +    { EPIC_SR_INT7_VEC_REG,  "External Serial Source 7"}, +    { EPIC_SR_INT8_VEC_REG,  "External Serial Source 8"}, +    { EPIC_SR_INT9_VEC_REG,  "External Serial Source 9"}, +    { EPIC_SR_INT10_VEC_REG, "External Serial Source 10"}, +    { EPIC_SR_INT11_VEC_REG, "External Serial Source 11"}, +    { EPIC_SR_INT12_VEC_REG, "External Serial Source 12"}, +    { EPIC_SR_INT13_VEC_REG, "External Serial Source 13"}, +    { EPIC_SR_INT14_VEC_REG, "External Serial Source 14"}, +    { EPIC_SR_INT15_VEC_REG, "External Serial Source 15"}, + +    { EPIC_I2C_INT_VEC_REG,  "Internal I2C Source"}, +    { EPIC_DMA0_INT_VEC_REG, "Internal DMA0 Source"}, +    { EPIC_DMA1_INT_VEC_REG, "Internal DMA1 Source"}, +    { EPIC_MSG_INT_VEC_REG,  "Internal Message Source"}, +    }; + +VOIDFUNCPTR intVecTbl[MAXVEC];    /* Interrupt vector table */ + + +/**************************************************************************** +*  epicInit - Initialize the EPIC registers +* +*  This routine resets the Global Configuration Register, thus it: +*     -  Disables all interrupts +*     -  Sets epic registers to reset values +*     -  Sets the value of the Processor Current Task Priority to the +*        highest priority (0xF). +*  epicInit then sets the EPIC operation mode to Mixed Mode (vs. Pass +*  Through or 8259 compatible mode). +* +*  If IRQType (input) is Direct IRQs: +*     - IRQType is written to the SIE bit of the EPIC Interrupt +*       Configuration register (ICR). +*     - clkRatio is ignored. +*  If IRQType is Serial IRQs: +*     - both IRQType and clkRatio will be written to the ICR register +*/ + +void epicInit +    ( +    unsigned int IRQType,      /* Direct or Serial */ +    unsigned int clkRatio      /* Clk Ratio for Serial IRQs */ +    ) +    { +    ULONG tmp; + +    tmp = sysEUMBBARRead(EPIC_GLOBAL_REG); +    tmp |= 0xa0000000;                  /* Set the Global Conf. register */ +    sysEUMBBARWrite(EPIC_GLOBAL_REG, tmp); +    sysEUMBBARWrite(EPIC_GLOBAL_REG, 0x20000000); +    tmp = sysEUMBBARRead(EPIC_INT_CONF_REG);    /* Read interrupt conf. reg */ + +    if (IRQType == EPIC_DIRECT_IRQ)             /* direct mode */ +        sysEUMBBARWrite(EPIC_INT_CONF_REG, tmp & 0xf7ffffff); +    else                                        /* Serial mode */ +        { +        tmp = (clkRatio << 28) | 0x08000000;    /* Set clock ratio */ +        sysEUMBBARWrite(EPIC_INT_CONF_REG, tmp); +        } + +    while (epicIntAck() != 0xff);       /* Clear all pending interrupts */ +} + +/**************************************************************************** + *  epicIntEnable - Enable an interrupt source + * + *  This routine clears the mask bit of an external, an internal or + *  a Timer register to enable the interrupt. + * + *  RETURNS:  None + */ +void epicIntEnable +    ( +    int intVec        /* Interrupt Vector Number */ +    ) +    { +    ULONG tmp; +    ULONG srAddr; + +    srAddr = SrcVecTable[intVec].srcAddr;  /* Retrieve src Vec/Prio register */ +    tmp = sysEUMBBARRead(srAddr); +    tmp &= 0x7fffffff;             /* Clear the mask bit */ +    sysEUMBBARWrite(srAddr, tmp); +    return; +    } + +/**************************************************************************** + *  epicIntDisable - Disable an interrupt source + * + *  This routine sets the mask bit of an external, an internal or + *  a Timer register to disable the interrupt. + * + *  RETURNS:  OK or ERROR + * + */ + +void epicIntDisable +    ( +    int intVec        /* Interrupt vector number */ +    ) +    { + +    ULONG tmp, srAddr; + +    srAddr = SrcVecTable[intVec].srcAddr; +    tmp = sysEUMBBARRead(srAddr); +    tmp |= 0x80000000;                      /* Set the mask bit */ +    sysEUMBBARWrite(srAddr, tmp); +    return; +    } + +/**************************************************************************** + * epicIntSourceConfig - Set properties of an interrupt source + * + * This function sets interrupt properites (Polarity, Sense, Interrupt + * Prority, and Interrupt Vector) of an Interrupt Source.  The properties + * can be set when the current source is not in-request or in-service, + * which is determined by the Activity bit.  This routine return ERROR + * if the the Activity bit is 1 (in-request or in-service). + * + * This function assumes that the Source Vector/Priority register (input) + * is a valid address. + * + * RETURNS:  OK or ERROR + */ + +int epicIntSourceConfig +    ( +    int   Vect,                         /* interrupt source vector number */ +    int   Polarity,                     /* interrupt source polarity */ +    int   Sense,                        /* interrupt source Sense */ +    int   Prio                          /* interrupt source priority */ +    ) + +    { +    ULONG tmp, newVal; +    ULONG actBit, srAddr; + +    srAddr = SrcVecTable[Vect].srcAddr; +    tmp = sysEUMBBARRead(srAddr); +    actBit = (tmp & 40000000) >> 30;    /* retrieve activity bit - bit 30 */ +    if (actBit == 1) +        return ERROR; + +    tmp &= 0xff30ff00;     /* Erase previously set P,S,Prio,Vector bits */ +    newVal = (Polarity << 23) | (Sense << 22) | (Prio << 16) | Vect; +    sysEUMBBARWrite(srAddr, tmp | newVal ); +    return (OK); +    } + +/**************************************************************************** + * epicIntAck - acknowledge an interrupt + * + * This function reads the Interrupt acknowldge register and return + * the vector number of the highest pending interrupt. + * + * RETURNS: Interrupt Vector number. + */ + +unsigned int epicIntAck(void) +{ +    return(sysEUMBBARRead( EPIC_PROC_INT_ACK_REG )); +} + +/**************************************************************************** + * epicEOI - signal an end of interrupt + * + * This function writes 0x0 to the EOI register to signal end of interrupt. + * It is usually called after an interrupt routine is served. + * + * RETURNS: None + */ + +void epicEOI(void) +    { +    sysEUMBBARWrite(EPIC_PROC_EOI_REG, 0x0); +    } + +/**************************************************************************** + *  epicCurTaskPrioSet - sets the priority of the Processor Current Task + * + *  This function should be called after epicInit() to lower the priority + *  of the processor current task. + * + *  RETURNS:  OK or ERROR + */ + +int epicCurTaskPrioSet +    ( +    int prioNum                 /* New priority value */ +    ) +    { + +    if ( (prioNum < 0) || (prioNum > 0xF)) +        return ERROR; +    sysEUMBBARWrite(EPIC_PROC_CTASK_PRI_REG, prioNum); +    return OK; +    } + + +/************************************************************************ + * function: epicIntTaskGet + * + * description: Get value of processor current interrupt task priority register + * + * note: + ***********************************************************************/ +unsigned char epicIntTaskGet() +{ +  /* get the interrupt task priority register */ +    ULONG reg; +    unsigned char rec; + +    reg = sysEUMBBARRead( EPIC_PROC_CTASK_PRI_REG ); +    rec = ( reg & 0x0F ); +    return rec; +} + + +/************************************************************** + * function: epicISR + * + * description: EPIC service routine called by the core exception + *              at 0x500 + * + * note: + **************************************************************/ +unsigned int epicISR(void) +{ +   return 0; +} + + +/************************************************************ + * function: epicModeGet + * + * description: query EPIC mode, return 0 if pass through mode + *                               return 1 if mixed mode + * + * note: + *************************************************************/ +unsigned int epicModeGet(void) +{ +    ULONG val; + +    val = sysEUMBBARRead( EPIC_GLOBAL_REG ); +    return (( val & 0x20000000 ) >> 29); +} + + +/********************************************* + * function: epicConfigGet + * + * description: Get the EPIC interrupt Configuration + *              return 0 if not error, otherwise return 1 + * + * note: + ********************************************/ +void epicConfigGet( unsigned int *clkRatio, unsigned int *serEnable) +{ +    ULONG val; + +    val = sysEUMBBARRead( EPIC_INT_CONF_REG ); +    *clkRatio = ( val & 0x70000000 ) >> 28; +    *serEnable = ( val & 0x8000000 ) >> 27; +} + + +/******************************************************************* + *  sysEUMBBARRead - Read a 32-bit EUMBBAR register + * + *  This routine reads the content of a register in the Embedded + *  Utilities Memory Block, and swaps to big endian before returning + *  the value. + * + *  RETURNS:  The content of the specified EUMBBAR register. + */ + +ULONG sysEUMBBARRead +    ( +    ULONG regNum +    ) +    { +    ULONG temp; + +    temp = *(ULONG *) (CFG_EUMB_ADDR + regNum); +    return ( LONGSWAP(temp)); +    } + +/******************************************************************* + *  sysEUMBBARWrite - Write a 32-bit EUMBBAR register + * + *  This routine swaps the value to little endian then writes it to + *  a register in the Embedded Utilities Memory Block address space. + * + *  RETURNS: N/A + */ + +void sysEUMBBARWrite +    ( +    ULONG regNum,               /* EUMBBAR register address */ +    ULONG regVal                /* Value to be written */ +    ) +    { + +    *(ULONG *) (CFG_EUMB_ADDR + regNum) = LONGSWAP(regVal); +    return ; +    } + + +/******************************************************** + * function: epicVendorId + * + * description: return the EPIC Vendor Identification + *              register: + * + *              siliccon version, device id, and vendor id + * + * note: + ********************************************************/ +void epicVendorId +   ( +    unsigned int *step, +    unsigned int *devId, +    unsigned int *venId +   ) +   { +    ULONG val; +    val = sysEUMBBARRead( EPIC_VENDOR_ID_REG ); +    *step  = ( val & 0x00FF0000 ) >> 16; +    *devId = ( val & 0x0000FF00 ) >> 8; +    *venId = ( val & 0x000000FF ); +    } + +/************************************************** + * function: epicFeatures + * + * description: return the number of IRQ supported, + *              number of CPU, and the version of the + *              OpenEPIC + * + * note: + *************************************************/ +void epicFeatures +    ( +    unsigned int *noIRQs, +    unsigned int *noCPUs, +    unsigned int *verId +    ) +    { +    ULONG val; + +    val = sysEUMBBARRead( EPIC_FEATURES_REG ); +    *noIRQs  = ( val & 0x07FF0000 ) >> 16; +    *noCPUs  = ( val & 0x00001F00 ) >> 8; +    *verId   = ( val & 0x000000FF ); +} + + +/********************************************************* + * function: epciTmFrequncySet + * + * description: Set the timer frequency reporting register + ********************************************************/ +void epicTmFrequencySet( unsigned int frq ) +{ +    sysEUMBBARWrite(EPIC_TM_FREQ_REG, frq); +} + +/******************************************************* + * function: epicTmFrequncyGet + * + * description: Get the current value of the Timer Frequency + * Reporting register + * + ******************************************************/ +unsigned int epicTmFrequencyGet(void) +{ +    return( sysEUMBBARRead(EPIC_TM_FREQ_REG)) ; +} + + +/**************************************************** + * function: epicTmBaseSet + * + * description: Set the #n global timer base count register + *              return 0 if no error, otherwise return 1. + * + * note: + ****************************************************/ +unsigned int epicTmBaseSet +    ( +    ULONG srcAddr,         /* Address of the Timer Base register */ +    unsigned int cnt,    /* Base count */ +    unsigned int inhibit   /* 1 - count inhibit */ +    ) +{ + +    unsigned int val = 0x80000000; +    /* First inhibit counting the timer */ +    sysEUMBBARWrite(srcAddr, val) ; + +    /* set the new value */ +    val = (cnt & 0x7fffffff) | ((inhibit & 0x1) << 31); +    sysEUMBBARWrite(srcAddr, val) ; +    return 0; +} + +/*********************************************************************** + * function: epicTmBaseGet + * + * description: Get the current value of the global timer base count register + *              return 0 if no error, otherwise return 1. + * + * note: + ***********************************************************************/ +unsigned int epicTmBaseGet( ULONG srcAddr, unsigned int *val ) +{ +    *val = sysEUMBBARRead( srcAddr ); +    *val = *val & 0x7fffffff; +    return 0; +} + +/*********************************************************** + * function: epicTmCountGet + * + * description: Get the value of a given global timer + *              current count register + *              return 0 if no error, otherwise return 1 + * note: + **********************************************************/ +unsigned int epicTmCountGet( ULONG srcAddr, unsigned int *val ) +{ +    *val = sysEUMBBARRead( srcAddr ); +    *val = *val & 0x7fffffff; +    return 0; +} + + + +/*********************************************************** + * function: epicTmInhibit + * + * description: Stop counting of a given global timer + *              return 0 if no error, otherwise return 1 + * + * note: + ***********************************************************/ +unsigned int epicTmInhibit( unsigned int srcAddr ) +{ +    ULONG val; + +    val = sysEUMBBARRead( srcAddr ); +    val |= 0x80000000; +    sysEUMBBARWrite( srcAddr, val ); +    return 0; +} + +/****************************************************************** + * function: epicTmEnable + * + * description: Enable counting of a given global timer + *              return 0 if no error, otherwise return 1 + * + * note: + *****************************************************************/ +unsigned int epicTmEnable( ULONG srcAddr ) +{ +    ULONG val; + +    val = sysEUMBBARRead( srcAddr ); +    val &= 0x7fffffff; +    sysEUMBBARWrite( srcAddr, val ); +    return 0; +} + +void epicSourcePrint(int Vect) +    { +    ULONG srcVal; + +    srcVal = sysEUMBBARRead(SrcVecTable[Vect].srcAddr); +    PRINT("%s\n", SrcVecTable[Vect].srcName); +    PRINT("Address   = 0x%lx\n", SrcVecTable[Vect].srcAddr); +    PRINT("Vector    = %ld\n", (srcVal & 0x000000FF) ); +    PRINT("Mask      = %ld\n", srcVal >> 31); +    PRINT("Activitiy = %ld\n", (srcVal & 40000000) >> 30); +    PRINT("Polarity  = %ld\n", (srcVal & 0x00800000) >> 23); +    PRINT("Sense     = %ld\n", (srcVal & 0x00400000) >> 22); +    PRINT("Priority  = %ld\n", (srcVal & 0x000F0000) >> 16); +    } diff --git a/cpu/mpc824x/traps.c b/cpu/mpc824x/traps.c new file mode 100644 index 000000000..11f51c250 --- /dev/null +++ b/cpu/mpc824x/traps.c @@ -0,0 +1,205 @@ +/* + * linux/arch/ppc/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. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * This file handles the architecture-dependent parts of hardware exceptions + */ + +#include <common.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	0x00400000 + +/* + * Trap & Exception support + */ + +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"); +		} +	} +} + + +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 & 0x0000F000) +	{ +	case (1<<12) : +		printf("Machine check signal - probably due to mm fault\n" +			"with mmu off\n"); +		break; +	case (1<<13) : +		printf("Transfer error ack signal\n"); +		break; +	case (1<<14) : +		printf("Data parity signal\n"); +		break; +	case (1<<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); +} + +/* Probe an address by reading.  If not present, return -1, otherwise + * return 0. + */ +int +addr_probe(uint *addr) +{ +#if 0 +	int	retval; + +	__asm__ __volatile__(			\ +		"1:	lwz %0,0(%1)\n"		\ +		"	eieio\n"		\ +		"	li %0,0\n"		\ +		"2:\n"				\ +		".section .fixup,\"ax\"\n"	\ +		"3:	li %0,-1\n"		\ +		"	b 2b\n"			\ +		".section __ex_table,\"a\"\n"	\ +		"	.align 2\n"		\ +		"	.long 1b,3b\n"		\ +		".text"				\ +		: "=r" (retval) : "r"(addr)); + +	return (retval); +#endif +	return 0; +} |