Initial revision

This commit is contained in:
wdenk 2001-11-28 17:49:55 +00:00
parent 12e4407c6a
commit 327f7a020a
27 changed files with 4866 additions and 0 deletions

101
board/mousse/u-boot.lds.ram Normal file
View File

@ -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 = .);
}

View File

@ -0,0 +1,154 @@
/*
* (C) Copyright 2001
* Thomas Koeller, tkoeller@gmx.net
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#ifndef __ASSEMBLY__
#define __ASSEMBLY__ 1
#endif
#include <config.h>
#include <asm/processor.h>
#include <mpc824x.h>
#include <ppc_asm.tmpl>
#if defined(USE_DINK32)
/* We are running from RAM, so do not clear the MCCR1_MEMGO bit! */
#define MCCR1VAL ((CFG_ROMNAL << MCCR1_ROMNAL_SHIFT) | (CFG_ROMFAL << MCCR1_ROMFAL_SHIFT) | MCCR1_MEMGO)
#else
#define MCCR1VAL (CFG_ROMNAL << MCCR1_ROMNAL_SHIFT) | (CFG_ROMFAL << MCCR1_ROMFAL_SHIFT)
#endif
.text
/* Values to program into memory controller registers */
tbl: .long MCCR1, MCCR1VAL
.long MCCR2, CFG_REFINT << MCCR2_REFINT_SHIFT
.long MCCR3
.long (((CFG_BSTOPRE & 0x000000f0) >> 4) << MCCR3_BSTOPRE2TO5_SHIFT) | \
(CFG_REFREC << MCCR3_REFREC_SHIFT) | \
(CFG_RDLAT << MCCR3_RDLAT_SHIFT)
.long MCCR4
.long (CFG_PRETOACT << MCCR4_PRETOACT_SHIFT) | (CFG_ACTTOPRE << MCCR4_ACTTOPRE_SHIFT) | \
(CFG_REGISTERD_TYPE_BUFFER << 20) | \
(((CFG_BSTOPRE & 0x00000300) >> 8) << MCCR4_BSTOPRE0TO1_SHIFT ) | \
((CFG_SDMODE_CAS_LAT << 4) | (CFG_SDMODE_WRAP << 3) | \
(CFG_SDMODE_BURSTLEN) << MCCR4_SDMODE_SHIFT) | \
(CFG_ACTTORW << MCCR4_ACTTORW_SHIFT) | \
((CFG_BSTOPRE & 0x0000000f) << MCCR4_BSTOPRE6TO9_SHIFT )
.long MSAR1
.long (((CFG_BANK0_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 0) | \
(((CFG_BANK1_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 8) | \
(((CFG_BANK2_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 16) | \
(((CFG_BANK3_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 24)
.long EMSAR1
.long (((CFG_BANK0_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 0) | \
(((CFG_BANK1_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 8) | \
(((CFG_BANK2_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 16) | \
(((CFG_BANK3_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 24)
.long MSAR2
.long (((CFG_BANK4_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 0) | \
(((CFG_BANK5_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 8) | \
(((CFG_BANK6_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 16) | \
(((CFG_BANK7_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 24)
.long EMSAR2
.long (((CFG_BANK4_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 0) | \
(((CFG_BANK5_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 8) | \
(((CFG_BANK6_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 16) | \
(((CFG_BANK7_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 24)
.long MEAR1
.long (((CFG_BANK0_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 0) | \
(((CFG_BANK1_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 8) | \
(((CFG_BANK2_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 16) | \
(((CFG_BANK3_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 24)
.long EMEAR1
.long (((CFG_BANK0_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 0) | \
(((CFG_BANK1_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 8) | \
(((CFG_BANK2_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 16) | \
(((CFG_BANK3_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 24)
.long MEAR2
.long (((CFG_BANK4_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 0) | \
(((CFG_BANK5_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 8) | \
(((CFG_BANK6_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 16) | \
(((CFG_BANK7_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 24)
.long EMEAR2
.long (((CFG_BANK4_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 0) | \
(((CFG_BANK5_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 8) | \
(((CFG_BANK6_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 16) | \
(((CFG_BANK7_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 24)
.long 0
/*
* Early CPU initialization. Set up memory controller, so we can access any RAM at all. This
* must be done in assembly, since we have no stack at this point.
*/
.global early_init_f
early_init_f:
mflr r10
/* basic memory controller configuration */
lis r3, CONFIG_ADDR_HIGH
lis r4, CONFIG_DATA_HIGH
bl lab
lab: mflr r5
lwzu r0, tbl - lab(r5)
loop: lwz r1, 4(r5)
stwbrx r0, 0, r3
eieio
stwbrx r1, 0, r4
eieio
lwzu r0, 8(r5)
cmpli cr0, 0, r0, 0
bne cr0, loop
/* set bank enable bits */
lis r0, MBER@h
ori r0, 0, MBER@l
li r1, CFG_BANK_ENABLE
stwbrx r0, 0, r3
eieio
stb r1, 0(r4)
eieio
/* delay loop */
lis r0, 0x0003
mtctr r0
delay: bdnz delay
/* enable memory controller */
lis r0, MCCR1@h
ori r0, 0, MCCR1@l
stwbrx r0, 0, r3
eieio
lwbrx r0, 0, r4
oris r0, 0, MCCR1_MEMGO@h
stwbrx r0, 0, r4
eieio
/* set up stack pointer */
lis r1, CFG_INIT_SP_OFFSET@h
ori r1, r1, CFG_INIT_SP_OFFSET@l
mtlr r10
blr

View File

@ -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 = .);
}

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1 @@
#include "epic/epic.h"

View File

@ -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.

View File

@ -0,0 +1,196 @@
/**************************************
*
* copyright @ Motorola, 1999
*
**************************************/
#include <ppc_asm.tmpl>
#include <ppc_defs.h>
#include <asm/processor.h>
/*********************************************
* function: CoreExtIntEnable
*
* description: Enable 603e core external interrupt
*
* note: mtmsr is context-synchronization
**********************************************/
.text
.align 2
.global CoreExtIntEnable
CoreExtIntEnable:
mfmsr r3
ori r3,r3,0x8000 /* enable external interrupt */
mtmsr r3
bclr 20, 0
/*******************************************
* function: CoreExtIntDisable
*
* description: Disable 603e core external interrupt
*
* note:
*******************************************/
.text
.align 2
.global CoreExtIntDisable
CoreExtIntDisable:
mfmsr r4
xor r3,r3,r3
or r3,r3,r4
andis. r4,r4,0xffff
andi. r3,r3,0x7fff /* disable external interrupt */
or r3,r3,r4
mtmsr r3
bclr 20, 0
/*********************************************************
* function: epicEOI
*
* description: signal the EOI and restore machine status
* Input: r3 - value of eumbbar
* Output: r3 - value of eumbbar
* r4 - ISR vector value
* note:
********************************************************/
.text
.align 2
.global epicEOI
epicEOI:
lis r5,0x0006 /* Build End Of Interrupt Register offset */
ori r5,r5,0x00b0
xor r7,r7,r7 /* Clear r7 */
stwbrx r7,r5,r3 /* Save r7, writing to this register will
* intidate the end of processing the
* highest interrupt.
*/
sync
/* ---RESTORE MACHINE STATE */
mfmsr r13 /* Clear Recoverable Interrupt bit in MSR */
or r7,r7,r13
andis. r7,r7,0xffff
andi. r13,r13,0x7ffd /* (and disable interrupts) */
or r13,r13,r7
mtmsr r13
lwz r13,0x1c(r1) /* pull ctr */
mtctr r13
lwz r13,0x18(r1) /* pull xer */
mtctr r13
lwz r13,0x14(r1) /* pull lr */
mtctr r13
lwz r13,0x10(r1) /* Pull SRR1 from stack */
mtspr SRR1,r13 /* Restore SRR1 */
lwz r13,0xc(r1) /* Pull SRR0 from stack */
mtspr SRR0,r13 /* Restore SRR0 */
lwz r13,0x8(r1) /* Pull User stack pointer from stack */
mtspr SPRG1,r13 /* Restore SPRG1 */
lwz r4,0x4(r1) /* vector value */
lwz r3,0x0(r1) /* eumbbar */
sync
addi r1,r1,0x20 /* Deallocate stack */
mtspr SPRG0,r1 /* Save updated Supervisor stack pointer */
mfspr r1,SPRG1 /* Restore User stack pointer */
bclr 20,0
/***********************************************************
* function: exception routine called by exception vector
* at 0x500, external interrupt
*
* description: Kahlua EPIC controller
*
* input: r3 - content of eumbbar
* output: r3 - ISR return value
* r4 - Interrupt vector number
* note:
***********************************************************/
.text
.align 2
.global epic_exception
epic_exception:
/*---SAVE MACHINE STATE TO A STACK */
mtspr SPRG1,r1 /* Save User stack pointer to SPRG1 */
mfspr r1,SPRG0 /* Load Supervisor stack pointer into r1 */
stwu r3,-0x20(r1) /* Push the value of eumbbar onto stack */
mfspr r3,SPRG1 /* Push User stack pointer onto stack */
stw r3,0x8(r1)
mfspr r3,SRR0 /* Push SRR0 onto stack */
stw r1,0xc(r1)
mfspr r3,SRR1 /* Push SRR1 onto stack */
stw r3,0x10(r1)
mflr r3
stw r3,0x14(r1) /* Push LR */
mfxer r3
stw r3,0x18(r1) /* Push Xer */
mfctr r3
stw r3,0x1c(r1) /* Push CTR */
mtspr SPRG0,r1 /* Save updated Supervisor stack pointer
* value to SPRG0
*/
mfmsr r3
ori r3,r3,0x0002 /* Set Recoverable Interrupt bit in MSR */
mtmsr r3
/* ---READ IN THE EUMBAR REGISTER */
lwz r6,0(r1) /* this is eumbbar */
sync
/* ---READ EPIC REGISTER: PROCESSOR INTERRUPT ACKNOWLEDGE REGISTER */
lis r5,0x0006 /* Build Interrupt Acknowledge Register
* offset
*/
ori r5,r5,0x00a0
lwbrx r7,r5,r6 /* Load interrupt vector into r7 */
sync
/* --MASK OFF ALL BITS EXCEPT THE VECTOR */
xor r3,r3,r3
xor r4,r4,r4
or r3, r3, r6 /* eumbbar in r3 */
andi. r4,r7,0x00ff /* Mask off bits, vector in r4 */
stw r4,0x04(r1) /* save the vector value */
lis r5,epicISR@ha
ori r5,r5,epicISR@l
mtlr r5
blrl
xor r30,r30,r30
or r30,r30,r3 /* save the r3 which containts the return value from epicISR */
/* ---READ IN THE EUMBAR REGISTER */
lwz r3,0(r1)
sync
lis r5,epicEOI@ha
ori r5,r5,epicEOI@l
mtlr r5
blrl
xor r3,r3,r3
or r3,r3,r30 /* restore the ISR return value */
bclr 20,0

View File

@ -0,0 +1,58 @@
/**************************************
*
* copyright @ Motorola, 1999
*
*
* This file contains two commonly used
* lower level utility routines.
*
* The utility routines are also in other
* Kahlua device driver libraries. The
* need to be linked in only once.
**************************************/
#include <ppc_asm.tmpl>
#include <ppc_defs.h>
/**********************************************************
* function: load_runtime_reg
*
* input: r3 - value of eumbbar
* r4 - register offset in embedded utility space
*
* output: r3 - register content
**********************************************************/
.text
.align 2
.global load_runtime_reg
load_runtime_reg:
xor r5,r5,r5
or r5,r5,r3 /* save eumbbar */
lwbrx r3,r4,r5
sync
bclr 20, 0
/****************************************************************
* function: store_runtime_reg
*
* input: r3 - value of eumbbar
* r4 - register offset in embedded utility space
* r5 - new value to be stored
*
****************************************************************/
.text
.align 2
.global store_runtime_reg
store_runtime_reg:
xor r0,r0,r0
stwbrx r5, r4, r3
sync
bclr 20,0

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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

344
cpu/mpc824x/drivers/i2o.h Normal file
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 );
}

View File

@ -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