8245 Uart & I2C
Etienne Martineau
etiennem at nortelnetworks.com
Sat Mar 16 08:18:08 EST 2002
I'm actually using PpcBoot & Linux HHL2.0 on a 8245 Custom board.
Everything work fine now bud I had to tweek some stuff to make it work
! (Uart, I2C, EPIC)
So here is how I did that (if anyone interested!)
UART:
I set the EUMBAR in ppcboot to be 0xf8f04500.
I also match this value in Linux sandpoint.h #define COM1 0xf8f04500
In Sandpoint_setup.c you point the Uart ppc_md.progress to
sandpoint_progress...
The first problem arrive when the CPU hit the code in
mpc10x_common.c
-> /* Map EPIC register part of EUMB into vitual memory */
OpenPIC_Addr =
ioremap(phys_eumb_base + MPC10X_EUMB_EPIC_OFFSET,
MPC10X_EUMB_EPIC_SIZE);
This stuff basically remap the EUMBAR and so for the UART. The
OpenPIC_Addr handle is used
by the open_pic.c file to basically set the IRQ stuff.
The trick I did to avoid playing with the OpenPIC ioremap stuff is
that I create a
var named: void* Uart_EUMBAR_Addr; which is global and AFTER the
ioremap I assign
this var to the new address of the Uart
->Uart_EUMBAR_Addr = ioremap(phys_eumb_base + 0x4500 ,0x4000);
if (ppc_md.progress) ppc_md.progress =
new_sandpoint_progress;
if (ppc_md.progress) ppc_md.progress("After Set
EUMBAR", 0x100); /*This Display stuff After EUMBAR Manipulation by
Linux*/
So you understand that the Redirection of ppc_md.progress need support
...
So In Sandpoint_setup.c I had that stuff.
extern void* Uart_EUMBAR_Addr;
void new_sandpoint_putc(volatile char s)
{
volatile struct NS16550 *com_port;
com_port = (volatile struct NS16550 *)(Uart_EUMBAR_Addr);
while ((com_port->lsr & LSR_THRE) == 0) ;
com_port->thr = s;
}
void
new_sandpoint_progress(char *s, unsigned short hex)
{
volatile char c;
volatile struct NS16550 *com_port;
com_port = (volatile struct NS16550 *)(Uart_EUMBAR_Addr);
while ((c = *s++) != 0) {
new_sandpoint_putc(c);
if (c == '\n') {
new_sandpoint_putc('\r');
}
}
return;
}
void new_sandpoint_printhex(unsigned int value, int cr)
{
int i;
const char hex[] = "0123456789abcdef";
for (i = 0; i < 8; i++)
new_sandpoint_putc(hex[value >> (28 - i * 4) & 0xf]);
if (cr)
new_sandpoint_putc('\n');
}
So now you have debug printout that look like that
Now booting the kernel
id mach(): doneMMU:enterMMU:hash inithash:enterhash:find
piecehash:patchhash:don
eMMU:mapinMMU:setbatMMU:exitsetup_arch: entersetup_arch:
bootmemmpc10x:enterAfte
r Set EUMBARmpc10x:exitarch: exitopenpic enteropenpic timeropenpic
extopenpic sp
uriousopenpic exit
The Serial Driver as to be fixed /driver/char/serial.c
-> static _INLINE_ unsigned int serial_in(struct async_struct *info, int
offset)
{
#ifdef CONFIG_yourflag
extern void* Uart_EUMBAR_Addr;
return readb((unsigned long) Uart_EUMBAR_Addr + offset);
#endif
->static _INLINE_ void serial_out(struct async_struct *info, int offset,
int value)
{
#ifdef CONFIG_yourflag
extern void* Uart_EUMBAR_Addr;
writeb(value, (unsigned long) Uart_EUMBAR_Addr + offset);
return;
#endif
for the IRQ stuff I define the Irq array in sandpoint_setup.c as
static u_char sandpoint_openpic_initsenses[16+130] __initdata;
And in Open_PIC.c I add that stuff in the function openpic_init (...
/*Uart IRQ*/
CurrIrq = 121+16;
irq_desc[CurrIrq].status = IRQ_LEVEL;
/* Enabled, Priority 8 or 9 */
openpic_initirq(CurrIrq, 8, CurrIrq, 0, 1);
/* Processor 0 */
openpic_mapirq(CurrIrq, 1<<0);
/* PMC 82559 Ethernet */
CurrIrq = 4+16;
irq_desc[CurrIrq].status = IRQ_LEVEL;
/* Enabled, Priority 8 or 9 */
openpic_initirq(CurrIrq, 8, CurrIrq, 0, 1);
/* Processor 0 */
openpic_mapirq(CurrIrq, 1<<0);
The Uart IRQ is 137 (I know it's look strange but with the OpenPic Stuff
that the Only way I found to access it with minimal code change)
you should modify SERIAL_PORT_DFNS Irq field to match that stuff in
/include/asm/serial.h
The Baudrate should be also set correctly and also the BASE_BAUD that
depend of you board speed (SDRAM_CLK).
NB: I'm using EPIC in parallel mode Ex: ethernet controller is on
External IRQ 4 >>> use 4 +16 to map it (the +16 is to deal with OpenPIC
vs EPIC difference)
I2C:
This is an User Space (mmap) driver for a generic I2C access.
I map the EUMBAR and I talk to the I2C engine directly.
I think I took that driver from PPCBOOT source tree but I can't remember
exactly anyway it's in a
primitive but working state.
->#include <linux/types.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <asm/io.h>
#include <sys/mman.h>
#include <stdio.h>
#include <string.h>
#ifdef I2C_DEBUG_ON
#define PRINTF printf
#else
#define PRINTF
#endif
#define OK 0
#define ERROR -1
#define EEPROM_TYPE_MPC8240 0
#define I2C_DRV_TYPE EEPROM_TYPE_MPC8240
/* low level definitions, specific */
#define SYNC __asm__ volatile ("sync")
#define BYTE_SWAP_16_BIT(x) ( (((x) & 0x00ff) << 8) | ( (x) >> 8) )
#define LONGSWAP(x) ((((x) & 0x000000ff) << 24) | (((x) & 0x0000ff00) <<
8)|\
(((x) & 0x00ff0000) >> 8) | (((x) & 0xff000000) >>
24) )
#define PCISWAP(x) LONGSWAP(x)
/* Mpc8240 IO / Internal Register */
#define MPC8240_EUMBAR 0xf8000000 - 0x100000
//#define I2C_BAR MPC8240_EUMBAR+0x41000
#define I2C_BAR MPC8240_EUMBAR+0x3000
typedef struct{
unsigned long i2cAddrReg;
unsigned long i2cFreqDivReg;
unsigned long i2cControlReg;
unsigned long i2cStatusReg;
unsigned long i2cDataReg;
}I2CStruct;
static volatile I2CStruct *I2Cptr;
#ifdef STUB
I2CStruct mystub;
#endif
static FILE *fh;
#define MPC8240_I2C_ADR_REG (unsigned long)&(I2Cptr->i2cAddrReg)
#define MPC8240_I2C_FREQ_DIV_REG (unsigned long)&(I2Cptr->i2cFreqDivReg)
#define MPC8240_I2C_CONTROL_REG (unsigned long)&(I2Cptr->i2cControlReg)
#define MPC8240_I2C_STATUS_REG (unsigned long)&(I2Cptr->i2cStatusReg)
#define MPC8240_I2C_DATA_REG (unsigned long)&(I2Cptr->i2cDataReg)
/* Mpc8240 Register masks */
#define MPC8240_I2C_ADDRESS_REG_MASK 0x000000FE
#define MPC8240_I2C_FREQ_DIV_REG_MASK 0x0000003F
#define MPC8240_I2C_CONTROL_REG_MASK 0x000000FC
#define MPC8240_I2C_STATUS_REG_MASK 0x000000F7
#define MPC8240_I2C_DATA_REG_MASK 0x000000FF
/* Mpc8240 Control register values */
#define MPC8240_I2C_CONTROL_REG_MEN (1<<7) /* module enable */
#define MPC8240_I2C_CONTROL_REG_MIEN (1<<6) /* module interrupt enable
*/
#define MPC8240_I2C_CONTROL_REG_MSTA (1<<5) /* master/slave mode */
#define MPC8240_I2C_CONTROL_REG_MTX (1<<4) /* transmit/receiver mode */
#define MPC8240_I2C_CONTROL_REG_TXAK (1<<3) /* transfer ack enable */
#define MPC8240_I2C_CONTROL_REG_RSTA (1<<2) /* repeat start */
/* Mpc8240 Status register values */
#define MPC8240_I2C_STATUS_REG_MCF (1<<7) /* data transferring */
#define MPC8240_I2C_STATUS_REG_MAAS (1<<6) /* addressed as a slave */
#define MPC8240_I2C_STATUS_REG_MBB (1<<5) /* bus busy */
#define MPC8240_I2C_STATUS_REG_MAL (1<<4) /* arbitration lost */
#define MPC8240_I2C_STATUS_REG_SRW (1<<2) /* slave read/write */
#define MPC8240_I2C_STATUS_REG_MIF (1<<1) /* module interrupt */
#define MPC8240_I2C_STATUS_REG_RXAK (1<<0) /* receive ack */
/*Application Specific*/
#define PRPMC600_EEPROM_WP 0x08
#define PRPMC600_SYS_STAT_REG1 0xffe00000
#define REAL_SPD_SIZE 256
/* forward declarations */
static unsigned long sysCalcBusSpd (void);
static unsigned long i2cPciInLong (unsigned long *);
static unsigned char i2cPciInByte (unsigned char *);
static void i2cPciOutLong (unsigned long *, unsigned long);
static void i2cPciOutByte (unsigned char *, unsigned char);
static int _abs(unsigned int);
static int _delta(unsigned int, unsigned int);
static unsigned long i2cPciIoctl(unsigned long, unsigned long,
unsigned long, unsigned long);
void mpc8240_mpc107_write8(unsigned int address, unsigned char data);
void mpc8240_mpc107_write16(unsigned int address, unsigned short data);
void mpc8240_mpc107_write32(unsigned int address, unsigned int data);
unsigned char mpc8240_mpc107_read8(unsigned int address);
unsigned short mpc8240_mpc107_read16(unsigned int address);
unsigned int mpc8240_mpc107_read32(unsigned int address);
int I2CDoRepeatStart = 0; /* indicates if a "Repeat Start" is requested
*/
/******************************************************************************
*
* i2cDrvInit - initialize the i2c device
*
* This function's purpose is to the initialize the I2C device
* controller device for operation. This function should only
* be executed once during system initialization time.
*
* RETURNS: OK, or ERROR if not prpmc600 board.
*/
int i2cCycleMpc8240Init
(
int i2cControllerType /* I2C controller type */
)
{
unsigned int busSpeed = 0;
unsigned char temp;
unsigned int statusReg;
int memoryhandle;
#ifndef STUB
/*Open an Handle to Access this Kernel Memory from User Process*/
fh = fopen ("/dev/mem", "rw+");
memoryhandle= (unsigned long) mmap (
/* where to map to: don't mind */
NULL,
/* how many bytes ? */
sizeof(I2CStruct),
/* want to read and write */
PROT_READ | PROT_WRITE,
/* no copy on write */
MAP_SHARED,
/* handle to /dev/mem */
fileno (fh),
/*Addr of the physical Page*/
I2C_BAR);
if(memoryhandle ==-1){
PRINTF("Failure on Allocation of region\n");
return 1;
}
/*Here I assign the I2C Structure to the Virtual Mem Addr that
as been mapped to Physical Addr*/
I2Cptr = (I2CStruct*)memoryhandle;
#endif
#ifdef STUB
/*Here I assign the Download Structure to the Virtual Mem Addr that
as been mapped to Physical Addr STUB*/
I2Cptr = (I2CStruct*)&mystub;
#endif
/*
* Check for unknown controller type, and initialize I2C controller
* for operation (if needed). Note: a switch will not work here if
* executing from ROM due to branch history table creation.
*/
if (i2cControllerType == 0) /* Mpc8240(MPC8240) */
{
/* disable the I2C module, set the device to Master Mode */
i2cPciIoctl(3, (unsigned long)MPC8240_I2C_CONTROL_REG,
~MPC8240_I2C_CONTROL_REG_MEN, 0);
SYNC;
/*Set Frequency*/
i2cPciIoctl(4, (unsigned long)MPC8240_I2C_FREQ_DIV_REG,
(~MPC8240_I2C_FREQ_DIV_REG_MASK), 0x29);
/* set the slave address */
i2cPciIoctl(4, (unsigned long)MPC8240_I2C_ADR_REG,
(~MPC8240_I2C_ADDRESS_REG_MASK), 0x02);
SYNC;
/* enable the interface */
i2cPciIoctl(2, (unsigned long)MPC8240_I2C_CONTROL_REG,
MPC8240_I2C_CONTROL_REG_MEN, 0);
SYNC;
PRINTF("\n I2C init:\n");
statusReg = i2cPciIoctl(1, (unsigned long)MPC8240_I2C_STATUS_REG,
0, 0);
PRINTF("status: 0x%08x ", statusReg);
statusReg = i2cPciIoctl(1, (unsigned
long)MPC8240_I2C_CONTROL_REG, 0, 0);
PRINTF("control: 0x%08x ", statusReg);
statusReg = i2cPciIoctl(1, (unsigned
long)MPC8240_I2C_FREQ_DIV_REG, 0, 0);
PRINTF("Freq: 0x%08x\n", statusReg);
statusReg = i2cPciIoctl(1, (unsigned long)MPC8240_I2C_ADR_REG,
0, 0);
PRINTF("Adr: 0x%08x\n", statusReg);
}
else
{
return (-1);
}
return (0);
}
int i2cCycleMpc8240Close(void)
{
#ifndef STUB
munmap((caddr_t) I2C_BAR, sizeof(I2CStruct));
fclose (fh);
#endif
return 0;
}
/******************************************************************************
*
* i2cCycleMpc8240Start - perform I2C "start" cycle
*
* This function's purpose is to perform an I2C start cycle.
*
* RETURNS:
* zero = operation successful
* non-zero = operation failed
*/
int i2cCycleMpc8240Start (void)
{
unsigned int timeOutCount;
unsigned int statusReg = 0;
/*
* if this is a repeat start, then set the required bits and return.
*
* NOTE:
* this driver ONLY supports one repeat start between the start
* stop and cycles.
*/
if(I2CDoRepeatStart == 1)
{
i2cCycleMpc8240Delay(1);
i2cPciIoctl(2, (unsigned long)MPC8240_I2C_CONTROL_REG,
(MPC8240_I2C_CONTROL_REG_RSTA |
MPC8240_I2C_CONTROL_REG_MSTA |
MPC8240_I2C_CONTROL_REG_MTX),0);
SYNC;
i2cCycleMpc8240Delay(1);
I2CDoRepeatStart = 0; /* one repeat start only, so clear this
bit */
return(0);
}
/*
* wait until the I2C bus is free. if it doesn't become free
* within a *reasonable* amount of time, exit with an error.
*/
for (timeOutCount = 10; timeOutCount; timeOutCount--)
{
i2cCycleMpc8240Delay(1);
statusReg = i2cPciIoctl(1, (unsigned
long)MPC8240_I2C_STATUS_REG, 0, 0);
SYNC;
if (!(statusReg & MPC8240_I2C_STATUS_REG_MBB))
{
break;
}
}
if (!timeOutCount)
{
return (-1);
}
/*
* since this is the first time through, generate a START(MSTA) and
* place the I2C interface into a master transmitter mode(MTX).
*/
i2cPciIoctl(2, (unsigned long)MPC8240_I2C_CONTROL_REG,
(MPC8240_I2C_CONTROL_REG_MTX |
MPC8240_I2C_CONTROL_REG_MSTA),0);
SYNC;
i2cCycleMpc8240Delay(1);
/*
* The first time through, set "I2CDoRepeatStart". If this function
* is called again BEFORE a STOP is sent, then we are doing a
* "dummy write", which sets the devices internal byte pointer
* to the byte we intend to read.
*/
I2CDoRepeatStart = 1;
return (0);
}
/******************************************************************************
*
* i2cCycleMpc8240Stop - perform I2C "stop" cycle
*
* This function's purpose is to perform an I2C stop cycle.
*
* RETURNS:
* zero = operation successful
* non-zero = operation failed
*/
int i2cCycleMpc8240Stop (void)
{
i2cCycleMpc8240Delay(1);
/*
* turn off MSTA bit(which will generate a STOP bus cycle)
* turn off MTX bit(which places the MPC8240 interface into receive
mode
* turn off TXAK bit(which allows 9th clock cycle acknowledges)
*/
i2cPciIoctl(3, (unsigned long)MPC8240_I2C_CONTROL_REG,
(~(MPC8240_I2C_CONTROL_REG_MTX |
MPC8240_I2C_CONTROL_REG_MSTA |
MPC8240_I2C_CONTROL_REG_TXAK)),0);
SYNC;
i2cCycleMpc8240Delay(1);
/*
* Clear the global I2C "Repeat Start" flag.
*/
I2CDoRepeatStart = 0;
return (0);
}
/******************************************************************************
*
* i2cCycleMpc8240Read - perform I2C "read" cycle
*
* This function's purpose is to perform an I2C read cycle.
*
* RETURNS:
* zero = operation successful
* non-zero = operation failed
*/
int ReadAckFlag =0;
void ReadAckFlag_ON(void)
{
ReadAckFlag =1;
}
void ReadAckFlag_OFF(void)
{
ReadAckFlag =0;
}
int i2cCycleMpc8240Read
(
unsigned char *pReadDataBuf /* pointer to read data buffer */
)
{
unsigned int readData = 0;
i2cCycleMpc8240Delay(1);
if(ReadAckFlag ==0){
/*
* place the I2C interface into receive mode(MTX=0) and set the
interface
* to NOT acknowledge(TXAK=1) the incoming data on the 9th clock
cycle.
* this is required when doing random reads of a I2C device.
*/
i2cPciIoctl(4, (unsigned long)MPC8240_I2C_CONTROL_REG,
(~MPC8240_I2C_CONTROL_REG_MTX),
MPC8240_I2C_CONTROL_REG_TXAK);
SYNC;
}
else{
i2cPciIoctl(3, (unsigned long)MPC8240_I2C_CONTROL_REG,
(~MPC8240_I2C_CONTROL_REG_MTX),0);
i2cPciIoctl(3, (unsigned long)MPC8240_I2C_CONTROL_REG,
(~MPC8240_I2C_CONTROL_REG_TXAK),0);
SYNC;
}
i2cCycleMpc8240Delay(1);
/* do a "dummy read". this latches the data off the bus. */
i2cPciIoctl(1, (unsigned long)MPC8240_I2C_DATA_REG, 0, 0);
SYNC;
i2cCycleMpc8240Delay(1);
/* now do the actual read, make this one count */
readData = i2cPciIoctl(1, (unsigned long)MPC8240_I2C_DATA_REG, 0,
0);
SYNC;
*pReadDataBuf = (unsigned char)readData;
return (0);
}
/******************************************************************************
*
* i2cCycleMpc8240Write - perform I2C "write" cycle
*
* This function's purpose is to perform an I2C write cycle.
*
* RETURNS:
* zero = operation successful
* non-zero = operation failed
*/
int i2cCycleMpc8240Write
(
unsigned char writeData /* character to write */
)
{
i2cCycleMpc8240Delay(1);
/*
* write the requested data to the data register, which will cause
* it to be transmitted on the I2C bus.
*/
i2cPciIoctl(0, (unsigned long)MPC8240_I2C_DATA_REG, writeData, 0);
SYNC;
i2cCycleMpc8240Delay(1);
return (0);
}
/******************************************************************************
*
* i2cCycleMpc8240AckIn - perform I2C "acknowledge-in" cycle
*
* This function's purpose is to perform an I2C acknowledge-in
* cycle.
*
* RETURNS:
* zero = operation successful
* non-zero = operation failed
*/
int i2cCycleMpc8240AckIn (void)
{
unsigned int statusReg = 0;
unsigned int timeOutCount;
/*
* wait until an *internal* device interrupt has been generated,
then
* clear it. if it is not received, return with an error.
* we are polling, so NO processor interrupt is generated.
*/
for (timeOutCount = 100; timeOutCount; timeOutCount--)
{
i2cCycleMpc8240Delay(1);
statusReg = i2cPciIoctl(1, (unsigned
long)MPC8240_I2C_STATUS_REG, 0, 0);
SYNC;
if (statusReg & MPC8240_I2C_STATUS_REG_MIF)
{
i2cPciIoctl(3, (unsigned long)MPC8240_I2C_STATUS_REG,
(~MPC8240_I2C_STATUS_REG_MIF), 0);
SYNC;
break;
}
}
if (!timeOutCount)
{
return (-1);
}
return (0);
}
/******************************************************************************
*
* i2cCycleMpc8240AckOut - perform I2C "acknowledge-out" cycle
*
* This function's purpose is to perform an I2C acknowledge-out
* cycle.
*
* RETURN:
* zero = operation successful
* non-zero = operation failed
*/
int i2cCycleMpc8240AckOut (void)
{
return (0);
}
/******************************************************************************
*
* i2cCycleMpc8240KnownState - initialize the I2C bus to a known state
*
* This function's purpose is to initialize the I2C bus to a
* known state.
*
* RETURNS:
* zero = operation successful
* non-zero = operation failed
*/
int i2cCycleMpc8240KnownState (void)
{
int status;
unsigned int timeOutCount;
unsigned int statusReg;
status = OK;
/*
* wait u til the I2C bus is free. if it doesn't become free
* within a *reasonable* amount of time, exit with an error.
*/
for (timeOutCount = 10; timeOutCount; timeOutCount--)
{
i2cCycleMpc8240Delay(1);
statusReg = i2cPciIoctl(1, (unsigned
long)MPC8240_I2C_STATUS_REG, 0, 0);
SYNC;
PRINTF("statusReg: 0x%08x MBB: 0x%08x Reg: 0x%08x\n",
statusReg,MPC8240_I2C_STATUS_REG_MBB,(statusReg &
MPC8240_I2C_STATUS_REG_MBB) );
if (!(statusReg & MPC8240_I2C_STATUS_REG_MBB))
{
status = OK;
break;
}
/*
* re-initialize the I2C if the BUS BUSY does not clear
* after trying half the *reasonable* amount of reads of the
* status register.
*/
}
if (!timeOutCount)
status = ERROR;
return (status);
}
/******************************************************************************
*
* i2cCycleMpc8240Delay - perform interface's I2C delay routine
*
* This function's purpose is to perform whatever delay
* required for the device.
*
* RETURNS:
* none.
*/
void i2cCycleMpc8240Delay
(
int mSeconds /* time to delay in milliseconds */
)
{
int i = 0;
for(i = 0;i < (mSeconds * 1000);i++){}
}
/******************************************************************************
*
* i2cPciIoctl - i2cPciIn/OutLong and/or-ing wrapper.
*
* The purpose of this function is to perform and, or and
* and/or i2cPciIn/OutLong operations with syncronization.
*
* RETURNS: UINT32, for read operations.
*/
static unsigned long i2cPciIoctl
(
unsigned long ioctlflg, /* input/ouput control flag
* 0, write
* 1, read
* 2, read/modify/write (ORing)
* 3, read/modify/write (ANDing)
* 4, read/modify/write (AND/ORing)
*/
unsigned long address, /* address of device register to be
operated upon */
unsigned long wdata1, /* data item 1 for read/write operation */
unsigned long wdata2 /* data item 2 for read/write operation */
)
{
unsigned long u32temp;
if (ioctlflg == 0) /* write */
i2cPciOutLong((unsigned long *)address, wdata1);
if (ioctlflg == 1) /* read */
{
wdata1 = i2cPciInLong((unsigned long *)address);
}
if (ioctlflg == 2) /* ORing */
{
u32temp = i2cPciInLong((unsigned long *)address);
SYNC;
u32temp |= wdata1;
i2cPciOutLong((unsigned long *)address, u32temp);
}
if (ioctlflg == 3) /* ANDing */
{
u32temp = i2cPciInLong((unsigned long *)address);
SYNC;
u32temp &= wdata1;
i2cPciOutLong((unsigned long *)address, u32temp);
}
if (ioctlflg == 4) /* AND/ORing */
{
u32temp = i2cPciInLong((unsigned long *)address);
SYNC;
u32temp &= wdata1;
u32temp |= wdata2;
i2cPciOutLong((unsigned long *)address, u32temp);
}
SYNC;
return (wdata1);
}
#define BAUD_RATE 9600
#define BAUD_RATE_CODE 12
#define EDGES_PER_PERIOD 2 /* one rising, one falling = 2 */
#define BAUD_CLOCK_RATIO 16 /* UART's BAUDOUT is 16x baud rate
*/
#define TIME_BASE_RATIO 4 /* time base clock is 1/4 bus
frequency */
#define MULTIPLIER (EDGES_PER_PERIOD * BAUD_CLOCK_RATIO *
TIME_BASE_RATIO)
static unsigned long sysCalcBusSpd (void)
{
extern unsigned int sysTimeEdges(unsigned int);
#if 0 /* We don't need to do this since we're already initialized */
UCHAR * pUart = (UCHAR *) PRPMC600_COM1_UART;
/* configure the uart for 9600 baud */
pUart[UART_LCR * UART_REG_ADDR_INTERVAL] |= I8250_LCR_DLAB;
pUart[UART_BRDL * UART_REG_ADDR_INTERVAL] = BAUD_RATE_CODE;
pUart[UART_BRDH * UART_REG_ADDR_INTERVAL] = 0;
pUart[UART_LCR * UART_REG_ADDR_INTERVAL] &= ~I8250_LCR_DLAB;
SYNC;
#endif
/*
* call low-level edge timing routine, calculate bus frequency and
* return the result.
*/
#if 0
return (sysTimeEdges (BAUD_RATE) * MULTIPLIER);
#else
return(1);
#endif
}
static int _abs(unsigned int x){
if(x < 0) return (-x);
else return (x);
}
static int _delta(unsigned int x,unsigned int y){
return( _abs((int)x - (int)y) );
}
/*****************************************************************************
*
* i2cPciInLong - reads a longword from PCI I/O or Memory space
*
* This function reads a longword from a specified PCI I/O or Memory
address
* via the PCI bridge chip. This function should be used for access
* to the I/O or Memory mapped registers of a PCI device. These
* registers are mapped as little-endian, so we byte reverse the data in
order
* to make the value returned look the same as it would in PCI space.
*
* RETURNS: longword from address.
*
*/
static unsigned long i2cPciInLong (unsigned long * dataPtr)
{
return(mpc8240_mpc107_read32((unsigned int)dataPtr));
}
/*****************************************************************************
*
* i2cPciOutLong - writes a longword to PCI I/O or Memory space
*
* This function writes a longword to a specified PCI I/O or Memory
address
* via the PCI bridge chip. This function should be used for access
* to the I/O or Memory mapped registers of a PCI device. These
* registers are mapped as little-endian, so we byte reverse the data in
order
* to make the value written correct for the registers in PCI space.
*
* RETURNS: N/A
*
*/
static void i2cPciOutLong
(
unsigned long * dataPtr,
unsigned long data
)
{
mpc8240_mpc107_write32((unsigned int)dataPtr,data);
}
/*****************************************************************************
*
* i2cPciInByte - reads a byte from PCI I/O or Memory space
*
* This function reads a byte from a specified PCI I/O or Memory address
* via the PCI bridge chip. This function should be used for access
* to the I/O or Memory mapped registers of a PCI device. Since this
routine
* accesses only a single byte of data no address or data manipulation is
* required.
*
* RETURNS: byte from address.
*/
static unsigned char i2cPciInByte (unsigned char * dataPtr)
{
return(mpc8240_mpc107_read8((unsigned int)dataPtr));
}
/*****************************************************************************
*
* i2cPciOutByte - writes a byte to PCI I/O or Memory space
*
* This function writes a byte to a specified PCI I/O or Memory address
* via the QSPAN bridge chip. This function should be used for writing
* to the I/O or Memory mapped registers of a PCI device. Since this
routine
* writes only a single byte of data no address or data manipulation is
* required.
*
* RETURNS: N/A
*
*/
static void i2cPciOutByte
(
unsigned char * dataPtr,
unsigned char data
)
{
mpc8240_mpc107_write8((unsigned int)dataPtr,data);
}
/*
* Write a byte (8 bits) to a memory location.
*/
void
mpc8240_mpc107_write8(unsigned int addr, unsigned char data)
{
*(unsigned char*)addr = data;
__asm__("sync");
}
/*
* Write a word (16 bits) to a memory location after the value
* has been byte swapped (big to little endian or vice versa)
*/
void
mpc8240_mpc107_write16(unsigned int address, unsigned short data)
{
*(volatile unsigned short *)address = BYTE_SWAP_16_BIT(data);
__asm__("sync");
}
/*
* Write a long word (32 bits) to a memory location after the value
* has been byte swapped (big to little endian or vice versa)
*/
void
mpc8240_mpc107_write32(unsigned int address, unsigned int data)
{
*(volatile unsigned int *)address = LONGSWAP(data);
__asm__("sync");
}
/*
* Read a byte (8 bits) from a memory location.
*/
unsigned char
mpc8240_mpc107_read8(unsigned int addr)
{
return *(volatile unsigned char*)addr;
}
/*
* Read a word (16 bits) from a memory location, and byte swap the
* value before returning to the caller.
*/
unsigned short
mpc8240_mpc107_read16(unsigned int address)
{
unsigned short retVal;
retVal = BYTE_SWAP_16_BIT(*(unsigned short*)address);
return retVal;
}
/*
* Read a long word (32 bits) from a memory location, and byte
* swap the value before returning to the caller.
*/
unsigned int
mpc8240_mpc107_read32(unsigned int address)
{
unsigned int retVal;
retVal = LONGSWAP(*(unsigned int *)address);
return (retVal);
}
Etienne
** Sent via the linuxppc-embedded mail list. See http://lists.linuxppc.org/
More information about the Linuxppc-embedded
mailing list