]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/glsdk-u-boot.git/blob - arch/ppc/cpu/mpc8xx/spi.c
fsl_i2c: Added a callpoint for i2c_board_late_init
[glsdk/glsdk-u-boot.git] / arch / ppc / cpu / mpc8xx / 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  */
27 /*
28  * MPC8xx 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  */
36 #include <common.h>
37 #include <mpc8xx.h>
38 #include <commproc.h>
39 #include <linux/ctype.h>
40 #include <malloc.h>
41 #include <post.h>
42 #include <serial.h>
44 #if (defined(CONFIG_SPI)) || (CONFIG_POST & CONFIG_SYS_POST_SPI)
46 /* Warning:
47  * You cannot enable DEBUG for early system initalization, i. e. when
48  * this driver is used to read environment parameters like "baudrate"
49  * from EEPROM which are used to initialize the serial port which is
50  * needed to print the debug messages...
51  */
52 #undef  DEBUG
54 #define SPI_EEPROM_WREN         0x06
55 #define SPI_EEPROM_RDSR         0x05
56 #define SPI_EEPROM_READ         0x03
57 #define SPI_EEPROM_WRITE        0x02
59 /* ---------------------------------------------------------------
60  * Offset for initial SPI buffers in DPRAM:
61  * We need a 520 byte scratch DPRAM area to use at an early stage.
62  * It is used between the two initialization calls (spi_init_f()
63  * and spi_init_r()).
64  * The value 0xb00 makes it far enough from the start of the data
65  * area (as well as from the stack pointer).
66  * --------------------------------------------------------------- */
67 #ifndef CONFIG_SYS_SPI_INIT_OFFSET
68 #define CONFIG_SYS_SPI_INIT_OFFSET      0xB00
69 #endif
71 #ifdef  DEBUG
73 #define DPRINT(a)       printf a;
74 /* -----------------------------------------------
75  * Helper functions to peek into tx and rx buffers
76  * ----------------------------------------------- */
77 static const char * const hex_digit = "0123456789ABCDEF";
79 static char quickhex (int i)
80 {
81         return hex_digit[i];
82 }
84 static void memdump (void *pv, int num)
85 {
86         int i;
87         unsigned char *pc = (unsigned char *) pv;
89         for (i = 0; i < num; i++)
90                 printf ("%c%c ", quickhex (pc[i] >> 4), quickhex (pc[i] & 0x0f));
91         printf ("\t");
92         for (i = 0; i < num; i++)
93                 printf ("%c", isprint (pc[i]) ? pc[i] : '.');
94         printf ("\n");
95 }
96 #else   /* !DEBUG */
98 #define DPRINT(a)
100 #endif  /* DEBUG */
102 /* -------------------
103  * Function prototypes
104  * ------------------- */
105 void spi_init (void);
107 ssize_t spi_read (uchar *, int, uchar *, int);
108 ssize_t spi_write (uchar *, int, uchar *, int);
109 ssize_t spi_xfer (size_t);
111 /* -------------------
112  * Variables
113  * ------------------- */
115 #define MAX_BUFFER      0x104
117 /* ----------------------------------------------------------------------
118  * Initially we place the RX and TX buffers at a fixed location in DPRAM!
119  * ---------------------------------------------------------------------- */
120 static uchar *rxbuf =
121   (uchar *)&((cpm8xx_t *)&((immap_t *)CONFIG_SYS_IMMR)->im_cpm)->cp_dpmem
122                         [CONFIG_SYS_SPI_INIT_OFFSET];
123 static uchar *txbuf =
124   (uchar *)&((cpm8xx_t *)&((immap_t *)CONFIG_SYS_IMMR)->im_cpm)->cp_dpmem
125                         [CONFIG_SYS_SPI_INIT_OFFSET+MAX_BUFFER];
127 /* **************************************************************************
128  *
129  *  Function:    spi_init_f
130  *
131  *  Description: Init SPI-Controller (ROM part)
132  *
133  *  return:      ---
134  *
135  * *********************************************************************** */
136 void spi_init_f (void)
138         unsigned int dpaddr;
140         volatile spi_t *spi;
141         volatile immap_t *immr;
142         volatile cpic8xx_t *cpi;
143         volatile cpm8xx_t *cp;
144         volatile iop8xx_t *iop;
145         volatile cbd_t *tbdf, *rbdf;
147         immr = (immap_t *)  CONFIG_SYS_IMMR;
148         cpi  = (cpic8xx_t *)&immr->im_cpic;
149         iop  = (iop8xx_t *) &immr->im_ioport;
150         cp   = (cpm8xx_t *) &immr->im_cpm;
152 #ifdef CONFIG_SYS_SPI_UCODE_PATCH
153         spi  = (spi_t *)&cp->cp_dpmem[spi->spi_rpbase];
154 #else
155         spi  = (spi_t *)&cp->cp_dparam[PROFF_SPI];
156         /* Disable relocation */
157         spi->spi_rpbase = 0;
158 #endif
160 /* 1 */
161         /* ------------------------------------------------
162          * Initialize Port B SPI pins -> page 34-8 MPC860UM
163          * (we are only in Master Mode !)
164          * ------------------------------------------------ */
166         /* --------------------------------------------
167          * GPIO or per. Function
168          * PBPAR[28] = 1 [0x00000008] -> PERI: (SPIMISO)
169          * PBPAR[29] = 1 [0x00000004] -> PERI: (SPIMOSI)
170          * PBPAR[30] = 1 [0x00000002] -> PERI: (SPICLK)
171          * PBPAR[31] = 0 [0x00000001] -> GPIO: (CS for PCUE/CCM-EEPROM)
172          * -------------------------------------------- */
173         cp->cp_pbpar |=  0x0000000E;    /* set  bits    */
174         cp->cp_pbpar &= ~0x00000001;    /* reset bit    */
176         /* ----------------------------------------------
177          * In/Out or per. Function 0/1
178          * PBDIR[28] = 1 [0x00000008] -> PERI1: SPIMISO
179          * PBDIR[29] = 1 [0x00000004] -> PERI1: SPIMOSI
180          * PBDIR[30] = 1 [0x00000002] -> PERI1: SPICLK
181          * PBDIR[31] = 1 [0x00000001] -> GPIO OUT: CS for PCUE/CCM-EEPROM
182          * ---------------------------------------------- */
183         cp->cp_pbdir |= 0x0000000F;
185         /* ----------------------------------------------
186          * open drain or active output
187          * PBODR[28] = 1 [0x00000008] -> open drain: SPIMISO
188          * PBODR[29] = 0 [0x00000004] -> active output SPIMOSI
189          * PBODR[30] = 0 [0x00000002] -> active output: SPICLK
190          * PBODR[31] = 0 [0x00000001] -> active output: GPIO OUT: CS for PCUE/CCM
191          * ---------------------------------------------- */
193         cp->cp_pbodr |=  0x00000008;
194         cp->cp_pbodr &= ~0x00000007;
196         /* Initialize the parameter ram.
197          * We need to make sure many things are initialized to zero
198          */
199         spi->spi_rstate = 0;
200         spi->spi_rdp    = 0;
201         spi->spi_rbptr  = 0;
202         spi->spi_rbc    = 0;
203         spi->spi_rxtmp  = 0;
204         spi->spi_tstate = 0;
205         spi->spi_tdp    = 0;
206         spi->spi_tbptr  = 0;
207         spi->spi_tbc    = 0;
208         spi->spi_txtmp  = 0;
210         /* Allocate space for one transmit and one receive buffer
211          * descriptor in the DP ram
212          */
213 #ifdef CONFIG_SYS_ALLOC_DPRAM
214         dpaddr = dpram_alloc_align (sizeof(cbd_t)*2, 8);
215 #else
216         dpaddr = CPM_SPI_BASE;
217 #endif
219 /* 3 */
220         /* Set up the SPI parameters in the parameter ram */
221         spi->spi_rbase = dpaddr;
222         spi->spi_tbase = dpaddr + sizeof (cbd_t);
224         /***********IMPORTANT******************/
226         /*
227          * Setting transmit and receive buffer descriptor pointers
228          * initially to rbase and tbase. Only the microcode patches
229          * documentation talks about initializing this pointer. This
230          * is missing from the sample I2C driver. If you dont
231          * initialize these pointers, the kernel hangs.
232          */
233         spi->spi_rbptr = spi->spi_rbase;
234         spi->spi_tbptr = spi->spi_tbase;
236 /* 4 */
237 #ifdef CONFIG_SYS_SPI_UCODE_PATCH
238         /*
239          *  Initialize required parameters if using microcode patch.
240          */
241         spi->spi_rstate = 0;
242         spi->spi_tstate = 0;
243 #else
244         /* Init SPI Tx + Rx Parameters */
245         while (cp->cp_cpcr & CPM_CR_FLG)
246                 ;
247         cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SPI, CPM_CR_INIT_TRX) | CPM_CR_FLG;
248         while (cp->cp_cpcr & CPM_CR_FLG)
249                 ;
250 #endif  /* CONFIG_SYS_SPI_UCODE_PATCH */
252 /* 5 */
253         /* Set SDMA configuration register */
254         immr->im_siu_conf.sc_sdcr = 0x0001;
256 /* 6 */
257         /* Set to big endian. */
258         spi->spi_tfcr = SMC_EB;
259         spi->spi_rfcr = SMC_EB;
261 /* 7 */
262         /* Set maximum receive size. */
263         spi->spi_mrblr = MAX_BUFFER;
265 /* 8 + 9 */
266         /* tx and rx buffer descriptors */
267         tbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_tbase];
268         rbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_rbase];
270         tbdf->cbd_sc &= ~BD_SC_READY;
271         rbdf->cbd_sc &= ~BD_SC_EMPTY;
273         /* Set the bd's rx and tx buffer address pointers */
274         rbdf->cbd_bufaddr = (ulong) rxbuf;
275         tbdf->cbd_bufaddr = (ulong) txbuf;
277 /* 10 + 11 */
278         cp->cp_spim = 0;                        /* Mask  all SPI events */
279         cp->cp_spie = SPI_EMASK;                /* Clear all SPI events */
281         return;
284 /* **************************************************************************
285  *
286  *  Function:    spi_init_r
287  *
288  *  Description: Init SPI-Controller (RAM part) -
289  *               The malloc engine is ready and we can move our buffers to
290  *               normal RAM
291  *
292  *  return:      ---
293  *
294  * *********************************************************************** */
295 void spi_init_r (void)
297         volatile cpm8xx_t *cp;
298         volatile spi_t *spi;
299         volatile immap_t *immr;
300         volatile cbd_t *tbdf, *rbdf;
302         immr = (immap_t *)  CONFIG_SYS_IMMR;
303         cp   = (cpm8xx_t *) &immr->im_cpm;
305 #ifdef CONFIG_SYS_SPI_UCODE_PATCH
306         spi  = (spi_t *)&cp->cp_dpmem[spi->spi_rpbase];
307 #else
308         spi  = (spi_t *)&cp->cp_dparam[PROFF_SPI];
309         /* Disable relocation */
310         spi->spi_rpbase = 0;
311 #endif
313         /* tx and rx buffer descriptors */
314         tbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_tbase];
315         rbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_rbase];
317         /* Allocate memory for RX and TX buffers */
318         rxbuf = (uchar *) malloc (MAX_BUFFER);
319         txbuf = (uchar *) malloc (MAX_BUFFER);
321         rbdf->cbd_bufaddr = (ulong) rxbuf;
322         tbdf->cbd_bufaddr = (ulong) txbuf;
324         return;
327 /****************************************************************************
328  *  Function:    spi_write
329  **************************************************************************** */
330 ssize_t spi_write (uchar *addr, int alen, uchar *buffer, int len)
332         int i;
334         memset(rxbuf, 0, MAX_BUFFER);
335         memset(txbuf, 0, MAX_BUFFER);
336         *txbuf = SPI_EEPROM_WREN;               /* write enable         */
337         spi_xfer(1);
338         memcpy(txbuf, addr, alen);
339         *txbuf = SPI_EEPROM_WRITE;              /* WRITE memory array   */
340         memcpy(alen + txbuf, buffer, len);
341         spi_xfer(alen + len);
342                                                 /* ignore received data */
343         for (i = 0; i < 1000; i++) {
344                 *txbuf = SPI_EEPROM_RDSR;       /* read status          */
345                 txbuf[1] = 0;
346                 spi_xfer(2);
347                 if (!(rxbuf[1] & 1)) {
348                         break;
349                 }
350                 udelay(1000);
351         }
352         if (i >= 1000) {
353                 printf ("*** spi_write: Time out while writing!\n");
354         }
356         return len;
359 /****************************************************************************
360  *  Function:    spi_read
361  **************************************************************************** */
362 ssize_t spi_read (uchar *addr, int alen, uchar *buffer, int len)
364         memset(rxbuf, 0, MAX_BUFFER);
365         memset(txbuf, 0, MAX_BUFFER);
366         memcpy(txbuf, addr, alen);
367         *txbuf = SPI_EEPROM_READ;               /* READ memory array    */
369         /*
370          * There is a bug in 860T (?) that cuts the last byte of input
371          * if we're reading into DPRAM. The solution we choose here is
372          * to always read len+1 bytes (we have one extra byte at the
373          * end of the buffer).
374          */
375         spi_xfer(alen + len + 1);
376         memcpy(buffer, alen + rxbuf, len);
378         return len;
381 /****************************************************************************
382  *  Function:    spi_xfer
383  **************************************************************************** */
384 ssize_t spi_xfer (size_t count)
386         volatile immap_t *immr;
387         volatile cpm8xx_t *cp;
388         volatile spi_t *spi;
389         cbd_t *tbdf, *rbdf;
390         ushort loop;
391         int tm;
393         DPRINT (("*** spi_xfer entered ***\n"));
395         immr = (immap_t *) CONFIG_SYS_IMMR;
396         cp   = (cpm8xx_t *) &immr->im_cpm;
398 #ifdef CONFIG_SYS_SPI_UCODE_PATCH
399         spi  = (spi_t *)&cp->cp_dpmem[spi->spi_rpbase];
400 #else
401         spi  = (spi_t *)&cp->cp_dparam[PROFF_SPI];
402         /* Disable relocation */
403         spi->spi_rpbase = 0;
404 #endif
406         tbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_tbase];
407         rbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_rbase];
409         /* Set CS for device */
410         cp->cp_pbdat &= ~0x0001;
412         /* Setting tx bd status and data length */
413         tbdf->cbd_sc  = BD_SC_READY | BD_SC_LAST | BD_SC_WRAP;
414         tbdf->cbd_datlen = count;
416         DPRINT (("*** spi_xfer: Bytes to be xferred: %d ***\n",
417                                                         tbdf->cbd_datlen));
419         /* Setting rx bd status and data length */
420         rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP;
421         rbdf->cbd_datlen = 0;    /* rx length has no significance */
423         loop = cp->cp_spmode & SPMODE_LOOP;
424         cp->cp_spmode = /*SPMODE_DIV16  |*/     /* BRG/16 mode not used here */
425                         loop            |
426                         SPMODE_REV      |
427                         SPMODE_MSTR     |
428                         SPMODE_EN       |
429                         SPMODE_LEN(8)   |       /* 8 Bits per char */
430                         SPMODE_PM(0x8) ;        /* medium speed */
431         cp->cp_spim = 0;                        /* Mask  all SPI events */
432         cp->cp_spie = SPI_EMASK;                /* Clear all SPI events */
434         /* start spi transfer */
435         DPRINT (("*** spi_xfer: Performing transfer ...\n"));
436         cp->cp_spcom |= SPI_STR;                /* Start transmit */
438         /* --------------------------------
439          * Wait for SPI transmit to get out
440          * or time out (1 second = 1000 ms)
441          * -------------------------------- */
442         for (tm=0; tm<1000; ++tm) {
443                 if (cp->cp_spie & SPI_TXB) {    /* Tx Buffer Empty */
444                         DPRINT (("*** spi_xfer: Tx buffer empty\n"));
445                         break;
446                 }
447                 if ((tbdf->cbd_sc & BD_SC_READY) == 0) {
448                         DPRINT (("*** spi_xfer: Tx BD done\n"));
449                         break;
450                 }
451                 udelay (1000);
452         }
453         if (tm >= 1000) {
454                 printf ("*** spi_xfer: Time out while xferring to/from SPI!\n");
455         }
456         DPRINT (("*** spi_xfer: ... transfer ended\n"));
458 #ifdef  DEBUG
459         printf ("\nspi_xfer: txbuf after xfer\n");
460         memdump ((void *) txbuf, 16);   /* dump of txbuf before transmit */
461         printf ("spi_xfer: rxbuf after xfer\n");
462         memdump ((void *) rxbuf, 16);   /* dump of rxbuf after transmit */
463         printf ("\n");
464 #endif
466         /* Clear CS for device */
467         cp->cp_pbdat |= 0x0001;
469         return count;
471 #endif  /* CONFIG_SPI || (CONFIG_POST & CONFIG_SYS_POST_SPI) */
473 /*
474  * SPI test
475  *
476  * The Serial Peripheral Interface (SPI) is tested in the local loopback mode.
477  * The interface is configured accordingly and several packets
478  * are transfered. The configurable test parameters are:
479  *   TEST_MIN_LENGTH - minimum size of packet to transfer
480  *   TEST_MAX_LENGTH - maximum size of packet to transfer
481  *   TEST_NUM - number of tests
482  */
484 #if CONFIG_POST & CONFIG_SYS_POST_SPI
486 #define TEST_MIN_LENGTH         1
487 #define TEST_MAX_LENGTH         MAX_BUFFER
488 #define TEST_NUM                1
490 static void packet_fill (char * packet, int length)
492         char c = (char) length;
493         int i;
495         for (i = 0; i < length; i++)
496         {
497             packet[i] = c++;
498         }
501 static int packet_check (char * packet, int length)
503         char c = (char) length;
504         int i;
506         for (i = 0; i < length; i++) {
507             if (packet[i] != c++) return -1;
508         }
510         return 0;
513 int spi_post_test (int flags)
515         int res = -1;
516         volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
517         volatile cpm8xx_t *cp = (cpm8xx_t *) & immr->im_cpm;
518         int i;
519         int l;
521         spi_init_f ();
522         spi_init_r ();
524         cp->cp_spmode |= SPMODE_LOOP;
526         for (i = 0; i < TEST_NUM; i++) {
527                 for (l = TEST_MIN_LENGTH; l <= TEST_MAX_LENGTH; l += 8) {
528                         packet_fill ((char *)txbuf, l);
530                         spi_xfer (l);
532                         if (packet_check ((char *)rxbuf, l) < 0) {
533                                 goto Done;
534                         }
535                 }
536         }
538         res = 0;
540       Done:
542         cp->cp_spmode &= ~SPMODE_LOOP;
544         /*
545          * SCC2 parameter RAM space overlaps
546          * the SPI parameter RAM space. So we need to restore
547          * the SCC2 configuration if it is used by UART.
548          */
550 #if !defined(CONFIG_8xx_CONS_NONE)
551         serial_reinit_all ();
552 #endif
554         if (res != 0) {
555                 post_log ("SPI test failed\n");
556         }
558         return res;
560 #endif  /* CONFIG_POST & CONFIG_SYS_POST_SPI */