]>
Commit | Line | Data |
---|---|---|
affae2bf WD |
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 */ | |
6d0f6bcf | 50 | #define VPD_P ((vpd_t *)(CONFIG_SYS_IMMR + 0x2000 + CONFIG_SYS_DPRAMVPD)) |
affae2bf WD |
51 | |
52 | /* transmit/receive buffers */ | |
53 | #define IIC_RX_LENGTH 128 | |
54 | ||
55 | #define WITH_MICROCODE_PATCH | |
56 | ||
57 | vpd_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 | ||
70 | void vpd_init(void) | |
71 | { | |
6d0f6bcf | 72 | volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR; |
affae2bf WD |
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 | */ | |
121 | int vpd_read(uint iic_device, uchar *buf, int count, int offset) | |
122 | { | |
6d0f6bcf | 123 | volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR; |
affae2bf WD |
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 | ||
191 | bailout: | |
192 | i2c->i2c_i2mod &= ~1; /* turn off iic operation */ | |
193 | i2c->i2c_i2cer = 0x1f; /* clear event mask */ | |
194 | ||
195 | return count; | |
196 | } |