3 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
4 * Marius Groeger <mgroeger@sysgo.de>
6 * Code in faintly related to linux/arch/ppc/8xx_io:
7 * MPC8xx CPM I2C interface. Copyright (c) 1999 Dan Malek (dmalek@jlc.net).
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).
14 * -----------------------------------------------------------------
15 * See file CREDITS for list of people who contributed to this
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.
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.
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,
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.
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))
49 /* FIXME -- replace 0x2000 with offsetof */
50 #define VPD_P ((vpd_t *)(CFG_IMMR + 0x2000 + CFG_DPRAMVPD))
52 /* transmit/receive buffers */
53 #define IIC_RX_LENGTH 128
55 #define WITH_MICROCODE_PATCH
57 vpd_packet_t
* vpd_find_packet(u_char ident
)
62 packet
= (vpd_packet_t
*)&vpd
->packets
;
63 while ((packet
->identifier
!= ident
) && packet
->identifier
!= 0xFF)
65 packet
= (vpd_packet_t
*)((char *)packet
+ packet
->size
+ 2);
72 volatile immap_t
*im
= (immap_t
*)CFG_IMMR
;
73 volatile cpm8xx_t
*cp
= &(im
->im_cpm
);
74 volatile i2c8xx_t
*i2c
= (i2c8xx_t
*)&(im
->im_i2c
);
76 #ifdef WITH_MICROCODE_PATCH
80 iip
= (iic_t
*)&cp
->cp_dparam
[PROFF_IIC
];
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
89 if ((ulong
)vpd_init
& 0xff000000)
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
];
97 /* Initialize Port B IIC pins */
98 cp
->cp_pbpar
|= 0x00000030;
99 cp
->cp_pbdir
|= 0x00000030;
100 cp
->cp_pbodr
|= 0x00000030;
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 */
109 if (vpd_read(0xa4, (uchar
*)VPD_P
, VPD_EEPROM_SIZE
, 0) != VPD_EEPROM_SIZE
)
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.
121 int vpd_read(uint iic_device
, uchar
*buf
, int count
, int offset
)
123 volatile immap_t
*im
= (immap_t
*)CFG_IMMR
;
124 volatile cpm8xx_t
*cp
= &(im
->im_cpm
);
125 volatile i2c8xx_t
*i2c
= (i2c8xx_t
*)&(im
->im_i2c
);
127 volatile cbd_t
*tbdf1
, *tbdf2
, *rbdf
;
130 #ifdef WITH_MICROCODE_PATCH
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
];
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
];
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
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;
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;
162 rbdf
->cbd_bufaddr
= (uint
)buf
;
163 rbdf
->cbd_datlen
= 0;
164 rbdf
->cbd_sc
= 0xb000;
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
;
176 i2c
->i2c_i2cer
= 0x1f; /* clear event mask */
177 i2c
->i2c_i2mod
|= 1; /* enable iic operation */
178 i2c
->i2c_i2com
|= 0x80; /* start master */
180 /* wait for IIC transfer */
182 __asm__
volatile ("eieio");
183 event
= i2c
->i2c_i2cer
;
184 } while (event
== 0);
186 if ((event
& 0x10) || (event
& 0x04)) {
192 i2c
->i2c_i2mod
&= ~1; /* turn off iic operation */
193 i2c
->i2c_i2cer
= 0x1f; /* clear event mask */