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>.
8 * See file CREDITS for list of people who contributed to this
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.
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.
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,
28 * MPC8xx CPM SPI interface.
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
39 #include <linux/ctype.h>
44 #if (defined(CONFIG_SPI)) || (CONFIG_POST & CONFIG_SYS_POST_SPI)
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...
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()
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
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)
84 static void memdump (void *pv, int num)
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));
92 for (i = 0; i < num; i++)
93 printf ("%c", isprint (pc[i]) ? pc[i] : '.');
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 /* -------------------
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 /* **************************************************************************
129 * Function: spi_init_f
131 * Description: Init SPI-Controller (ROM part)
135 * *********************************************************************** */
136 void spi_init_f (void)
141 volatile immap_t *immr;
142 volatile cpm8xx_t *cp;
143 volatile cbd_t *tbdf, *rbdf;
145 immr = (immap_t *) CONFIG_SYS_IMMR;
146 cp = (cpm8xx_t *) &immr->im_cpm;
148 #ifdef CONFIG_SYS_SPI_UCODE_PATCH
149 spi = (spi_t *)&cp->cp_dpmem[spi->spi_rpbase];
151 spi = (spi_t *)&cp->cp_dparam[PROFF_SPI];
152 /* Disable relocation */
157 /* ------------------------------------------------
158 * Initialize Port B SPI pins -> page 34-8 MPC860UM
159 * (we are only in Master Mode !)
160 * ------------------------------------------------ */
162 /* --------------------------------------------
163 * GPIO or per. Function
164 * PBPAR[28] = 1 [0x00000008] -> PERI: (SPIMISO)
165 * PBPAR[29] = 1 [0x00000004] -> PERI: (SPIMOSI)
166 * PBPAR[30] = 1 [0x00000002] -> PERI: (SPICLK)
167 * PBPAR[31] = 0 [0x00000001] -> GPIO: (CS for PCUE/CCM-EEPROM)
168 * -------------------------------------------- */
169 cp->cp_pbpar |= 0x0000000E; /* set bits */
170 cp->cp_pbpar &= ~0x00000001; /* reset bit */
172 /* ----------------------------------------------
173 * In/Out or per. Function 0/1
174 * PBDIR[28] = 1 [0x00000008] -> PERI1: SPIMISO
175 * PBDIR[29] = 1 [0x00000004] -> PERI1: SPIMOSI
176 * PBDIR[30] = 1 [0x00000002] -> PERI1: SPICLK
177 * PBDIR[31] = 1 [0x00000001] -> GPIO OUT: CS for PCUE/CCM-EEPROM
178 * ---------------------------------------------- */
179 cp->cp_pbdir |= 0x0000000F;
181 /* ----------------------------------------------
182 * open drain or active output
183 * PBODR[28] = 1 [0x00000008] -> open drain: SPIMISO
184 * PBODR[29] = 0 [0x00000004] -> active output SPIMOSI
185 * PBODR[30] = 0 [0x00000002] -> active output: SPICLK
186 * PBODR[31] = 0 [0x00000001] -> active output: GPIO OUT: CS for PCUE/CCM
187 * ---------------------------------------------- */
189 cp->cp_pbodr |= 0x00000008;
190 cp->cp_pbodr &= ~0x00000007;
192 /* Initialize the parameter ram.
193 * We need to make sure many things are initialized to zero
206 /* Allocate space for one transmit and one receive buffer
207 * descriptor in the DP ram
209 #ifdef CONFIG_SYS_ALLOC_DPRAM
210 dpaddr = dpram_alloc_align (sizeof(cbd_t)*2, 8);
212 dpaddr = CPM_SPI_BASE;
216 /* Set up the SPI parameters in the parameter ram */
217 spi->spi_rbase = dpaddr;
218 spi->spi_tbase = dpaddr + sizeof (cbd_t);
220 /***********IMPORTANT******************/
223 * Setting transmit and receive buffer descriptor pointers
224 * initially to rbase and tbase. Only the microcode patches
225 * documentation talks about initializing this pointer. This
226 * is missing from the sample I2C driver. If you dont
227 * initialize these pointers, the kernel hangs.
229 spi->spi_rbptr = spi->spi_rbase;
230 spi->spi_tbptr = spi->spi_tbase;
233 #ifdef CONFIG_SYS_SPI_UCODE_PATCH
235 * Initialize required parameters if using microcode patch.
240 /* Init SPI Tx + Rx Parameters */
241 while (cp->cp_cpcr & CPM_CR_FLG)
243 cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SPI, CPM_CR_INIT_TRX) | CPM_CR_FLG;
244 while (cp->cp_cpcr & CPM_CR_FLG)
246 #endif /* CONFIG_SYS_SPI_UCODE_PATCH */
249 /* Set SDMA configuration register */
250 immr->im_siu_conf.sc_sdcr = 0x0001;
253 /* Set to big endian. */
254 spi->spi_tfcr = SMC_EB;
255 spi->spi_rfcr = SMC_EB;
258 /* Set maximum receive size. */
259 spi->spi_mrblr = MAX_BUFFER;
262 /* tx and rx buffer descriptors */
263 tbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_tbase];
264 rbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_rbase];
266 tbdf->cbd_sc &= ~BD_SC_READY;
267 rbdf->cbd_sc &= ~BD_SC_EMPTY;
269 /* Set the bd's rx and tx buffer address pointers */
270 rbdf->cbd_bufaddr = (ulong) rxbuf;
271 tbdf->cbd_bufaddr = (ulong) txbuf;
274 cp->cp_spim = 0; /* Mask all SPI events */
275 cp->cp_spie = SPI_EMASK; /* Clear all SPI events */
280 /* **************************************************************************
282 * Function: spi_init_r
284 * Description: Init SPI-Controller (RAM part) -
285 * The malloc engine is ready and we can move our buffers to
290 * *********************************************************************** */
291 void spi_init_r (void)
293 volatile cpm8xx_t *cp;
295 volatile immap_t *immr;
296 volatile cbd_t *tbdf, *rbdf;
298 immr = (immap_t *) CONFIG_SYS_IMMR;
299 cp = (cpm8xx_t *) &immr->im_cpm;
301 #ifdef CONFIG_SYS_SPI_UCODE_PATCH
302 spi = (spi_t *)&cp->cp_dpmem[spi->spi_rpbase];
304 spi = (spi_t *)&cp->cp_dparam[PROFF_SPI];
305 /* Disable relocation */
309 /* tx and rx buffer descriptors */
310 tbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_tbase];
311 rbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_rbase];
313 /* Allocate memory for RX and TX buffers */
314 rxbuf = (uchar *) malloc (MAX_BUFFER);
315 txbuf = (uchar *) malloc (MAX_BUFFER);
317 rbdf->cbd_bufaddr = (ulong) rxbuf;
318 tbdf->cbd_bufaddr = (ulong) txbuf;
323 /****************************************************************************
324 * Function: spi_write
325 **************************************************************************** */
326 ssize_t spi_write (uchar *addr, int alen, uchar *buffer, int len)
330 memset(rxbuf, 0, MAX_BUFFER);
331 memset(txbuf, 0, MAX_BUFFER);
332 *txbuf = SPI_EEPROM_WREN; /* write enable */
334 memcpy(txbuf, addr, alen);
335 *txbuf = SPI_EEPROM_WRITE; /* WRITE memory array */
336 memcpy(alen + txbuf, buffer, len);
337 spi_xfer(alen + len);
338 /* ignore received data */
339 for (i = 0; i < 1000; i++) {
340 *txbuf = SPI_EEPROM_RDSR; /* read status */
343 if (!(rxbuf[1] & 1)) {
349 printf ("*** spi_write: Time out while writing!\n");
355 /****************************************************************************
357 **************************************************************************** */
358 ssize_t spi_read (uchar *addr, int alen, uchar *buffer, int len)
360 memset(rxbuf, 0, MAX_BUFFER);
361 memset(txbuf, 0, MAX_BUFFER);
362 memcpy(txbuf, addr, alen);
363 *txbuf = SPI_EEPROM_READ; /* READ memory array */
366 * There is a bug in 860T (?) that cuts the last byte of input
367 * if we're reading into DPRAM. The solution we choose here is
368 * to always read len+1 bytes (we have one extra byte at the
369 * end of the buffer).
371 spi_xfer(alen + len + 1);
372 memcpy(buffer, alen + rxbuf, len);
377 /****************************************************************************
379 **************************************************************************** */
380 ssize_t spi_xfer (size_t count)
382 volatile immap_t *immr;
383 volatile cpm8xx_t *cp;
389 DPRINT (("*** spi_xfer entered ***\n"));
391 immr = (immap_t *) CONFIG_SYS_IMMR;
392 cp = (cpm8xx_t *) &immr->im_cpm;
394 #ifdef CONFIG_SYS_SPI_UCODE_PATCH
395 spi = (spi_t *)&cp->cp_dpmem[spi->spi_rpbase];
397 spi = (spi_t *)&cp->cp_dparam[PROFF_SPI];
398 /* Disable relocation */
402 tbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_tbase];
403 rbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_rbase];
405 /* Set CS for device */
406 cp->cp_pbdat &= ~0x0001;
408 /* Setting tx bd status and data length */
409 tbdf->cbd_sc = BD_SC_READY | BD_SC_LAST | BD_SC_WRAP;
410 tbdf->cbd_datlen = count;
412 DPRINT (("*** spi_xfer: Bytes to be xferred: %d ***\n",
415 /* Setting rx bd status and data length */
416 rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP;
417 rbdf->cbd_datlen = 0; /* rx length has no significance */
419 loop = cp->cp_spmode & SPMODE_LOOP;
420 cp->cp_spmode = /*SPMODE_DIV16 |*/ /* BRG/16 mode not used here */
425 SPMODE_LEN(8) | /* 8 Bits per char */
426 SPMODE_PM(0x8) ; /* medium speed */
427 cp->cp_spim = 0; /* Mask all SPI events */
428 cp->cp_spie = SPI_EMASK; /* Clear all SPI events */
430 /* start spi transfer */
431 DPRINT (("*** spi_xfer: Performing transfer ...\n"));
432 cp->cp_spcom |= SPI_STR; /* Start transmit */
434 /* --------------------------------
435 * Wait for SPI transmit to get out
436 * or time out (1 second = 1000 ms)
437 * -------------------------------- */
438 for (tm=0; tm<1000; ++tm) {
439 if (cp->cp_spie & SPI_TXB) { /* Tx Buffer Empty */
440 DPRINT (("*** spi_xfer: Tx buffer empty\n"));
443 if ((tbdf->cbd_sc & BD_SC_READY) == 0) {
444 DPRINT (("*** spi_xfer: Tx BD done\n"));
450 printf ("*** spi_xfer: Time out while xferring to/from SPI!\n");
452 DPRINT (("*** spi_xfer: ... transfer ended\n"));
455 printf ("\nspi_xfer: txbuf after xfer\n");
456 memdump ((void *) txbuf, 16); /* dump of txbuf before transmit */
457 printf ("spi_xfer: rxbuf after xfer\n");
458 memdump ((void *) rxbuf, 16); /* dump of rxbuf after transmit */
462 /* Clear CS for device */
463 cp->cp_pbdat |= 0x0001;
467 #endif /* CONFIG_SPI || (CONFIG_POST & CONFIG_SYS_POST_SPI) */
472 * The Serial Peripheral Interface (SPI) is tested in the local loopback mode.
473 * The interface is configured accordingly and several packets
474 * are transfered. The configurable test parameters are:
475 * TEST_MIN_LENGTH - minimum size of packet to transfer
476 * TEST_MAX_LENGTH - maximum size of packet to transfer
477 * TEST_NUM - number of tests
480 #if CONFIG_POST & CONFIG_SYS_POST_SPI
482 #define TEST_MIN_LENGTH 1
483 #define TEST_MAX_LENGTH MAX_BUFFER
486 static void packet_fill (char * packet, int length)
488 char c = (char) length;
491 for (i = 0; i < length; i++)
497 static int packet_check (char * packet, int length)
499 char c = (char) length;
502 for (i = 0; i < length; i++) {
503 if (packet[i] != c++) return -1;
509 int spi_post_test (int flags)
512 volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
513 volatile cpm8xx_t *cp = (cpm8xx_t *) & immr->im_cpm;
520 cp->cp_spmode |= SPMODE_LOOP;
522 for (i = 0; i < TEST_NUM; i++) {
523 for (l = TEST_MIN_LENGTH; l <= TEST_MAX_LENGTH; l += 8) {
524 packet_fill ((char *)txbuf, l);
528 if (packet_check ((char *)rxbuf, l) < 0) {
538 cp->cp_spmode &= ~SPMODE_LOOP;
541 * SCC2 parameter RAM space overlaps
542 * the SPI parameter RAM space. So we need to restore
543 * the SCC2 configuration if it is used by UART.
546 #if !defined(CONFIG_8xx_CONS_NONE)
547 serial_reinit_all ();
551 post_log ("SPI test failed\n");
556 #endif /* CONFIG_POST & CONFIG_SYS_POST_SPI */