]>
Commit | Line | Data |
---|---|---|
b6e4c403 WD |
1 | /* |
2 | * Copyright (c) 2001 Navin Boppuri / Prashant Patel | |
3 | * <nboppuri@trinetcommunication.com>, | |
4 | * <pmpatel@trinetcommunication.com> | |
5 | * Copyright (c) 2001 Gerd Mennchen <Gerd.Mennchen@icn.siemens.de> | |
6 | * Copyright (c) 2001 Wolfgang Denk, DENX Software Engineering, <wd@denx.de>. | |
7 | * | |
8 | * See file CREDITS for list of people who contributed to this | |
9 | * project. | |
10 | * | |
11 | * This program is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU General Public License as | |
13 | * published by the Free Software Foundation; either version 2 of | |
14 | * the License, or (at your option) any later version. | |
15 | * | |
16 | * This program is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 | * GNU General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU General Public License | |
22 | * along with this program; if not, write to the Free Software | |
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
24 | * MA 02111-1307 USA | |
25 | */ | |
26 | ||
27 | /* | |
28 | * MPC5xx CPM SPI interface. | |
29 | * | |
30 | * Parts of this code are probably not portable and/or specific to | |
31 | * the board which I used for the tests. Please send fixes/complaints | |
32 | * to wd@denx.de | |
33 | * | |
34 | * Ported to MPC5xx | |
35 | * Copyright (c) 2003 Denis Peter, MPL AG Switzerland, d.petr@mpl.ch. | |
36 | */ | |
37 | ||
38 | #include <common.h> | |
39 | #include <mpc5xx.h> | |
40 | #include <asm/5xx_immap.h> | |
41 | #include <linux/ctype.h> | |
42 | #include <malloc.h> | |
43 | #include <post.h> | |
44 | #include <net.h> | |
45 | ||
46 | #if defined(CONFIG_SPI) | |
47 | ||
48 | #undef DEBUG | |
49 | ||
50 | #define SPI_EEPROM_WREN 0x06 | |
51 | #define SPI_EEPROM_RDSR 0x05 | |
52 | #define SPI_EEPROM_READ 0x03 | |
53 | #define SPI_EEPROM_WRITE 0x02 | |
54 | ||
55 | ||
56 | #ifdef DEBUG | |
57 | ||
58 | #define DPRINT(a) printf a; | |
59 | /* ----------------------------------------------- | |
60 | * Helper functions to peek into tx and rx buffers | |
61 | * ----------------------------------------------- */ | |
62 | static const char * const hex_digit = "0123456789ABCDEF"; | |
63 | ||
64 | static char quickhex (int i) | |
65 | { | |
66 | return hex_digit[i]; | |
67 | } | |
68 | ||
69 | static void memdump (void *pv, int num) | |
70 | { | |
71 | int i; | |
72 | unsigned char *pc = (unsigned char *) pv; | |
73 | ||
74 | for (i = 0; i < num; i++) | |
75 | printf ("%c%c ", quickhex (pc[i] >> 4), quickhex (pc[i] & 0x0f)); | |
76 | printf ("\t"); | |
77 | for (i = 0; i < num; i++) | |
78 | printf ("%c", isprint (pc[i]) ? pc[i] : '.'); | |
79 | printf ("\n"); | |
80 | } | |
81 | #else /* !DEBUG */ | |
82 | ||
83 | #define DPRINT(a) | |
84 | ||
85 | #endif /* DEBUG */ | |
86 | ||
87 | /* ------------------- | |
88 | * Function prototypes | |
89 | * ------------------- */ | |
90 | void spi_init (void); | |
91 | ||
92 | ssize_t spi_read (uchar *, int, uchar *, int); | |
93 | ssize_t spi_write (uchar *, int, uchar *, int); | |
94 | ssize_t spi_xfer (size_t); | |
95 | ||
96 | ||
97 | /* ************************************************************************** | |
98 | * | |
99 | * Function: spi_init_f | |
100 | * | |
101 | * Description: Init SPI-Controller (ROM part) | |
102 | * | |
103 | * return: --- | |
104 | * | |
105 | * *********************************************************************** */ | |
106 | ||
107 | void spi_init_f (void) | |
108 | { | |
109 | int i; | |
110 | ||
111 | volatile immap_t *immr; | |
112 | volatile qsmcm5xx_t *qsmcm; | |
113 | ||
6d0f6bcf | 114 | immr = (immap_t *) CONFIG_SYS_IMMR; |
b6e4c403 WD |
115 | qsmcm = (qsmcm5xx_t *)&immr->im_qsmcm; |
116 | ||
117 | qsmcm->qsmcm_qsmcr = 0; /* all accesses enabled */ | |
118 | qsmcm->qsmcm_qspi_il = 0; /* lowest IRQ */ | |
119 | ||
120 | /* -------------------------------------------- | |
121 | * GPIO or per. Function | |
122 | * PQSPAR[00] = 0 reserved | |
123 | * PQSPAR[01] = 1 [0x4000] -> PERI: (SPICS3) | |
124 | * PQSPAR[02] = 0 [0x0000] -> GPIO | |
125 | * PQSPAR[03] = 0 [0x0000] -> GPIO | |
126 | * PQSPAR[04] = 1 [0x0800] -> PERI: (SPICS0) | |
127 | * PQSPAR[05] = 0 reseved | |
128 | * PQSPAR[06] = 1 [0x0200] -> PERI: (SPIMOSI) | |
129 | * PQSPAR[07] = 1 [0x0100] -> PERI: (SPIMISO) | |
130 | * -------------------------------------------- */ | |
6d0f6bcf | 131 | qsmcm->qsmcm_pqspar = 0x3 | (CONFIG_SYS_SPI_CS_USED << 3); |
b6e4c403 WD |
132 | |
133 | /* -------------------------------------------- | |
134 | * DDRQS[00] = 0 reserved | |
135 | * DDRQS[01] = 1 [0x0040] -> SPICS3 Output | |
136 | * DDRQS[02] = 0 [0x0000] -> GPIO Output | |
137 | * DDRQS[03] = 0 [0x0000] -> GPIO Output | |
138 | * DDRQS[04] = 1 [0x0008] -> SPICS0 Output | |
139 | * DDRQS[05] = 1 [0x0004] -> SPICLK Output | |
140 | * DDRQS[06] = 1 [0x0002] -> SPIMOSI Output | |
141 | * DDRQS[07] = 0 [0x0001] -> SPIMISO Input | |
142 | * -------------------------------------------- */ | |
143 | qsmcm->qsmcm_ddrqs = 0x7E; | |
144 | /* -------------------------------------------- | |
145 | * Base state for used SPI CS pins, if base = 0 active must be 1 | |
146 | * PORTQS[00] = 0 reserved | |
147 | * PORTQS[01] = 0 reserved | |
148 | * PORTQS[02] = 0 reserved | |
149 | * PORTQS[03] = 0 reserved | |
150 | * PORTQS[04] = 0 [0x0000] RxD2 | |
151 | * PORTQS[05] = 1 [0x0400] TxD2 | |
152 | * PORTQS[06] = 0 [0x0000] RxD1 | |
153 | * PORTQS[07] = 1 [0x0100] TxD1 | |
154 | * PORTQS[08] = 0 reserved | |
155 | * PORTQS[09] = 0 [0x0000] -> SPICS3 Base Output | |
156 | * PORTQS[10] = 0 [0x0000] -> SPICS2 Base Output | |
157 | * PORTQS[11] = 0 [0x0000] -> SPICS1 Base Output | |
158 | * PORTQS[12] = 0 [0x0000] -> SPICS0 Base Output | |
159 | * PORTQS[13] = 0 [0x0004] -> SPICLK Output | |
160 | * PORTQS[14] = 0 [0x0002] -> SPIMOSI Output | |
161 | * PORTQS[15] = 0 [0x0001] -> SPIMISO Input | |
162 | * -------------------------------------------- */ | |
6d0f6bcf | 163 | qsmcm->qsmcm_portqs |= (CONFIG_SYS_SPI_CS_BASE << 3); |
b6e4c403 WD |
164 | /* -------------------------------------------- |
165 | * Controll Register 0 | |
166 | * SPCR0[00] = 1 (0x8000) Master | |
167 | * SPCR0[01] = 0 (0x0000) Wired-Or | |
168 | * SPCR0[2..5] = (0x2000) Bits per transfer (default 8) | |
169 | * SPCR0[06] = 0 (0x0000) Normal polarity | |
170 | * SPCR0[07] = 0 (0x0000) Normal Clock Phase | |
171 | * SPCR0[08..15] = 14 1.4MHz | |
172 | */ | |
173 | qsmcm->qsmcm_spcr0=0xA00E; | |
174 | /* -------------------------------------------- | |
175 | * Controll Register 1 | |
176 | * SPCR1[00] = 0 (0x0000) QSPI enabled | |
177 | * SPCR1[1..7] = (0x7F00) Delay before Transfer | |
178 | * SPCR1[8..15] = (0x0000) Delay After transfer (204.8usec@40MHz) | |
179 | */ | |
180 | qsmcm->qsmcm_spcr1=0x7F00; | |
181 | /* -------------------------------------------- | |
182 | * Controll Register 2 | |
183 | * SPCR2[00] = 0 (0x0000) SPI IRQs Disabeld | |
184 | * SPCR2[01] = 0 (0x0000) No Wrap around | |
185 | * SPCR2[02] = 0 (0x0000) Wrap to 0 | |
186 | * SPCR2[3..7] = (0x0000) End Queue pointer = 0 | |
187 | * SPCR2[8..10] = 0 (0x0000) reserved | |
188 | * SPCR2[11..15] = 0 (0x0000) NewQueue Address = 0 | |
189 | */ | |
190 | qsmcm->qsmcm_spcr2=0x0000; | |
191 | /* -------------------------------------------- | |
192 | * Controll Register 3 | |
193 | * SPCR3[00..04] = 0 (0x0000) reserved | |
194 | * SPCR3[05] = 0 (0x0000) Feedback disabled | |
195 | * SPCR3[06] = 0 (0x0000) IRQ on HALTA & MODF disabled | |
196 | * SPCR3[07] = 0 (0x0000) Not halted | |
197 | */ | |
198 | qsmcm->qsmcm_spcr3=0x00; | |
199 | /* -------------------------------------------- | |
200 | * SPSR (Controll Register 3) Read only/ reset Flags 08,09,10 | |
201 | * SPCR3[08] = 1 (0x80) QSPI finished | |
202 | * SPCR3[09] = 1 (0x40) Mode Fault Flag | |
203 | * SPCR3[10] = 1 (0x20) HALTA | |
204 | * SPCR3[11..15] = 0 (0x0000) Last executed command | |
205 | */ | |
206 | qsmcm->qsmcm_spsr=0xE0; | |
207 | /*------------------------------------------- | |
208 | * Setup RAM | |
209 | */ | |
210 | for(i=0;i<32;i++) { | |
53677ef1 WD |
211 | qsmcm->qsmcm_recram[i]=0x0000; |
212 | qsmcm->qsmcm_tranram[i]=0x0000; | |
213 | qsmcm->qsmcm_comdram[i]=0x00; | |
b6e4c403 WD |
214 | } |
215 | return; | |
216 | } | |
217 | ||
218 | /* ************************************************************************** | |
219 | * | |
220 | * Function: spi_init_r | |
221 | * Dummy, all initializations have been done in spi_init_r | |
222 | * *********************************************************************** */ | |
223 | void spi_init_r (void) | |
224 | { | |
225 | return; | |
226 | ||
227 | } | |
228 | ||
229 | /**************************************************************************** | |
230 | * Function: spi_write | |
231 | **************************************************************************** */ | |
232 | ssize_t short_spi_write (uchar *addr, int alen, uchar *buffer, int len) | |
233 | { | |
234 | int i,dlen; | |
235 | volatile immap_t *immr; | |
236 | volatile qsmcm5xx_t *qsmcm; | |
237 | ||
6d0f6bcf | 238 | immr = (immap_t *) CONFIG_SYS_IMMR; |
b6e4c403 WD |
239 | qsmcm = (qsmcm5xx_t *)&immr->im_qsmcm; |
240 | for(i=0;i<32;i++) { | |
53677ef1 WD |
241 | qsmcm->qsmcm_recram[i]=0x0000; |
242 | qsmcm->qsmcm_tranram[i]=0x0000; | |
243 | qsmcm->qsmcm_comdram[i]=0x00; | |
b6e4c403 WD |
244 | } |
245 | qsmcm->qsmcm_tranram[0] = SPI_EEPROM_WREN; /* write enable */ | |
246 | spi_xfer(1); | |
247 | i=0; | |
248 | qsmcm->qsmcm_tranram[i++] = SPI_EEPROM_WRITE; /* WRITE memory array */ | |
249 | qsmcm->qsmcm_tranram[i++] = addr[0]; | |
250 | qsmcm->qsmcm_tranram[i++] = addr[1]; | |
251 | ||
252 | for(dlen=0;dlen<len;dlen++) { | |
253 | qsmcm->qsmcm_tranram[i+dlen] = buffer[dlen]; /* WRITE memory array */ | |
254 | } | |
255 | /* transmit it */ | |
256 | spi_xfer(i+dlen); | |
257 | /* ignore received data */ | |
258 | for (i = 0; i < 1000; i++) { | |
259 | qsmcm->qsmcm_tranram[0] = SPI_EEPROM_RDSR; /* read status */ | |
260 | qsmcm->qsmcm_tranram[1] = 0; | |
261 | spi_xfer(2); | |
262 | if (!(qsmcm->qsmcm_recram[1] & 1)) { | |
263 | break; | |
264 | } | |
265 | udelay(1000); | |
266 | } | |
267 | if (i >= 1000) { | |
268 | printf ("*** spi_write: Time out while writing!\n"); | |
269 | } | |
270 | return len; | |
271 | } | |
272 | ||
273 | #define TRANSFER_LEN 16 | |
274 | ||
275 | ssize_t spi_write (uchar *addr, int alen, uchar *buffer, int len) | |
276 | { | |
277 | int index,i,newlen; | |
278 | uchar newaddr[2]; | |
279 | int curraddr; | |
280 | ||
281 | curraddr=(addr[alen-2]<<8)+addr[alen-1]; | |
282 | i=len; | |
283 | index=0; | |
284 | do { | |
285 | newaddr[1]=(curraddr & 0xff); | |
286 | newaddr[0]=((curraddr>>8) & 0xff); | |
287 | if(i>TRANSFER_LEN) { | |
288 | newlen=TRANSFER_LEN; | |
289 | i-=TRANSFER_LEN; | |
290 | } | |
291 | else { | |
292 | newlen=i; | |
293 | i=0; | |
294 | } | |
295 | short_spi_write (newaddr, 2, &buffer[index], newlen); | |
296 | index+=newlen; | |
297 | curraddr+=newlen; | |
298 | }while(i); | |
299 | return (len); | |
300 | } | |
301 | ||
302 | /**************************************************************************** | |
303 | * Function: spi_read | |
304 | **************************************************************************** */ | |
305 | ssize_t short_spi_read (uchar *addr, int alen, uchar *buffer, int len) | |
306 | { | |
307 | int i; | |
308 | volatile immap_t *immr; | |
309 | volatile qsmcm5xx_t *qsmcm; | |
310 | ||
6d0f6bcf | 311 | immr = (immap_t *) CONFIG_SYS_IMMR; |
b6e4c403 WD |
312 | qsmcm = (qsmcm5xx_t *)&immr->im_qsmcm; |
313 | ||
314 | for(i=0;i<32;i++) { | |
53677ef1 WD |
315 | qsmcm->qsmcm_recram[i]=0x0000; |
316 | qsmcm->qsmcm_tranram[i]=0x0000; | |
317 | qsmcm->qsmcm_comdram[i]=0x00; | |
b6e4c403 WD |
318 | } |
319 | i=0; | |
320 | qsmcm->qsmcm_tranram[i++] = (SPI_EEPROM_READ); /* READ memory array */ | |
321 | qsmcm->qsmcm_tranram[i++] = addr[0] & 0xff; | |
322 | qsmcm->qsmcm_tranram[i++] = addr[1] & 0xff; | |
323 | spi_xfer(3 + len); | |
324 | for(i=0;i<len;i++) { | |
325 | *buffer++=(char)qsmcm->qsmcm_recram[i+3]; | |
326 | } | |
327 | return len; | |
328 | } | |
329 | ||
330 | ssize_t spi_read (uchar *addr, int alen, uchar *buffer, int len) | |
331 | { | |
332 | int index,i,newlen; | |
333 | uchar newaddr[2]; | |
334 | int curraddr; | |
335 | ||
336 | curraddr=(addr[alen-2]<<8)+addr[alen-1]; | |
337 | i=len; | |
338 | index=0; | |
339 | do { | |
340 | newaddr[1]=(curraddr & 0xff); | |
341 | newaddr[0]=((curraddr>>8) & 0xff); | |
342 | if(i>TRANSFER_LEN) { | |
343 | newlen=TRANSFER_LEN; | |
344 | i-=TRANSFER_LEN; | |
345 | } | |
346 | else { | |
347 | newlen=i; | |
348 | i=0; | |
349 | } | |
350 | short_spi_read (newaddr, 2, &buffer[index], newlen); | |
351 | index+=newlen; | |
352 | curraddr+=newlen; | |
353 | }while(i); | |
354 | return (len); | |
355 | } | |
356 | ||
b6e4c403 WD |
357 | /**************************************************************************** |
358 | * Function: spi_xfer | |
359 | **************************************************************************** */ | |
360 | ssize_t spi_xfer (size_t count) | |
361 | { | |
362 | volatile immap_t *immr; | |
363 | volatile qsmcm5xx_t *qsmcm; | |
364 | int i; | |
365 | int tm; | |
366 | ushort status; | |
6d0f6bcf | 367 | immr = (immap_t *) CONFIG_SYS_IMMR; |
b6e4c403 WD |
368 | qsmcm = (qsmcm5xx_t *)&immr->im_qsmcm; |
369 | DPRINT (("*** spi_xfer entered count %d***\n",count)); | |
370 | ||
371 | /* Set CS for device */ | |
372 | for(i=0;i<(count-1);i++) | |
6d0f6bcf | 373 | qsmcm->qsmcm_comdram[i] = 0x80 | CONFIG_SYS_SPI_CS_ACT; /* CS3 is connected to the SPI EEPROM */ |
b6e4c403 | 374 | |
6d0f6bcf | 375 | qsmcm->qsmcm_comdram[i] = CONFIG_SYS_SPI_CS_ACT; /* CS3 is connected to the SPI EEPROM */ |
b6e4c403 WD |
376 | qsmcm->qsmcm_spcr2=((count-1)&0x1F)<<8; |
377 | ||
378 | DPRINT (("*** spi_xfer: Bytes to be xferred: %d ***\n", count)); | |
379 | ||
380 | qsmcm->qsmcm_spsr=0xE0; /* clear all flags */ | |
381 | ||
382 | /* start spi transfer */ | |
383 | DPRINT (("*** spi_xfer: Performing transfer ...\n")); | |
384 | qsmcm->qsmcm_spcr1 |= 0x8000; /* Start transmit */ | |
385 | ||
386 | /* -------------------------------- | |
387 | * Wait for SPI transmit to get out | |
388 | * or time out (1 second = 1000 ms) | |
389 | * -------------------------------- */ | |
390 | for (tm=0; tm<1000; ++tm) { | |
391 | status=qsmcm->qsmcm_spcr1; | |
392 | if((status & 0x8000)==0) | |
393 | break; | |
394 | udelay (1000); | |
395 | } | |
396 | if (tm >= 1000) { | |
397 | printf ("*** spi_xfer: Time out while xferring to/from SPI!\n"); | |
398 | } | |
399 | #ifdef DEBUG | |
400 | printf ("\nspi_xfer: txbuf after xfer\n"); | |
401 | memdump ((void *) qsmcm->qsmcm_tranram, 32); /* dump of txbuf before transmit */ | |
402 | printf ("spi_xfer: rxbuf after xfer\n"); | |
403 | memdump ((void *) qsmcm->qsmcm_recram, 32); /* dump of rxbuf after transmit */ | |
404 | printf ("\nspi_xfer: commbuf after xfer\n"); | |
405 | memdump ((void *) qsmcm->qsmcm_comdram, 32); /* dump of txbuf before transmit */ | |
406 | printf ("\n"); | |
407 | #endif | |
408 | ||
409 | return count; | |
410 | } | |
411 | ||
412 | #endif /* CONFIG_SPI */ |