From 15701420121607d860847e0d15719253f9a82456 Mon Sep 17 00:00:00 2001 From: wdenk Date: Wed, 28 Nov 2001 17:49:55 +0000 Subject: [PATCH] Das U-Boot: Universal Boot Loader --- board/mousse/u-boot.lds.ram | 101 +++ board/sandpoint/early_init.S | 154 +++++ board/sandpoint/u-boot.lds.mw.debug | 101 +++ cpu/mpc824x/drivers/dma/Makefile | 83 +++ cpu/mpc824x/drivers/dma/Makefile_pc | 89 +++ cpu/mpc824x/drivers/dma/README | 102 +++ cpu/mpc824x/drivers/dma/dma.h | 326 ++++++++++ cpu/mpc824x/drivers/dma/dma1.c | 801 ++++++++++++++++++++++++ cpu/mpc824x/drivers/dma/dma2.S | 45 ++ cpu/mpc824x/drivers/dma/dma_export.h | 100 +++ cpu/mpc824x/drivers/dma_export.h | 100 +++ cpu/mpc824x/drivers/epic.h | 1 + cpu/mpc824x/drivers/epic/README | 104 ++++ cpu/mpc824x/drivers/epic/epic2.S | 196 ++++++ cpu/mpc824x/drivers/epic/epicutil.S | 58 ++ cpu/mpc824x/drivers/errors.h | 218 +++++++ cpu/mpc824x/drivers/i2c/Makefile | 84 +++ cpu/mpc824x/drivers/i2c/Makefile_pc | 91 +++ cpu/mpc824x/drivers/i2c/README | 105 ++++ cpu/mpc824x/drivers/i2c/i2c_export.h | 103 ++++ cpu/mpc824x/drivers/i2c_export.h | 103 ++++ cpu/mpc824x/drivers/i2o.h | 344 +++++++++++ cpu/mpc824x/drivers/i2o/Makefile | 84 +++ cpu/mpc824x/drivers/i2o/Makefile_pc | 90 +++ cpu/mpc824x/drivers/i2o/i2o.h | 345 +++++++++++ cpu/mpc824x/drivers/i2o/i2o1.c | 890 +++++++++++++++++++++++++++ cpu/mpc824x/drivers/i2o/i2o2.S | 48 ++ 27 files changed, 4866 insertions(+) create mode 100644 board/mousse/u-boot.lds.ram create mode 100644 board/sandpoint/early_init.S create mode 100644 board/sandpoint/u-boot.lds.mw.debug create mode 100644 cpu/mpc824x/drivers/dma/Makefile create mode 100644 cpu/mpc824x/drivers/dma/Makefile_pc create mode 100644 cpu/mpc824x/drivers/dma/README create mode 100644 cpu/mpc824x/drivers/dma/dma.h create mode 100644 cpu/mpc824x/drivers/dma/dma1.c create mode 100644 cpu/mpc824x/drivers/dma/dma2.S create mode 100644 cpu/mpc824x/drivers/dma/dma_export.h create mode 100644 cpu/mpc824x/drivers/dma_export.h create mode 100644 cpu/mpc824x/drivers/epic.h create mode 100644 cpu/mpc824x/drivers/epic/README create mode 100644 cpu/mpc824x/drivers/epic/epic2.S create mode 100644 cpu/mpc824x/drivers/epic/epicutil.S create mode 100644 cpu/mpc824x/drivers/errors.h create mode 100644 cpu/mpc824x/drivers/i2c/Makefile create mode 100644 cpu/mpc824x/drivers/i2c/Makefile_pc create mode 100644 cpu/mpc824x/drivers/i2c/README create mode 100644 cpu/mpc824x/drivers/i2c/i2c_export.h create mode 100644 cpu/mpc824x/drivers/i2c_export.h create mode 100644 cpu/mpc824x/drivers/i2o.h create mode 100644 cpu/mpc824x/drivers/i2o/Makefile create mode 100644 cpu/mpc824x/drivers/i2o/Makefile_pc create mode 100644 cpu/mpc824x/drivers/i2o/i2o.h create mode 100644 cpu/mpc824x/drivers/i2o/i2o1.c create mode 100644 cpu/mpc824x/drivers/i2o/i2o2.S diff --git a/board/mousse/u-boot.lds.ram b/board/mousse/u-boot.lds.ram new file mode 100644 index 0000000000..9166c9cd78 --- /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 0000000000..127bd37fa5 --- /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 +#include +#include +#include + +#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 0000000000..a0378cb4a1 --- /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 0000000000..59e2fac863 --- /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 0000000000..8df2a3cb79 --- /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 0000000000..ab4b68bd12 --- /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 0000000000..a21be74ad1 --- /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 0000000000..8c3834e4bc --- /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 0000000000..dab1de3493 --- /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 0000000000..cb750dd89b --- /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 0000000000..cb750dd89b --- /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 0000000000..2803f631cf --- /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 0000000000..ae95b8859e --- /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 0000000000..8979f88445 --- /dev/null +++ b/cpu/mpc824x/drivers/epic/epic2.S @@ -0,0 +1,196 @@ +/************************************** + * + * copyright @ Motorola, 1999 + * + **************************************/ + +#include +#include +#include + +/********************************************* + * 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 0000000000..a83fbd8d31 --- /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 +#include + +/********************************************************** + * 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 0000000000..1435188095 --- /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 0000000000..ae1a94c536 --- /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 0000000000..4d42c7b848 --- /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 0000000000..8d82df3597 --- /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 0000000000..17403ea2cb --- /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 0000000000..17403ea2cb --- /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 0000000000..87225ab162 --- /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 0000000000..3f5ca26683 --- /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 0000000000..6867f5837c --- /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 0000000000..26f7c5c623 --- /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 0000000000..d840af0a91 --- /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 0000000000..10339792bf --- /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 + -- 2.39.5