| /* Minimal support functions to read configuration from IIC EEPROMS | |
| * on MPC8xx boards. Originally written for RPGC RPX-Lite. | |
| * Dan Malek (dmalek@jlc.net). | |
| */ | |
| #include <linux/types.h> | |
| #include <asm/uaccess.h> | |
| #include <asm/mpc8xx.h> | |
| #include <asm/commproc.h> | |
| /* IIC functions. | |
| * These are just the basic master read/write operations so we can | |
| * examine serial EEPROM. | |
| */ | |
| void iic_read(uint devaddr, u_char *buf, uint offset, uint count); | |
| static int iic_init_done; | |
| static void | |
| iic_init(void) | |
| { | |
| volatile iic_t *iip; | |
| volatile i2c8xx_t *i2c; | |
| volatile cpm8xx_t *cp; | |
| volatile immap_t *immap; | |
| uint dpaddr; | |
| immap = (immap_t *)IMAP_ADDR; | |
| cp = (cpm8xx_t *)&(immap->im_cpm); | |
| /* Reset the CPM. This is necessary on the 860 processors | |
| * that may have started the SCC1 ethernet without relocating | |
| * the IIC. | |
| * This also stops the Ethernet in case we were loaded by a | |
| * BOOTP rom monitor. | |
| */ | |
| cp->cp_cpcr = (CPM_CR_RST | CPM_CR_FLG); | |
| /* Wait for it. | |
| */ | |
| while (cp->cp_cpcr & (CPM_CR_RST | CPM_CR_FLG)); | |
| /* Remove any microcode patches. We will install our own | |
| * later. | |
| */ | |
| cp->cp_cpmcr1 = 0; | |
| cp->cp_cpmcr2 = 0; | |
| cp->cp_cpmcr3 = 0; | |
| cp->cp_cpmcr4 = 0; | |
| cp->cp_rccr = 0; | |
| iip = (iic_t *)&cp->cp_dparam[PROFF_IIC]; | |
| i2c = (i2c8xx_t *)&(immap->im_i2c); | |
| /* Initialize Port B IIC pins. | |
| */ | |
| cp->cp_pbpar |= 0x00000030; | |
| cp->cp_pbdir |= 0x00000030; | |
| cp->cp_pbodr |= 0x00000030; | |
| /* Initialize the parameter ram. | |
| */ | |
| /* Allocate space for a two transmit and one receive buffer | |
| * descriptor in the DP ram. | |
| * For now, this address seems OK, but it may have to | |
| * change with newer versions of the firmware. | |
| */ | |
| dpaddr = 0x0840; | |
| /* Set up the IIC parameters in the parameter ram. | |
| */ | |
| iip->iic_tbase = dpaddr; | |
| iip->iic_rbase = dpaddr + (2 * sizeof(cbd_t)); | |
| iip->iic_tfcr = SMC_EB; | |
| iip->iic_rfcr = SMC_EB; | |
| /* This should really be done by the reader/writer. | |
| */ | |
| iip->iic_mrblr = 128; | |
| /* Initialize Tx/Rx parameters. | |
| */ | |
| cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_INIT_TRX) | CPM_CR_FLG; | |
| while (cp->cp_cpcr & CPM_CR_FLG); | |
| /* Select an arbitrary address. Just make sure it is unique. | |
| */ | |
| i2c->i2c_i2add = 0x34; | |
| /* Make clock run maximum slow. | |
| */ | |
| i2c->i2c_i2brg = 7; | |
| /* Disable interrupts. | |
| */ | |
| i2c->i2c_i2cmr = 0; | |
| i2c->i2c_i2cer = 0xff; | |
| /* Enable SDMA. | |
| */ | |
| immap->im_siu_conf.sc_sdcr = 1; | |
| iic_init_done = 1; | |
| } | |
| /* Read from IIC. | |
| * Caller provides device address, memory buffer, and byte count. | |
| */ | |
| static u_char iitemp[32]; | |
| void | |
| iic_read(uint devaddr, u_char *buf, uint offset, uint count) | |
| { | |
| volatile iic_t *iip; | |
| volatile i2c8xx_t *i2c; | |
| volatile cbd_t *tbdf, *rbdf; | |
| volatile cpm8xx_t *cp; | |
| volatile immap_t *immap; | |
| u_char *tb; | |
| uint temp; | |
| /* If the interface has not been initialized, do that now. | |
| */ | |
| if (!iic_init_done) | |
| iic_init(); | |
| immap = (immap_t *)IMAP_ADDR; | |
| cp = (cpm8xx_t *)&(immap->im_cpm); | |
| iip = (iic_t *)&cp->cp_dparam[PROFF_IIC]; | |
| i2c = (i2c8xx_t *)&(immap->im_i2c); | |
| tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase]; | |
| rbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_rbase]; | |
| /* Send a "dummy write" operation. This is a write request with | |
| * only the offset sent, followed by another start condition. | |
| * This will ensure we start reading from the first location | |
| * of the EEPROM. | |
| */ | |
| tb = iitemp; | |
| tb = (u_char *)(((uint)tb + 15) & ~15); | |
| tbdf->cbd_bufaddr = (int)tb; | |
| *tb = devaddr & 0xfe; /* Device address */ | |
| *(tb+1) = offset; /* Offset */ | |
| tbdf->cbd_datlen = 2; /* Length */ | |
| tbdf->cbd_sc = | |
| BD_SC_READY | BD_SC_LAST | BD_SC_WRAP | BD_IIC_START; | |
| i2c->i2c_i2mod = 1; /* Enable */ | |
| i2c->i2c_i2cer = 0xff; | |
| i2c->i2c_i2com = 0x81; /* Start master */ | |
| /* Wait for IIC transfer. | |
| */ | |
| #if 0 | |
| while ((i2c->i2c_i2cer & 3) == 0); | |
| if (tbdf->cbd_sc & BD_SC_READY) | |
| printf("IIC ra complete but tbuf ready\n"); | |
| #else | |
| temp = 10000000; | |
| while ((tbdf->cbd_sc & BD_SC_READY) && (temp != 0)) | |
| temp--; | |
| #if 0 | |
| /* We can't do this...there is no serial port yet! | |
| */ | |
| if (temp == 0) { | |
| printf("Timeout reading EEPROM\n"); | |
| return; | |
| } | |
| #endif | |
| #endif | |
| /* Chip errata, clear enable. | |
| */ | |
| i2c->i2c_i2mod = 0; | |
| /* To read, we need an empty buffer of the proper length. | |
| * All that is used is the first byte for address, the remainder | |
| * is just used for timing (and doesn't really have to exist). | |
| */ | |
| tbdf->cbd_bufaddr = (int)tb; | |
| *tb = devaddr | 1; /* Device address */ | |
| rbdf->cbd_bufaddr = (uint)buf; /* Desination buffer */ | |
| tbdf->cbd_datlen = rbdf->cbd_datlen = count + 1; /* Length */ | |
| tbdf->cbd_sc = BD_SC_READY | BD_SC_LAST | BD_SC_WRAP | BD_IIC_START; | |
| rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP; | |
| /* Chip bug, set enable here. | |
| */ | |
| i2c->i2c_i2mod = 1; /* Enable */ | |
| i2c->i2c_i2cer = 0xff; | |
| i2c->i2c_i2com = 0x81; /* Start master */ | |
| /* Wait for IIC transfer. | |
| */ | |
| #if 0 | |
| while ((i2c->i2c_i2cer & 1) == 0); | |
| if (rbdf->cbd_sc & BD_SC_EMPTY) | |
| printf("IIC read complete but rbuf empty\n"); | |
| #else | |
| temp = 10000000; | |
| while ((tbdf->cbd_sc & BD_SC_READY) && (temp != 0)) | |
| temp--; | |
| #endif | |
| /* Chip errata, clear enable. | |
| */ | |
| i2c->i2c_i2mod = 0; | |
| } |