/* Minimal support functions to read configuration from IIC EEPROMS * on MPC8xx boards. Originally written for RPGC RPX-Lite. * Dan Malek (dmalek@jlc.net). */ #include #include #include #include /* 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; }