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