1/* 2 * (C) Copyright 2000 3 * Sysgo Real-Time Solutions, GmbH <www.elinos.com> 4 * Marius Groeger <mgroeger@sysgo.de> 5 * 6 * Code in faintly related to linux/arch/ppc/8xx_io: 7 * MPC8xx CPM I2C interface. Copyright (c) 1999 Dan Malek (dmalek@jlc.net). 8 * 9 * This file implements functions to read the MBX's Vital Product Data 10 * (VPD). I can't use the more general i2c code in mpc8xx/... since I need 11 * the VPD at a time where there is no RAM available yet. Hence the VPD is 12 * read into a special area in the DPRAM (see config_MBX.h::CFG_DPRAMVPD). 13 * 14 * ----------------------------------------------------------------- 15 * See file CREDITS for list of people who contributed to this 16 * project. 17 * 18 * This program is free software; you can redistribute it and/or 19 * modify it under the terms of the GNU General Public License as 20 * published by the Free Software Foundation; either version 2 of 21 * the License, or (at your option) any later version. 22 * 23 * This program is distributed in the hope that it will be useful, 24 * but WITHOUT ANY WARRANTY; without even the implied warranty of 25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 26 * GNU General Public License for more details. 27 * 28 * You should have received a copy of the GNU General Public License 29 * along with this program; if not, write to the Free Software 30 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 31 * MA 02111-1307 USA 32 */ 33 34#include <common.h> 35#ifdef CONFIG_8xx 36#include <commproc.h> 37#endif 38#include "vpd.h" 39 40/* Location of receive/transmit buffer descriptors 41 * Allocate one transmit bd and one receive bd. 42 * IIC_BD_FREE points to free bd space which we'll use as tx buffer. 43 */ 44#define IIC_BD_TX1 (BD_IIC_START + 0*sizeof(cbd_t)) 45#define IIC_BD_TX2 (BD_IIC_START + 1*sizeof(cbd_t)) 46#define IIC_BD_RX (BD_IIC_START + 2*sizeof(cbd_t)) 47#define IIC_BD_FREE (BD_IIC_START + 3*sizeof(cbd_t)) 48 49/* FIXME -- replace 0x2000 with offsetof */ 50#define VPD_P ((vpd_t *)(CONFIG_SYS_IMMR + 0x2000 + CONFIG_SYS_DPRAMVPD)) 51 52/* transmit/receive buffers */ 53#define IIC_RX_LENGTH 128 54 55#define WITH_MICROCODE_PATCH 56 57vpd_packet_t * vpd_find_packet(u_char ident) 58{ 59 vpd_packet_t *packet; 60 vpd_t *vpd = VPD_P; 61 62 packet = (vpd_packet_t *)&vpd->packets; 63 while ((packet->identifier != ident) && packet->identifier != 0xFF) 64 { 65 packet = (vpd_packet_t *)((char *)packet + packet->size + 2); 66 } 67 return packet; 68} 69 70void vpd_init(void) 71{ 72 volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR; 73 volatile cpm8xx_t *cp = &(im->im_cpm); 74 volatile i2c8xx_t *i2c = (i2c8xx_t *)&(im->im_i2c); 75 volatile iic_t *iip; 76#ifdef WITH_MICROCODE_PATCH 77 ulong reloc = 0; 78#endif 79 80 iip = (iic_t *)&cp->cp_dparam[PROFF_IIC]; 81 82 /* 83 * kludge: when running from flash, no microcode patch can be 84 * installed. However, the DPMEM usually contains non-zero 85 * garbage at the relocatable patch base location, so lets clear 86 * it now. This way the rest of the code can support the microcode 87 * patch dynamically. 88 */ 89 if ((ulong)vpd_init & 0xff000000) 90 iip->iic_rpbase = 0; 91 92#ifdef WITH_MICROCODE_PATCH 93 /* Check for and use a microcode relocation patch. */ 94 if ((reloc = iip->iic_rpbase)) 95 iip = (iic_t *)&cp->cp_dpmem[iip->iic_rpbase]; 96#endif 97 /* Initialize Port B IIC pins */ 98 cp->cp_pbpar |= 0x00000030; 99 cp->cp_pbdir |= 0x00000030; 100 cp->cp_pbodr |= 0x00000030; 101 102 i2c->i2c_i2mod = 0x04; /* filter clock */ 103 i2c->i2c_i2add = 0x34; /* select an arbitrary (unique) address */ 104 i2c->i2c_i2brg = 0x07; /* make clock run maximum slow */ 105 i2c->i2c_i2cmr = 0x00; /* disable interrupts */ 106 i2c->i2c_i2cer = 0x1f; /* clear events */ 107 i2c->i2c_i2com = 0x01; /* configure i2c to work as master */ 108 109 if (vpd_read(0xa4, (uchar*)VPD_P, VPD_EEPROM_SIZE, 0) != VPD_EEPROM_SIZE) 110 { 111 hang(); 112 } 113} 114 115 116/* Read from I2C. 117 * This is a two step process. First, we send the "dummy" write 118 * to set the device offset for the read. Second, we perform 119 * the read operation. 120 */ 121int vpd_read(uint iic_device, uchar *buf, int count, int offset) 122{ 123 volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR; 124 volatile cpm8xx_t *cp = &(im->im_cpm); 125 volatile i2c8xx_t *i2c = (i2c8xx_t *)&(im->im_i2c); 126 volatile iic_t *iip; 127 volatile cbd_t *tbdf1, *tbdf2, *rbdf; 128 uchar *tb; 129 uchar event; 130#ifdef WITH_MICROCODE_PATCH 131 ulong reloc = 0; 132#endif 133 134 iip = (iic_t *)&cp->cp_dparam[PROFF_IIC]; 135#ifdef WITH_MICROCODE_PATCH 136 /* Check for and use a microcode relocation patch. */ 137 if ((reloc = iip->iic_rpbase)) 138 iip = (iic_t *)&cp->cp_dpmem[iip->iic_rpbase]; 139#endif 140 tbdf1 = (cbd_t *)&cp->cp_dpmem[IIC_BD_TX1]; 141 tbdf2 = (cbd_t *)&cp->cp_dpmem[IIC_BD_TX2]; 142 rbdf = (cbd_t *)&cp->cp_dpmem[IIC_BD_RX]; 143 144 /* Send a "dummy write" operation. This is a write request with 145 * only the offset sent, followed by another start condition. 146 * This will ensure we start reading from the first location 147 * of the EEPROM. 148 */ 149 tb = (uchar*)&cp->cp_dpmem[IIC_BD_FREE]; 150 tb[0] = iic_device & 0xfe; /* device address */ 151 tb[1] = offset; /* offset */ 152 tbdf1->cbd_bufaddr = (uint)tb; 153 tbdf1->cbd_datlen = 2; 154 tbdf1->cbd_sc = 0x8400; 155 156 tb += 2; 157 tb[0] = iic_device | 1; /* device address */ 158 tbdf2->cbd_bufaddr = (uint)tb; 159 tbdf2->cbd_datlen = count+1; 160 tbdf2->cbd_sc = 0xbc00; 161 162 rbdf->cbd_bufaddr = (uint)buf; 163 rbdf->cbd_datlen = 0; 164 rbdf->cbd_sc = 0xb000; 165 166 iip->iic_tbase = IIC_BD_TX1; 167 iip->iic_tbptr = IIC_BD_TX1; 168 iip->iic_rbase = IIC_BD_RX; 169 iip->iic_rbptr = IIC_BD_RX; 170 iip->iic_rfcr = 0x15; 171 iip->iic_tfcr = 0x15; 172 iip->iic_mrblr = count; 173 iip->iic_rstate = 0; 174 iip->iic_tstate = 0; 175 176 i2c->i2c_i2cer = 0x1f; /* clear event mask */ 177 i2c->i2c_i2mod |= 1; /* enable iic operation */ 178 i2c->i2c_i2com |= 0x80; /* start master */ 179 180 /* wait for IIC transfer */ 181 do { 182 __asm__ volatile ("eieio"); 183 event = i2c->i2c_i2cer; 184 } while (event == 0); 185 186 if ((event & 0x10) || (event & 0x04)) { 187 count = -1; 188 goto bailout; 189 } 190 191bailout: 192 i2c->i2c_i2mod &= ~1; /* turn off iic operation */ 193 i2c->i2c_i2cer = 0x1f; /* clear event mask */ 194 195 return count; 196} 197