📄 patchi2c.c
字号:
/*
*
* File: patchi2c.c
* Description: Simple I2C driver using patch to relocate I2C parameters
*
* Target device: Any MPC8xx processor with a CPM-driven I2C
*
* This driver uses the RAM microcode patch which relocates the I2C and
* SPI parameters to locations other than their default.
*
* The driver first loads and enables and enables the microcode.
*
* Then the driver sets up the I2C in master mode to transmit a message
* to itself (i.e. loopback). It performs an I2C write transmission to its
* own station address. [Note that loopback operation is not possible for
* I2C read transmissions.]
*
* After sending the message, the driver 'terminates' in an infinite loop.
*
* NOTES <<<IMPORTANT: PLEASE READ>>>:
* 1) A pullup resistor is required on the I2C data and clock lines (PB27
* and PB26 of the MPC860)
* 2) DISABLE Data Cache for pages containing Rx/Tx buffers.
*
*
* 7/18/97 sgj Initial version.
* 10/14/97 sgj Fixed bug -- initialize RSTATE and TSTATE params
*
*/
#include <string.h>
#include "mpc860.h"
#include "patchi2c.h"
/* Internal Routines */
void startup(void);
void UcodeInit();
void RLI2CInit();
void I2CStart();
void Main(void);
/* Set of I2C Receive Buffers and Transmit Buffer */
LB rtxbuf[NUM_RXBDS+1];
/* Stack Frame Stuff for mpc8bug */
int stack[100];
int stackTop;
/* Arrays containing I2C/SPI-parameter-relocating microcode patch */
unsigned long ucodeArray1[0x74] =
{ 0x7fffefd9, 0x3ffd0000, 0x7ffb49f7, 0x7ff90000,
0x5fefadf7, 0x5f89adf7, 0x5fefaff7, 0x5f89aff7,
0x3a9cfbc8, 0xe7c0edf0, 0x77c1e1bb, 0xf4dc7f1d,
0xabad932f, 0x4e08fdcf, 0x6e0faff8, 0x7ccf76cf,
0xfd1ff9cf, 0xabf88dc6, 0xab5679f7, 0xb0937383,
0xdfce79f7, 0xb091e6bb, 0xe5bbe74f, 0xb3fa6f0f,
0x6ffb76ce, 0xee0df9cf, 0x2bfbefef, 0xcfeef9cf,
0x76cead24, 0x90b2df9a, 0x7fddd0bf, 0x4bf847fd,
0x7ccf76ce, 0xcfef7e1f, 0x7f1d7dfd, 0xf0b6ef71,
0x7fc177c1, 0xfbc86079, 0xe722fbc8, 0x5fffdfff,
0x5fb2fffb, 0xfbc8f3c8, 0x94a67f01, 0x7f1d5f39,
0xafe85f5e, 0xffdfdf96, 0xcb9faf7d, 0x5fc1afed,
0x8c1c5fc1, 0xafdd5fc3, 0xdf9a7efd, 0xb0b25fb2,
0xfffeabad, 0x5fb2fffe, 0x5fce600b, 0xe6bb600b,
0x5fcedfc6, 0x27fbefdf, 0x5fc8cfde, 0x3a9ce7c0,
0xedf0f3c8, 0x7f0154cd, 0x7f1d2d3d, 0x363a7570,
0x7e0af1ce, 0x37ef2e68, 0x7fee10ec, 0xadf8efde,
0xcfeae52f, 0x7d0fe12b, 0xf1ce5f65, 0x7e0a4df8,
0xcfea5f72, 0x7d0befee, 0xcfea5f74, 0xe522efde,
0x5f74cfda, 0x0b627385, 0xdf627e0a, 0x30d8145b,
0xbffff3c8, 0x5fffdfff, 0xa7f85f5e, 0xbffe7f7d,
0x10d31450, 0x5f36bfff, 0xaf785f5e, 0xbffda7f8,
0x5f36bffe, 0x77fd30c0, 0x4e08fdcf, 0xe5ff6e0f,
0xaff87e1f, 0x7e0ffd1f, 0xf1cf5f1b, 0xabf80d5e,
0x5f5effef, 0x79f730a2, 0xafdd5f34, 0x47f85f34,
0xafed7fdd, 0x50b24978, 0x47fd7f1d, 0x7dfd70ad,
0xef717ec1, 0x6ba47f01, 0x2d267efd, 0x30de5f5e,
0xfffd5f5e, 0xffef5f5e, 0xffdf0ca0, 0xafed0a9e,
0xafdd0c3a, 0x5f3aafbd, 0x7fbdb082, 0x5f8247f8
};
unsigned long ucodeArray2[0x1d] =
{ 0x3e303430, 0x34343737, 0xabf7bf9b, 0x994b4fbd,
0xbd599493, 0x349fff37, 0xfb9b177d, 0xd9936956,
0xbbfdd697, 0xbdd2fd11, 0x31db9bb3, 0x63139637,
0x93733693, 0x193137f7, 0x331737af, 0x7bb9b999,
0xbb197957, 0x7fdfd3d5, 0x73b773f7, 0x37933b99,
0x1d115316, 0x99315315, 0x31694bf4, 0xfbdbd359,
0x31497353, 0x76956d69, 0x7b9d9693, 0x13131979,
0x79376935
};
/* startup -- Initial program entry point */
void startup(void)
{
/* Stack Frame / Entrypoint Stuff for mpc8bug */
#ifdef MetaWare
_ASM("_start: .global _start ");
_ASM(" addis %r1,%r0,stackTop@ha");
_ASM(" ori %r1,%r1,stackTop@l");
#else
#ifdef Diab
asm("_start: .gbl _start ");
asm(" addis r1,r0,stackTop@ha");
asm(" ori r1,r1,stackTop@l");
#endif
#endif
Main();
while(1); /* loop here for a while */
}
void Main()
{
int breakonme = 0;
/* Initialize Microcode */
UcodeInit();
/* Initialize I2C (using relocated parameters) */
RLI2CInit();
/* Start I2C in loopback */
I2CStart();
breakonme++; /* This is just a convenient place to break using
a source-level debugger. No significance. */
while(1);
}
/**************************************************************
*
* Microcode Initialization Routine
*
* Function UcodeInit -- Copies two blocks of microcode (the
* first to the lowest block of DPRAM,
* the second to the microcode extension
* block in DPRAM). Then enables the
* microcode
*
* Input Parameters: none
*
*************************************************************/
void UcodeInit()
{
EPPC *immr = (EPPC *) (GetIMMR() & 0xffff0000);
unsigned long *targetptr;
unsigned int i;
immr->cp_rccr = 0; /* Unlock microcode program area */
/* Copy first block of microcode to lowest block of DPRAM */
targetptr = (unsigned long *) & (immr->udata_bd_ucode);
for(i=0; i<(0x74); i++) *(targetptr++) = ucodeArray1[i];
/* Copy second block of microcode to microcode extension block of DPRAM */
targetptr = (unsigned long *) & (immr->ucode_ext);
for(i=0; i<(0x1d); i++) *(targetptr++) = ucodeArray2[i];
/* Activate the microcode per the instructions in the microcode manual*/
immr->cp_rccr = 0;
immr->cp_rctr3 = 0x802e; /* We're only relocating the I2C parameters */
immr->cp_rctr4 = 0x802c;
immr->cp_rccr = 1;
}
/**************************************************************
*
* I2C Initialization Routine using relocated I2C parameters
*
* Function: I2CInit -- Initializes I2C registers, parameters,
* and buffer descriptors
*
* Sets pointer to relocated I2C parameters, then
* sets up I2C for write transmission to its own station
* address. Interrupts are not enabled.
*
* Input Parameters: none
*
*************************************************************/
void RLI2CInit()
{
EPPC *immr = (EPPC *) (GetIMMR() & 0xffff0000); /* MPC8xx internal register map */
RTXBD *rtx = (RTXBD *) immr->udata_bd_ucode2; /* Pointer to BD area of DPRAM */
char *txbuf;
unsigned short *rpbase; /* Pointer to relocated I2C parameters */
struct i2c_pram *rli2cparams; /* Relocated I2C parameters */
unsigned long templong; /* Temporary unsigned long for pointer arithmetic */
/* Point to RPBASE in old I2C param area */
templong = (unsigned long) (& (immr->pram[PAGE1_PRAM].scc.pothers.i2c_idma.i2c) );
templong = templong + 0x0000002c;
rpbase = (unsigned short *) templong;
/* Put I2C parameters in DSP2 area */
rli2cparams = (struct i2c_pram *) (& (immr->pram[PAGE4_PRAM].scc.pothers.smc_modem.modem_param) );
/* Relocate the I2C parameters */
*rpbase = 0x1fc0; /* Locate parameters in DSP2 area (Offset from DPRAM base) */
/* Configure Port B pins to enable I2CSDA and I2CSCL */
immr->pip_pbodr |= (0x0030); /* Set I2CSDA and I2CSCL to open-drain */
immr->pip_pbpar |= (0x00000030); /* Enable I2CSDA and I2CSCL as outputs */
immr->pip_pbdir |= (0x00000030);
/* I2C Parameter RAM */
rli2cparams->rfcr = 0x10;
rli2cparams->tfcr = 0x10;
rli2cparams->mrblr = BUFF_MAX_LEN;
/* You have to manually initialize rstate and tstate if using the microcode patch.
[You don't normally have to for I2C */
rli2cparams->rstate = 0;
rli2cparams->tstate = 0;
/* I2C Registers */
immr->i2c_i2mod = 0x00; /* Disable I2C before initializing it */
immr->i2c_i2add = 0x80; /* Station address = 0x80 */
immr->i2c_i2brg = 0x20; /* Arbitrary choice of baud rate: BRGCLK/32 */
immr->i2c_i2cer = 0x17; /* Clear out I2C events */
immr->i2c_i2cmr = 0x00; /* Disable interrupts from I2C */
immr->i2c_i2mod = 0x01;
/* Note: Original version of MPC860 manual states that the REVD=1 in the I2CMOD
register sends MSB first (I2C normal operation). This was an ERRATUM.
REVD must be set to zero for normal I2C operation.
/* I2C Buffers */
/* point RBASE to first RX BD */
rli2cparams->rbase = (unsigned short) & rtx->rxbd[0];
/* point TBASE to TX BD */
rli2cparams->tbase = (unsigned short) & rtx->txbd;
/* You have to manually initialize rbptr and tbptr if using the microcode patch.
[You don't normally have to for I2C */
rli2cparams->rbptr = rli2cparams->rbase;
rli2cparams->tbptr = rli2cparams->tbase;
rtx->rxbd[0].bd_length = 0; /* reset */
rtx->rxbd[0].bd_addr = (char *) & rtxbuf[0]; /* point RX BD to first RX buffer address */
rtx->rxbd[0].bd_cstatus = 0xa000; /* ready and wrap */
rtx->txbd.bd_length = 0x0019;
rtx->txbd.bd_addr = (char *) & rtxbuf[TXBD_INDX];
/* Put address and message in TX buffer */
txbuf = (char *) rtx->txbd.bd_addr;
txbuf[0] = 0x80; /* TX address and write command, sending to our own address 0x80 */
strcpy((txbuf+1), "In-a-gadda-da-vida, baby");
rtx->txbd.bd_cstatus = 0xac00; /* ready, wrap, last, and start */
/*
* Init RX & TX Parameters Command not supported by the microcode patch,
* so do it in two separate commands.
*/
/*
* Issue Init RX Parameters Command for I2C.
*/
while( immr->cp_cr & (0x0001) ); /* SPIN UNTIL READY TO ISSUE COMMAND */
immr->cp_cr = (0x0111); /* ISSUE COMMAND */
while( immr->cp_cr & (0x0001) ); /* SPIN UNTIL COMMAND PROCESSED */
/*
* Issue Init TX Parameters Command for I2C.
*/
while( immr->cp_cr & (0x0001) ); /* SPIN UNTIL READY TO ISSUE COMMAND */
immr->cp_cr = (0x0211); /* ISSUE COMMAND */
while( immr->cp_cr & (0x0001) ); /* SPIN UNTIL COMMAND PROCESSED */
}
/*
* I2C Start routine
*
* Function: I2CStart -- sets master mode and starts the transmitter
*
*/
void I2CStart()
{
EPPC *immr = (EPPC *) (GetIMMR() & 0xffff0000); /* MPC8xx internal register map */
immr->i2c_i2com = 0x81; /* Set master mode and issue start command */
}
/*
* GetIMMR() returns the current value in IMMR register.
*/
GetIMMR()
{
#ifdef MetaWare
_ASM(" mfspr %r3,638 "); /* IMMR is spr #638 */
#else
#ifdef Diab
asm(" mfspr r3,638 "); /* IMMR is spr #638 */
#endif
#endif
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -