]>
Commit | Line | Data |
---|---|---|
9d407995 WD |
1 | #include <common.h> |
2 | #include <mpc8xx.h> | |
3 | #include <pcmcia.h> | |
4 | ||
5 | #undef CONFIG_PCMCIA | |
6 | ||
3fe00109 | 7 | #if defined(CONFIG_CMD_PCMCIA) |
9d407995 WD |
8 | #define CONFIG_PCMCIA |
9 | #endif | |
10 | ||
3fe00109 | 11 | #if defined(CONFIG_CMD_IDE) && defined(CONFIG_IDE_8xx_PCCARD) |
9d407995 WD |
12 | #define CONFIG_PCMCIA |
13 | #endif | |
14 | ||
15 | #ifdef CONFIG_PCMCIA | |
16 | ||
17 | /* some sane bit macros */ | |
18 | #define _BD(_b) (1U << (31-(_b))) | |
19 | #define _BDR(_l, _h) (((((1U << (31-(_l))) - 1) << 1) | 1) & ~((1U << (31-(_h))) - 1)) | |
20 | ||
21 | #define _BW(_b) (1U << (15-(_b))) | |
22 | #define _BWR(_l, _h) (((((1U << (15-(_l))) - 1) << 1) | 1) & ~((1U << (15-(_h))) - 1)) | |
23 | ||
24 | #define _BB(_b) (1U << (7-(_b))) | |
25 | #define _BBR(_l, _h) (((((1U << (7-(_l))) - 1) << 1) | 1) & ~((1U << (7-(_h))) - 1)) | |
26 | ||
27 | #define _B(_b) _BD(_b) | |
28 | #define _BR(_l, _h) _BDR(_l, _h) | |
29 | ||
30 | #define PCMCIA_BOARD_MSG "NETTA" | |
31 | ||
32 | static const unsigned short vppd_masks[2] = { _BW(14), _BW(15) }; | |
33 | ||
34 | static void cfg_vppd(int no) | |
35 | { | |
6d0f6bcf | 36 | volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR; |
9d407995 WD |
37 | unsigned short mask; |
38 | ||
39 | if ((unsigned int)no >= sizeof(vppd_masks)/sizeof(vppd_masks[0])) | |
40 | return; | |
41 | ||
42 | mask = vppd_masks[no]; | |
43 | ||
44 | immap->im_ioport.iop_papar &= ~mask; | |
45 | immap->im_ioport.iop_paodr &= ~mask; | |
46 | immap->im_ioport.iop_padir |= mask; | |
47 | } | |
48 | ||
49 | static void set_vppd(int no, int what) | |
50 | { | |
6d0f6bcf | 51 | volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR; |
9d407995 WD |
52 | unsigned short mask; |
53 | ||
54 | if ((unsigned int)no >= sizeof(vppd_masks)/sizeof(vppd_masks[0])) | |
55 | return; | |
56 | ||
57 | mask = vppd_masks[no]; | |
58 | ||
59 | if (what) | |
60 | immap->im_ioport.iop_padat |= mask; | |
61 | else | |
62 | immap->im_ioport.iop_padat &= ~mask; | |
63 | } | |
64 | ||
65 | static const unsigned short vccd_masks[2] = { _BW(10), _BW(6) }; | |
66 | ||
67 | static void cfg_vccd(int no) | |
68 | { | |
6d0f6bcf | 69 | volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR; |
9d407995 WD |
70 | unsigned short mask; |
71 | ||
72 | if ((unsigned int)no >= sizeof(vccd_masks)/sizeof(vccd_masks[0])) | |
73 | return; | |
74 | ||
75 | mask = vccd_masks[no]; | |
76 | ||
77 | immap->im_ioport.iop_papar &= ~mask; | |
78 | immap->im_ioport.iop_paodr &= ~mask; | |
79 | immap->im_ioport.iop_padir |= mask; | |
80 | } | |
81 | ||
82 | static void set_vccd(int no, int what) | |
83 | { | |
6d0f6bcf | 84 | volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR; |
9d407995 WD |
85 | unsigned short mask; |
86 | ||
87 | if ((unsigned int)no >= sizeof(vccd_masks)/sizeof(vccd_masks[0])) | |
88 | return; | |
89 | ||
90 | mask = vccd_masks[no]; | |
91 | ||
92 | if (what) | |
93 | immap->im_ioport.iop_padat |= mask; | |
94 | else | |
95 | immap->im_ioport.iop_padat &= ~mask; | |
96 | } | |
97 | ||
98 | static const unsigned short oc_mask = _BW(8); | |
99 | ||
100 | static void cfg_oc(void) | |
101 | { | |
6d0f6bcf | 102 | volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR; |
9d407995 WD |
103 | unsigned short mask = oc_mask; |
104 | ||
105 | immap->im_ioport.iop_pcdir &= ~mask; | |
106 | immap->im_ioport.iop_pcso &= ~mask; | |
107 | immap->im_ioport.iop_pcint &= ~mask; | |
108 | immap->im_ioport.iop_pcpar &= ~mask; | |
109 | } | |
110 | ||
111 | static int get_oc(void) | |
112 | { | |
6d0f6bcf | 113 | volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR; |
9d407995 WD |
114 | unsigned short mask = oc_mask; |
115 | int what; | |
116 | ||
117 | what = !!(immap->im_ioport.iop_pcdat & mask);; | |
118 | return what; | |
119 | } | |
120 | ||
121 | static const unsigned short shdn_mask = _BW(12); | |
122 | ||
123 | static void cfg_shdn(void) | |
124 | { | |
6d0f6bcf | 125 | volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR; |
9d407995 WD |
126 | unsigned short mask; |
127 | ||
128 | mask = shdn_mask; | |
129 | ||
130 | immap->im_ioport.iop_papar &= ~mask; | |
131 | immap->im_ioport.iop_paodr &= ~mask; | |
132 | immap->im_ioport.iop_padir |= mask; | |
133 | } | |
134 | ||
135 | static void set_shdn(int what) | |
136 | { | |
6d0f6bcf | 137 | volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR; |
9d407995 WD |
138 | unsigned short mask; |
139 | ||
140 | mask = shdn_mask; | |
141 | ||
142 | if (what) | |
143 | immap->im_ioport.iop_padat |= mask; | |
144 | else | |
145 | immap->im_ioport.iop_padat &= ~mask; | |
146 | } | |
147 | ||
148 | static void cfg_ports (void) | |
149 | { | |
150 | volatile immap_t *immap; | |
151 | volatile cpm8xx_t *cp; | |
152 | ||
6d0f6bcf JCPV |
153 | immap = (immap_t *)CONFIG_SYS_IMMR; |
154 | cp = (cpm8xx_t *)(&(((immap_t *)CONFIG_SYS_IMMR)->im_cpm)); | |
9d407995 WD |
155 | |
156 | ||
157 | cfg_vppd(0); cfg_vppd(1); /* VPPD0,VPPD1 VAVPP => Hi-Z */ | |
158 | cfg_vccd(0); cfg_vccd(1); /* 3V and 5V off */ | |
159 | cfg_shdn(); | |
160 | cfg_oc(); | |
161 | ||
162 | /* | |
163 | * Configure Port A for TPS2211 PC-Card Power-Interface Switch | |
164 | * | |
165 | * Switch off all voltages, assert shutdown | |
166 | */ | |
167 | set_vppd(0, 1); set_vppd(1, 1); | |
168 | set_vccd(0, 0); set_vccd(1, 0); | |
169 | set_shdn(1); | |
170 | ||
171 | udelay(100000); | |
172 | } | |
173 | ||
174 | int pcmcia_hardware_enable(int slot) | |
175 | { | |
176 | volatile immap_t *immap; | |
177 | volatile cpm8xx_t *cp; | |
178 | volatile pcmconf8xx_t *pcmp; | |
179 | volatile sysconf8xx_t *sysp; | |
180 | uint reg, pipr, mask; | |
181 | int i; | |
182 | ||
183 | debug ("hardware_enable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot); | |
184 | ||
185 | udelay(10000); | |
186 | ||
6d0f6bcf JCPV |
187 | immap = (immap_t *)CONFIG_SYS_IMMR; |
188 | sysp = (sysconf8xx_t *)(&(((immap_t *)CONFIG_SYS_IMMR)->im_siu_conf)); | |
189 | pcmp = (pcmconf8xx_t *)(&(((immap_t *)CONFIG_SYS_IMMR)->im_pcmcia)); | |
190 | cp = (cpm8xx_t *)(&(((immap_t *)CONFIG_SYS_IMMR)->im_cpm)); | |
9d407995 WD |
191 | |
192 | /* Configure Ports for TPS2211A PC-Card Power-Interface Switch */ | |
193 | cfg_ports (); | |
194 | ||
195 | /* clear interrupt state, and disable interrupts */ | |
196 | pcmp->pcmc_pscr = PCMCIA_MASK(_slot_); | |
197 | pcmp->pcmc_per &= ~PCMCIA_MASK(_slot_); | |
198 | ||
199 | /* | |
200 | * Disable interrupts, DMA, and PCMCIA buffers | |
201 | * (isolate the interface) and assert RESET signal | |
202 | */ | |
203 | debug ("Disable PCMCIA buffers and assert RESET\n"); | |
204 | reg = 0; | |
205 | reg |= __MY_PCMCIA_GCRX_CXRESET; /* active high */ | |
206 | reg |= __MY_PCMCIA_GCRX_CXOE; /* active low */ | |
207 | PCMCIA_PGCRX(_slot_) = reg; | |
208 | ||
209 | udelay(500); | |
210 | ||
211 | /* | |
212 | * Make sure there is a card in the slot, then configure the interface. | |
213 | */ | |
214 | udelay(10000); | |
215 | debug ("[%d] %s: PIPR(%p)=0x%x\n", | |
216 | __LINE__,__FUNCTION__, | |
217 | &(pcmp->pcmc_pipr),pcmp->pcmc_pipr); | |
218 | if (pcmp->pcmc_pipr & (0x18000000 >> (slot << 4))) { | |
219 | printf (" No Card found\n"); | |
220 | return (1); | |
221 | } | |
222 | ||
223 | /* | |
224 | * Power On: Set VAVCC to 3.3V or 5V, set VAVPP to Hi-Z | |
225 | */ | |
226 | mask = PCMCIA_VS1(slot) | PCMCIA_VS2(slot); | |
227 | pipr = pcmp->pcmc_pipr; | |
228 | debug ("PIPR: 0x%x ==> VS1=o%s, VS2=o%s\n", | |
229 | pipr, | |
230 | (reg&PCMCIA_VS1(slot))?"n":"ff", | |
231 | (reg&PCMCIA_VS2(slot))?"n":"ff"); | |
232 | ||
233 | if ((pipr & mask) == mask) { | |
53677ef1 WD |
234 | set_vppd(0, 1); set_vppd(1, 1); /* VAVPP => Hi-Z */ |
235 | set_vccd(0, 0); set_vccd(1, 1); /* 5V on, 3V off */ | |
9d407995 WD |
236 | puts (" 5.0V card found: "); |
237 | } else { | |
53677ef1 WD |
238 | set_vppd(0, 1); set_vppd(1, 1); /* VAVPP => Hi-Z */ |
239 | set_vccd(0, 1); set_vccd(1, 0); /* 5V off, 3V on */ | |
9d407995 WD |
240 | puts (" 3.3V card found: "); |
241 | } | |
242 | ||
243 | /* Wait 500 ms; use this to check for over-current */ | |
244 | for (i=0; i<5000; ++i) { | |
245 | if (!get_oc()) { | |
246 | printf (" *** Overcurrent - Safety shutdown ***\n"); | |
53677ef1 | 247 | set_vccd(0, 0); set_vccd(1, 0); /* VAVPP => Hi-Z */ |
9d407995 WD |
248 | return (1); |
249 | } | |
250 | udelay (100); | |
251 | } | |
252 | ||
253 | debug ("Enable PCMCIA buffers and stop RESET\n"); | |
254 | reg = PCMCIA_PGCRX(_slot_); | |
255 | reg &= ~__MY_PCMCIA_GCRX_CXRESET; /* active high */ | |
256 | reg &= ~__MY_PCMCIA_GCRX_CXOE; /* active low */ | |
257 | PCMCIA_PGCRX(_slot_) = reg; | |
258 | ||
259 | udelay(250000); /* some cards need >150 ms to come up :-( */ | |
260 | ||
261 | debug ("# hardware_enable done\n"); | |
262 | ||
263 | return (0); | |
264 | } | |
265 | ||
266 | ||
3fe00109 | 267 | #if defined(CONFIG_CMD_PCMCIA) |
9d407995 WD |
268 | int pcmcia_hardware_disable(int slot) |
269 | { | |
270 | volatile immap_t *immap; | |
271 | volatile pcmconf8xx_t *pcmp; | |
272 | u_long reg; | |
273 | ||
274 | debug ("hardware_disable: " PCMCIA_BOARD_MSG " Slot %c\n", 'A'+slot); | |
275 | ||
6d0f6bcf JCPV |
276 | immap = (immap_t *)CONFIG_SYS_IMMR; |
277 | pcmp = (pcmconf8xx_t *)(&(((immap_t *)CONFIG_SYS_IMMR)->im_pcmcia)); | |
9d407995 WD |
278 | |
279 | /* Configure PCMCIA General Control Register */ | |
280 | debug ("Disable PCMCIA buffers and assert RESET\n"); | |
281 | reg = 0; | |
282 | reg |= __MY_PCMCIA_GCRX_CXRESET; /* active high */ | |
283 | reg |= __MY_PCMCIA_GCRX_CXOE; /* active low */ | |
284 | PCMCIA_PGCRX(_slot_) = reg; | |
285 | ||
286 | /* All voltages off / Hi-Z */ | |
287 | set_vppd(0, 1); set_vppd(1, 1); | |
288 | set_vccd(0, 1); set_vccd(1, 1); | |
289 | ||
290 | udelay(10000); | |
291 | ||
292 | return (0); | |
293 | } | |
d39b5741 | 294 | #endif |
9d407995 WD |
295 | |
296 | ||
297 | int pcmcia_voltage_set(int slot, int vcc, int vpp) | |
298 | { | |
299 | volatile immap_t *immap; | |
300 | volatile cpm8xx_t *cp; | |
301 | volatile pcmconf8xx_t *pcmp; | |
302 | u_long reg; | |
303 | ushort sreg; | |
304 | ||
305 | debug ("voltage_set: " | |
306 | PCMCIA_BOARD_MSG | |
307 | " Slot %c, Vcc=%d.%d, Vpp=%d.%d\n", | |
308 | 'A'+slot, vcc/10, vcc%10, vpp/10, vcc%10); | |
309 | ||
6d0f6bcf JCPV |
310 | immap = (immap_t *)CONFIG_SYS_IMMR; |
311 | cp = (cpm8xx_t *)(&(((immap_t *)CONFIG_SYS_IMMR)->im_cpm)); | |
312 | pcmp = (pcmconf8xx_t *)(&(((immap_t *)CONFIG_SYS_IMMR)->im_pcmcia)); | |
9d407995 WD |
313 | /* |
314 | * Disable PCMCIA buffers (isolate the interface) | |
315 | * and assert RESET signal | |
316 | */ | |
317 | debug ("Disable PCMCIA buffers and assert RESET\n"); | |
318 | reg = PCMCIA_PGCRX(_slot_); | |
319 | reg |= __MY_PCMCIA_GCRX_CXRESET; /* active high */ | |
320 | reg |= __MY_PCMCIA_GCRX_CXOE; /* active low */ | |
321 | PCMCIA_PGCRX(_slot_) = reg; | |
322 | udelay(500); | |
323 | ||
324 | /* | |
325 | * Configure Port C pins for | |
326 | * 5 Volts Enable and 3 Volts enable, | |
327 | * Turn all power pins to Hi-Z | |
328 | */ | |
329 | debug ("PCMCIA power OFF\n"); | |
330 | cfg_ports (); /* Enables switch, but all in Hi-Z */ | |
331 | ||
332 | sreg = immap->im_ioport.iop_pcdat; | |
333 | set_vppd(0, 1); set_vppd(1, 1); | |
334 | ||
335 | switch(vcc) { | |
336 | case 0: | |
337 | break; /* Switch off */ | |
338 | ||
339 | case 33: | |
340 | set_vccd(0, 1); set_vccd(1, 0); | |
341 | break; | |
342 | ||
343 | case 50: | |
344 | set_vccd(0, 0); set_vccd(1, 1); | |
345 | break; | |
346 | ||
347 | default: | |
348 | goto done; | |
349 | } | |
350 | ||
351 | /* Checking supported voltages */ | |
352 | ||
353 | debug ("PIPR: 0x%x --> %s\n", | |
354 | pcmp->pcmc_pipr, | |
355 | (pcmp->pcmc_pipr & 0x00008000) ? "only 5 V" : "can do 3.3V"); | |
356 | ||
357 | done: | |
358 | debug ("Enable PCMCIA buffers and stop RESET\n"); | |
359 | reg = PCMCIA_PGCRX(_slot_); | |
360 | reg &= ~__MY_PCMCIA_GCRX_CXRESET; /* active high */ | |
361 | reg &= ~__MY_PCMCIA_GCRX_CXOE; /* active low */ | |
362 | PCMCIA_PGCRX(_slot_) = reg; | |
363 | udelay(500); | |
364 | ||
365 | debug ("voltage_set: " PCMCIA_BOARD_MSG " Slot %c, DONE\n", | |
366 | slot+'A'); | |
367 | return (0); | |
368 | } | |
369 | ||
370 | #endif /* CONFIG_PCMCIA */ |