diff options
27 files changed, 4866 insertions, 0 deletions
| diff --git a/board/mousse/u-boot.lds.ram b/board/mousse/u-boot.lds.ram new file mode 100644 index 000000000..9166c9cd7 --- /dev/null +++ b/board/mousse/u-boot.lds.ram @@ -0,0 +1,101 @@ +/* + * (C) Copyright 2000 + * Rob Taylor, Flying Pig Systems Ltd. robt@flyingpig.com + * + * 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 + */ + +OUTPUT_ARCH(powerpc) +SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib); + +MEMORY { + 	ram  (!rx) : org = 0x00000000 , LENGTH = 8M + 	code (!rx) : org = 0x00002000 , LENGTH = (4M - 0x2000) + 	rom   (rx) : org = 0xfff00000 , LENGTH = 512K +} + +SECTIONS +{ +  _f_init = .; +  PROVIDE(_f_init = .); +  _f_init_rom = .; +  PROVIDE(_f_init_rom = .); + +  .init : { +      cpu/mpc824x/start.o	(.text) +      *(.init) +  } > ram +  _init_size = SIZEOF(.init); +  PROVIDE(_init_size = SIZEOF(.init)); + +  ENTRY(_start) + +/*  _ftext = .; +  _ftext_rom = .; +  _text_size = SIZEOF(.text); + */ +  .text : { +      *(.text) +      *(.got1) +      } > ram +  .rodata : { *(.rodata) } > ram +  .dtors : { *(.dtors) } > ram +  .data : { *(.data) } > ram +  .sdata : { *(.sdata) } > ram +  .sdata2 : { *(.sdata2) +      *(.got) +    _GOT2_TABLE_ = .; +    *(.got2) +    _FIXUP_TABLE_ = .; +    *(.fixup) +    } > ram +  __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >>2; +  __fixup_entries = (. - _FIXUP_TABLE_)>>2; + +  .sbss : { *(.sbss) } > ram +  .sbss2 : { *(.sbss2) } > ram +  .bss : { *(.bss) } > ram +  .debug : { *(.debug) } > ram +  .line : { *(.line) } > ram +  .symtab : { *(.symtab) } > ram +  .shrstrtab : { *(.shstrtab) } > ram +  .strtab : { *(.strtab) } > ram + /* .reloc   : +  { +    *(.got) +    _GOT2_TABLE_ = .; +    *(.got2) +    _FIXUP_TABLE_ = .; +    *(.fixup) +  } > ram +  */ +   __start___ex_table = .; +    __ex_table : { *(__ex_table) } > ram +    __stop___ex_table = .; + + +  .ppcenv	: +  { +    common/environment.o (.ppcenv) +  } > ram + +  _end = . ; +  PROVIDE (end = .); +} + diff --git a/board/sandpoint/early_init.S b/board/sandpoint/early_init.S new file mode 100644 index 000000000..127bd37fa --- /dev/null +++ b/board/sandpoint/early_init.S @@ -0,0 +1,154 @@ +/* + * (C) Copyright 2001 + * Thomas Koeller, tkoeller@gmx.net + * + * 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 + */ + +#ifndef	__ASSEMBLY__ +#define __ASSEMBLY__	1 +#endif + +#include <config.h> +#include <asm/processor.h> +#include <mpc824x.h> +#include <ppc_asm.tmpl> + +#if defined(USE_DINK32) +  /* We are running from RAM, so do not clear the MCCR1_MEMGO bit! */ +  #define MCCR1VAL ((CFG_ROMNAL << MCCR1_ROMNAL_SHIFT) | (CFG_ROMFAL << MCCR1_ROMFAL_SHIFT) | MCCR1_MEMGO) +#else +  #define MCCR1VAL (CFG_ROMNAL << MCCR1_ROMNAL_SHIFT) | (CFG_ROMFAL << MCCR1_ROMFAL_SHIFT) +#endif + +	.text + +	/* Values to program into memory controller registers */ +tbl:	.long	MCCR1, MCCR1VAL +	.long	MCCR2, CFG_REFINT << MCCR2_REFINT_SHIFT +	.long	MCCR3 +	.long	(((CFG_BSTOPRE & 0x000000f0) >> 4) << MCCR3_BSTOPRE2TO5_SHIFT) | \ +		(CFG_REFREC << MCCR3_REFREC_SHIFT) | \ +		(CFG_RDLAT  << MCCR3_RDLAT_SHIFT) +	.long	MCCR4 +        .long	(CFG_PRETOACT << MCCR4_PRETOACT_SHIFT) | (CFG_ACTTOPRE << MCCR4_ACTTOPRE_SHIFT) | \ +		(CFG_REGISTERD_TYPE_BUFFER << 20) | \ +        	(((CFG_BSTOPRE & 0x00000300) >> 8) << MCCR4_BSTOPRE0TO1_SHIFT ) | \ +        	((CFG_SDMODE_CAS_LAT << 4) | (CFG_SDMODE_WRAP << 3) | \ +		(CFG_SDMODE_BURSTLEN) << MCCR4_SDMODE_SHIFT) | \ +		(CFG_ACTTORW << MCCR4_ACTTORW_SHIFT) | \ +        	((CFG_BSTOPRE & 0x0000000f) << MCCR4_BSTOPRE6TO9_SHIFT ) +	.long	MSAR1 +        .long	(((CFG_BANK0_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) <<  0) | \ +		(((CFG_BANK1_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) <<  8) | \ +		(((CFG_BANK2_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 16) | \ +		(((CFG_BANK3_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 24) +	.long	EMSAR1 +	.long	(((CFG_BANK0_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) <<  0) | \ +		(((CFG_BANK1_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) <<  8) | \ +		(((CFG_BANK2_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 16) | \ +		(((CFG_BANK3_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 24) +	.long	MSAR2 +        .long	(((CFG_BANK4_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) <<  0) | \ +		(((CFG_BANK5_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) <<  8) | \ +		(((CFG_BANK6_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 16) | \ +		(((CFG_BANK7_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 24) +	.long	EMSAR2 +	.long	(((CFG_BANK4_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) <<  0) | \ +		(((CFG_BANK5_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) <<  8) | \ +		(((CFG_BANK6_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 16) | \ +		(((CFG_BANK7_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 24) +	.long	MEAR1 +        .long	(((CFG_BANK0_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) <<  0) | \ +		(((CFG_BANK1_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) <<  8) | \ +		(((CFG_BANK2_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 16) | \ +		(((CFG_BANK3_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 24) +	.long	EMEAR1 +	.long	(((CFG_BANK0_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) <<  0) | \ +		(((CFG_BANK1_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) <<  8) | \ +		(((CFG_BANK2_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 16) | \ +		(((CFG_BANK3_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 24) +	.long	MEAR2 +        .long	(((CFG_BANK4_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) <<  0) | \ +		(((CFG_BANK5_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) <<  8) | \ +		(((CFG_BANK6_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 16) | \ +		(((CFG_BANK7_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 24) +	.long	EMEAR2 +	.long	(((CFG_BANK4_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) <<  0) | \ +		(((CFG_BANK5_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) <<  8) | \ +		(((CFG_BANK6_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 16) | \ +		(((CFG_BANK7_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 24) +	.long	0 + + + +	/* +	 * Early CPU initialization. Set up memory controller, so we can access any RAM at all. This +	 * must be done in assembly, since we have no stack at this point. +	 */ +	.global	early_init_f +early_init_f: +	mflr	r10 + +	/* basic memory controller configuration */ +	lis	r3, CONFIG_ADDR_HIGH +	lis	r4, CONFIG_DATA_HIGH +	bl	lab +lab:	mflr	r5 +	lwzu	r0, tbl - lab(r5) +loop:	lwz	r1, 4(r5) +	stwbrx	r0, 0, r3 +	eieio +	stwbrx	r1, 0, r4 +	eieio +	lwzu	r0, 8(r5) +	cmpli	cr0, 0, r0, 0 +	bne	cr0, loop + +	/* set bank enable bits */ +	lis	r0, MBER@h +	ori	r0, 0, MBER@l +	li	r1, CFG_BANK_ENABLE +	stwbrx	r0, 0, r3 +	eieio +	stb	r1, 0(r4) +	eieio + +	/* delay loop */ +	lis	r0, 0x0003 +	mtctr   r0 +delay:	bdnz	delay + +	/* enable memory controller */ +	lis	r0, MCCR1@h +	ori	r0, 0, MCCR1@l +	stwbrx	r0, 0, r3 +	eieio +	lwbrx	r0, 0, r4 +	oris	r0, 0, MCCR1_MEMGO@h +	stwbrx	r0, 0, r4 +	eieio + +	/* set up stack pointer */ +	lis	r1, CFG_INIT_SP_OFFSET@h +	ori	r1, r1, CFG_INIT_SP_OFFSET@l + +	mtlr	r10 +	blr + diff --git a/board/sandpoint/u-boot.lds.mw.debug b/board/sandpoint/u-boot.lds.mw.debug new file mode 100644 index 000000000..a0378cb4a --- /dev/null +++ b/board/sandpoint/u-boot.lds.mw.debug @@ -0,0 +1,101 @@ +/* + * (C) Copyright 2000 + * Rob Taylor, Flying Pig Systems Ltd. robt@flyingpig.com + * + * 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 + */ + +OUTPUT_ARCH(powerpc) +SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib); + +MEMORY { + 	ram  (!rx) : org = 0x00000000 , LENGTH = 8M + 	code (!rx) : org = 0x00002000 , LENGTH = (4M - 0x2000) + 	rom   (rx) : org = 0xfe000000 , LENGTH = (0x100000000 - 0xfe000000) +} + +SECTIONS +{ +  _f_init = .; +  PROVIDE(_f_init = .); +  _f_init_rom = .; +  PROVIDE(_f_init_rom = .); + +  .init : { +      cpu/mpc824x/start.o	(.text) +      *(.init) +  } > ram +  _init_size = SIZEOF(.init); +  PROVIDE(_init_size = SIZEOF(.init)); + +  ENTRY(_start) + +/*  _ftext = .; +  _ftext_rom = .; +  _text_size = SIZEOF(.text); + */ +  .text : { +      *(.text) +      *(.got1) +      } > ram +  .rodata : { *(.rodata) } > ram +  .dtors : { *(.dtors) } > ram +  .data : { *(.data) } > ram +  .sdata : { *(.sdata) } > ram +  .sdata2 : { *(.sdata2) +      *(.got) +    _GOT2_TABLE_ = .; +    *(.got2) +    _FIXUP_TABLE_ = .; +    *(.fixup) +    } > ram +  __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >>2; +  __fixup_entries = (. - _FIXUP_TABLE_)>>2; + +  .sbss : { *(.sbss) } > ram +  .sbss2 : { *(.sbss2) } > ram +  .bss : { *(.bss) } > ram +  .debug : { *(.debug) } > ram +  .line : { *(.line) } > ram +  .symtab : { *(.symtab) } > ram +  .shrstrtab : { *(.shstrtab) } > ram +  .strtab : { *(.strtab) } > ram + /* .reloc   : +  { +    *(.got) +    _GOT2_TABLE_ = .; +    *(.got2) +    _FIXUP_TABLE_ = .; +    *(.fixup) +  } > ram +  */ +   __start___ex_table = .; +    __ex_table : { *(__ex_table) } > ram +    __stop___ex_table = .; + + +  .ppcenv	: +  { +    common/environment.o (.ppcenv) +  } > ram + +  _end = . ; +  PROVIDE (end = .); +} + diff --git a/cpu/mpc824x/drivers/dma/Makefile b/cpu/mpc824x/drivers/dma/Makefile new file mode 100644 index 000000000..59e2fac86 --- /dev/null +++ b/cpu/mpc824x/drivers/dma/Makefile @@ -0,0 +1,83 @@ +########################################################################## +# +#       Copyright Motorola, Inc. 1997 +#       ALL RIGHTS RESERVED +# +#       You are hereby granted a copyright license to use, modify, and +#       distribute the SOFTWARE so long as this entire notice is retained +#       without alteration in any modified and/or redistributed versions, +#       and that such modified versions are clearly identified as such. +#       No licenses are granted by implication, estoppel or otherwise under +#       any patents or trademarks of Motorola, Inc. +# +#       The SOFTWARE is provided on an "AS IS" basis and without warranty. +#       To the maximum extent permitted by applicable law, MOTOROLA DISCLAIMS +#       ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, INCLUDING IMPLIED +#       WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR +#       PURPOSE AND ANY WARRANTY AGAINST INFRINGEMENT WITH +#       REGARD TO THE SOFTWARE (INCLUDING ANY MODIFIED VERSIONS +#       THEREOF) AND ANY ACCOMPANYING WRITTEN MATERIALS. +# +#       To the maximum extent permitted by applicable law, IN NO EVENT SHALL +#       MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER +#       (INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF +#       BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS +#       INFORMATION, OR OTHER PECUNIARY LOSS) ARISING OF THE USE OR +#       INABILITY TO USE THE SOFTWARE. +# +############################################################################ +TARGET = libdma.a + +DEBUG   = -DDMADBG +LST     = -Hanno -S +OPTIM   = +CC      = /risc/tools/pkgs/metaware/bin/hcppc +CFLAGS  = -Hnocopyr -c -Hsds -Hon=Char_default_unsigned -Hon=Char_is_rep -I../inc -I/risc/tools/pkgs/metaware/inc +CCobj   = $(CC) $(CFLAGS) $(DEBUG) $(OPTIM) +PREP    = $(CC) $(CFLAGS) -P + +# Assembler used to build the .s files (for the board version) + +ASOPT   = -big_si -c +ASDEBUG = -l -fm +AS      = /risc/tools/pkgs/metaware/bin/asppc + +# Linker to bring .o files together into an executable. + +LKOPT	=  -Bbase=0 -q -r -Qn +LKCMD   = +LINK    =  /risc/tools/pkgs/metaware/bin/ldppc $(LKCMD) $(LKOPT) + +# DOS Utilities + +DEL     = rm +COPY    = cp +LIST    = ls + +OBJECTS = dma1.o dma2.o + +all: $(TARGET) + +$(TARGET): $(OBJECTS) +	$(LINK) $(OBJECTS) -o $@ + +objects: dma1.o + +clean: +	$(DEL) -f *.o *.i *.map *.lst $(TARGET) $(OBJECTS) + +.s.o: +	$(DEL) -f $*.i +	$(PREP) -Hasmcpp $< +	$(AS) $(ASOPT) $*.i +#	$(AS) $(ASOPT) $(ASDEBUG) $*.i > $*.lst + +.c.o: +	$(CCobj) $< + +.c.s: +	$(CCobj) $(LST) $< + +dma1.o: dma_export.h dma.h dma1.c + +dma2.o: dma.h dma2.s diff --git a/cpu/mpc824x/drivers/dma/Makefile_pc b/cpu/mpc824x/drivers/dma/Makefile_pc new file mode 100644 index 000000000..8df2a3cb7 --- /dev/null +++ b/cpu/mpc824x/drivers/dma/Makefile_pc @@ -0,0 +1,89 @@ +########################################################################## +# +#   makefile_pc  for use with mksnt tools   drivers/dma +# +#       Copyright Motorola, Inc. 1997 +#       ALL RIGHTS RESERVED +# +#       You are hereby granted a copyright license to use, modify, and +#       distribute the SOFTWARE so long as this entire notice is retained +#       without alteration in any modified and/or redistributed versions, +#       and that such modified versions are clearly identified as such. +#       No licenses are granted by implication, estoppel or otherwise under +#       any patents or trademarks of Motorola, Inc. +# +#       The SOFTWARE is provided on an "AS IS" basis and without warranty. +#       To the maximum extent permitted by applicable law, MOTOROLA DISCLAIMS +#       ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, INCLUDING IMPLIED +#       WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR +#       PURPOSE AND ANY WARRANTY AGAINST INFRINGEMENT WITH +#       REGARD TO THE SOFTWARE (INCLUDING ANY MODIFIED VERSIONS +#       THEREOF) AND ANY ACCOMPANYING WRITTEN MATERIALS. +# +#       To the maximum extent permitted by applicable law, IN NO EVENT SHALL +#       MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER +#       (INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF +#       BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS +#       INFORMATION, OR OTHER PECUNIARY LOSS) ARISING OF THE USE OR +#       INABILITY TO USE THE SOFTWARE. +# +############################################################################ +TARGET = libdma.a + +DEBUG   = -DDMADBG +LST     = -Hanno -S +OPTIM   = +CC      = m:/old_tools/tools/hcppc/bin/hcppc +CFLAGS  = -Hnocopyr -c -Hsds -Hon=Char_default_unsigned -Hon=Char_is_rep -I../inc -I/risc/tools/pkgs/metaware/inc +CCobj   = $(CC) $(CFLAGS) $(DEBUG) $(OPTIM) +PREP    = $(CC) $(CFLAGS) -P + +# Assembler used to build the .s files (for the board version) + +ASOPT   = -big_si -c +ASDEBUG = -l -fm +AS      = m:/old_tools/tools/hcppc/bin/asppc + +# Linker to bring .o files together into an executable. + +LKOPT	=  -Bbase=0 -q -r -Qn +LKCMD   = +LINK    = m:/old_tools/tools/hcppc/bin/ldppc $(LKCMD) $(LKOPT) + +# DOS Utilities + +DEL     = rm +COPY    = cp +LIST    = ls + +OBJECTS = dma1.o dma2.o + +all: $(TARGET) + +$(TARGET): $(OBJECTS) +	$(LINK) $(OBJECTS) -o $@ + +objects: dma1.o + +clean: +	$(DEL) -f *.o *.i *.map *.lst $(TARGET) $(OBJECTS) + +.s.o: +	$(DEL) -f $*.i +	$(PREP) -Hasmcpp $< +	$(AS) $(ASOPT) $*.i +#	$(AS) $(ASOPT) $(ASDEBUG) $*.i > $*.lst + +.c.o: +	$(CCobj) $< + +.c.s: +	$(CCobj) $(LST) $< + +dma1.o: dma_export.h dma.h dma1.c +	$(CCobj) $< + +dma2.o: dma.h dma2.s +	$(DEL) -f $*.i +	$(PREP) -Hasmcpp $< +	$(AS) $(ASOPT) $*.i diff --git a/cpu/mpc824x/drivers/dma/README b/cpu/mpc824x/drivers/dma/README new file mode 100644 index 000000000..ab4b68bd1 --- /dev/null +++ b/cpu/mpc824x/drivers/dma/README @@ -0,0 +1,102 @@ +CONTENT: + +   dma.h +   dma1.c +   dma2.s + +WHAT ARE THESE FILES: + +These files contain MPC8240 (Kahlua) DMA controller +driver routines. The driver routines are not +written for any specific operating system. +They serves the purpose of code sample, and +jump-start for using the MPC8240 DMA controller. + +For the reason of correctness of C language +syntax, these files are compiled by Metaware +C compiler and assembler. + +ENDIAN NOTATION: + +The algorithm is designed for big-endian mode, +software is responsible for byte swapping. + +USAGE: + +1. The host system that is running on MPC8240 +   or using MPC8240 as I/O device shall link +   the files listed here. The memory location +   of driver routines shall take into account of +   that driver routines need to run in supervisor +   mode and they process DMA controller interrupt. + +2. The host system is responsible for configuring +   the MPC8240 including Embedded Utilities Memory +   Block. Since the DMA controller on MPC8240 can +   be accessed by either local 603e core or the host +   that MPC8240 serves as I/O processor through host +   PCI configuration, it is important that the local +   processor uses EUMBBAR to access its local DMA +   controller while the PCI master uses I/O +   processor's PCSRBAR to access the DMA controller +   on I/O device. + +   To qualify whether is EUMBBAR or PCSRBAR, one +   additional parameter is requied from the host +   system, LOCAL or REMOTE so that the base value +   can be correctly interpreted. + +3. If the host system is also using the EPIC unit +   on MPC8240, the system can register the +   DMA_ISR with the EPIC including other +   desired resources. + +   If the host system does not using the EPIC unit +   on MPC8240, DMA_ISR function can be called for +   each desired time interval. + +   In both cases, the host system is free to +   provide its own interrupt service routine. + +4. To start a direct mode DMA transaction, +   use DMA_Bld_Curr with the start parameter +   set to 1. + +   To start a chaining mode DMA transaction, +   the application shall build descriptors +   in memory first, next, use DMA_Bld_Desp +   with the start parameter set to 1. + +5. DMA_Start function clears, then sets the CS +   bit of DMA mode register. + +   DMA_Halt function clears the CS bit of DMA +   mode register. + +   These functions can be used to start and +   halt the DMA transaction. + +   If the chaining descriptors has been +   modified since the last time a DMA +   transaction started, use DMA_Chn_Cnt +   function to let DMA controller process +   the modified descriptor chain without +   stopping or disturbing the current DMA +   transaction. + +   It is the host system's responsibility of +   setting up the correct DMA transfer mode +   and pass the correct memory address parameters. + +6. It is the host system's responsibility of +   queueing the DMA I/O request. The host +   system can call the DMA_ISR with its own +   desired interrupt service subroutines to +   handle each individual interrupt and queued +   DMA I/O requests. + +7. The DMA driver routines contains a set +   of utilities, Set and Get, for host system +   to query and modify the desired DMA registers. + + diff --git a/cpu/mpc824x/drivers/dma/dma.h b/cpu/mpc824x/drivers/dma/dma.h new file mode 100644 index 000000000..a21be74ad --- /dev/null +++ b/cpu/mpc824x/drivers/dma/dma.h @@ -0,0 +1,326 @@ +#ifndef DMA_H +#define DMA_H +/******************************************************* + * + * copyright @ Motorola 1999 + * + *******************************************************/ +#define NUM_DMA_REG   7 +#define DMA_MR_REG    0 +#define DMA_SR_REG    1 +#define DMA_CDAR_REG  2 +#define DMA_SAR_REG   3 +#define DMA_DAR_REG   4 +#define DMA_BCR_REG   5 +#define DMA_NDAR_REG  6 + +typedef enum _dmastatus +{ +	DMASUCCESS = 0x1000, +	DMALMERROR, +	DMAPERROR, +	DMACHNBUSY, +	DMAEOSINT, +	DMAEOCAINT, +	DMAINVALID, +	DMANOEVENT, +} DMAStatus; + +typedef enum _location +{ +	LOCAL = 0,     /* local processor accesses on board DMA, +			          local processor's eumbbar is required */ +	REMOTE = 1,    /* PCI master accesses DMA on I/O board, +			          I/O processor's pcsrbar is required */ +} LOCATION; + +typedef enum dma_mr_bit +{ +	IRQS    = 0x00080000, +    PDE     = 0x00040000, +	DAHTS   = 0x00030000, +	SAHTS   = 0x0000c000, +	DAHE    = 0x00002000, +	SAHE    = 0x00001000, +	PRC     = 0x00000c00, +	EIE     = 0x00000080, +	EOTIE   = 0x00000040, +	DL      = 0x00000008, +	CTM     = 0x00000004, +	CC      = 0x00000002, +	CS      = 0x00000001, +} DMA_MR_BIT; + +typedef enum dma_sr_bit +{ +	LME     = 0x00000080, +	PE      = 0x00000010, +	CB      = 0x00000004, +	EOSI    = 0x00000002, +	EOCAI   = 0x00000001, +} DMA_SR_BIT; + +/* structure for DMA Mode Register */ +typedef struct _dma_mr +{ +	unsigned int  reserved0 : 12; +	unsigned int  irqs      : 1; +	unsigned int  pde       : 1; +	unsigned int  dahts     : 2; +    unsigned int  sahts     : 2; +	unsigned int  dahe      : 1; +	unsigned int  sahe      : 1; +	unsigned int  prc       : 2; +	unsigned int  reserved1 : 1; +	unsigned int  eie       : 1; +	unsigned int  eotie     : 1; +	unsigned int  reserved2 : 3; +	unsigned int  dl        : 1; +	unsigned int  ctm       : 1; +	/* if chaining mode is enabled, any time, user can modify the +	 * descriptor and does not need to halt the current DMA transaction. +	 * Set CC bit, enable DMA to process the modified descriptors +	 * Hardware will clear this bit each time, DMA starts. +	 */ +	unsigned int  cc        : 1; +	/* cs bit has dua role, halt the current DMA transaction and +	 * (re)start DMA transaction. In chaining mode, if the descriptor +	 * needs modification, cs bit shall be used not the cc bit. +	 * Hardware will not set/clear this bit each time DMA transaction +	 * stops or starts. Software shall do it. +	 * +	 * cs bit shall not be used to halt chaining DMA transaction for +	 * modifying the descriptor. That is the role of CC bit. +	 */ +	unsigned int  cs        : 1; +} DMA_MR; + +/* structure for DMA Status register */ +typedef struct _dma_sr +{ +	unsigned int  reserved0 : 24; +	unsigned int  lme       : 1; +	unsigned int  reserved1 : 2; +	unsigned int  pe        : 1; +	unsigned int  reserved2 : 1; +	unsigned int  cb        : 1; +	unsigned int  eosi      : 1; +	unsigned int  eocai     : 1; +} DMA_SR; + +/* structure for DMA current descriptor address register */ +typedef struct _dma_cdar +{ +	unsigned int  cda    : 27; +	unsigned int snen    : 1; +	unsigned int eosie   : 1; +	unsigned int ctt     : 2; +	unsigned int eotd    : 1; +} DMA_CDAR; + +/* structure for DMA byte count register */ +typedef struct _dma_bcr +{ +	unsigned int reserved : 6; +	unsigned int  bcr      : 26; +} DMA_BCR; + +/* structure for DMA Next Descriptor Address register */ +typedef struct _dma_ndar +{ +	unsigned int nda    : 27; +	unsigned int ndsnen : 1; +	unsigned int ndeosie: 1; +	unsigned int ndctt  : 2; +	unsigned int eotd   : 1; +} DMA_NDAR; + +/* structure for DMA current transaction info */ +typedef struct _dma_curr +{ +	unsigned int src_addr; +	unsigned int dest_addr; +	unsigned int byte_cnt; +} DMA_CURR; + +/************************* Kernel API******************** + * Kernel APIs are used to interface with O.S. kernel. + * They are the functions required by O.S. kernel to + * provide I/O service. + ********************************************************/ + +/**************DMA Device Control Functions ********/ + +/** + * Note: + * + * In all following functions, the host (KAHLUA) processor has a + * choice of accessing on board local DMA (LOCAL), + * or DMA on a distributed KAHLUA (REMOTE). In either case, + * the caller shall pass the configured embedded utility memory + * block base address relative to the DMA. If LOCAL DMA is used, + * this parameter shall be EUMBBAR, if REMOTE is used, the + * parameter shall be the corresponding PCSRBAR. + **/ + +/************************************************************** + * function: DMA_Get_Stat + * + * description: return the content of status register of + *              the given DMA channel + *              if error, return DMAINVALID. Otherwise return + *              DMASUCCESS. + * + **************************************************************/ +static DMAStatus DMA_Get_Stat( LOCATION, unsigned int eumbbar, unsigned int channel, DMA_SR * ); + +/************************************************************** + * function: DMA_Get_Mode + * + * description: return the content of mode register of the + *              given DMA channel + *              if error, return DMAINVALID. Otherwise return DMASUCCESS. + * + **************************************************************/ +static DMAStatus DMA_Get_Mode( LOCATION, unsigned int eumbbar, unsigned int channel, DMA_MR * ); + +/************************************************************** + * function: DMA_Set_Mode + * + * description: Set a new mode to a given DMA channel + *              return DMASUCCESS if success, otherwise return DMACHNINVALID + * + * note: It is not a good idea of changing the DMA mode during + *       the middle of a transaction. + **************************************************************/ +static DMAStatus DMA_Set_Mode( LOCATION, unsigned int eumbbar, unsigned int channel, DMA_MR mode ); + +/************************************************************* + * function: DMA_ISR + * + * description: DMA interrupt service routine + *              return DMAStatus based on the status + * + *************************************************************/ +static DMAStatus    DMA_ISR( unsigned int eumbbar, +							 unsigned int channel, +						     DMAStatus (*lme_func)( unsigned int, unsigned int, DMAStatus ), +					         DMAStatus (*pe_func) ( unsigned int, unsigned int, DMAStatus ), +					         DMAStatus (*eosi_func)( unsigned int, unsigned int, DMAStatus ), +					         DMAStatus (*eocai_func)(unsigned int, unsigned int, DMAStatus )); + +static DMAStatus dma_error_func( unsigned int, unsigned int, DMAStatus ); + +/********************* DMA I/O function ********************/ + +/************************************************************ + * function: DMA_Start + * + * description: start a given DMA channel transaction + *              return DMASUCCESS if success, otherwise return DMACHNINVALID + * + * note: this function will clear DMA_MR(CC) first, then + *       set DMA_MR(CC). + ***********************************************************/ +static DMAStatus DMA_Start( LOCATION, unsigned int eumbbar,unsigned int channel ); + +/*********************************************************** + * function: DMA_Halt + * + * description: halt the current dma transaction on the specified + *              channel. + *              return DMASUCCESS if success, otherwise return DMACHNINVALID + * + * note: if the specified DMA channel is idle, nothing happens + *************************************************************/ +static DMAStatus DMA_Halt( LOCATION, unsigned int eumbbar,unsigned int channel ); + +/************************************************************* + * function: DMA_Chn_Cnt + * + * description: set the DMA_MR(CC) bit for a given channel + *              that is in chaining mode. + *              return DMASUCCESS if successfule, otherwise return DMACHNINVALID + * + * note: if the given channel is not in chaining mode, nothing + *       happen. + * + *************************************************************/ +static DMAStatus DMA_Chn_Cnt( LOCATION, unsigned int eumbbar,unsigned int channel ); + +/*********************** App. API *************************** + * App. API are the APIs Kernel provides for the application + * level program + ************************************************************/ +/************************************************************** + * function: DMA_Bld_Curr + * + * description: set current src, dest, byte count registers + *              according to the desp for a given channel + * + *              if the given channel is busy,  no change made, + *              return DMACHNBUSY. + * + *              otherwise return DMASUCCESS. + * + * note: + **************************************************************/ +static DMAStatus DMA_Bld_Curr( LOCATION, +								  unsigned int eumbbar, +								  unsigned int channel, +							      DMA_CURR     desp ); + +/************************************************************** + * function: DMA_Poke_Curr + * + * description: poke the current src, dest, byte count registers + *              for a given channel. + * + *              return DMASUCCESS if no error otherwise return DMACHNERROR + * + * note:        Due to the undeterministic parallelism, in chaining + *              mode, the value returned by this function shall + *              be taken as reference when the query is made rather + *              than the absolute snapshot when the value is returned. + **************************************************************/ +static DMAStatus DMA_Poke_Curr( LOCATION, +							   unsigned int eumbbar, +							   unsigned int channel, +						       DMA_CURR*    desp ); + +/************************************************************** + * function: DMA_Bld_Desp + * + * description: set current descriptor address register + *              according to the desp for a given channel + * + *              if the given channel is busy return DMACHNBUSY + *              and no change made, otherwise return DMASUCCESS. + * + * note: + **************************************************************/ +static DMAStatus DMA_Bld_Desp( LOCATION host, +					          unsigned int eumbbar, +					          unsigned int channel, +					          DMA_CDAR     desp ); + +/************************************************************** + * function: DMA_Poke_Desp + * + * description: poke the current descriptor address register + *              for a given channel + * + *              return DMASUCCESS if no error otherwise return + *              DMAINVALID + * + * note: Due to the undeterministic parallellism of DMA operation, + *       the value returned by this function shall be taken as + *       the most recently used descriptor when the last time + *       DMA starts a chaining mode operation. + **************************************************************/ +static DMAStatus DMA_Poke_Desp( LOCATION, +							   unsigned int eumbbar, +							   unsigned int channel, +						       DMA_CDAR     *desp ); + +#endif diff --git a/cpu/mpc824x/drivers/dma/dma1.c b/cpu/mpc824x/drivers/dma/dma1.c new file mode 100644 index 000000000..8c3834e4b --- /dev/null +++ b/cpu/mpc824x/drivers/dma/dma1.c @@ -0,0 +1,801 @@ +/************************************************************ + * + * copyright @ Motorola, 1999 + * + * App. API + * + * App. API are the APIs Kernel provides for the application + * level program + * + ************************************************************/ +#include "dma_export.h" +#include "dma.h" + +/* Define a macro to use an optional application-layer print function, if + * one was passed to the library during initialization.  If there was no + * function pointer passed, this protects against referencing a NULL pointer. + * Also define The global variable that holds the passed pointer. + */ +#define PRINT if ( app_print ) app_print +static int (*app_print)(char *,...); + +/* Set by call to get_eumbbar during DMA_Initialize. + * This could be globally available to the library, but there is + * an advantage to passing it as a parameter: it is already in a register + * and doesn't have to be loaded from memory.  Also, that is the way the + * library was already implemented and I don't want to change it without + * a more detailed analysis. + * It is being set as a global variable during initialization to hide it from + * the DINK application layer, because it is Kahlua-specific.  I think that + * get_eumbbar, load_runtime_reg, and store_runtime_reg should be defined in + * a Kahlua-specific library dealing with the embedded utilities memory block. + * Right now, get_eumbbar is defined in dink32/kahlua.s.  The other two are + * defined in dink32/drivers/i2c/i2c2.s, drivers/dma/dma2.s, etc. + */ +static unsigned int Global_eumbbar = 0; +extern unsigned int get_eumbbar(); + + +extern unsigned int load_runtime_reg( unsigned int eumbbar, unsigned int reg ); +#pragma Alias( load_runtime_reg, "load_runtime_reg" ); + +extern void store_runtime_reg( unsigned int eumbbar, unsigned int reg, unsigned int val ); +#pragma Alias( store_runtime_reg, "store_runtime_reg" ); + +unsigned int dma_reg_tb[][14] = { +	/* local DMA registers */ +	{ +      /* DMA_0_MR   */  0x00001100, +      /* DMA_0_SR   */  0x00001104, +      /* DMA_0_CDAR */  0x00001108, +      /* DMA_0_SAR  */  0x00001110, +      /* DMA_0_DAR  */  0x00001118, +      /* DMA_0_BCR  */  0x00001120, +      /* DMA_0_NDAR */  0x00001124, +      /* DMA_1_MR   */  0x00001200, +      /* DMA_1_SR   */  0x00001204, +      /* DMA_1_CDAR */  0x00001208, +      /* DMA_1_SAR  */  0x00001210, +      /* DMA_1_DAR  */  0x00001218, +      /* DMA_1_BCR  */  0x00001220, +      /* DMA_1_NDAR */  0x00001224, +	}, +	/* remote DMA registers */ +	{ +      /* DMA_0_MR   */  0x00000100, +      /* DMA_0_SR   */  0x00000104, +      /* DMA_0_CDAR */  0x00000108, +      /* DMA_0_SAR  */  0x00000110, +      /* DMA_0_DAR  */  0x00000118, +      /* DMA_0_BCR  */  0x00000120, +      /* DMA_0_NDAR */  0x00000124, +      /* DMA_1_MR   */  0x00000200, +      /* DMA_1_SR   */  0x00000204, +      /* DMA_1_CDAR */  0x00000208, +      /* DMA_1_SAR  */  0x00000210, +      /* DMA_1_DAR  */  0x00000218, +      /* DMA_1_BCR  */  0x00000220, +      /* DMA_1_NDAR */  0x00000224, +	}, +}; + +/* API functions */ + +/*  Initialize DMA unit with the following: + *  optional pointer to application layer print function + * + *  These parameters may be added: + *  ??? + *  Interrupt enables, modes, etc. are set for each transfer. + * + *  This function must be called before DMA unit can be used. + */ +extern +DMA_Status DMA_Initialize( int (*p)(char *,...)) +{ +  DMAStatus status; +  /* establish the pointer, if there is one, to the application's "printf" */ +  app_print = p; + +  /* If this is the first call, get the embedded utilities memory block +   * base address.  I'm not sure what to do about error handling here: +   * if a non-zero value is returned, accept it. +   */ +  if ( Global_eumbbar == 0) +     Global_eumbbar = get_eumbbar(); +  if ( Global_eumbbar == 0) +  { +    PRINT( "DMA_Initialize: can't find EUMBBAR\n" ); +    return DMA_ERROR; +  } + +  return DMA_SUCCESS; +} + + +/* Perform the DMA transfer, only direct mode is currently implemented. + * At this point, I think it would be better to define a different + * function for chaining mode. + * Also, I'm not sure if it is appropriate to have the "generic" API + * accept snoop and int_steer parameters.  The DINK user interface allows + * them, so for now I'll leave them. + * + * int_steer controls DMA interrupt steering to PCI or local processor + * type is the type of transfer: M2M, M2P, P2M, P2P + * source is the source address of the data + * dest is the destination address of the data + * len is the length of data to transfer + * channel is the DMA channel to use for the transfer + * snoop is the snoop enable control + */ +extern DMA_Status DMA_direct_transfer( DMA_INTERRUPT_STEER int_steer, +                                       DMA_TRANSFER_TYPE type, +                                       unsigned int source, +                                       unsigned int dest, +                                       unsigned int len, +                                       DMA_CHANNEL channel, +                                       DMA_SNOOP_MODE snoop) +{ +    DMA_MR md; +    DMA_CDAR cdar; +    /* it's inappropriate for curr to be a struct, but I'll leave it */ +    DMA_CURR curr; + +    DMAStatus stat; + +	/* The rest of this code was moved from device.c test_dma to here. +	 * It needs to be cleaned up and validated, but at least it is removed +	 * from the application and API.  Most of the mode is left hard coded. +	 * This should be changed after the final API is defined and the user +	 * application has a way to control the transfer. +	 * +	 */ + +	if ( DMA_Get_Mode( LOCAL, Global_eumbbar, channel, &md ) != DMASUCCESS ) +	{ +		return DMA_ERROR; +	} + +	md.irqs = int_steer; +	md.pde = 0; +	md.dahts = 3; /* 8 - byte */ +	md.sahts = 3; /* 8 - byte */ +	md.dahe = 0; +	md.sahe = 0; +	md.prc = 0; +	/* if steering interrupts to local processor, use polling mode */ +	if ( int_steer == DMA_INT_STEER_PCI ) +	{ +		md.eie = 1; +		md.eotie = 1; +	} else { +		md.eie = 0; +		md.eotie = 0; +	} +	md.dl = 0; +	md.ctm = 1;   /* direct mode */ +    md.cc = 0; + +	/* validate the length range */ +	if (len > 0x3ffffff ) +	{ +		PRINT( "dev DMA: length of transfer too large: %d\n", len ); +		return DMA_ERROR; +	} + +	/* inappropriate to use a struct, but leave as is for now */ +	curr.src_addr = source; +	curr.dest_addr = dest; +	curr.byte_cnt = len; + +	(void)DMA_Poke_Desp( LOCAL, Global_eumbbar, channel, &cdar ); +	cdar.snen = snoop; +	cdar.ctt = type; + +	if ( ( stat = DMA_Bld_Desp( LOCAL, Global_eumbbar, channel, cdar )) +			!= DMASUCCESS || +		 ( stat = DMA_Bld_Curr( LOCAL, Global_eumbbar, channel, curr )) +			!= DMASUCCESS || +	     ( stat = DMA_Set_Mode( LOCAL, Global_eumbbar, channel, md )) +			!= DMASUCCESS || +		 ( stat = DMA_Start( LOCAL, Global_eumbbar, channel )) +			!= DMASUCCESS ) +	{ +		if ( stat == DMACHNBUSY ) +		{ +			PRINT( "dev DMA: channel %d busy.\n", channel ); +		} +		else +		{ +			PRINT( "dev DMA: invalid channel request.\n", channel ); +		} + +		return DMA_ERROR; +	} + +/* Since we are interested at the DMA performace right now, +   we are going to do as less as possible to burden the +   603e core. + +   if you have epic enabled or don't care the return from +   DMA operation, you can just return SUCCESS. + +   if you don't have epic enabled and care the DMA result, +   you can use the polling method below. + +   Note: I'll attempt to activate the code for handling polling. + */ + +#if 0 +	/* if steering interrupt to local processor, let it handle results */ +	if ( int_steer == DMA_INT_STEER_LOCAL ) +	{ +	    return DMA_SUCCESS; +	} + +	/* polling since interrupt goes to PCI */ +	do +	{ +		stat = DMA_ISR( Global_eumbbar, channel, dma_error_func, +			dma_error_func, dma_error_func, dma_error_func ); +	} +	while ( stat == DMANOEVENT ); +#endif + +    return DMA_SUCCESS; +} + +/* DMA library internal functions */ + +/** + * Note: + * + * In all following functions, the host (KAHLUA) processor has a + * choice of accessing on board local DMA (LOCAL), + * or DMA on a distributed KAHLUA (REMOTE). In either case, + * the caller shall pass the configured embedded utility memory + * block base address relative to the DMA. If LOCAL DMA is used, + * this parameter shall be EUMBBAR, if REMOTE is used, the + * parameter shall be the corresponding PCSRBAR. + **/ + +/************************************************************** + * function: DMA_Get_Stat + * + * description: return the content of status register of + *              the given DMA channel + * + *              if error, reserved0 field all 1s. + **************************************************************/ +static +DMAStatus DMA_Get_Stat( LOCATION host, unsigned int eumbbar, unsigned int channel, DMA_SR *stat ) +{ +    unsigned int tmp; + +   if ( channel != 0 && channel != 1 || stat == 0 ) +   { +       return DMAINVALID; +   } + +    tmp = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_SR_REG] ); +#ifdef DMADBG0 +   PRINT( "%s(%d): %s DMA %d (0x%08x) stat = 0x%08x\n", __FILE__, __LINE__, +		  ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_SR_REG], tmp ); +#endif + +	 stat->reserved0 = ( tmp & 0xffffff00 ) >> 8; +	 stat->lme       = ( tmp & 0x00000080 ) >> 7; +	 stat->reserved1 = ( tmp & 0x00000060 ) >> 5; +	 stat->pe        = ( tmp & 0x00000010 ) >> 4; +	 stat->reserved2 = ( tmp & 0x00000008 ) >> 3; +	 stat->cb        = ( tmp & 0x00000004 ) >> 2; +	 stat->eosi      = ( tmp & 0x00000002 ) >> 1; +	 stat->eocai     = ( tmp & 0x00000001 ); + +   return DMASUCCESS; +} + +/************************************************************** + * function: DMA_Get_Mode + * + * description: return the content of mode register of the + *              given DMA channel + * + *              if error, return DMAINVALID, otherwise return + *              DMASUCCESS + **************************************************************/ +static +DMAStatus DMA_Get_Mode( LOCATION host, unsigned eumbbar, unsigned int channel, DMA_MR *mode ) +{ +    unsigned int tmp; +   if ( channel != 0 && channel != 1 || mode == 0 ) +   { +     return DMAINVALID; +   } + +    tmp = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_MR_REG] ); + +#ifdef DMADBG0 +   PRINT( "%s(%d): %s DMA %d (0x%08x) mode = 0x%08x\n", __FILE__, __LINE__, +		  ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_MR_REG], tmp ); +#endif + +	 mode->reserved0 = (tmp & 0xfff00000) >> 20; +	 mode->irqs      = (tmp & 0x00080000) >> 19; +	 mode->pde       = (tmp & 0x00040000) >> 18; +	 mode->dahts     = (tmp & 0x00030000) >> 16; +     mode->sahts     = (tmp & 0x0000c000) >> 14; +	 mode->dahe      = (tmp & 0x00002000) >> 13; +	 mode->sahe      = (tmp & 0x00001000) >> 12; +	 mode->prc       = (tmp & 0x00000c00) >> 10; +	 mode->reserved1 = (tmp & 0x00000200) >> 9; +	 mode->eie       = (tmp & 0x00000100) >> 8; +	 mode->eotie     = (tmp & 0x00000080) >> 7; +	 mode->reserved2 = (tmp & 0x00000070) >> 4; +	 mode->dl        = (tmp & 0x00000008) >> 3; +	 mode->ctm       = (tmp & 0x00000004) >> 2; +	 mode->cc        = (tmp & 0x00000002) >> 1; +	 mode->cs        = (tmp & 0x00000001); + +   return DMASUCCESS; +} + +/************************************************************** + * function: DMA_Set_Mode + * + * description: Set a new mode to a given DMA channel + * + * note: It is not a good idea of changing the DMA mode during + *       the middle of a transaction. + **************************************************************/ +static +DMAStatus DMA_Set_Mode( LOCATION host, unsigned eumbbar, unsigned int channel, DMA_MR mode ) +{ +    unsigned int tmp; +   if ( channel != 0 && channel != 1 ) +   { +	   return DMAINVALID; +   } + +   tmp = ( mode.reserved0 & 0xfff ) << 20; +   tmp |= ( ( mode.irqs  & 0x1 ) << 19); +   tmp |= ( ( mode.pde   & 0x1 ) << 18 ); +   tmp |= ( ( mode.dahts & 0x3 ) << 16 ); +   tmp |= ( ( mode.sahts & 0x3 ) << 14 ); +   tmp |= ( ( mode.dahe  & 0x1 ) << 13 ); +   tmp |= ( ( mode.sahe  & 0x1 ) << 12 ); +   tmp |= ( ( mode.prc   & 0x3 ) << 10 ); +   tmp |= ( ( mode.reserved1 & 0x1 ) << 9 ); +   tmp |= ( ( mode.eie   & 0x1 ) << 8 ); +   tmp |= ( ( mode.eotie & 0x1 ) << 7 ); +   tmp |= ( ( mode.reserved2 & 0x7 ) << 4 ); +   tmp |= ( ( mode.dl    & 0x1 ) << 3 ); +   tmp |= ( ( mode.ctm   & 0x1 ) << 2 ); +   tmp |= ( ( mode.cc    & 0x1 ) << 1 ) ; +   tmp |= ( mode.cs    & 0x1 ); + +   store_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG + DMA_MR_REG], tmp ); +   return DMASUCCESS; +} + +/************************************************************ + * function: DMA_Start + * + * description: start a given DMA channel transaction + *              return DMASUCCESS if success otherwise return + *              DMAStatus value + * + * note: this function will clear DMA_MR(CC) first, then + *       set DMA_MR(CC). + ***********************************************************/ +static +DMAStatus DMA_Start( LOCATION host, unsigned int eumbbar, unsigned int channel ) +{ +   DMA_SR stat; +   unsigned int mode; + +   if ( channel != 0 && channel != 1 ) +   { +	   return DMAINVALID; +   } + +   if ( DMA_Get_Stat( host, eumbbar, channel, &stat ) != DMASUCCESS ) +   { +		   return DMAINVALID; +   } + +   if ( stat.cb == 1 ) +   { +	   /* DMA is not free */ +	   return DMACHNBUSY; +   } + +   mode = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG + DMA_MR_REG] ); +   /* clear DMA_MR(CS) */ +   mode &= 0xfffffffe; +   store_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG + DMA_MR_REG], mode ); + +   /* set DMA_MR(CS) */ +   mode |= CS; +   store_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG + DMA_MR_REG], mode ); +   return DMASUCCESS; +} + +/*********************************************************** + * function: DMA_Halt + * + * description: halt the current dma transaction on the specified + *              channel. + *              return DMASUCCESS if success otherwise return DMAINVALID + * + * note: if the specified DMA channel is idle, nothing happens + *************************************************************/ +static +DMAStatus DMA_Halt( LOCATION host, unsigned int eumbbar, unsigned int channel ) +{ +   unsigned int mode; +   if ( channel != 0 && channel != 1 ) +   { +	   return DMAINVALID; +   } + +   mode = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG + DMA_MR_REG]); + +   /* clear DMA_MR(CS) */ +   mode &= 0xfffffffe; +   store_runtime_reg(eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG + DMA_MR_REG], mode ); +   return DMASUCCESS; +} + +/************************************************************* + * function: DMA_Chn_Cnt + * + * description: set the DMA_MR(CC) bit for a given channel + *              that is in chaining mode. + *              return DMASUCCESS if successfule, otherwise return + *              DMAINVALID. + * + * note: if the given channel is not in chaining mode, nothing + *       happen. + * + *************************************************************/ +static +DMAStatus DMA_Chn_Cnt( LOCATION host, unsigned int eumbbar, unsigned int channel ) +{ +	DMA_MR mode; +	if ( channel != 0 && channel != 1 ) +	{ +		return DMAINVALID; +	} + +	if ( DMA_Get_Mode( host, eumbbar, channel, &mode ) != DMASUCCESS ) +	{ +			return DMAINVALID; +	} + +	if ( mode.ctm == 0 ) +	{ +		/* either illegal mode or not chaining mode */ +		return DMAINVALID; +	} + +	mode.cc = 1; +	return DMA_Set_Mode( host, eumbbar, channel, mode ); +} + +/************************************************************** + * function: DMA_Bld_Desp + * + * description: set current descriptor address register + *              according to the desp for a given channel + * + *              if the given channel is busy return DMACHNBUSY + *              and no change made, otherwise return DMASUCCESS. + * + * note: + **************************************************************/ +static +DMAStatus DMA_Bld_Desp( LOCATION host, +						   unsigned int eumbbar, +						   unsigned int channel, +						   DMA_CDAR     desp ) +{ +	DMA_SR status; +	unsigned int temp; + +	if ( channel != 0 && channel != 1 ) +	{ +		/* channel number out of range */ +		return DMAINVALID; +	} + +	if ( DMA_Get_Stat( host, eumbbar, channel, &status ) != DMASUCCESS ) +	{ +			return DMAINVALID; +	} + +	if ( status.cb == 1 ) +	{ +		/* channel busy */ +		return DMACHNBUSY; +	} + +	temp = ( desp.cda & 0x7ffffff ) << 5; +	temp |= (( desp.snen & 0x1 ) << 4 ); +	temp |= (( desp.eosie & 0x1 ) << 3 ); +	temp |= (( desp.ctt   & 0x3 ) << 1 ); +    temp |= ( desp.eotd  & 0x1 ); + +    store_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], temp ); + +#ifdef DMADBG0 +   PRINT( "%s(%d): %s DMA %d (0x%08x) cdar := 0x%08x\n", __FILE__, __LINE__, +		  ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], temp ); +#endif + +	return DMASUCCESS; +} + +/************************************************************** + * function: DMA_Poke_Desp + * + * description: poke the current descriptor address register + *              for a given channel + * + *              return DMASUCCESS if no error + * + * note: Due to the undeterministic parallellism of DMA operation, + *       the value returned by this function shall be taken as + *       the most recently used descriptor when the last time + *       DMA starts a chaining mode operation. + **************************************************************/ +static +DMAStatus DMA_Poke_Desp( LOCATION host, +						    unsigned int eumbbar, +						    unsigned int channel, +						    DMA_CDAR     *desp ) +{ +	unsigned int cdar; +	if ( channel != 0 && channel != 1 || desp == 0 ) +	{ +			return DMAINVALID; +	} + +    cdar = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG] ); + +#ifdef DMADBG0 +   PRINT( "%s(%d): %s DMA %d (0x%08x) cdar : 0x%08x\n", __FILE__, __LINE__, +		  ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], cdar ); +#endif + + +	desp->cda   = ( cdar & 0xffffffe0 ) >> 5; +	desp->snen  = ( cdar & 0x00000010 ) >> 4; +	desp->eosie = ( cdar & 0x00000008 ) >> 3; +	desp->ctt   = ( cdar & 0x00000006 ) >> 1; +	desp->eotd  = ( cdar & 0x00000001 ); + +	return DMASUCCESS; +} + +/************************************************************** + * function: DMA_Bld_Curr + * + * description: set current src, dest, byte count registers + *              according to the desp for a given channel + *              return DMASUCCESS if no error. + * + * note: + **************************************************************/ +static +DMAStatus DMA_Bld_Curr( LOCATION host, +					   unsigned int eumbbar, +					   unsigned int channel, +					   DMA_CURR     desp ) +{ +	DMA_SR status; +	if ( channel != 0 && channel != 1 ) +	{ +		/* channel number out of range */ +		return DMAINVALID; +	} + +	if ( DMA_Get_Stat( host, eumbbar, channel, &status ) != DMASUCCESS ) +	{ +		 return DMAINVALID; +	} + +	if ( status.cb == 1  ) +	{ +		/* channel busy */ +		return DMACHNBUSY; +	} + +	desp.byte_cnt &= 0x03ffffff; /* upper 6-bits are 0s */ + +    store_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_SAR_REG], desp.src_addr ); +#ifdef DMADBG0 +   PRINT( "%s(%d): %s DMA %d (0x%08x) src := 0x%08x\n", __FILE__, __LINE__, +		  ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], desp.src_addr ); +#endif + +    store_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_DAR_REG], desp.dest_addr ); +#ifdef DMADBG0 +   PRINT( "%s(%d): %s DMA %d (0x%08x) dest := 0x%08x\n", __FILE__, __LINE__, +		  ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], desp.dest_addr ); +#endif + +    store_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_BCR_REG], desp.byte_cnt ); +#ifdef DMADBG0 +   PRINT( "%s(%d): %s DMA %d (0x%08x) count := 0x%08x\n", __FILE__, __LINE__, +		  ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], desp.byte_cnt ); +#endif + + +	return DMASUCCESS; + +} + +/************************************************************** + * function: DMA_Poke_Curr + * + * description: poke the current src, dest, byte count registers + *              for a given channel. + * + *              return DMASUCCESS if no error + * + * note:        Due to the undeterministic parallelism, in chaining + *              mode, the value returned by this function shall + *              be taken as reference when the query is made rather + *              than the absolute snapshot when the value is returned. + **************************************************************/ +static +DMAStatus DMA_Poke_Curr( LOCATION host, +					    unsigned int eumbbar, +					    unsigned int channel, +					    DMA_CURR*    desp ) +{ +	if ( channel != 0 && channel != 1 || desp == 0 ) +	{ +			return DMAINVALID; +	} + +	desp->src_addr = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_SAR_REG] ); +#ifdef DMADBG0 +   PRINT( "%s(%d): %s DMA %d (0x%08x) src : 0x%08x\n", __FILE__, __LINE__, +		  ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], desp->src_addr ); +#endif + +	desp->dest_addr = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_DAR_REG] ); +#ifdef DMADBG0 +   PRINT( "%s(%d): %s DMA %d (0x%08x) dest : 0x%08x\n", __FILE__, __LINE__, +		  ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], desp->dest_addr ); +#endif + +    desp->byte_cnt = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_BCR_REG] ); +#ifdef DMADBG0 +   PRINT( "%s(%d): %s DMA %d (0x%08x) count : 0x%08x\n", __FILE__, __LINE__, +		  ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], desp->byte_cnt ); +#endif + + +	return DMASUCCESS; +} + +/***************************************************************** + * function: dma_error_func + * + * description: display the error information + * + * note: This seems like a highly convoluted way to handle messages, + * but I'll leave it as it was in device.c when I moved it into the + * DMA library source. + ****************************************************************/ +static +DMAStatus dma_error_func( unsigned int eumbbar, unsigned int chn, DMAStatus err) +{ +	unsigned char *msg[] = +		{ +			"Local Memory Error", +			"PCI Error", +			"Channel Busy", +			"End-of-Segment Interrupt", +			"End-of-Chain/Direct Interrupt", +		}; + +	   if ( err >= DMALMERROR && err <= DMAEOCAINT ) +	   { +	     PRINT( "DMA Status: channel %d  %s\n", chn, msg[err-DMASUCCESS-1] ); +	   } + +	   return err; + +} + +/************************************************************* + * function: DMA_ISR + * + * description: DMA interrupt service routine + *              return DMAStatus value based on + *              the status + * + *************************************************************/ +static +DMAStatus DMA_ISR( unsigned int eumbbar, +				  unsigned int channel, +				  DMAStatus (*lme_func)( unsigned int, unsigned int, DMAStatus ), +				  DMAStatus (*pe_func) ( unsigned int, unsigned int, DMAStatus ), +				  DMAStatus (*eosi_func)( unsigned int, unsigned int, DMAStatus ), +				  DMAStatus (*eocai_func)(unsigned int, unsigned int, DMAStatus )) +{ + +	DMA_SR stat; +	DMAStatus rval = DMANOEVENT; +    unsigned int temp; + +	if ( channel != 0 && channel != 1 ) +	{ +		return DMAINVALID; +	} + +	if ( DMA_Get_Stat( LOCAL, eumbbar, channel, &stat ) != DMASUCCESS ) +	{ +			return DMAINVALID; +	} + +	if ( stat.lme == 1 ) +	{ +		/* local memory error */ +		rval = DMALMERROR; +		if ( lme_func != 0 ) +		{ +		  rval = (*lme_func)(eumbbar, channel, DMALMERROR ); +	    } + +	} +	else if ( stat.pe == 1 ) +	{ +        /* PCI error */ +		rval = DMAPERROR; +		if ( pe_func != 0 ) +		{ +		  rval = (*pe_func)(eumbbar, channel, DMAPERROR ); +	    } + +	} +	else if ( stat.eosi == 1 ) +	{ +		/* end-of-segment interrupt */ +		rval = DMAEOSINT; +		if ( eosi_func != 0 ) +		{ +		  rval = (*eosi_func)(eumbbar, channel, DMAEOSINT ); +	    } +	} +	else +	{ +		/* End-of-chain/direct interrupt */ +		rval = DMAEOCAINT; +		if ( eocai_func != 0 ) +		{ +		  rval = (*eocai_func)(eumbbar, channel, DMAEOCAINT ); +	    } +	} + +    temp = ( stat.reserved0 & 0xffffff ) << 8; +   	temp |= ( ( stat.lme       & 0x1 ) << 7 );  /* write one to clear */ +	temp |= ( ( stat.reserved1 & 0x3 ) << 5 ); +    temp |= ( ( stat.pe        & 0x1 ) << 4 );  /* write one to clear */ +    temp |= ( ( stat.reserved2 & 0x1 ) << 3 ); +	temp |= ( ( stat.cb        & 0x1 ) << 2 );  /* write one to clear */ +    temp |= ( ( stat.eosi      & 0x1 ) << 1 );  /* write one to clear */ +    temp |= ( stat.eocai & 0x1 );               /* write one to clear */ + +    store_runtime_reg( eumbbar, dma_reg_tb[LOCAL][channel*NUM_DMA_REG + DMA_SR_REG], temp ); + +#ifdef DMADBG0 +	PRINT( "%s(%d): DMA channel %d SR := 0x%08x\n", __FILE__, __LINE__, channel, temp ); +#endif + +	return rval; +} diff --git a/cpu/mpc824x/drivers/dma/dma2.S b/cpu/mpc824x/drivers/dma/dma2.S new file mode 100644 index 000000000..dab1de349 --- /dev/null +++ b/cpu/mpc824x/drivers/dma/dma2.S @@ -0,0 +1,45 @@ +/************************************** + * + * copyright @ Motorola, 1999 + * + **************************************/ + +/********************************************************** + * function: load_runtime_reg + * + * input:  r3 - value of eumbbar + *         r4 - register offset in embedded utility space + * + * output: r3 - register content + **********************************************************/ +      .text +      .align 2 +      .global load_runtime_reg + +load_runtime_reg: + +	      lwbrx	r3,r4,r3 +	      sync + + 	      bclr 20, 0 + +/**************************************************************** + * function: store_runtime_reg + * + * input: r3 - value of eumbbar + *        r4 - register offset in embedded utility space + *        r5 - new value to be stored + * + ****************************************************************/ +           .text +           .align 2 +           .global store_runtime_reg +store_runtime_reg: + +	      stwbrx r5,  r4, r3 +	      sync + +		  bclr   20,0 + + + diff --git a/cpu/mpc824x/drivers/dma/dma_export.h b/cpu/mpc824x/drivers/dma/dma_export.h new file mode 100644 index 000000000..cb750dd89 --- /dev/null +++ b/cpu/mpc824x/drivers/dma/dma_export.h @@ -0,0 +1,100 @@ +#ifndef DMA_EXPORT_H +#define DMA_EXPORT_H + +/**************************************************** + * $Id: + * + * Copyright Motorola 1999 + * + * $Log: + * + ****************************************************/ + +/* These are the defined return values for the DMA_* functions. + * Any non-zero value indicates failure.  Failure modes can be added for + * more detailed error reporting. + */ +typedef enum _dma_status +{ + DMA_SUCCESS     = 0, + DMA_ERROR, +} DMA_Status; + +/* These are the defined channel transfer types.  */ +typedef enum _dma_transfer_types +{ +	DMA_M2M =  0,	/* local memory to local memory */ +	DMA_M2P =  1,	/* local memory to PCI */ +	DMA_P2M =  2,	/* PCI to local memory */ +	DMA_P2P =  3,	/* PCI to PCI */ +} DMA_TRANSFER_TYPE; + +typedef enum _dma_interrupt_steer +{ +	DMA_INT_STEER_LOCAL =  0, /* steer DMA int to local processor */ +	DMA_INT_STEER_PCI = 1,    /* steer DMA int to PCI bus through INTA_ */ +} DMA_INTERRUPT_STEER; + +typedef enum _dma_channel +{ +	DMA_CHN_0 =  0, /* kahlua has two dma channels: 0 and 1 */ +	DMA_CHN_1 =  1, +} DMA_CHANNEL; + +typedef enum _dma_snoop_mode +{ +	DMA_SNOOP_DISABLE =  0, +	DMA_SNOOP_ENABLE = 1, +} DMA_SNOOP_MODE; + +/******************** App. API ******************** + * The application API is for user level application + * to use the functionality provided by DMA driver. + * This is a "generic" DMA interface, it should contain + * nothing specific to the Kahlua implementation. + * Only the generic functions are exported by the library. + * + * Note: Its App.s responsibility to swap the data + *       byte. In our API, we currently transfer whatever + *       we are given - Big/Little Endian.  This could + *       become part of the DMA config, though. + **************************************************/ + + +/*  Initialize DMA unit with the following: + *  optional pointer to application layer print function + * + *  These parameters may be added: + *  ??? + *  Interrupt enables, modes, etc. are set for each transfer. + * + *  This function must be called before DMA unit can be used. + */ +extern DMA_Status DMA_Initialize( +        int (*app_print_function)(char *,...)); /* pointer to optional "printf" +                                                 * provided by application +                                                 */ + +/* Perform the DMA transfer, only direct mode is currently implemented. + * At this point, I think it would be better to define a different + * function for chaining mode. + * Also, I'm not sure if it is appropriate to have the "generic" API + * accept snoop and int_steer parameters.  The DINK user interface allows + * them, so for now I'll leave them. + * + * int_steer controls DMA interrupt steering to PCI or local processor + * type is the type of transfer: M2M, M2P, P2M, P2P + * source is the source address of the data + * dest is the destination address of the data + * len is the length of data to transfer + * channel is the DMA channel to use for the transfer + * snoop is the snoop enable control + */ +extern DMA_Status DMA_direct_transfer( DMA_INTERRUPT_STEER int_steer, +                                       DMA_TRANSFER_TYPE type, +                                       unsigned int source, +                                       unsigned int dest, +                                       unsigned int len, +                                       DMA_CHANNEL channel, +                                       DMA_SNOOP_MODE snoop); +#endif diff --git a/cpu/mpc824x/drivers/dma_export.h b/cpu/mpc824x/drivers/dma_export.h new file mode 100644 index 000000000..cb750dd89 --- /dev/null +++ b/cpu/mpc824x/drivers/dma_export.h @@ -0,0 +1,100 @@ +#ifndef DMA_EXPORT_H +#define DMA_EXPORT_H + +/**************************************************** + * $Id: + * + * Copyright Motorola 1999 + * + * $Log: + * + ****************************************************/ + +/* These are the defined return values for the DMA_* functions. + * Any non-zero value indicates failure.  Failure modes can be added for + * more detailed error reporting. + */ +typedef enum _dma_status +{ + DMA_SUCCESS     = 0, + DMA_ERROR, +} DMA_Status; + +/* These are the defined channel transfer types.  */ +typedef enum _dma_transfer_types +{ +	DMA_M2M =  0,	/* local memory to local memory */ +	DMA_M2P =  1,	/* local memory to PCI */ +	DMA_P2M =  2,	/* PCI to local memory */ +	DMA_P2P =  3,	/* PCI to PCI */ +} DMA_TRANSFER_TYPE; + +typedef enum _dma_interrupt_steer +{ +	DMA_INT_STEER_LOCAL =  0, /* steer DMA int to local processor */ +	DMA_INT_STEER_PCI = 1,    /* steer DMA int to PCI bus through INTA_ */ +} DMA_INTERRUPT_STEER; + +typedef enum _dma_channel +{ +	DMA_CHN_0 =  0, /* kahlua has two dma channels: 0 and 1 */ +	DMA_CHN_1 =  1, +} DMA_CHANNEL; + +typedef enum _dma_snoop_mode +{ +	DMA_SNOOP_DISABLE =  0, +	DMA_SNOOP_ENABLE = 1, +} DMA_SNOOP_MODE; + +/******************** App. API ******************** + * The application API is for user level application + * to use the functionality provided by DMA driver. + * This is a "generic" DMA interface, it should contain + * nothing specific to the Kahlua implementation. + * Only the generic functions are exported by the library. + * + * Note: Its App.s responsibility to swap the data + *       byte. In our API, we currently transfer whatever + *       we are given - Big/Little Endian.  This could + *       become part of the DMA config, though. + **************************************************/ + + +/*  Initialize DMA unit with the following: + *  optional pointer to application layer print function + * + *  These parameters may be added: + *  ??? + *  Interrupt enables, modes, etc. are set for each transfer. + * + *  This function must be called before DMA unit can be used. + */ +extern DMA_Status DMA_Initialize( +        int (*app_print_function)(char *,...)); /* pointer to optional "printf" +                                                 * provided by application +                                                 */ + +/* Perform the DMA transfer, only direct mode is currently implemented. + * At this point, I think it would be better to define a different + * function for chaining mode. + * Also, I'm not sure if it is appropriate to have the "generic" API + * accept snoop and int_steer parameters.  The DINK user interface allows + * them, so for now I'll leave them. + * + * int_steer controls DMA interrupt steering to PCI or local processor + * type is the type of transfer: M2M, M2P, P2M, P2P + * source is the source address of the data + * dest is the destination address of the data + * len is the length of data to transfer + * channel is the DMA channel to use for the transfer + * snoop is the snoop enable control + */ +extern DMA_Status DMA_direct_transfer( DMA_INTERRUPT_STEER int_steer, +                                       DMA_TRANSFER_TYPE type, +                                       unsigned int source, +                                       unsigned int dest, +                                       unsigned int len, +                                       DMA_CHANNEL channel, +                                       DMA_SNOOP_MODE snoop); +#endif diff --git a/cpu/mpc824x/drivers/epic.h b/cpu/mpc824x/drivers/epic.h new file mode 100644 index 000000000..2803f631c --- /dev/null +++ b/cpu/mpc824x/drivers/epic.h @@ -0,0 +1 @@ +#include "epic/epic.h" diff --git a/cpu/mpc824x/drivers/epic/README b/cpu/mpc824x/drivers/epic/README new file mode 100644 index 000000000..ae95b8859 --- /dev/null +++ b/cpu/mpc824x/drivers/epic/README @@ -0,0 +1,104 @@ +CONTENT: + +   epic.h +   epic1.c +   epic2.s + +WHAT ARE THESE FILES: + +These files contain MPC8240 (Kahlua) EPIC +driver routines. The driver routines are not +written for any specific operating system. +They serves the purpose of code sample, and +jump-start for using the MPC8240 EPIC unit. + +For the reason of correctness of C language +syntax, these files are compiled by Metaware +C compiler and assembler. + +ENDIAN NOTATION: + +The algorithm is designed for big-endian mode, +software is responsible for byte swapping. + +USAGE: + +1. The host system that is running on MPC8240 +   shall link the files listed here. The memory +   location of driver routines shall take into +   account of that driver routines need to run +   in supervisor mode and they process external +   interrupts. + +   The routine epic_exception shall be called by +   exception vector at location 0x500, i.e., +   603e core external exception vector. + +2. The host system is responsible for configuring +   the MPC8240 including Embedded Utilities Memory +   Block. All EPIC driver functions require the +   content of Embedded Utilities Memory Block +   Base Address Register, EUMBBAR, as the first +   parameter. + +3. Before EPIC unit of MPC8240 can be used, +   initialize EPIC unit by calling epicInit +   with the corresponding parameters. + +   The initialization shall disable the 603e +   core External Exception by calling CoreExtIntDisable( ). +   Next, call epicInit( ). Last, enable the 603e core +   External Exception by calling CoreExtIntEnable( ). + +4. After EPIC unit has been successfully initialized, +   epicIntSourceSet( ) shall be used to register each +   external interrupt source. Anytime, an external +   interrupt source can be disabled or enabled by +   calling corresponding function, epicIntDisable( ), +   or epicIntEnable( ). + +   Global Timers' resource, base count and frequency, +   can be changed by calling epicTmFrequencySet( ) +   and epicTmBaseSet( ). + +   To stop counting a specific global timer, use +   the function, epicTmInhibit while epicTmEnable +   can be used to start counting a timer. + +5. To mask a set of external interrupts that are +   are certain level below, epicIntPrioritySet( ) +   can be used. For example, if the processor's +   current task priority register is set to 0x7, +   only interrupts of priority 0x8 or higher will +   be passed to the processor. + +   Be careful when using this function. It may +   corrupt the current interrupt pending, selector, +   and request registers, resulting an invalid vetor. + +   After enabling an interrupt, disable it may also +   cause an invalid vector. User may consider using +   the spurious vector interrupt service routine to +   handle this case. + +6. The EPIC driver routines contains a set +   of utilities, Set and Get, for host system +   to query and modify the desired EPIC source +   registers. + +7. Each external interrupt source shall register +   its interrupt service routine. The routine +   shall contain all interrupt source specific +   processes and keep as short as possible. + +   Special customized end of interrupt routine +   is optional. If it is needed, it shall contain +   the external interrupt source specific end of +   interrupt process. + +   External interrupt exception vector at 0x500 +   shall always call the epicEOI just before +   rfi instruction. Refer to the routine, +   epic_exception, for a code sample. + + diff --git a/cpu/mpc824x/drivers/epic/epic2.S b/cpu/mpc824x/drivers/epic/epic2.S new file mode 100644 index 000000000..8979f8844 --- /dev/null +++ b/cpu/mpc824x/drivers/epic/epic2.S @@ -0,0 +1,196 @@ +/************************************** + * + * copyright @ Motorola, 1999 + * + **************************************/ + +#include <ppc_asm.tmpl> +#include <ppc_defs.h> +#include <asm/processor.h> + +/********************************************* + * function: CoreExtIntEnable + * + * description: Enable 603e core external interrupt + * + * note: mtmsr is context-synchronization + **********************************************/ +		.text +		.align 2 +        .global CoreExtIntEnable +CoreExtIntEnable: +         mfmsr    r3 + +         ori      r3,r3,0x8000         /* enable external interrupt */ +         mtmsr    r3 + +         bclr 20, 0 + +/******************************************* + * function: CoreExtIntDisable + * + * description: Disable 603e core external interrupt + * + * note: + *******************************************/ +		.text +		.align 2 +        .global CoreExtIntDisable +CoreExtIntDisable: +        mfmsr    r4 + +	xor	r3,r3,r3 +	or      r3,r3,r4 + +	andis.	r4,r4,0xffff +        andi.   r3,r3,0x7fff         /* disable external interrupt */ + +	or      r3,r3,r4 +        mtmsr    r3 + +        bclr 20, 0 + +/********************************************************* + * function: epicEOI + * + * description: signal the EOI and restore machine status + *       Input: r3 - value of eumbbar + *       Output: r3 - value of eumbbar + *               r4 - ISR vector value + * note: + ********************************************************/ +		.text +		.align 2 +        .global epicEOI +epicEOI: +	lis	r5,0x0006	        /* Build End Of Interrupt Register offset */ +	ori	r5,r5,0x00b0 +	xor	r7,r7,r7	        /* Clear r7 */ +	stwbrx	r7,r5,r3	    /* Save r7, writing to this register will +				             * intidate the end of processing the +	 			             * highest interrupt. +                             */ +	sync + +	/* ---RESTORE MACHINE STATE */ +	mfmsr	r13		        /* Clear Recoverable Interrupt bit in MSR */ +        or      r7,r7,r13 + +	andis.  r7,r7,0xffff +	andi.	r13,r13,0x7ffd	/* (and disable interrupts) */ +	or      r13,r13,r7 +	mtmsr	r13 + +	lwz   r13,0x1c(r1)      /* pull ctr */ +	mtctr r13 + +	lwz   r13,0x18(r1)      /* pull xer */ +	mtctr r13 + +	lwz   r13,0x14(r1)      /* pull lr */ +	mtctr r13 + +	lwz	    r13,0x10(r1)	/* Pull SRR1 from stack */ +	mtspr   SRR1,r13	    /* Restore SRR1 */ + +	lwz	    r13,0xc(r1)	    /* Pull SRR0 from stack */ +	mtspr   SRR0,r13	    /* Restore SRR0 */ + +	lwz	    r13,0x8(r1)	    /* Pull User stack pointer from stack */ +	mtspr   SPRG1,r13	    /* Restore SPRG1 */ + +	lwz	r4,0x4(r1)          /* vector value */ +	lwz	r3,0x0(r1)          /* eumbbar */ +	sync + +	addi	r1,r1,0x20	/* Deallocate stack */ +	mtspr   SPRG0,r1	/* Save updated Supervisor stack pointer */ +	mfspr   r1,SPRG1	/* Restore User stack pointer */ + +	bclr     20,0 + +/*********************************************************** + * function: exception routine called by exception vector + *           at 0x500, external interrupt + * + * description: Kahlua EPIC controller + * + * input:  r3 - content of eumbbar + * output: r3 - ISR return value + *         r4 - Interrupt vector number + * note: + ***********************************************************/ + +       .text +	   .align 2 +       .global epic_exception + +epic_exception: + +	/*---SAVE MACHINE STATE TO A STACK */ +	mtspr   SPRG1,r1	/* Save User stack pointer to SPRG1 */ +	mfspr	r1,SPRG0	/* Load Supervisor stack pointer into r1 */ + +	stwu	r3,-0x20(r1)	/* Push the value of eumbbar onto stack */ + +	mfspr	r3,SPRG1	/* Push User stack pointer onto stack */ +	stw	    r3,0x8(r1) +	mfspr	r3,SRR0	    /* Push SRR0 onto stack */ +	stw	    r1,0xc(r1) +	mfspr	r3,SRR1	    /* Push SRR1 onto stack */ +	stw	    r3,0x10(r1) +	mflr    r3 +	stw     r3,0x14(r1) /* Push LR */ +	mfxer   r3 +	stw     r3,0x18(r1) /* Push Xer */ +	mfctr   r3 +	stw     r3,0x1c(r1) /* Push CTR */ + +	mtspr	SPRG0,r1	/* Save updated Supervisor stack pointer +				         * value to SPRG0 +                         */ +	mfmsr	r3 +	ori	    r3,r3,0x0002	/* Set Recoverable Interrupt bit in MSR */ +	mtmsr	r3 + +	/* ---READ IN THE EUMBAR REGISTER */ +    lwz     r6,0(r1)       /* this is eumbbar */ +    sync + +	/* ---READ EPIC REGISTER:	PROCESSOR INTERRUPT ACKNOWLEDGE REGISTER */ +	lis	r5,0x0006	        /* Build Interrupt Acknowledge Register +				             * offset +                             */ +	ori	r5,r5,0x00a0 +	lwbrx	r7,r5,r6    /* Load interrupt vector into r7 */ +	sync + +	/* --MASK OFF ALL BITS EXCEPT THE VECTOR */ +	xor	r3,r3,r3 +    xor r4,r4,r4 +	or    r3, r3, r6        /*  eumbbar in r3 */ +	andi. r4,r7,0x00ff   	/* Mask off bits, vector in r4 */ + +    stw     r4,0x04(r1)     /* save the vector value */ + +    lis     r5,epicISR@ha +	ori     r5,r5,epicISR@l +	mtlr    r5 +	blrl + +    xor   r30,r30,r30 +	or    r30,r30,r3        /* save the r3 which containts the return value from epicISR */ + +	/* ---READ IN THE EUMBAR REGISTER */ +    lwz     r3,0(r1) +    sync + +    lis     r5,epicEOI@ha +	ori     r5,r5,epicEOI@l +	mtlr    r5 +	blrl + +    xor  r3,r3,r3 +	or   r3,r3,r30           /* restore the ISR return value  */ + +	bclr     20,0 diff --git a/cpu/mpc824x/drivers/epic/epicutil.S b/cpu/mpc824x/drivers/epic/epicutil.S new file mode 100644 index 000000000..a83fbd8d3 --- /dev/null +++ b/cpu/mpc824x/drivers/epic/epicutil.S @@ -0,0 +1,58 @@ +/************************************** + * + * copyright @ Motorola, 1999 + * + * + * This file contains two commonly used + * lower level utility routines. + * + * The utility routines are also in other + * Kahlua device driver libraries. The + * need to be linked in only once. + **************************************/ + +#include <ppc_asm.tmpl> +#include <ppc_defs.h> + +/********************************************************** + * function: load_runtime_reg + * + * input:  r3 - value of eumbbar + *         r4 - register offset in embedded utility space + * + * output: r3 - register content + **********************************************************/ +      .text +      .align 2 +      .global load_runtime_reg + +load_runtime_reg: + +		  xor r5,r5,r5 +          or  r5,r5,r3       /* save eumbbar */ + +	      lwbrx	r3,r4,r5 +	      sync + + 	      bclr 20, 0 + +/**************************************************************** + * function: store_runtime_reg + * + * input: r3 - value of eumbbar + *        r4 - register offset in embedded utility space + *        r5 - new value to be stored + * + ****************************************************************/ +           .text +           .align 2 +           .global store_runtime_reg +store_runtime_reg: + +		  xor r0,r0,r0 + +	      stwbrx r5,  r4, r3 +	      sync + +		  bclr   20,0 + diff --git a/cpu/mpc824x/drivers/errors.h b/cpu/mpc824x/drivers/errors.h new file mode 100644 index 000000000..143518809 --- /dev/null +++ b/cpu/mpc824x/drivers/errors.h @@ -0,0 +1,218 @@ +/*	Copyright Motorola, Inc. 1993, 1994 +	ALL RIGHTS RESERVED + +	You are hereby granted a copyright license to use, modify, and +	distribute the SOFTWARE so long as this entire notice is retained +	without alteration in any modified and/or redistributed versions, +	and that such modified versions are clearly identified as such. +	No licenses are granted by implication, estoppel or otherwise under +	any patents or trademarks of Motorola, Inc. + +	The SOFTWARE is provided on an "AS IS" basis and without warranty. +	To the maximum extent permitted by applicable law, MOTOROLA DISCLAIMS +	ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, INCLUDING IMPLIED +	WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR +	PURPOSE AND ANY WARRANTY AGAINST INFRINGEMENT WITH +	REGARD TO THE SOFTWARE (INCLUDING ANY MODIFIED VERSIONS +	THEREOF) AND ANY ACCOMPANYING WRITTEN MATERIALS. + +	To the maximum extent permitted by applicable law, IN NO EVENT SHALL +	MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER +	(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF +	BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS +	INFORMATION, OR OTHER PECUNIARY LOSS) ARISING OF THE USE OR +	INABILITY TO USE THE SOFTWARE.   Motorola assumes no responsibility +	for the maintenance and support of the SOFTWARE. + +*/ + + +#include "config.h" + +/* +         1         2         3         4         5         6         7         8 +01234567890123456789012345678901234567890123456789012345678901234567890123456789 +*/ +/* List define statements here */ + +/* These are for all the toolboxes and functions to use. These will help +to standardize the error handling in the current project */ + +				/* this is the "data type" for the error +				messages in the system */ +#define STATUS unsigned int + +				/* this is a success status code */ +#define SUCCESS 1 + +				/* likewise this is failure */ +#define FAILURE 0 + +#define NUM_ERRORS 47 + +/* This first section of "defines" are for error codes ONLY.  The called +   routine will return one of these error codes to the caller.  If the final +   returned code is "VALID", then everything is a-okay.  However, if one +   of the functions returns a non-valid status, that error code should be +   propogated back to all the callers.  At the end, the last caller will +   call an error_processing function, and send in the status which was +   returned.  It's up to the error_processing function to determine which +   error occured (as indicated by the status), and print an appropriate +   message back to the user. +*/ +/*----------------------------------------------------------------------*/ +/* these are specifically for the parser routines 			*/ + +#define UNKNOWN_COMMAND		0xfb00 /* "unrecognized command " */ +#define UNKNOWN_REGISTER	0xfb01 /* "unknown register "*/ +#define ILLEGAL_RD_STAGE	0xfb02 /* cannot specify reg. family in range*/ +#define ILLEGAL_REG_FAMILY	0xfb03 /* "cannot specify a range of special +					or miscellaneous registers"*/ +#define RANGE_CROSS_FAMILY	0xfb04 /* "cannot specify a range across +					register families" */ +#define UNIMPLEMENTED_STAGE	0xfb05 /* invalid rd or rmm parameter format */ +#define REG_NOT_WRITEABLE	0xfb06 /* "unknown operator in arguements"*/ +#define INVALID_FILENAME	0xfb07 /* "invalid download filename" */ +#define INVALID_BAUD_RATE	0xfb08 	/* invalid baud rate from sb command */ +#define UNSUPPORTED_REGISTER	0xfb09 	/* Special register is not supported */ +#define FOR_BOARD_ONLY		0xfb0a  /* "Not available for Unix." */ + + + +/*----------------------------------------------------------------------*/ +/* these are for the error checking toolbox				*/ + +#define INVALID			0xfd00 /* NOT valid */ +#define VALID			0xfd01 /* valid */ + +					/* This error is found in the fcn: +					is_right_size_input() to indicate +					that the input was not 8 characters +					long.  */ +#define INVALID_SIZE		0xfd02 + +					/* This error is found in the fcn: +					is_valid_address_range() to indicate +					that the address given falls outside +					of valid memory defined by MEM_START +					to MEM_END. +					*/ +#define OUT_OF_BOUNDS_ADDRESS	0xfd03 + +					/* This error is found in the fcn: +					is_valid_hex_input() to indicate that +					one of more of the characters entered +					are not valid hex characters.  Valid +					hex characters are 0-9, A-F, a-f. +					*/ +#define INVALID_HEX_INPUT	0xfd04 + +					/* This error is found in the fcn: +					is_valid_register_number() to indicate +					that a given register does not exist. +					*/ +#define REG_NOT_READABLE	0xfd05 + +					/* This error is found in the fcn: +					is_word_aligned_address() to indicate +					that the given address is not word- +					aligned.  A word-aligned address ends +					in 0x0,0x4,0x8,0xc. +					*/ +#define	NOT_WORD_ALIGNED	0xfd07 + +					/* This error is found in the fcn: +					is_valid_address_range() to indicate +					that the starting address is greater +					than the ending address. +					*/ +#define REVERSED_ADDRESS	0xfd08 + +					/* this error tells us that the address +					specified as the destination is within +					the source addresses  */ +#define RANGE_OVERLAP		0xfd09 + + +#define	ERROR			0xfd0a /* An error occured */ +#define INVALID_PARAM		0xfd0b /* "invalid input parameter " */ + + +#define INVALID_FLAG		0xfd0c	/* invalid flag */ + +/*----------------------------------------------------------------------*/ +/* these are for the getarg toolbox 					*/ + +#define INVALID_NUMBER_ARGS 	0xFE00 /* invalid number of commd arguements */ +#define UNKNOWN_PARAMETER	0xFE01 /* "unknown type of parameter "*/ + + + + + +/*----------------------------------------------------------------------*/ +/* these are for the tokenizer toolbox 					*/ + +#define ILLEGAL_CHARACTER 	0xFF00 /* unrecognized char. in input stream*/ +#define TTL_NOT_SORTED 		0xFF01 /* token translation list not sorted */ +#define TTL_NOT_DEFINED 	0xFF02 /* token translation list not assigned*/ +#define INVALID_STRING 		0xFF03 /* unable to extract string from input */ +#define BUFFER_EMPTY 		0xFF04 /* "input buffer is empty" */ +#define INVALID_MODE		0xFF05 /* input buf is in an unrecognized mode*/ +#define TOK_INTERNAL_ERROR	0xFF06 /* "internal tokenizer error" */ +#define TOO_MANY_IBS		0xFF07 /* "too many open input buffers" */ +#define NO_OPEN_IBS		0xFF08 /* "no open input buffers" */ + + + +/* these are for the read from screen toolbox */ + +#define RESERVED_WORD		0xFC00 /* used a reserved word as an arguement*/ + + +/* these are for the breakpoint routines */ + +#define FULL_BPDS		0xFA00 /* breakpoint data structure is full */ + + + +/* THESE are for the downloader */ + +#define NOT_IN_S_RECORD_FORMAT 	0xf900 /* "not in S-Record Format" */ +#define UNREC_RECORD_TYPE	0xf901 /* "unrecognized record type" */ +#define CONVERSION_ERROR	0xf902 /* "ascii to int conversion error" */ +#define INVALID_MEMORY		0xf903 /* "bad s-record memory address " */ + + +/* these are for the compression and decompression stuff */ + +#define COMP_UNK_CHARACTER	0xf800 /* "unknown compressed character " */ + +#define COMP_UNKNOWN_STATE	0xf801 /* "unknown binary state" */ + +#define NOT_IN_COMPRESSED_FORMAT 0xf802 /* not in compressed S-Record format */ + + +/* these are for the DUART handling things */ + +					/* "unrecognized serial port configuration" */ +#define UNKNOWN_PORT_STATE 	0xf700 + + +/* these are for the register toolbox */ + +					/* "cannot find register in special +					 purpose register file " */ +#define SPR_NOT_FOUND		0xf600 + + +/* these are for the duart specific stuff */ + +					/* "transparent mode needs access to +						two serial ports" */ +#define TM_NEEDS_BOTH_PORTS	0xf500 + + +/*----------------------------------------------------------------------*/ +/* these are specifically for the flash routines 			*/ +#define FLASH_ERROR	 	0xf100		/* general flash error */ diff --git a/cpu/mpc824x/drivers/i2c/Makefile b/cpu/mpc824x/drivers/i2c/Makefile new file mode 100644 index 000000000..ae1a94c53 --- /dev/null +++ b/cpu/mpc824x/drivers/i2c/Makefile @@ -0,0 +1,84 @@ +########################################################################## +# +#       Copyright Motorola, Inc. 1997 +#       ALL RIGHTS RESERVED +# +#       You are hereby granted a copyright license to use, modify, and +#       distribute the SOFTWARE so long as this entire notice is retained +#       without alteration in any modified and/or redistributed versions, +#       and that such modified versions are clearly identified as such. +#       No licenses are granted by implication, estoppel or otherwise under +#       any patents or trademarks of Motorola, Inc. +# +#       The SOFTWARE is provided on an "AS IS" basis and without warranty. +#       To the maximum extent permitted by applicable law, MOTOROLA DISCLAIMS +#       ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, INCLUDING IMPLIED +#       WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR +#       PURPOSE AND ANY WARRANTY AGAINST INFRINGEMENT WITH +#       REGARD TO THE SOFTWARE (INCLUDING ANY MODIFIED VERSIONS +#       THEREOF) AND ANY ACCOMPANYING WRITTEN MATERIALS. +# +#       To the maximum extent permitted by applicable law, IN NO EVENT SHALL +#       MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER +#       (INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF +#       BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS +#       INFORMATION, OR OTHER PECUNIARY LOSS) ARISING OF THE USE OR +#       INABILITY TO USE THE SOFTWARE. +# +############################################################################ +TARGET = libi2c.a + +#DEBUG  = -g +DEBUG   = -DI2CDBG +LST     = -Hanno -S +OPTIM   = +CC      = /risc/tools/pkgs/metaware/bin/hcppc +CFLAGS  = -Hnocopyr -c -Hsds -Hon=Char_default_unsigned -Hon=Char_is_rep -I../inc -I/risc/tools/pkgs/metaware/inc +CCobj   = $(CC) $(CFLAGS) $(DEBUG) $(OPTIM) +PREP    = $(CC) $(CFLAGS) -P + +# Assembler used to build the .s files (for the board version) + +ASOPT   = -big_si -c +ASDEBUG = -l -fm +AS      = /risc/tools/pkgs/metaware/bin/asppc + +# Linker to bring .o files together into an executable. + +LKOPT	=  -Bbase=0 -q -Qn -r +LKCMD   = +LINK    =  /risc/tools/pkgs/metaware/bin/ldppc $(LKCMD) $(LKOPT) + +# DOS Utilities + +DEL     = rm +COPY    = cp +LIST    = ls + +OBJECTS = i2c1.o i2c2.o + +all: $(TARGET) + +objects: $(OBJECTS) + +$(TARGET): $(OBJECTS) +	$(LINK) $(OBJECTS) -o $@ + +clean: +	$(DEL) -f *.o *.i *.map *.lst $(TARGET) $(OBJECTS) + +.s.o: +	$(DEL) -f $*.i +	$(PREP) -Hasmcpp $< +	$(AS) $(ASOPT) $*.i +#	$(AS) $(ASOPT) $(ASDEBUG) $*.i > $*.lst + +.c.o: +	$(CCobj) $< + +.c.s: +	$(CCobj) $(LST) $< + +i2c1.o: i2c_export.h i2c.h i2c1.c + +i2c2.o: i2c.h i2c2.s diff --git a/cpu/mpc824x/drivers/i2c/Makefile_pc b/cpu/mpc824x/drivers/i2c/Makefile_pc new file mode 100644 index 000000000..4d42c7b84 --- /dev/null +++ b/cpu/mpc824x/drivers/i2c/Makefile_pc @@ -0,0 +1,91 @@ +########################################################################## +# +#       makefile_pc for use with PC mksnt tools  dink32/drivers/i2c +# +#       Copyright Motorola, Inc. 1997 +#       ALL RIGHTS RESERVED +# +#       You are hereby granted a copyright license to use, modify, and +#       distribute the SOFTWARE so long as this entire notice is retained +#       without alteration in any modified and/or redistributed versions, +#       and that such modified versions are clearly identified as such. +#       No licenses are granted by implication, estoppel or otherwise under +#       any patents or trademarks of Motorola, Inc. +# +#       The SOFTWARE is provided on an "AS IS" basis and without warranty. +#       To the maximum extent permitted by applicable law, MOTOROLA DISCLAIMS +#       ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, INCLUDING IMPLIED +#       WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR +#       PURPOSE AND ANY WARRANTY AGAINST INFRINGEMENT WITH +#       REGARD TO THE SOFTWARE (INCLUDING ANY MODIFIED VERSIONS +#       THEREOF) AND ANY ACCOMPANYING WRITTEN MATERIALS. +# +#       To the maximum extent permitted by applicable law, IN NO EVENT SHALL +#       MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER +#       (INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF +#       BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS +#       INFORMATION, OR OTHER PECUNIARY LOSS) ARISING OF THE USE OR +#       INABILITY TO USE THE SOFTWARE. +# +############################################################################ +TARGET = libi2c.a + +#DEBUG  = -g +DEBUG   = -DI2CDBG +LST     = -Hanno -S +OPTIM   = +CC      = m:/old_tools/tools/hcppc/bin/hcppc +CFLAGS  = -Hnocopyr -c -Hsds -Hon=Char_default_unsigned -Hon=Char_is_rep -I../inc -I/risc/tools/pkgs/metaware/inc +CCobj   = $(CC) $(CFLAGS) $(DEBUG) $(OPTIM) +PREP    = $(CC) $(CFLAGS) -P + +# Assembler used to build the .s files (for the board version) + +ASOPT   = -big_si -c +ASDEBUG = -l -fm +AS      = m:/old_tools/tools/hcppc/bin/asppc + +# Linker to bring .o files together into an executable. + +LKOPT	=  -Bbase=0 -q -Qn -r +LKCMD   = +LINK    = m:/old_tools/tools/hcppc/bin/ldppc $(LKCMD) $(LKOPT) + +# DOS Utilities + +DEL     = rm +COPY    = cp +LIST    = ls + +OBJECTS = i2c1.o i2c2.o + +all: $(TARGET) + +objects: $(OBJECTS) + +$(TARGET): $(OBJECTS) +	$(LINK) $(OBJECTS) -o $@ + +clean: +	$(DEL) -f *.o *.i *.map *.lst $(TARGET) $(OBJECTS) + +.s.o: +	$(DEL) -f $*.i +	$(PREP) -Hasmcpp $< +	$(AS) $(ASOPT) $*.i +#	$(AS) $(ASOPT) $(ASDEBUG) $*.i > $*.lst + +.c.o: +	$(CCobj) $< + +.c.s: +	$(CCobj) $(LST) $< + +i2c1.o: i2c_export.h i2c.h i2c1.c +	$(CCobj) $< + + +i2c2.o: i2c.h i2c2.s +	$(DEL) -f $*.i +	$(PREP) -Hasmcpp $< +	$(AS) $(ASOPT) $*.i diff --git a/cpu/mpc824x/drivers/i2c/README b/cpu/mpc824x/drivers/i2c/README new file mode 100644 index 000000000..8d82df359 --- /dev/null +++ b/cpu/mpc824x/drivers/i2c/README @@ -0,0 +1,105 @@ +CONTENT: + +   i2c.h +   i2c1.c +   i2c2.s + +WHAT ARE THESE FILES: + +These files contain MPC8240 (Kahlua) I2C +driver routines. The driver routines are not +written for any specific operating system. +They serves the purpose of code sample, and +jump-start for using the MPC8240 I2C unit. + +For the reason of correctness of C language +syntax, these files are compiled by Metaware +C compiler and assembler. + +ENDIAN NOTATION: + +The algorithm is designed for big-endian mode, +software is responsible for byte swapping. + +USAGE: + +1. The host system that is running on MPC8240 +   shall link the files listed here. The memory +   location of driver routines shall take into +   account of that driver routines need to run +   in supervisor mode and they process I2C +   interrupt. + +2. The host system is responsible for configuring +   the MPC8240 including Embedded Utilities Memory +   Block. All I2C driver functions require the +   content of Embedded Utilities Memory Block +   Base Address Register, EUMBBAR, as the first +   parameter. + +3. Before I2C unit of MPC8240 can be used, +   initialize I2C unit by calling I2C_Init +   with the corresponding parameters. + +   Note that the I2CFDR register shall be written +   once during the initialization. If it is written +   in the midst of transers, or after I2C STOPs or +   REPEAT STATRs, depending on the data written, +   a long reset time may be encountered. + +4. After I2C unit has been successfully initialized, +   use the Application level API to send data or +   receive data upon the desired mode, Master or +   Slave. + +5. If the host system is also using the EPIC unit +   on MPC8240, the system can register the +   I2C_ISR with the EPIC including other +   desired resources. + +   If the host system does not using the EPIC unit +   on MPC8240, I2C_Timer_Event function can +   be called for each desired time interval. + +   In both cases, the host system is free to provide +   its own timer event handler and interrupt service +   routine. + +6. The I2C driver routines contains a set +   of utilities, Set and Get, for host system +   to query and modify the desired I2C registers. + +7. It is the host system's responsibility of +   queueing the I2C I/O request. The host +   system shall check the I2C_ISR return code +   for I2C I/O status. If I2C_ISR returns +   I2CBUFFEMPTY or I2CBUFFFULL, it means +   I2C unit has completed a I/O request +   stated by the Application API. + +8. If the host system has more than one master +   mode I2C unit I/O requests but doesn't want +   to be intervented by being addressed as slave, +   the host system can use the master mode +   Application API with stop_flag set to 0 in +   conjunction with is_cnt flag set to 1. +   The first API call sets both stop_flag and +   is_cnt to 0, indicating a START condition +   shall be generated but when the end of +   transaction is reached, do not generate a +   STOP condition. Once the host system is +   informed that the transaction has been +   completed, the next Application API call +   shall set is_cnt flag to 1, indicating a +   repeated START condition shall be generated. +   The last Application API call shall set +   stop_flag +   to 1. + +9. The I2C_Timer_Event function containes +   a user defined function pointer. It +   serves the purpose of providing the +   host system a way to use its own event +   handler instead of the I2C_ISR provided +   here. + diff --git a/cpu/mpc824x/drivers/i2c/i2c_export.h b/cpu/mpc824x/drivers/i2c/i2c_export.h new file mode 100644 index 000000000..17403ea2c --- /dev/null +++ b/cpu/mpc824x/drivers/i2c/i2c_export.h @@ -0,0 +1,103 @@ +#ifndef I2C_EXPORT_H +#define I2C_EXPORT_H + +/**************************************************** + * + * Copyright Motrola 1999 + * + ****************************************************/ + +/* These are the defined return values for the I2C_do_transaction function. + * Any non-zero value indicates failure.  Failure modes can be added for + * more detailed error reporting. + */ +typedef enum _i2c_status +{ + I2C_SUCCESS     = 0, + I2C_ERROR, +} I2C_Status; + +/* These are the defined tasks for I2C_do_transaction. + * Modes for SLAVE_RCV and SLAVE_XMIT will be added. + */ +typedef enum _i2c_transaction_mode +{ +	I2C_MASTER_RCV =  0, +	I2C_MASTER_XMIT = 1, +} I2C_TRANSACTION_MODE; + +typedef enum _i2c_interrupt_mode +{ +	I2C_INT_DISABLE =  0, +	I2C_INT_ENABLE = 1, +} I2C_INTERRUPT_MODE; + +typedef enum _i2c_stop +{ +	I2C_NO_STOP =  0, +	I2C_STOP = 1, +} I2C_STOP_MODE; + +typedef enum _i2c_restart +{ +	I2C_NO_RESTART =  0, +	I2C_RESTART = 1, +} I2C_RESTART_MODE; + +/******************** App. API ******************** + * The application API is for user level application + * to use the functionality provided by I2C driver. + * This is a "generic" I2C interface, it should contain + * nothing specific to the Kahlua implementation. + * Only the generic functions are exported by the library. + * + * Note: Its App.s responsibility to swap the data + *       byte. In our API, we just transfer whatever + *       we are given + **************************************************/ + + +/*  Initialize I2C unit with the following: + *  driver's slave address + *  interrupt enabled + *  optional pointer to application layer print function + * + *  These parameters may be added: + *  desired clock rate + *  digital filter frequency sampling rate + * + *  This function must be called before I2C unit can be used. + */ +extern I2C_Status I2C_Initialize( +	unsigned char addr,            /* driver's I2C slave address */ +	I2C_INTERRUPT_MODE en_int,     /* 1 - enable I2C interrupt +	                                * 0 - disable I2C interrupt +	                                */ +        int (*app_print_function)(char *,...)); /* pointer to optional "printf" +                                                 * provided by application +                                                 */ + +/* Perform the given I2C transaction, only MASTER_XMIT and MASTER_RCV + * are implemented.  Both are only in polling mode. + * + * en_int controls interrupt/polling mode + * act is the type of transaction + * addr is the I2C address of the slave device + * len is the length of data to send or receive + * buffer is the address of the data buffer + * stop = I2C_NO_STOP, don't signal STOP at end of transaction + *        I2C_STOP, signal STOP at end of transaction + * retry is the timeout retry value, currently ignored + * rsta = I2C_NO_RESTART, this is not continuation of existing transaction + *        I2C_RESTART, this is a continuation of existing transaction + */ +extern I2C_Status I2C_do_transaction( I2C_INTERRUPT_MODE en_int, +                                      I2C_TRANSACTION_MODE act, +                                      unsigned char i2c_addr, +                                      unsigned char data_addr, +                                      int len, +                                      char *buffer, +                                      I2C_STOP_MODE stop, +                                      int retry, +                                      I2C_RESTART_MODE rsta); +#endif diff --git a/cpu/mpc824x/drivers/i2c_export.h b/cpu/mpc824x/drivers/i2c_export.h new file mode 100644 index 000000000..17403ea2c --- /dev/null +++ b/cpu/mpc824x/drivers/i2c_export.h @@ -0,0 +1,103 @@ +#ifndef I2C_EXPORT_H +#define I2C_EXPORT_H + +/**************************************************** + * + * Copyright Motrola 1999 + * + ****************************************************/ + +/* These are the defined return values for the I2C_do_transaction function. + * Any non-zero value indicates failure.  Failure modes can be added for + * more detailed error reporting. + */ +typedef enum _i2c_status +{ + I2C_SUCCESS     = 0, + I2C_ERROR, +} I2C_Status; + +/* These are the defined tasks for I2C_do_transaction. + * Modes for SLAVE_RCV and SLAVE_XMIT will be added. + */ +typedef enum _i2c_transaction_mode +{ +	I2C_MASTER_RCV =  0, +	I2C_MASTER_XMIT = 1, +} I2C_TRANSACTION_MODE; + +typedef enum _i2c_interrupt_mode +{ +	I2C_INT_DISABLE =  0, +	I2C_INT_ENABLE = 1, +} I2C_INTERRUPT_MODE; + +typedef enum _i2c_stop +{ +	I2C_NO_STOP =  0, +	I2C_STOP = 1, +} I2C_STOP_MODE; + +typedef enum _i2c_restart +{ +	I2C_NO_RESTART =  0, +	I2C_RESTART = 1, +} I2C_RESTART_MODE; + +/******************** App. API ******************** + * The application API is for user level application + * to use the functionality provided by I2C driver. + * This is a "generic" I2C interface, it should contain + * nothing specific to the Kahlua implementation. + * Only the generic functions are exported by the library. + * + * Note: Its App.s responsibility to swap the data + *       byte. In our API, we just transfer whatever + *       we are given + **************************************************/ + + +/*  Initialize I2C unit with the following: + *  driver's slave address + *  interrupt enabled + *  optional pointer to application layer print function + * + *  These parameters may be added: + *  desired clock rate + *  digital filter frequency sampling rate + * + *  This function must be called before I2C unit can be used. + */ +extern I2C_Status I2C_Initialize( +	unsigned char addr,            /* driver's I2C slave address */ +	I2C_INTERRUPT_MODE en_int,     /* 1 - enable I2C interrupt +	                                * 0 - disable I2C interrupt +	                                */ +        int (*app_print_function)(char *,...)); /* pointer to optional "printf" +                                                 * provided by application +                                                 */ + +/* Perform the given I2C transaction, only MASTER_XMIT and MASTER_RCV + * are implemented.  Both are only in polling mode. + * + * en_int controls interrupt/polling mode + * act is the type of transaction + * addr is the I2C address of the slave device + * len is the length of data to send or receive + * buffer is the address of the data buffer + * stop = I2C_NO_STOP, don't signal STOP at end of transaction + *        I2C_STOP, signal STOP at end of transaction + * retry is the timeout retry value, currently ignored + * rsta = I2C_NO_RESTART, this is not continuation of existing transaction + *        I2C_RESTART, this is a continuation of existing transaction + */ +extern I2C_Status I2C_do_transaction( I2C_INTERRUPT_MODE en_int, +                                      I2C_TRANSACTION_MODE act, +                                      unsigned char i2c_addr, +                                      unsigned char data_addr, +                                      int len, +                                      char *buffer, +                                      I2C_STOP_MODE stop, +                                      int retry, +                                      I2C_RESTART_MODE rsta); +#endif diff --git a/cpu/mpc824x/drivers/i2o.h b/cpu/mpc824x/drivers/i2o.h new file mode 100644 index 000000000..87225ab16 --- /dev/null +++ b/cpu/mpc824x/drivers/i2o.h @@ -0,0 +1,344 @@ +#ifndef I2O_H +#define I2O_H +/********************************************************* + * + * copyright @ Motorola, 1999 + *********************************************************/ + +#define I2O_REG_OFFSET 0x0004 + +#define PCI_CFG_CLA    0x0B +#define PCI_CFG_SCL    0x0A +#define PCI_CFG_PIC    0x09 + +#define I2O_IMR0 0x0050 +#define I2O_IMR1 0x0054 +#define I2O_OMR0 0x0058 +#define I2O_OMR1 0x005C + +#define I2O_ODBR 0x0060 +#define I2O_IDBR 0x0068 + +#define I2O_OMISR  0x0030 +#define I2O_OMIMR  0x0034 +#define I2O_IMISR  0x0100 +#define I2O_IMIMR  0x0104 + +/* accessable to PCI master but local processor */ +#define I2O_IFQPR  0x0040 +#define I2O_OFQPR  0x0044 + +/* accessable to local processor */ +#define I2O_IFHPR  0x0120 +#define I2O_IFTPR  0x0128 +#define I2O_IPHPR  0x0130 +#define I2O_IPTPR  0x0138 +#define I2O_OFHPR  0x0140 +#define I2O_OFTPR  0x0148 +#define I2O_OPHPR  0x0150 +#define I2O_OPTPR  0x0158 +#define I2O_MUCR   0x0164 +#define I2O_QBAR   0x0170 + +#define I2O_NUM_MSG 2 + +typedef enum _i2o_status +{ +	I2OSUCCESS = 0, +	I2OINVALID, +	I2OMSGINVALID, +	I2ODBINVALID, +	I2OQUEINVALID, +	I2OQUEEMPTY, +	I2OQUEFULL, +	I2ONOEVENT, +} I2OSTATUS; + +typedef enum _queue_size +{ +    QSIZE_4K = 0x02, +    QSIZE_8K = 0x04, +    QSIZE_16K = 0x08, +    QSIZE_32K = 0x10, +    QSIZe_64K = 0x20, +} QUEUE_SIZE; + +typedef enum _location +{ +    LOCAL = 0,     /* used by local processor to access its own on board device, +		      local processor's eumbbar is required */ +    REMOTE,        /* used by PCI master to access the devices on its PCI device, +		      device's pcsrbar is required */ +} LOCATION; + +/* door bell */ +typedef enum _i2o_in_db +{ +  IN_DB = 1, +  MC,         /* machine check */ +} I2O_IN_DB; + +/* I2O PCI configuration identification */ +typedef struct _i2o_iop +{ +	unsigned int base_class : 8; +	unsigned int sub_class  : 8; +	unsigned int prg_code   : 8; +} I2OIOP; + +/* I2O Outbound Message Interrupt Status Register */ +typedef struct _i2o_om_stat +{ +	unsigned int rsvd0 : 26; +	unsigned int opqi  : 1; +	unsigned int rsvd1 : 1; +	unsigned int odi   : 1; +	unsigned int rsvd2 : 1; +	unsigned int om1i  : 1; +	unsigned int om0i  : 1; +} I2OOMSTAT; + +/* I2O inbound Message Interrupt Status Register */ +typedef struct _i2o_im_stat +{ +	unsigned int rsvd0 : 23; +	unsigned int ofoi  : 1; +	unsigned int ipoi  : 1; +	unsigned int rsvd1 : 1; +	unsigned int ipqi  : 1; +	unsigned int mci   : 1; +	unsigned int idi   : 1; +	unsigned int rsvd2 : 1; +	unsigned int im1i  : 1; +	unsigned int im0i  : 1; +} I2OIMSTAT; + +/** + Enable the interrupt associated with in/out bound msg + + Inbound message interrupt generated by PCI master and serviced by local processor + local processor needs to enable its inbound interrupts it wants to handle (LOCAL) + + Outbound message interrupt generated by local processor and serviced by PCI master + PCI master needs to enable the devices' outbound interrupts it wants to handle (REMOTE) + **/ +extern I2OSTATUS I2OMsgEnable( LOCATION,            /*  REMOTE/LOCAL   */ +                               unsigned int base,   /* pcsrbar/eumbbar */ +                               unsigned char n );   /* b'1' - msg 0 +						                             * b'10'- msg 1 +						                             * b'11'- both +						                             */ + +/** + Disable the interrupt associated with in/out bound msg + + local processor needs to disable its inbound interrupts it is not interested (LOCAL) + + PCI master needs to disable outbound interrupts of devices it is not interested (REMOTE) + **/ +extern I2OSTATUS I2OMsgDisable( LOCATION,          /*  REMOTE/LOCAL   */ +                                unsigned int base, /* pcsrbar/eumbbar */ +                                unsigned char n ); /* b'1' - msg 0 +			   			                            * b'10'- msg 1 +						                            * b'11'- both +						                            */ + +/** + Read the msg register either from local inbound msg 0/1, + or an outbound msg 0/1 of devices. + + If it is not local, pcsrbar must be passed to the function. + Otherwise eumbbar is passed. + + If it is remote, outbound msg of the device is read. + Otherwise local inbound msg is read. + **/ +extern I2OSTATUS I2OMsgGet ( LOCATION,                 /* REMOTE/LOCAL */ +                             unsigned int base,        /*pcsrbar/eumbbar */ +                             unsigned int n,           /* 0 or 1 */ +                             unsigned int *msg ); + +/** + Write to nth Msg register either on local outbound msg 0/1, + or aninbound msg 0/1 of devices + + If it is not local, pcsrbar must be passed to the function. + Otherwise eumbbar is passed. + + If it is remote, inbound msg on the device is written. + Otherwise local outbound msg is written. + **/ +extern I2OSTATUS I2OMsgPost( LOCATION,                 /* REMOTE/LOCAL */ +                                unsigned int base,        /*pcsrbar/eumbbar */ +                                unsigned int n,           /* 0 or 1 */ +                                unsigned int msg ); + +/** + Enable the In/Out DoorBell Interrupt + + InDoorBell interrupt is generated by PCI master and serviced by local processor + local processor needs to enable its inbound doorbell interrupts it wants to handle + + OutDoorbell interrupt is generated by local processor and serviced by PCI master + PCI master needs to enable outbound doorbell interrupts of the devices it wants to handle + **/ +extern I2OSTATUS I2ODBEnable( LOCATION,            /*  REMOTE/LOCAL   */ +                              unsigned int base,   /* pcsrbar/eumbbar */ +                              unsigned int in_db );/* when LOCAL, I2O_IN_DB, MC, I2O_IN_DB|MC */ + +/** + Disable the In/Out DoorBell Interrupt + + local processor needs to disable its inbound doorbell interrupts it is not interested + + PCI master needs to disable outbound doorbell interrupts of devices it is not interested + + **/ +extern I2OSTATUS I2ODBDisable( LOCATION,              /*  REMOTE/LOCAL   */ +                               unsigned int base,     /* pcsrbar/eumbbar */ +                               unsigned int in_db );  /* when LOCAL, I2O_IN_DB, MC, I2O_IN_DB|MC */ + +/** + Read a local indoorbell register, or an outdoorbell of devices. + Reading a doorbell register, the register will be cleared. + + If it is not local, pcsrbar must be passed to the function. + Otherwise eumbbar is passed. + + If it is remote, outdoorbell register on the device is read. + Otherwise local in doorbell is read + **/ +extern unsigned int I2ODBGet( LOCATION,             /*  REMOTE/LOCAL   */ +                              unsigned int base);   /* pcsrbar/eumbbar */ + +/** + Write to a local outdoorbell register, or an indoorbell register of devices. + + If it is not local, pcsrbar must be passed to the function. + Otherwise eumbbar is passed. + + If it is remote, in doorbell register on the device is written. + Otherwise local out doorbell is written + **/ +extern void I2ODBPost( LOCATION,                 /*  REMOTE/LOCAL   */ +                       unsigned int base,        /* pcsrbar/eumbbar */ +                       unsigned int msg );       /*   in   / out    */ + +/** + Read the outbound msg unit interrupt status of devices. Reading an interrupt status register, + the register will be cleared. + + The outbound interrupt status is AND with the outbound + interrupt mask. The result is returned. + + PCI master must pass the pcsrbar to the function. + **/ +extern I2OSTATUS I2OOutMsgStatGet( unsigned int pcsrbar, I2OOMSTAT * ); + +/** + Read the inbound msg unit interrupt status. Reading an interrupt status register, + the register will be cleared. + + The inbound interrupt status is AND with the inbound + interrupt mask. The result is returned. + + Local process must pass its eumbbar to the function. +**/ +extern I2OSTATUS I2OInMsgStatGet( unsigned int eumbbar, I2OIMSTAT * ); + +/** + Configure the I2O FIFO, including QBAR, IFHPR/IFTPR,IPHPR/IPTPR,OFHPR/OFTPR, OPHPR/OPTPR, + MUCR. + **/ +extern I2OSTATUS I2OFIFOInit( unsigned int eumbbar, +				              QUEUE_SIZE, +				              unsigned int qba);/* queue base address that must be aligned at 1M */ +/** + Enable the circular queue + **/ +extern I2OSTATUS I2OFIFOEnable( unsigned int eumbbar ); + +/** + Disable the circular queue + **/ +extern void I2OFIFODisable( unsigned int eumbbar ); + +/** + Enable the circular queue interrupt + PCI master enables outbound FIFO interrupt of device + Device enables its inbound FIFO interrupt + **/ +extern void I2OFIFOIntEnable( LOCATION, unsigned int base  ); + +/** + Disable the circular queue interrupt + PCI master disables outbound FIFO interrupt of device + Device disables its inbound FIFO interrupt + **/ +extern void I2OFIFOIntDisable( LOCATION, unsigned int base ); + +/** + Enable the circular queue overflow interrupt + **/ +extern void I2OFIFOOverflowIntEnable( unsigned int eumbbar ); + +/** + Disable the circular queue overflow interrupt + **/ +extern void I2OFIFOOverflowIntDisable( unsigned int eumbbar ); + +/** + Allocate a free msg frame from free FIFO. + + PCI Master allocates a free msg frame through inbound queue port of device(IFQPR) + while local processor allocates a free msg frame from outbound free queue(OFTPR) + + Unless both free queues are initialized, allocating a free MF will return 0xffffffff + **/ +extern I2OSTATUS I2OFIFOAlloc( LOCATION, +			 	               unsigned int base, +				               void         **pMsg); +/** + Free a used msg frame back to free queue + PCI Master frees a MFA through outbound queue port of device(OFQPR) + while local processor frees a MFA into its inbound free queue(IFHPR) + + Used msg frame does not need to be recycled in the order they + read + + This function has to be called by PCI master to initialize Inbound free queue + and by device to initialize Outbound free queue before I2OFIFOAlloc can be used. + **/ +extern I2OSTATUS I2OFIFOFree( LOCATION, +			                  unsigned int base, +			                  void        *pMsg ); + +/** + Post a msg into FIFO + PCI Master posts a msg through inbound queue port of device(IFQPR) + while local processor post a msg into its outbound post queue(OPHPR) + + The total number of msg must be less than the max size of the queue + Otherwise queue overflow interrupt will assert. + **/ +extern I2OSTATUS I2OFIFOPost( LOCATION, +		                      unsigned int base, +		                      void         *pMsg ); + +/** + Read a msg from FIFO + PCI Master reads a msg through outbound queue port of device(OFQPR) + while local processor reads a msg from its inbound post queue(IPTPR) + **/ +extern I2OSTATUS I2OFIFOGet( LOCATION, +	 		                  unsigned int base, +							  void     **pMsg ); + +/** + Get the I2O PCI configuration identification register + **/ +extern I2OSTATUS I2OPCIConfigGet( LOCATION, +			                   unsigned int base, +							   I2OIOP *); + +#endif diff --git a/cpu/mpc824x/drivers/i2o/Makefile b/cpu/mpc824x/drivers/i2o/Makefile new file mode 100644 index 000000000..3f5ca2668 --- /dev/null +++ b/cpu/mpc824x/drivers/i2o/Makefile @@ -0,0 +1,84 @@ +########################################################################## +# +#       Copyright Motorola, Inc. 1997 +#       ALL RIGHTS RESERVED +# +#       You are hereby granted a copyright license to use, modify, and +#       distribute the SOFTWARE so long as this entire notice is retained +#       without alteration in any modified and/or redistributed versions, +#       and that such modified versions are clearly identified as such. +#       No licenses are granted by implication, estoppel or otherwise under +#       any patents or trademarks of Motorola, Inc. +# +#       The SOFTWARE is provided on an "AS IS" basis and without warranty. +#       To the maximum extent permitted by applicable law, MOTOROLA DISCLAIMS +#       ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, INCLUDING IMPLIED +#       WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR +#       PURPOSE AND ANY WARRANTY AGAINST INFRINGEMENT WITH +#       REGARD TO THE SOFTWARE (INCLUDING ANY MODIFIED VERSIONS +#       THEREOF) AND ANY ACCOMPANYING WRITTEN MATERIALS. +# +#       To the maximum extent permitted by applicable law, IN NO EVENT SHALL +#       MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER +#       (INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF +#       BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS +#       INFORMATION, OR OTHER PECUNIARY LOSS) ARISING OF THE USE OR +#       INABILITY TO USE THE SOFTWARE. +# +############################################################################ +TARGET = libi2o.a + +#DEBUG  = -g +DEBUG   = +LST     = -Hanno -S +OPTIM   = +CC      = /risc/tools/pkgs/metaware/bin/hcppc +CFLAGS  = -Hnocopyr -c -Hsds -Hon=Char_default_unsigned -Hon=Char_is_rep -I../inc -I/risc/tools/pkgs/metaware/inc +CCobj   = $(CC) $(CFLAGS) $(DEBUG) $(OPTIM) +PREP    = $(CC) $(CFLAGS) -P + +# Assembler used to build the .s files (for the board version) + +ASOPT   = -big_si -c +ASDEBUG  = -l -fm +AS      = /risc/tools/pkgs/metaware/bin/asppc + +# Linker to bring .o files together into an executable. + +LKOPT	=  -Bbase=0 -Qn -q -r +LKCMD    = +LINK    =  /risc/tools/pkgs/metaware/bin/ldppc $(LKCMD) $(LKOPT) + +# DOS Utilities + +DEL     = rm +COPY    = cp +LIST    = ls + +OBJECTS = i2o1.o i2o2.o + +all: $(TARGET) + +$(TARGET): $(OBJECTS) +	$(LINK) $(OBJECTS) -o $@ + +objects: i2o1.o + +clean: +	$(DEL) -f *.o *.i *.map *.lst $(TARGET) $(OBJECTS) + +.s.o: +	$(DEL) -f $*.i +	$(PREP) -Hasmcpp $< +	$(AS) $(ASOPT) $*.i +#	$(AS) $(ASOPT) $(ASDEBUG) $*.i > $*.lst + +.c.o: +	$(CCobj) $< + +.c.s: +	$(CCobj) $(LST) $< + +i2o1.o: i2o.h i2o1.c + +i2o2.o: i2o.h i2o2.s diff --git a/cpu/mpc824x/drivers/i2o/Makefile_pc b/cpu/mpc824x/drivers/i2o/Makefile_pc new file mode 100644 index 000000000..6867f5837 --- /dev/null +++ b/cpu/mpc824x/drivers/i2o/Makefile_pc @@ -0,0 +1,90 @@ +########################################################################## +# +#      makefile_pc for use with PC mksnt tools   dink32/drivers/i2o +# +#       Copyright Motorola, Inc. 1997 +#       ALL RIGHTS RESERVED +# +#       You are hereby granted a copyright license to use, modify, and +#       distribute the SOFTWARE so long as this entire notice is retained +#       without alteration in any modified and/or redistributed versions, +#       and that such modified versions are clearly identified as such. +#       No licenses are granted by implication, estoppel or otherwise under +#       any patents or trademarks of Motorola, Inc. +# +#       The SOFTWARE is provided on an "AS IS" basis and without warranty. +#       To the maximum extent permitted by applicable law, MOTOROLA DISCLAIMS +#       ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, INCLUDING IMPLIED +#       WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR +#       PURPOSE AND ANY WARRANTY AGAINST INFRINGEMENT WITH +#       REGARD TO THE SOFTWARE (INCLUDING ANY MODIFIED VERSIONS +#       THEREOF) AND ANY ACCOMPANYING WRITTEN MATERIALS. +# +#       To the maximum extent permitted by applicable law, IN NO EVENT SHALL +#       MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER +#       (INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF +#       BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS +#       INFORMATION, OR OTHER PECUNIARY LOSS) ARISING OF THE USE OR +#       INABILITY TO USE THE SOFTWARE. +# +############################################################################ +TARGET = libi2o.a + +#DEBUG  = -g +DEBUG   = +LST     = -Hanno -S +OPTIM   = +CC      = m:/old_tools/tools/hcppc/bin/hcppc +CFLAGS  = -Hnocopyr -c -Hsds -Hon=Char_default_unsigned -Hon=Char_is_rep -I../inc -I/risc/tools/pkgs/metaware/inc +CCobj   = $(CC) $(CFLAGS) $(DEBUG) $(OPTIM) +PREP    = $(CC) $(CFLAGS) -P + +# Assembler used to build the .s files (for the board version) + +ASOPT   = -big_si -c +ASDEBUG  = -l -fm +AS      = m:/old_tools/tools/hcppc/bin/asppc + +# Linker to bring .o files together into an executable. + +LKOPT	=  -Bbase=0 -Qn -q -r +LKCMD    = +LINK    = m:/old_tools/tools/hcppc/bin/ldppc $(LKCMD) $(LKOPT) + +# DOS Utilities + +DEL     = rm +COPY    = cp +LIST    = ls + +OBJECTS = i2o1.o i2o2.o + +all: $(TARGET) + +$(TARGET): $(OBJECTS) +	$(LINK) $(OBJECTS) -o $@ + +objects: i2o1.o + +clean: +	$(DEL) -f *.o *.i *.map *.lst $(TARGET) $(OBJECTS) + +.s.o: +	$(DEL) -f $*.i +	$(PREP) -Hasmcpp $< +	$(AS) $(ASOPT) $*.i +#	$(AS) $(ASOPT) $(ASDEBUG) $*.i > $*.lst + +.c.o: +	$(CCobj) $< + +.c.s: +	$(CCobj) $(LST) $< + +i2o1.o: i2o.h i2o1.c +	$(CCobj) $< + +i2o2.o: i2o.h i2o2.s +	$(DEL) -f $*.i +	$(PREP) -Hasmcpp $< +	$(AS) $(ASOPT) $*.i diff --git a/cpu/mpc824x/drivers/i2o/i2o.h b/cpu/mpc824x/drivers/i2o/i2o.h new file mode 100644 index 000000000..26f7c5c62 --- /dev/null +++ b/cpu/mpc824x/drivers/i2o/i2o.h @@ -0,0 +1,345 @@ +#ifndef I2O_H +#define I2O_H +/********************************************************* + * + * copyright @ Motorola, 1999 + * + *********************************************************/ + +#define I2O_REG_OFFSET 0x0004 + +#define PCI_CFG_CLA    0x0B +#define PCI_CFG_SCL    0x0A +#define PCI_CFG_PIC    0x09 + +#define I2O_IMR0 0x0050 +#define I2O_IMR1 0x0054 +#define I2O_OMR0 0x0058 +#define I2O_OMR1 0x005C + +#define I2O_ODBR 0x0060 +#define I2O_IDBR 0x0068 + +#define I2O_OMISR  0x0030 +#define I2O_OMIMR  0x0034 +#define I2O_IMISR  0x0100 +#define I2O_IMIMR  0x0104 + +/* accessable to PCI master but local processor */ +#define I2O_IFQPR  0x0040 +#define I2O_OFQPR  0x0044 + +/* accessable to local processor */ +#define I2O_IFHPR  0x0120 +#define I2O_IFTPR  0x0128 +#define I2O_IPHPR  0x0130 +#define I2O_IPTPR  0x0138 +#define I2O_OFHPR  0x0140 +#define I2O_OFTPR  0x0148 +#define I2O_OPHPR  0x0150 +#define I2O_OPTPR  0x0158 +#define I2O_MUCR   0x0164 +#define I2O_QBAR   0x0170 + +#define I2O_NUM_MSG 2 + +typedef enum _i2o_status +{ +	I2OSUCCESS = 0, +	I2OINVALID, +	I2OMSGINVALID, +	I2ODBINVALID, +	I2OQUEINVALID, +	I2OQUEEMPTY, +	I2OQUEFULL, +	I2ONOEVENT, +} I2OSTATUS; + +typedef enum _queue_size +{ +    QSIZE_4K = 0x02, +    QSIZE_8K = 0x04, +    QSIZE_16K = 0x08, +    QSIZE_32K = 0x10, +    QSIZe_64K = 0x20, +} QUEUE_SIZE; + +typedef enum _location +{ +    LOCAL = 0,     /* used by local processor to access its own on board device, +		      local processor's eumbbar is required */ +    REMOTE,        /* used by PCI master to access the devices on its PCI device, +		      device's pcsrbar is required */ +} LOCATION; + +/* door bell */ +typedef enum _i2o_in_db +{ +  IN_DB = 1, +  MC,         /* machine check */ +} I2O_IN_DB; + +/* I2O PCI configuration identification */ +typedef struct _i2o_iop +{ +	unsigned int base_class : 8; +	unsigned int sub_class  : 8; +	unsigned int prg_code   : 8; +} I2OIOP; + +/* I2O Outbound Message Interrupt Status Register */ +typedef struct _i2o_om_stat +{ +	unsigned int rsvd0 : 26; +	unsigned int opqi  : 1; +	unsigned int rsvd1 : 1; +	unsigned int odi   : 1; +	unsigned int rsvd2 : 1; +	unsigned int om1i  : 1; +	unsigned int om0i  : 1; +} I2OOMSTAT; + +/* I2O inbound Message Interrupt Status Register */ +typedef struct _i2o_im_stat +{ +	unsigned int rsvd0 : 23; +	unsigned int ofoi  : 1; +	unsigned int ipoi  : 1; +	unsigned int rsvd1 : 1; +	unsigned int ipqi  : 1; +	unsigned int mci   : 1; +	unsigned int idi   : 1; +	unsigned int rsvd2 : 1; +	unsigned int im1i  : 1; +	unsigned int im0i  : 1; +} I2OIMSTAT; + +/** + Enable the interrupt associated with in/out bound msg + + Inbound message interrupt generated by PCI master and serviced by local processor + local processor needs to enable its inbound interrupts it wants to handle (LOCAL) + + Outbound message interrupt generated by local processor and serviced by PCI master + PCI master needs to enable the devices' outbound interrupts it wants to handle (REMOTE) + **/ +extern I2OSTATUS I2OMsgEnable( LOCATION,            /*  REMOTE/LOCAL   */ +                               unsigned int base,   /* pcsrbar/eumbbar */ +                               unsigned char n );   /* b'1' - msg 0 +						                             * b'10'- msg 1 +						                             * b'11'- both +						                             */ + +/** + Disable the interrupt associated with in/out bound msg + + local processor needs to disable its inbound interrupts it is not interested (LOCAL) + + PCI master needs to disable outbound interrupts of devices it is not interested (REMOTE) + **/ +extern I2OSTATUS I2OMsgDisable( LOCATION,          /*  REMOTE/LOCAL   */ +                                unsigned int base, /* pcsrbar/eumbbar */ +                                unsigned char n ); /* b'1' - msg 0 +			   			                            * b'10'- msg 1 +						                            * b'11'- both +						                            */ + +/** + Read the msg register either from local inbound msg 0/1, + or an outbound msg 0/1 of devices. + + If it is not local, pcsrbar must be passed to the function. + Otherwise eumbbar is passed. + + If it is remote, outbound msg of the device is read. + Otherwise local inbound msg is read. + **/ +extern I2OSTATUS I2OMsgGet ( LOCATION,                 /* REMOTE/LOCAL */ +                             unsigned int base,        /*pcsrbar/eumbbar */ +                             unsigned int n,           /* 0 or 1 */ +                             unsigned int *msg ); + +/** + Write to nth Msg register either on local outbound msg 0/1, + or aninbound msg 0/1 of devices + + If it is not local, pcsrbar must be passed to the function. + Otherwise eumbbar is passed. + + If it is remote, inbound msg on the device is written. + Otherwise local outbound msg is written. + **/ +extern I2OSTATUS I2OMsgPost( LOCATION,                 /* REMOTE/LOCAL */ +                                unsigned int base,        /*pcsrbar/eumbbar */ +                                unsigned int n,           /* 0 or 1 */ +                                unsigned int msg ); + +/** + Enable the In/Out DoorBell Interrupt + + InDoorBell interrupt is generated by PCI master and serviced by local processor + local processor needs to enable its inbound doorbell interrupts it wants to handle + + OutDoorbell interrupt is generated by local processor and serviced by PCI master + PCI master needs to enable outbound doorbell interrupts of the devices it wants to handle + **/ +extern I2OSTATUS I2ODBEnable( LOCATION,            /*  REMOTE/LOCAL   */ +                              unsigned int base,   /* pcsrbar/eumbbar */ +                              unsigned int in_db );/* when LOCAL, I2O_IN_DB, MC, I2O_IN_DB|MC */ + +/** + Disable the In/Out DoorBell Interrupt + + local processor needs to disable its inbound doorbell interrupts it is not interested + + PCI master needs to disable outbound doorbell interrupts of devices it is not interested + + **/ +extern I2OSTATUS I2ODBDisable( LOCATION,              /*  REMOTE/LOCAL   */ +                               unsigned int base,     /* pcsrbar/eumbbar */ +                               unsigned int in_db );  /* when LOCAL, I2O_IN_DB, MC, I2O_IN_DB|MC */ + +/** + Read a local indoorbell register, or an outdoorbell of devices. + Reading a doorbell register, the register will be cleared. + + If it is not local, pcsrbar must be passed to the function. + Otherwise eumbbar is passed. + + If it is remote, outdoorbell register on the device is read. + Otherwise local in doorbell is read + **/ +extern unsigned int I2ODBGet( LOCATION,             /*  REMOTE/LOCAL   */ +                              unsigned int base);   /* pcsrbar/eumbbar */ + +/** + Write to a local outdoorbell register, or an indoorbell register of devices. + + If it is not local, pcsrbar must be passed to the function. + Otherwise eumbbar is passed. + + If it is remote, in doorbell register on the device is written. + Otherwise local out doorbell is written + **/ +extern void I2ODBPost( LOCATION,                 /*  REMOTE/LOCAL   */ +                       unsigned int base,        /* pcsrbar/eumbbar */ +                       unsigned int msg );       /*   in   / out    */ + +/** + Read the outbound msg unit interrupt status of devices. Reading an interrupt status register, + the register will be cleared. + + The outbound interrupt status is AND with the outbound + interrupt mask. The result is returned. + + PCI master must pass the pcsrbar to the function. + **/ +extern I2OSTATUS I2OOutMsgStatGet( unsigned int pcsrbar, I2OOMSTAT * ); + +/** + Read the inbound msg unit interrupt status. Reading an interrupt status register, + the register will be cleared. + + The inbound interrupt status is AND with the inbound + interrupt mask. The result is returned. + + Local process must pass its eumbbar to the function. +**/ +extern I2OSTATUS I2OInMsgStatGet( unsigned int eumbbar, I2OIMSTAT * ); + +/** + Configure the I2O FIFO, including QBAR, IFHPR/IFTPR,IPHPR/IPTPR,OFHPR/OFTPR, OPHPR/OPTPR, + MUCR. + **/ +extern I2OSTATUS I2OFIFOInit( unsigned int eumbbar, +				              QUEUE_SIZE, +				              unsigned int qba);/* queue base address that must be aligned at 1M */ +/** + Enable the circular queue + **/ +extern I2OSTATUS I2OFIFOEnable( unsigned int eumbbar ); + +/** + Disable the circular queue + **/ +extern void I2OFIFODisable( unsigned int eumbbar ); + +/** + Enable the circular queue interrupt + PCI master enables outbound FIFO interrupt of device + Device enables its inbound FIFO interrupt + **/ +extern void I2OFIFOIntEnable( LOCATION, unsigned int base  ); + +/** + Disable the circular queue interrupt + PCI master disables outbound FIFO interrupt of device + Device disables its inbound FIFO interrupt + **/ +extern void I2OFIFOIntDisable( LOCATION, unsigned int base ); + +/** + Enable the circular queue overflow interrupt + **/ +extern void I2OFIFOOverflowIntEnable( unsigned int eumbbar ); + +/** + Disable the circular queue overflow interrupt + **/ +extern void I2OFIFOOverflowIntDisable( unsigned int eumbbar ); + +/** + Allocate a free msg frame from free FIFO. + + PCI Master allocates a free msg frame through inbound queue port of device(IFQPR) + while local processor allocates a free msg frame from outbound free queue(OFTPR) + + Unless both free queues are initialized, allocating a free MF will return 0xffffffff + **/ +extern I2OSTATUS I2OFIFOAlloc( LOCATION, +			 	               unsigned int base, +				               void         **pMsg); +/** + Free a used msg frame back to free queue + PCI Master frees a MFA through outbound queue port of device(OFQPR) + while local processor frees a MFA into its inbound free queue(IFHPR) + + Used msg frame does not need to be recycled in the order they + read + + This function has to be called by PCI master to initialize Inbound free queue + and by device to initialize Outbound free queue before I2OFIFOAlloc can be used. + **/ +extern I2OSTATUS I2OFIFOFree( LOCATION, +			                  unsigned int base, +			                  void        *pMsg ); + +/** + Post a msg into FIFO + PCI Master posts a msg through inbound queue port of device(IFQPR) + while local processor post a msg into its outbound post queue(OPHPR) + + The total number of msg must be less than the max size of the queue + Otherwise queue overflow interrupt will assert. + **/ +extern I2OSTATUS I2OFIFOPost( LOCATION, +		                      unsigned int base, +		                      void         *pMsg ); + +/** + Read a msg from FIFO + PCI Master reads a msg through outbound queue port of device(OFQPR) + while local processor reads a msg from its inbound post queue(IPTPR) + **/ +extern I2OSTATUS I2OFIFOGet( LOCATION, +	 		                  unsigned int base, +							  void     **pMsg ); + +/** + Get the I2O PCI configuration identification register + **/ +extern I2OSTATUS I2OPCIConfigGet( LOCATION, +			                   unsigned int base, +							   I2OIOP *); + +#endif diff --git a/cpu/mpc824x/drivers/i2o/i2o1.c b/cpu/mpc824x/drivers/i2o/i2o1.c new file mode 100644 index 000000000..d840af0a9 --- /dev/null +++ b/cpu/mpc824x/drivers/i2o/i2o1.c @@ -0,0 +1,890 @@ +/********************************************************* + * $Id + * + * copyright @ Motorola, 1999 + *********************************************************/ +#include "i2o.h" + +extern unsigned int load_runtime_reg( unsigned int eumbbar, unsigned int reg ); +#pragma Alias( load_runtime_reg, "load_runtime_reg" ); + +extern void store_runtime_reg( unsigned int eumbbar, unsigned int reg, unsigned int val ); +#pragma Alias( store_runtime_reg, "store_runtime_reg" ); + +typedef struct _fifo_stat +{ +    QUEUE_SIZE   qsz; +    unsigned int qba; +} FIFOSTAT; + +FIFOSTAT fifo_stat = { QSIZE_4K, 0xffffffff }; + +/********************************************************************************** + * function: I2OMsgEnable + * + * description: Enable the interrupt associated with in/out bound msg + *              return I2OSUCCESS if no error, otherwise return I2OMSGINVALID. + * + *              All previously enabled interrupts are preserved. + * note: + * Inbound message interrupt generated by PCI master and serviced by local processor + * Outbound message interrupt generated by local processor and serviced by PCI master + * + * local processor needs to enable its inbound interrupts it wants to handle(LOCAL) + * PCI master needs to enable the outbound interrupts of devices it wants to handle(REMOTE) + ************************************************************************************/ +I2OSTATUS I2OMsgEnable ( LOCATION loc,        /*  REMOTE/LOCAL   */ +                         unsigned int base,   /* pcsrbar/eumbbar */ +                         unsigned char n )    /* b'1' - msg 0 +				               * b'10'- msg 1 +		 		               * b'11'- both +					       */ +{ +    unsigned int reg, val; +    if ( ( n & 0x3 ) == 0 ) +    { +	/* neither msg 0, nor msg 1 */ +	return I2OMSGINVALID; +    } + +    n = (~n) & 0x3; +    /* LOCATION - REMOTE : enable outbound message of device, pcsrbar as base +     *            LOCAL  : enable local inbound message, eumbbar as base +     */ +    reg = ( loc == REMOTE ? I2O_OMIMR : I2O_IMIMR ); +    val = load_runtime_reg( base, reg ); + +    val &= 0xfffffffc; /* masked out the msg interrupt bits */ +    val |= n;          /* LSB are the one we want */ +    store_runtime_reg( base, reg, val ); + +    return I2OSUCCESS; +} + +/********************************************************************************* + * function: I2OMsgDisable + * + * description: Disable the interrupt associated with in/out bound msg + *              Other previously enabled interrupts are preserved. + *              return I2OSUCCESS if no error otherwise return I2OMSGINVALID + * + * note: + *  local processor needs to disable its inbound interrupts it is not interested(LOCAL) + *  PCI master needs to disable outbound interrupts of devices it is not interested(REMOTE) + *********************************************************************************/ +I2OSTATUS I2OMsgDisable( LOCATION loc,      /*  REMOTE/LOCAL   */ +                         unsigned int base, /* pcsrbar/eumbbar */ +                         unsigned char n )  /* b'1' - msg 0 +					     * b'10'- msg 1 +					     * b'11'- both +					     */ +{ +    unsigned int reg, val; + +    if ( ( n & 0x3 ) == 0 ) +    { +	/* neither msg 0, nor msg 1 */ +	return I2OMSGINVALID; +    } + +    /* LOCATION - REMOTE : disable outbound message interrupt of device, pcsrbar as base +     *            LOCAL  : disable local inbound message interrupt, eumbbar as base +     */ +    reg = ( loc == REMOTE ? I2O_OMIMR : I2O_IMIMR ); +    val = load_runtime_reg( base, reg ); + +    val &= 0xfffffffc; /* masked out the msg interrupt bits */ +    val |= ( n & 0x3 ); +    store_runtime_reg( base, reg, val ); + +    return I2OSUCCESS; + +} + +/************************************************************************** + * function: I2OMsgGet + * + * description: Local processor reads the nth Msg register from its inbound msg, + *              or a PCI Master reads nth outbound msg from device + * + *              return I2OSUCCESS if no error, otherwise return I2OMSGINVALID. + * + * note: + * If it is not local, pcsrbar must be passed to the function. Otherwise eumbbar is passed. + * If it is remote, outbound msg on the device is read; otherwise local inbound msg is read + *************************************************************************/ +I2OSTATUS I2OMsgGet ( LOCATION loc,             /* REMOTE/LOCAL */ +                         unsigned int base,        /*pcsrbar/eumbbar */ +                         unsigned int n,           /* 0 or 1 */ +                         unsigned int *msg ) +{ +    if ( n >= I2O_NUM_MSG || msg == 0 ) +    { +	return I2OMSGINVALID; +    } + +    if ( loc == REMOTE ) +    { +	/* read the outbound msg of the device, pcsrbar as base */ +	*msg = load_runtime_reg( base, I2O_OMR0+n*I2O_REG_OFFSET ); +    } +    else +    { +	/* read the inbound msg sent by PCI master, eumbbar as base */ +	*msg = load_runtime_reg( base, I2O_IMR0+n*I2O_REG_OFFSET ); +    } + +    return I2OSUCCESS; +} + +/*************************************************************** + * function: I2OMsgPost + * + * description: Kahlua  writes to its nth outbound msg register + *              PCI master writes to nth inbound msg register of device + * + *              return I2OSUCCESS if no error, otherwise return I2OMSGINVALID. + * + * note: + * If it is not local, pcsrbar must be passed to the function. Otherwise eumbbar is passed. + * + * If it is remote, inbound msg on the device is written; otherwise local outbound msg is written + ***************************************************************/ +I2OSTATUS I2OMsgPost( LOCATION loc,             /* REMOTE/LOCAL */ +                      unsigned int base,        /*pcsrbar/eumbbar */ +                      unsigned int n,           /* 0 or 1 */ +                      unsigned int msg ) +{ +    if ( n >= I2O_NUM_MSG ) +    { +	return I2OMSGINVALID; +    } + +    if ( loc == REMOTE ) +    { +	/* write to the inbound msg register of the device, pcsrbar as base  */ +	store_runtime_reg( base, I2O_IMR0+n*I2O_REG_OFFSET, msg ); +    } +    else +    { +	/* write to the outbound msg register for PCI master to read, eumbbar as base */ +	store_runtime_reg( base, I2O_OMR0+n*I2O_REG_OFFSET, msg ); +    } + +    return I2OSUCCESS; +} + +/*********************************************************************** + * function: I2ODBEnable + * + * description: Local processor enables it's inbound doorbell interrupt + *              PCI master enables outbound doorbell interrupt of devices + *              Other previously enabled interrupts are preserved. + *              Return I2OSUCCESS if no error otherwise return I2ODBINVALID + * + * note: + * In DoorBell interrupt is generated by PCI master and serviced by local processor + * Out Doorbell interrupt is generated by local processor and serviced by PCI master + * + * Out Doorbell interrupt is generated by local processor and serviced by PCI master + * PCI master needs to enable the outbound doorbell interrupts of device it wants to handle + **********************************************************************/ +I2OSTATUS I2ODBEnable( LOCATION loc,        /*  REMOTE/LOCAL   */ +                  unsigned int base,   /* pcsrbar/eumbbar */ +                  unsigned int in_db ) /* when LOCAL, I2O_IN_DB, MC, I2O_IN_DB|MC */ +{ + +    /* LOCATION - REMOTE : PCI master initializes outbound doorbell message of device +     *            LOCAL  : Kahlua initializes its inbound doorbell message +     */ +    unsigned int val; + +    if ( loc == LOCAL && ( in_db & 0x3 ) == 0 ) +    { +	return I2ODBINVALID; +    } + +    if ( loc == REMOTE ) +    { +	/* pcsrbar is base */ +	val = load_runtime_reg( base, I2O_OMIMR ); +	val &= 0xfffffff7; +        store_runtime_reg( base, I2O_OMIMR , val ); +    } +    else +    { +	/* eumbbar is base */ +	val = load_runtime_reg( base, I2O_IMIMR); +        in_db = ( (~in_db) & 0x3 ) << 3; +        val = ( val & 0xffffffe7) | in_db; +        store_runtime_reg( base,  I2O_IMIMR, val ); +    } + +    return I2OSUCCESS; +} + +/********************************************************************************** + * function: I2ODBDisable + * + * description: local processor disables its inbound DoorBell Interrupt + *              PCI master disables outbound DoorBell interrupt of device + *              Other previously enabled interrupts are preserved. + *              return I2OSUCCESS if no error.Otherwise return I2ODBINVALID + * + * note: + * local processor needs to disable its inbound doorbell interrupts it is not interested + * + * PCI master needs to disable outbound doorbell interrupts of device it is not interested + ************************************************************************************/ +I2OSTATUS I2ODBDisable( LOCATION loc,          /*  REMOTE/LOCAL   */ +                        unsigned int base,     /* pcsrbar/eumbbar */ +                        unsigned int in_db )   /* when LOCAL, I2O_IN_DB, MC, I2O_IN_DB|MC */ +{ +    /* LOCATION - REMOTE : handle device's out bound message initialization +     *            LOCAL  : handle local in bound message initialization +     */ +    unsigned int val; + +    if ( loc == LOCAL && ( in_db & 0x3 ) == 0 ) +    { +	    return I2ODBINVALID; +    } + +    if ( loc == REMOTE ) +    { +	/* pcsrbar is the base */ +	val = load_runtime_reg( base, I2O_OMIMR ); +	val |= 0x8; +        store_runtime_reg( base, I2O_OMIMR, val ); +    } +    else +    { +	    val = load_runtime_reg( base, I2O_IMIMR); +            in_db = ( in_db & 0x3 ) << 3; +            val |= in_db; +            store_runtime_reg( base, I2O_IMIMR, val ); +    } + +    return I2OSUCCESS; +} + +/********************************************************************************** + * function: I2ODBGet + * + * description: Local processor reads its in doorbell register, + *              PCI master reads the outdoorbell register of device. + *              After a doorbell register is read, the whole register will be cleared. + *              Otherwise, HW keeps generating interrupt. + * + * note: + * If it is not local, pcsrbar must be passed to the function. + * Otherwise eumbbar is passed. + * + * If it is remote, out doorbell register on the device is read. + * Otherwise local in doorbell is read + * + * If the register is not cleared by write to it, any remaining bit of b'1's + * will cause interrupt pending. + *********************************************************************************/ +unsigned int I2ODBGet( LOCATION loc,         /*  REMOTE/LOCAL   */ +                       unsigned int base)    /* pcsrbar/eumbbar */ +{ +    unsigned int msg, val; + +    if ( loc == REMOTE ) +    { +	/* read outbound doorbell register of device, pcsrbar is the base */ +        val = load_runtime_reg( base, I2O_ODBR ); +        msg = val & 0xe0000000; +        store_runtime_reg( base, I2O_ODBR, val ); /* clear the register */ +    } +    else +    { +	/* read the inbound doorbell register, eumbbar is the base */ +        val = load_runtime_reg( base, I2O_IDBR ); +        store_runtime_reg( base, I2O_IDBR, val ); /* clear the register */ +	msg = val; +    } + +    return msg; +} + +/********************************************************************** + * function: I2ODBPost + * + * description: local processor writes to a outbound doorbell register, + *              PCI master writes to the inbound doorbell register of device + * + * note: + * If it is not local, pcsrbar must be passed to the function. + * Otherwise eumbbar is passed. + * + * If it is remote, in doorbell register on the device is written. + * Otherwise local out doorbell is written + *********************************************************************/ +void I2ODBPost( LOCATION loc,             /*  REMOTE/LOCAL   */ +                unsigned int base,        /* pcsrbar/eumbbar */ +                unsigned int msg )        /*   in   / out    */ +{ +    if ( loc == REMOTE ) +    { +	/* write to inbound doorbell register of device, pcsrbar is the base */ +	store_runtime_reg( base, I2O_IDBR, msg ); +    } +    else +    { +	/* write to local outbound doorbell register, eumbbar is the base */ +	store_runtime_reg( base, I2O_ODBR, msg & 0x1fffffff ); +    } + +} + +/******************************************************************** + * function: I2OOutMsgStatGet + * + * description: PCI master reads device's outbound msg unit interrupt status. + *              Reading an interrupt status register, + *              the register will be cleared. + * + *              The value of the status register is AND with the outbound + *              interrupt mask and result is returned. + * + * note: + * pcsrbar must be passed to the function. + ********************************************************************/ +I2OSTATUS I2OOutMsgStatGet( unsigned int pcsrbar, I2OOMSTAT *val ) +{ +    unsigned int stat; +    unsigned int mask; + +    if ( val == 0 ) +    { +	    return I2OINVALID; +    } + +    /* read device's outbound status */ +    stat = load_runtime_reg( pcsrbar, I2O_OMISR ); +    mask = load_runtime_reg( pcsrbar, I2O_OMIMR ); +    store_runtime_reg( pcsrbar, I2O_OMISR, stat & 0xffffffd7); + +    stat &= mask; +    val->rsvd0 = ( stat & 0xffffffc0 ) >> 6; +    val->opqi  = ( stat & 0x00000020 ) >> 5; +    val->rsvd1 = ( stat & 0x00000010 ) >> 4; +    val->odi   = ( stat & 0x00000008 ) >> 3; +    val->rsvd2 = ( stat & 0x00000004 ) >> 2; +    val->om1i  = ( stat & 0x00000002 ) >> 1; +    val->om0i  = ( stat & 0x00000001 ); + +    return I2OSUCCESS; +} + +/******************************************************************** + * function: I2OInMsgStatGet + * + * description: Local processor reads its inbound msg unit interrupt status. + *              Reading an interrupt status register, + *              the register will be cleared. + * + *              The inbound msg interrupt status is AND with the inbound + *              msg interrupt mask and result is returned. + * + * note: + * eumbbar must be passed to the function. + ********************************************************************/ +I2OSTATUS I2OInMsgStatGet(unsigned int eumbbar, I2OIMSTAT *val) +{ +    unsigned int stat; +    unsigned int mask; + +    if ( val == 0 ) +    { +	    return I2OINVALID; +    } + +    /* read device's outbound status */ +    stat = load_runtime_reg( eumbbar, I2O_OMISR ); +    mask = load_runtime_reg( eumbbar, I2O_OMIMR ); +    store_runtime_reg( eumbbar, I2O_OMISR, stat & 0xffffffe7 ); + +    stat &= mask; +    val->rsvd0 = ( stat & 0xfffffe00 ) >> 9; +    val->ofoi  = ( stat & 0x00000100 ) >> 8; +    val->ipoi  = ( stat & 0x00000080 ) >> 7; +    val->rsvd1 = ( stat & 0x00000040 ) >> 6; +    val->ipqi  = ( stat & 0x00000020 ) >> 5; +    val->mci   = ( stat & 0x00000010 ) >> 4; +    val->idi   = ( stat & 0x00000008 ) >> 3; +    val->rsvd2 = ( stat & 0x00000004 ) >> 2; +    val->im1i  = ( stat & 0x00000002 ) >> 1; +    val->im0i  = ( stat & 0x00000001 ); + +    return I2OSUCCESS; + +} + +/*********************************************************** + * function: I2OFIFOInit + * + * description: Configure the I2O FIFO, including QBAR, + *              IFHPR/IFTPR, IPHPR/IPTPR, OFHPR/OFTPR, + *              OPHPR/OPTPR, MUCR. + * + *              return I2OSUCCESS if no error, + *              otherwise return I2OQUEINVALID + * + * note: It is NOT this driver's responsibility of initializing + *       MFA blocks, i.e., FIFO queue itself. The MFA blocks + *       must be initialized before I2O unit can be used. + ***********************************************************/ +I2OSTATUS I2OFIFOInit( unsigned int eumbbar, +		       QUEUE_SIZE   sz,      /* value of CQS of MUCR */ +		       unsigned int qba)     /* queue base address that must be aligned at 1M */ +{ + +    if ( ( qba & 0xfffff ) != 0 ) +    { +	/* QBA must be aligned at 1Mbyte boundary */ +	return I2OQUEINVALID; +    } + +    store_runtime_reg( eumbbar, I2O_QBAR, qba ); +    store_runtime_reg( eumbbar, I2O_MUCR, (unsigned int)sz ); +    store_runtime_reg( eumbbar, I2O_IFHPR, qba ); +    store_runtime_reg( eumbbar, I2O_IFTPR, qba ); +    store_runtime_reg( eumbbar, I2O_IPHPR, qba + 1 * ( sz << 11 )); +    store_runtime_reg( eumbbar, I2O_IPTPR, qba + 1 * ( sz << 11 )); +    store_runtime_reg( eumbbar, I2O_OFHPR, qba + 2 * ( sz << 11 )); +    store_runtime_reg( eumbbar, I2O_OFTPR, qba + 2 * ( sz << 11 )); +    store_runtime_reg( eumbbar, I2O_OPHPR, qba + 3 * ( sz << 11 )); +    store_runtime_reg( eumbbar, I2O_OPTPR, qba + 3 * ( sz << 11 )); + +    fifo_stat.qsz = sz; +    fifo_stat.qba = qba; + +    return I2OSUCCESS; +} + +/************************************************** + * function: I2OFIFOEnable + * + * description: Enable the circular queue + *              return I2OSUCCESS if no error. + *              Otherwise I2OQUEINVALID is returned. + * + * note: + *************************************************/ +I2OSTATUS I2OFIFOEnable( unsigned int eumbbar ) +{ +    unsigned int val; + +    if ( fifo_stat.qba == 0xfffffff ) +    { +	return I2OQUEINVALID; +    } + +    val = load_runtime_reg( eumbbar, I2O_MUCR ); +    store_runtime_reg( eumbbar, I2O_MUCR, val | 0x1 ); + +    return I2OSUCCESS; +} + +/************************************************** + * function: I2OFIFODisable + * + * description: Disable the circular queue + * + * note: + *************************************************/ +void I2OFIFODisable( unsigned int eumbbar ) +{ +    if ( fifo_stat.qba == 0xffffffff ) +    { +	/* not enabled */ +	return; +    } + +    unsigned int val = load_runtime_reg( eumbbar, I2O_MUCR ); +    store_runtime_reg( eumbbar, I2O_MUCR, val & 0xfffffffe ); +} + +/**************************************************** + * function: I2OFIFOAlloc + * + * description: Allocate a free MFA from free FIFO. + *              return I2OSUCCESS if no error. + *              return I2OQUEEMPTY if no more free MFA. + *              return I2OINVALID on other errors. + * + *              A free MFA must be allocated before a + *              message can be posted. + * + * note: + * PCI Master allocates a free MFA from inbound queue of device + * (pcsrbar is the base,) through the inbound queue port of device + * while local processor allocates a free MFA from its outbound + * queue (eumbbar is the base.) + * + ****************************************************/ +I2OSTATUS I2OFIFOAlloc( LOCATION loc, +		        unsigned int base, +		        void         **pMsg ) +{ +    I2OSTATUS stat = I2OSUCCESS; +    void *pHdr, *pTil; + +    if ( pMsg == 0 || *pMsg == 0 || fifo_stat.qba == 0xffffffff ) +    { +	/* not configured */ +	return I2OQUEINVALID; +    } + +    if ( loc == REMOTE ) +    { +	/* pcsrbar is the base and read the inbound free tail ptr */ +	pTil = (void *)load_runtime_reg( base, I2O_IFQPR ); +        if ( ( (unsigned int)pTil & 0xFFFFFFF ) == 0xFFFFFFFF ) +        { +	    stat = I2OQUEEMPTY; +        } +	else +        { +	    *pMsg = pTil; +	} +    } +    else +    { +	/* eumbbar is the base and read the outbound free tail ptr */ +	pHdr = (void *)load_runtime_reg( base, I2O_OFHPR ); /* queue head */ +	pTil = (void *)load_runtime_reg( base, I2O_OFTPR ); /* queue tail */ + +	/* check underflow */ +	if ( pHdr == pTil ) +	{ +	    /* hdr and til point to the same fifo item, no free MFA */ +            stat = I2OQUEEMPTY; +	} +	else +	{ +	  /* update OFTPR */ +	  *pMsg = (void *)(*(unsigned char *)pTil); +	  pTil = (void *)((unsigned int)pTil + 4); +	  if ( (unsigned int)pTil == fifo_stat.qba + ( 4 * ( fifo_stat.qsz << 11 ) ) ) +	  { +		/* reach the upper limit */ +		pTil = (void *)(fifo_stat.qba + ( 3 * (fifo_stat.qsz << 11) )); +	  } +	  store_runtime_reg( base, I2O_OFTPR, (unsigned int)pTil ); +	} +    } + +    return stat; +} + +/****************************************************** + * function: I2OFIFOFree + * + * description: Free a used MFA back to free queue after + *              use. + *              return I2OSUCCESS if no error. + *              return I2OQUEFULL if inbound free queue + *              overflow + * + * note: PCI Master frees a MFA into device's outbound queue + *       (OFQPR) while local processor frees a MFA into its + *       inbound queue (IFHPR). + *****************************************************/ +I2OSTATUS I2OFIFOFree( LOCATION loc, +		  unsigned int base, +		  void *pMsg ) +{ +    void **pHdr, **pTil; +    I2OSTATUS stat = I2OSUCCESS; + +    if ( fifo_stat.qba == 0xffffffff || pMsg == 0 ) +    { +	    return I2OQUEINVALID; +    } + +    if ( loc == REMOTE ) +    { +	/* pcsrbar is the base */ +	store_runtime_reg( base, I2O_OFQPR, (unsigned int)pMsg ); +    } +    else +    { +	/* eumbbar is the base */ +	pHdr = (void **)load_runtime_reg( base, I2O_IFHPR ); +        pTil = (void **)load_runtime_reg( base, I2O_IFTPR ); + +	/* store MFA */ +	*pHdr = pMsg; + +	/* update IFHPR */ +	pHdr += 4; + +	if ( (unsigned int)pHdr == fifo_stat.qba + ( fifo_stat.qsz << 11 ) ) +	{ +	  /* reach the upper limit */ +	  pHdr = (void **)fifo_stat.qba; +	} + +	/* check inbound free queue overflow */ +	if ( pHdr != pTil ) +	{ +	   store_runtime_reg( base, I2O_OPHPR, (unsigned int)pHdr); +        } +	else +	{ +	    stat = I2OQUEFULL; +	} + +    } + +    return stat; + +} + +/********************************************* + * function: I2OFIFOPost + * + * description: Post a msg into FIFO post queue + *              the value of msg must be the one + *              returned by I2OFIFOAlloc + * + * note: PCI Master posts a msg into device's inbound queue + *       (IFQPR) while local processor post a msg into device's + *       outbound queue (OPHPR) + *********************************************/ +I2OSTATUS I2OFIFOPost( LOCATION loc, +		       unsigned int base, +		       void *pMsg ) +{ +    void **pHdr, **pTil; +    I2OSTATUS stat = I2OSUCCESS; + +    if ( fifo_stat.qba == 0xffffffff || pMsg == 0 ) +    { +	return I2OQUEINVALID; +    } + +    if ( loc == REMOTE ) +    { +	/* pcsrbar is the base */ +	store_runtime_reg( base, I2O_IFQPR, (unsigned int)pMsg ); +    } +    else +    { +	/* eumbbar is the base */ +	pHdr = (void **)load_runtime_reg( base, I2O_OPHPR ); +        pTil = (void **)load_runtime_reg( base, I2O_OPTPR ); + +	/* store MFA */ +	*pHdr = pMsg; + +	/* update IFHPR */ +	pHdr += 4; + +	if ( (unsigned int)pHdr == fifo_stat.qba + 3 * ( fifo_stat.qsz << 11 ) ) +	{ +	  /* reach the upper limit */ +	  pHdr = (void **)(fifo_stat.qba + 2 * ( fifo_stat.qsz << 11 ) ); +	} + +	/* check post queue overflow */ +	if ( pHdr != pTil ) +	{ +	   store_runtime_reg( base, I2O_OPHPR, (unsigned int)pHdr); +        } +	else +	{ +	    stat = I2OQUEFULL; +	} +    } + +    return stat; +} + +/************************************************ + * function: I2OFIFOGet + * + * description:  Read a msg from FIFO + *               This function should be called + *               only when there is a corresponding + *               msg interrupt. + * + * note: PCI Master reads a msg from device's outbound queue + *       (OFQPR) while local processor reads a msg from device's + *       inbound queue (IPTPR) + ************************************************/ +I2OSTATUS I2OFIFOGet( LOCATION loc, +		       unsigned int base, +		       void **pMsg ) +{ +    I2OSTATUS stat = I2OSUCCESS; +    void *pHdr, *pTil; + +    if ( pMsg == 0 || *pMsg == 0 || fifo_stat.qba == 0xffffffff ) +    { +	/* not configured */ +	return I2OQUEINVALID; +    } + +    if ( loc == REMOTE ) +    { +	/* pcsrbar is the base */ +	pTil = (void *)load_runtime_reg( base, I2O_OFQPR ); +        if ( ( (unsigned int)pTil & 0xFFFFFFF ) == 0xFFFFFFFF ) +        { +	    stat = I2OQUEEMPTY; +        } +	else +        { +	    *pMsg = pTil; +	} +    } +    else +    { +	/* eumbbar is the base and read the outbound free tail ptr */ +	pHdr = (void *)load_runtime_reg( base, I2O_IPHPR ); /* queue head */ +	pTil = (void *)load_runtime_reg( base, I2O_IPTPR ); /* queue tail */ + +	/* check underflow */ +	if ( pHdr == pTil ) +	{ +	    /* no free MFA */ +            stat = I2OQUEEMPTY; +	} +	else +	{ +	  /* update OFTPR */ +	  *pMsg = (void *)(*(unsigned char *)pTil); +	  pTil = (void *)((unsigned int)pTil + 4); +	  if ( (unsigned int)pTil == fifo_stat.qba + 2 * ( fifo_stat.qsz << 11 ) ) +	  { +		/* reach the upper limit */ +		pTil = (void *)(fifo_stat.qba + 1 * (fifo_stat.qsz << 11) ); +	  } + +	  store_runtime_reg( base, I2O_IPTPR, (unsigned int)pTil ); +	} +    } + +    return stat; +} + +/******************************************************** + * function: I2OIOP + * + * description: Get the I2O PCI configuration identification + *              register. + * + * note: PCI master should pass pcsrbar while local processor + *       should pass eumbbar. + *********************************************************/ +I2OSTATUS I2OPCIConfigGet( LOCATION loc, +		        unsigned int base, +		        I2OIOP * val) +{ +    unsigned int tmp; +    if ( val == 0 ) +    { +	    return I2OINVALID; +    } +    tmp = load_runtime_reg( base, PCI_CFG_CLA ); +    val->base_class = ( tmp & 0xFF) << 16; +    tmp = load_runtime_reg( base, PCI_CFG_SCL ); +    val->sub_class= ( (tmp & 0xFF) << 8 ); +    tmp = load_runtime_reg( base, PCI_CFG_PIC ); +    val->prg_code = (tmp & 0xFF); +    return I2OSUCCESS; +} + +/********************************************************* + * function: I2OFIFOIntEnable + * + * description: Enable the circular post queue interrupt + * + * note: + * PCI master enables outbound FIFO interrupt of device + * pscrbar is the base + * Device enables its inbound FIFO interrupt + * eumbbar is the base + *******************************************************/ +void I2OFIFOIntEnable( LOCATION loc, unsigned int base  ) +{ +    unsigned int reg, val; + +    /* LOCATION - REMOTE : enable outbound message of device, pcsrbar as base +     *            LOCAL  : enable local inbound message, eumbbar as base +     */ +    reg = ( loc == REMOTE ? I2O_OMIMR : I2O_IMIMR ); +    val = load_runtime_reg( base, reg ); + +    val &= 0xffffffdf; /* clear the msg interrupt bits */ +    store_runtime_reg( base, reg, val ); + +} + +/**************************************************** + * function: I2OFIFOIntDisable + * + * description: Disable the circular post queue interrupt + * + * note: + * PCI master disables outbound FIFO interrupt of device + * (pscrbar is the base) + * Device disables its inbound FIFO interrupt + * (eumbbar is the base) + *****************************************************/ +void I2OFIFOIntDisable( LOCATION loc, unsigned int base ) +{ + +    /* LOCATION - REMOTE : disable outbound message interrupt of device, pcsrbar as base +     *            LOCAL  : disable local inbound message interrupt, eumbbar as base +     */ +    unsigned int reg = ( loc == REMOTE ? I2O_OMIMR : I2O_IMIMR ); +    unsigned int val = load_runtime_reg( base, reg ); + +    val |= 0x00000020; /* masked out the msg interrupt bits */ +    store_runtime_reg( base, reg, val ); + +} + +/********************************************************* + * function: I2OFIFOOverflowIntEnable + * + * description: Enable the circular queue overflow interrupt + * + * note: + * Device enables its inbound FIFO post overflow interrupt + * and outbound free overflow interrupt. + * eumbbar is the base + *******************************************************/ +void I2OFIFOOverflowIntEnable( unsigned int eumbbar  ) +{ +    unsigned int val = load_runtime_reg( eumbbar, I2O_IMIMR ); + +    val &= 0xfffffe7f; /* clear the two overflow interrupt bits */ +    store_runtime_reg( eumbbar, I2O_IMIMR, val ); + +} + +/**************************************************** + * function: I2OFIFOOverflowIntDisable + * + * description: Disable the circular queue overflow interrupt + * + * note: + * Device disables its inbound post FIFO overflow interrupt + * and outbound free FIFO overflow interrupt + * (eumbbar is the base) + *****************************************************/ +void I2OFIFOOverflowIntDisable( unsigned int eumbbar ) +{ + +    unsigned int val = load_runtime_reg( eumbbar, I2O_IMIMR ); + +    val |= 0x00000180; /* masked out the msg overflow interrupt bits */ +    store_runtime_reg( eumbbar, I2O_IMIMR, val ); +} diff --git a/cpu/mpc824x/drivers/i2o/i2o2.S b/cpu/mpc824x/drivers/i2o/i2o2.S new file mode 100644 index 000000000..10339792b --- /dev/null +++ b/cpu/mpc824x/drivers/i2o/i2o2.S @@ -0,0 +1,48 @@ +/************************************** + * + * copyright @ Motorola, 1999 + * + **************************************/ + +/********************************************************** + * function: load_runtime_reg + * + * input:  r3 - value of eumbbar + *         r4 - register offset in embedded utility space + * + * output: r3 - register content + **********************************************************/ +      .text +      .align 2 +      .global load_runtime_reg + +load_runtime_reg: + +		  xor r5,r5,r5 +          or  r5,r5,r3       /* save eumbbar */ + +	      lwbrx	r3,r4,r5 +	      sync + + 	      bclr 20, 0 + +/**************************************************************** + * function: store_runtime_reg + * + * input: r3 - value of eumbbar + *        r4 - register offset in embedded utility space + *        r5 - new value to be stored + * + ****************************************************************/ +           .text +           .align 2 +           .global store_runtime_reg +store_runtime_reg: + +		  xor r0,r0,r0 + +	      stwbrx r5,  r4, r3 +	      sync + +		  bclr   20,0 + |