]> git.sur5r.net Git - u-boot/blob - cpu/mpc5xx/spi.c
powerpc: Fix bootm to boot up again with a Ramdisk
[u-boot] / cpu / mpc5xx / spi.c
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
114         immr = (immap_t *)  CFG_IMMR;
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          * -------------------------------------------- */
131         qsmcm->qsmcm_pqspar =  0x3 | (CFG_SPI_CS_USED << 3);
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          * -------------------------------------------- */
163         qsmcm->qsmcm_portqs |= (CFG_SPI_CS_BASE << 3);
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++) {
211                  qsmcm->qsmcm_recram[i]=0x0000;
212                  qsmcm->qsmcm_tranram[i]=0x0000;
213                  qsmcm->qsmcm_comdram[i]=0x00;
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
238         immr = (immap_t *)  CFG_IMMR;
239         qsmcm = (qsmcm5xx_t *)&immr->im_qsmcm;
240         for(i=0;i<32;i++) {
241                  qsmcm->qsmcm_recram[i]=0x0000;
242                  qsmcm->qsmcm_tranram[i]=0x0000;
243                  qsmcm->qsmcm_comdram[i]=0x00;
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
311         immr = (immap_t *)  CFG_IMMR;
312         qsmcm = (qsmcm5xx_t *)&immr->im_qsmcm;
313
314         for(i=0;i<32;i++) {
315                  qsmcm->qsmcm_recram[i]=0x0000;
316                  qsmcm->qsmcm_tranram[i]=0x0000;
317                  qsmcm->qsmcm_comdram[i]=0x00;
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
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;
367         immr = (immap_t *)  CFG_IMMR;
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++)
373                 qsmcm->qsmcm_comdram[i] = 0x80 | CFG_SPI_CS_ACT;  /* CS3 is connected to the SPI EEPROM */
374
375         qsmcm->qsmcm_comdram[i] = CFG_SPI_CS_ACT; /* CS3 is connected to the SPI EEPROM */
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  */