]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/powerpc/cpu/mpc8260/spi.c
nios2: Move individual board linker scripts to common script in cpu tree.
[karo-tx-uboot.git] / arch / powerpc / cpu / mpc8260 / 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-2003 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  * MPC8260 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  */
35
36 #include <common.h>
37 #include <asm/cpm_8260.h>
38 #include <linux/ctype.h>
39 #include <malloc.h>
40 #include <post.h>
41 #include <net.h>
42
43 #if defined(CONFIG_SPI)
44
45 /* Warning:
46  * You cannot enable DEBUG for early system initalization, i. e. when
47  * this driver is used to read environment parameters like "baudrate"
48  * from EEPROM which are used to initialize the serial port which is
49  * needed to print the debug messages...
50  */
51 #undef  DEBUG
52
53 #define SPI_EEPROM_WREN         0x06
54 #define SPI_EEPROM_RDSR         0x05
55 #define SPI_EEPROM_READ         0x03
56 #define SPI_EEPROM_WRITE        0x02
57
58 /* ---------------------------------------------------------------
59  * Offset for initial SPI buffers in DPRAM:
60  * We need a 520 byte scratch DPRAM area to use at an early stage.
61  * It is used between the two initialization calls (spi_init_f()
62  * and spi_init_r()).
63  * The value 0x2000 makes it far enough from the start of the data
64  * area (as well as from the stack pointer).
65  * --------------------------------------------------------------- */
66 #ifndef CONFIG_SYS_SPI_INIT_OFFSET
67 #define CONFIG_SYS_SPI_INIT_OFFSET      0x2000
68 #endif
69
70 #define CPM_SPI_BASE 0x100
71
72 #ifdef  DEBUG
73
74 #define DPRINT(a)       printf a;
75 /* -----------------------------------------------
76  * Helper functions to peek into tx and rx buffers
77  * ----------------------------------------------- */
78 static const char * const hex_digit = "0123456789ABCDEF";
79
80 static char quickhex (int i)
81 {
82         return hex_digit[i];
83 }
84
85 static void memdump (void *pv, int num)
86 {
87         int i;
88         unsigned char *pc = (unsigned char *) pv;
89
90         for (i = 0; i < num; i++)
91                 printf ("%c%c ", quickhex (pc[i] >> 4), quickhex (pc[i] & 0x0f));
92         printf ("\t");
93         for (i = 0; i < num; i++)
94                 printf ("%c", isprint (pc[i]) ? pc[i] : '.');
95         printf ("\n");
96 }
97 #else   /* !DEBUG */
98
99 #define DPRINT(a)
100
101 #endif  /* DEBUG */
102
103 /* -------------------
104  * Function prototypes
105  * ------------------- */
106 void spi_init (void);
107
108 ssize_t spi_read (uchar *, int, uchar *, int);
109 ssize_t spi_write (uchar *, int, uchar *, int);
110 ssize_t spi_xfer (size_t);
111
112 /* -------------------
113  * Variables
114  * ------------------- */
115
116 #define MAX_BUFFER      0x104
117
118 /* ----------------------------------------------------------------------
119  * Initially we place the RX and TX buffers at a fixed location in DPRAM!
120  * ---------------------------------------------------------------------- */
121 static uchar *rxbuf =
122   (uchar *)&((immap_t *)CONFIG_SYS_IMMR)->im_dprambase
123                         [CONFIG_SYS_SPI_INIT_OFFSET];
124 static uchar *txbuf =
125   (uchar *)&((immap_t *)CONFIG_SYS_IMMR)->im_dprambase
126                         [CONFIG_SYS_SPI_INIT_OFFSET+MAX_BUFFER];
127
128 /* **************************************************************************
129  *
130  *  Function:    spi_init_f
131  *
132  *  Description: Init SPI-Controller (ROM part)
133  *
134  *  return:      ---
135  *
136  * *********************************************************************** */
137 void spi_init_f (void)
138 {
139         unsigned int dpaddr;
140
141         volatile spi_t *spi;
142         volatile immap_t *immr;
143         volatile cpm8260_t *cp;
144         volatile cbd_t *tbdf, *rbdf;
145
146         immr = (immap_t *)  CONFIG_SYS_IMMR;
147         cp   = (cpm8260_t *) &immr->im_cpm;
148
149         *(ushort *)(&immr->im_dprambase[PROFF_SPI_BASE]) = PROFF_SPI;
150         spi  = (spi_t *)&immr->im_dprambase[PROFF_SPI];
151
152 /* 1 */
153         /* ------------------------------------------------
154          * Initialize Port D SPI pins
155          * (we are only in Master Mode !)
156          * ------------------------------------------------ */
157
158         /* --------------------------------------------
159          * GPIO or per. Function
160          * PPARD[16] = 1 [0x00008000] (SPIMISO)
161          * PPARD[17] = 1 [0x00004000] (SPIMOSI)
162          * PPARD[18] = 1 [0x00002000] (SPICLK)
163          * PPARD[12] = 0 [0x00080000] -> GPIO: (CS for ATC EEPROM)
164          * -------------------------------------------- */
165         immr->im_ioport.iop_ppard |=  0x0000E000;       /* set  bits    */
166         immr->im_ioport.iop_ppard &= ~0x00080000;       /* reset bit    */
167
168         /* ----------------------------------------------
169          * In/Out or per. Function 0/1
170          * PDIRD[16] = 0 [0x00008000] -> PERI1: SPIMISO
171          * PDIRD[17] = 0 [0x00004000] -> PERI1: SPIMOSI
172          * PDIRD[18] = 0 [0x00002000] -> PERI1: SPICLK
173          * PDIRD[12] = 1 [0x00080000] -> GPIO OUT: CS for ATC EEPROM
174          * ---------------------------------------------- */
175         immr->im_ioport.iop_pdird &= ~0x0000E000;
176         immr->im_ioport.iop_pdird |= 0x00080000;
177
178         /* ----------------------------------------------
179          * special option reg.
180          * PSORD[16] = 1 [0x00008000] -> SPIMISO
181          * PSORD[17] = 1 [0x00004000] -> SPIMOSI
182          * PSORD[18] = 1 [0x00002000] -> SPICLK
183          * ---------------------------------------------- */
184         immr->im_ioport.iop_psord |= 0x0000E000;
185
186         /* Initialize the parameter ram.
187          * We need to make sure many things are initialized to zero
188          */
189         spi->spi_rstate = 0;
190         spi->spi_rdp    = 0;
191         spi->spi_rbptr  = 0;
192         spi->spi_rbc    = 0;
193         spi->spi_rxtmp  = 0;
194         spi->spi_tstate = 0;
195         spi->spi_tdp    = 0;
196         spi->spi_tbptr  = 0;
197         spi->spi_tbc    = 0;
198         spi->spi_txtmp  = 0;
199
200         /* Allocate space for one transmit and one receive buffer
201          * descriptor in the DP ram
202          */
203 #ifdef CONFIG_SYS_ALLOC_DPRAM
204         dpaddr = m8260_cpm_dpalloc (sizeof(cbd_t)*2, 8);
205 #else
206         dpaddr = CPM_SPI_BASE;
207 #endif
208
209 /* 3 */
210         /* Set up the SPI parameters in the parameter ram */
211         spi->spi_rbase = dpaddr;
212         spi->spi_tbase = dpaddr + sizeof (cbd_t);
213
214         /***********IMPORTANT******************/
215
216         /*
217          * Setting transmit and receive buffer descriptor pointers
218          * initially to rbase and tbase. Only the microcode patches
219          * documentation talks about initializing this pointer. This
220          * is missing from the sample I2C driver. If you dont
221          * initialize these pointers, the kernel hangs.
222          */
223         spi->spi_rbptr = spi->spi_rbase;
224         spi->spi_tbptr = spi->spi_tbase;
225
226 /* 4 */
227         /* Init SPI Tx + Rx Parameters */
228         while (cp->cp_cpcr & CPM_CR_FLG)
229                 ;
230         cp->cp_cpcr = mk_cr_cmd(CPM_CR_SPI_PAGE, CPM_CR_SPI_SBLOCK,
231                                                         0, CPM_CR_INIT_TRX) | CPM_CR_FLG;
232         while (cp->cp_cpcr & CPM_CR_FLG)
233                 ;
234
235 /* 6 */
236         /* Set to big endian. */
237         spi->spi_tfcr = CPMFCR_EB;
238         spi->spi_rfcr = CPMFCR_EB;
239
240 /* 7 */
241         /* Set maximum receive size. */
242         spi->spi_mrblr = MAX_BUFFER;
243
244 /* 8 + 9 */
245         /* tx and rx buffer descriptors */
246         tbdf = (cbd_t *) & immr->im_dprambase[spi->spi_tbase];
247         rbdf = (cbd_t *) & immr->im_dprambase[spi->spi_rbase];
248
249         tbdf->cbd_sc &= ~BD_SC_READY;
250         rbdf->cbd_sc &= ~BD_SC_EMPTY;
251
252         /* Set the bd's rx and tx buffer address pointers */
253         rbdf->cbd_bufaddr = (ulong) rxbuf;
254         tbdf->cbd_bufaddr = (ulong) txbuf;
255
256 /* 10 + 11 */
257         immr->im_spi.spi_spie = SPI_EMASK;              /* Clear all SPI events */
258         immr->im_spi.spi_spim = 0x00;                   /* Mask  all SPI events */
259
260
261         return;
262 }
263
264 /* **************************************************************************
265  *
266  *  Function:    spi_init_r
267  *
268  *  Description: Init SPI-Controller (RAM part) -
269  *               The malloc engine is ready and we can move our buffers to
270  *               normal RAM
271  *
272  *  return:      ---
273  *
274  * *********************************************************************** */
275 void spi_init_r (void)
276 {
277         volatile spi_t *spi;
278         volatile immap_t *immr;
279         volatile cpm8260_t *cp;
280         volatile cbd_t *tbdf, *rbdf;
281
282         immr = (immap_t *)  CONFIG_SYS_IMMR;
283         cp   = (cpm8260_t *) &immr->im_cpm;
284
285         spi  = (spi_t *)&immr->im_dprambase[PROFF_SPI];
286
287         /* tx and rx buffer descriptors */
288         tbdf = (cbd_t *) & immr->im_dprambase[spi->spi_tbase];
289         rbdf = (cbd_t *) & immr->im_dprambase[spi->spi_rbase];
290
291         /* Allocate memory for RX and TX buffers */
292         rxbuf = (uchar *) malloc (MAX_BUFFER);
293         txbuf = (uchar *) malloc (MAX_BUFFER);
294
295         rbdf->cbd_bufaddr = (ulong) rxbuf;
296         tbdf->cbd_bufaddr = (ulong) txbuf;
297
298         return;
299 }
300
301 /****************************************************************************
302  *  Function:    spi_write
303  **************************************************************************** */
304 ssize_t spi_write (uchar *addr, int alen, uchar *buffer, int len)
305 {
306         int i;
307
308         memset(rxbuf, 0, MAX_BUFFER);
309         memset(txbuf, 0, MAX_BUFFER);
310         *txbuf = SPI_EEPROM_WREN;               /* write enable         */
311         spi_xfer(1);
312         memcpy(txbuf, addr, alen);
313         *txbuf = SPI_EEPROM_WRITE;              /* WRITE memory array   */
314         memcpy(alen + txbuf, buffer, len);
315         spi_xfer(alen + len);
316                                                 /* ignore received data */
317         for (i = 0; i < 1000; i++) {
318                 *txbuf = SPI_EEPROM_RDSR;       /* read status          */
319                 txbuf[1] = 0;
320                 spi_xfer(2);
321                 if (!(rxbuf[1] & 1)) {
322                         break;
323                 }
324                 udelay(1000);
325         }
326         if (i >= 1000) {
327                 printf ("*** spi_write: Time out while writing!\n");
328         }
329
330         return len;
331 }
332
333 /****************************************************************************
334  *  Function:    spi_read
335  **************************************************************************** */
336 ssize_t spi_read (uchar *addr, int alen, uchar *buffer, int len)
337 {
338         memset(rxbuf, 0, MAX_BUFFER);
339         memset(txbuf, 0, MAX_BUFFER);
340         memcpy(txbuf, addr, alen);
341         *txbuf = SPI_EEPROM_READ;               /* READ memory array    */
342
343         /*
344          * There is a bug in 860T (?) that cuts the last byte of input
345          * if we're reading into DPRAM. The solution we choose here is
346          * to always read len+1 bytes (we have one extra byte at the
347          * end of the buffer).
348          */
349         spi_xfer(alen + len + 1);
350         memcpy(buffer, alen + rxbuf, len);
351
352         return len;
353 }
354
355 /****************************************************************************
356  *  Function:    spi_xfer
357  **************************************************************************** */
358 ssize_t spi_xfer (size_t count)
359 {
360         volatile immap_t *immr;
361         volatile cpm8260_t *cp;
362         volatile spi_t *spi;
363         cbd_t *tbdf, *rbdf;
364         int tm;
365
366         DPRINT (("*** spi_xfer entered ***\n"));
367
368         immr = (immap_t *) CONFIG_SYS_IMMR;
369         cp   = (cpm8260_t *) &immr->im_cpm;
370
371         spi  = (spi_t *)&immr->im_dprambase[PROFF_SPI];
372
373         tbdf = (cbd_t *) & immr->im_dprambase[spi->spi_tbase];
374         rbdf = (cbd_t *) & immr->im_dprambase[spi->spi_rbase];
375
376         /* Board-specific: Set CS for device (ATC EEPROM) */
377         immr->im_ioport.iop_pdatd &= ~0x00080000;
378
379         /* Setting tx bd status and data length */
380         tbdf->cbd_sc  = BD_SC_READY | BD_SC_LAST | BD_SC_WRAP;
381         tbdf->cbd_datlen = count;
382
383         DPRINT (("*** spi_xfer: Bytes to be xferred: %d ***\n",
384                                                         tbdf->cbd_datlen));
385
386         /* Setting rx bd status and data length */
387         rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP;
388         rbdf->cbd_datlen = 0;    /* rx length has no significance */
389
390         immr->im_spi.spi_spmode = SPMODE_REV    |
391                         SPMODE_MSTR     |
392                         SPMODE_EN       |
393                         SPMODE_LEN(8)   |       /* 8 Bits per char */
394                         SPMODE_PM(0x8) ;        /* medium speed */
395         immr->im_spi.spi_spie = SPI_EMASK;              /* Clear all SPI events */
396         immr->im_spi.spi_spim = 0x00;                   /* Mask  all SPI events */
397
398         /* start spi transfer */
399         DPRINT (("*** spi_xfer: Performing transfer ...\n"));
400         immr->im_spi.spi_spcom |= SPI_STR;              /* Start transmit */
401
402         /* --------------------------------
403          * Wait for SPI transmit to get out
404          * or time out (1 second = 1000 ms)
405          * -------------------------------- */
406         for (tm=0; tm<1000; ++tm) {
407                 if (immr->im_spi.spi_spie & SPI_TXB) {  /* Tx Buffer Empty */
408                         DPRINT (("*** spi_xfer: Tx buffer empty\n"));
409                         break;
410                 }
411                 if ((tbdf->cbd_sc & BD_SC_READY) == 0) {
412                         DPRINT (("*** spi_xfer: Tx BD done\n"));
413                         break;
414                 }
415                 udelay (1000);
416         }
417         if (tm >= 1000) {
418                 printf ("*** spi_xfer: Time out while xferring to/from SPI!\n");
419         }
420         DPRINT (("*** spi_xfer: ... transfer ended\n"));
421
422 #ifdef  DEBUG
423         printf ("\nspi_xfer: txbuf after xfer\n");
424         memdump ((void *) txbuf, 16);   /* dump of txbuf before transmit */
425         printf ("spi_xfer: rxbuf after xfer\n");
426         memdump ((void *) rxbuf, 16);   /* dump of rxbuf after transmit */
427         printf ("\n");
428 #endif
429
430         /* Clear CS for device */
431         immr->im_ioport.iop_pdatd |= 0x00080000;
432
433         return count;
434 }
435 #endif  /* CONFIG_SPI */