]> git.sur5r.net Git - u-boot/blob - drivers/spi/mpc8xx_spi.c
dm: core: Add a function to decode a memory region
[u-boot] / drivers / spi / mpc8xx_spi.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2001 Navin Boppuri / Prashant Patel
4  *      <nboppuri@trinetcommunication.com>,
5  *      <pmpatel@trinetcommunication.com>
6  * Copyright (c) 2001 Gerd Mennchen <Gerd.Mennchen@icn.siemens.de>
7  * Copyright (c) 2001 Wolfgang Denk, DENX Software Engineering, <wd@denx.de>.
8  */
9
10 /*
11  * MPC8xx CPM SPI interface.
12  *
13  * Parts of this code are probably not portable and/or specific to
14  * the board which I used for the tests. Please send fixes/complaints
15  * to wd@denx.de
16  *
17  */
18
19 #include <common.h>
20 #include <mpc8xx.h>
21 #include <asm/cpm_8xx.h>
22 #include <linux/ctype.h>
23 #include <malloc.h>
24 #include <post.h>
25 #include <serial.h>
26
27 #define SPI_EEPROM_WREN         0x06
28 #define SPI_EEPROM_RDSR         0x05
29 #define SPI_EEPROM_READ         0x03
30 #define SPI_EEPROM_WRITE        0x02
31
32 /* ---------------------------------------------------------------
33  * Offset for initial SPI buffers in DPRAM:
34  * We need a 520 byte scratch DPRAM area to use at an early stage.
35  * It is used between the two initialization calls (spi_init_f()
36  * and spi_init_r()).
37  * The value 0xb00 makes it far enough from the start of the data
38  * area (as well as from the stack pointer).
39  * --------------------------------------------------------------- */
40 #ifndef CONFIG_SYS_SPI_INIT_OFFSET
41 #define CONFIG_SYS_SPI_INIT_OFFSET      0xB00
42 #endif
43
44 #define CPM_SPI_BASE_RX CPM_SPI_BASE
45 #define CPM_SPI_BASE_TX (CPM_SPI_BASE + sizeof(cbd_t))
46
47 /* -------------------
48  * Function prototypes
49  * ------------------- */
50 ssize_t spi_xfer(size_t);
51
52 /* -------------------
53  * Variables
54  * ------------------- */
55
56 #define MAX_BUFFER      0x104
57
58 /* ----------------------------------------------------------------------
59  * Initially we place the RX and TX buffers at a fixed location in DPRAM!
60  * ---------------------------------------------------------------------- */
61 static uchar *rxbuf =
62         (uchar *)&((cpm8xx_t *)&((immap_t *)CONFIG_SYS_IMMR)->im_cpm)->cp_dpmem
63                         [CONFIG_SYS_SPI_INIT_OFFSET];
64 static uchar *txbuf =
65         (uchar *)&((cpm8xx_t *)&((immap_t *)CONFIG_SYS_IMMR)->im_cpm)->cp_dpmem
66                         [CONFIG_SYS_SPI_INIT_OFFSET+MAX_BUFFER];
67
68 /* **************************************************************************
69  *
70  *  Function:    spi_init_f
71  *
72  *  Description: Init SPI-Controller (ROM part)
73  *
74  *  return:      ---
75  *
76  * *********************************************************************** */
77 void spi_init_f(void)
78 {
79         immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR;
80         cpm8xx_t __iomem *cp = &immr->im_cpm;
81         spi_t __iomem *spi = (spi_t __iomem *)&cp->cp_dparam[PROFF_SPI];
82         cbd_t __iomem *tbdf, *rbdf;
83
84         /* Disable relocation */
85         out_be16(&spi->spi_rpbase, 0);
86
87 /* 1 */
88         /* ------------------------------------------------
89          * Initialize Port B SPI pins -> page 34-8 MPC860UM
90          * (we are only in Master Mode !)
91          * ------------------------------------------------ */
92
93         /* --------------------------------------------
94          * GPIO or per. Function
95          * PBPAR[28] = 1 [0x00000008] -> PERI: (SPIMISO)
96          * PBPAR[29] = 1 [0x00000004] -> PERI: (SPIMOSI)
97          * PBPAR[30] = 1 [0x00000002] -> PERI: (SPICLK)
98          * PBPAR[31] = 0 [0x00000001] -> GPIO: (CS for PCUE/CCM-EEPROM)
99          * -------------------------------------------- */
100         clrsetbits_be32(&cp->cp_pbpar, 0x00000001, 0x0000000E); /* set  bits */
101
102         /* ----------------------------------------------
103          * In/Out or per. Function 0/1
104          * PBDIR[28] = 1 [0x00000008] -> PERI1: SPIMISO
105          * PBDIR[29] = 1 [0x00000004] -> PERI1: SPIMOSI
106          * PBDIR[30] = 1 [0x00000002] -> PERI1: SPICLK
107          * PBDIR[31] = 1 [0x00000001] -> GPIO OUT: CS for PCUE/CCM-EEPROM
108          * ---------------------------------------------- */
109         setbits_be32(&cp->cp_pbdir, 0x0000000F);
110
111         /* ----------------------------------------------
112          * open drain or active output
113          * PBODR[28] = 1 [0x00000008] -> open drain: SPIMISO
114          * PBODR[29] = 0 [0x00000004] -> active output SPIMOSI
115          * PBODR[30] = 0 [0x00000002] -> active output: SPICLK
116          * PBODR[31] = 0 [0x00000001] -> active output GPIO OUT: CS for PCUE/CCM
117          * ---------------------------------------------- */
118
119         clrsetbits_be16(&cp->cp_pbodr, 0x00000007, 0x00000008);
120
121         /* Initialize the parameter ram.
122          * We need to make sure many things are initialized to zero
123          */
124         out_be32(&spi->spi_rstate, 0);
125         out_be32(&spi->spi_rdp, 0);
126         out_be16(&spi->spi_rbptr, 0);
127         out_be16(&spi->spi_rbc, 0);
128         out_be32(&spi->spi_rxtmp, 0);
129         out_be32(&spi->spi_tstate, 0);
130         out_be32(&spi->spi_tdp, 0);
131         out_be16(&spi->spi_tbptr, 0);
132         out_be16(&spi->spi_tbc, 0);
133         out_be32(&spi->spi_txtmp, 0);
134
135 /* 3 */
136         /* Set up the SPI parameters in the parameter ram */
137         out_be16(&spi->spi_rbase, CPM_SPI_BASE_RX);
138         out_be16(&spi->spi_tbase, CPM_SPI_BASE_TX);
139
140         /***********IMPORTANT******************/
141
142         /*
143          * Setting transmit and receive buffer descriptor pointers
144          * initially to rbase and tbase. Only the microcode patches
145          * documentation talks about initializing this pointer. This
146          * is missing from the sample I2C driver. If you dont
147          * initialize these pointers, the kernel hangs.
148          */
149         out_be16(&spi->spi_rbptr, CPM_SPI_BASE_RX);
150         out_be16(&spi->spi_tbptr, CPM_SPI_BASE_TX);
151
152 /* 4 */
153         /* Init SPI Tx + Rx Parameters */
154         while (in_be16(&cp->cp_cpcr) & CPM_CR_FLG)
155                 ;
156
157         out_be16(&cp->cp_cpcr, mk_cr_cmd(CPM_CR_CH_SPI, CPM_CR_INIT_TRX) |
158                                CPM_CR_FLG);
159         while (in_be16(&cp->cp_cpcr) & CPM_CR_FLG)
160                 ;
161
162 /* 5 */
163         /* Set SDMA configuration register */
164         out_be32(&immr->im_siu_conf.sc_sdcr, 0x0001);
165
166 /* 6 */
167         /* Set to big endian. */
168         out_8(&spi->spi_tfcr, SMC_EB);
169         out_8(&spi->spi_rfcr, SMC_EB);
170
171 /* 7 */
172         /* Set maximum receive size. */
173         out_be16(&spi->spi_mrblr, MAX_BUFFER);
174
175 /* 8 + 9 */
176         /* tx and rx buffer descriptors */
177         tbdf = (cbd_t __iomem *)&cp->cp_dpmem[CPM_SPI_BASE_TX];
178         rbdf = (cbd_t __iomem *)&cp->cp_dpmem[CPM_SPI_BASE_RX];
179
180         clrbits_be16(&tbdf->cbd_sc, BD_SC_READY);
181         clrbits_be16(&rbdf->cbd_sc, BD_SC_EMPTY);
182
183         /* Set the bd's rx and tx buffer address pointers */
184         out_be32(&rbdf->cbd_bufaddr, (ulong)rxbuf);
185         out_be32(&tbdf->cbd_bufaddr, (ulong)txbuf);
186
187 /* 10 + 11 */
188         out_8(&cp->cp_spim, 0);                 /* Mask  all SPI events */
189         out_8(&cp->cp_spie, SPI_EMASK);         /* Clear all SPI events */
190
191         return;
192 }
193
194 /* **************************************************************************
195  *
196  *  Function:    spi_init_r
197  *
198  *  Description: Init SPI-Controller (RAM part) -
199  *               The malloc engine is ready and we can move our buffers to
200  *               normal RAM
201  *
202  *  return:      ---
203  *
204  * *********************************************************************** */
205 void spi_init_r(void)
206 {
207         immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR;
208         cpm8xx_t __iomem *cp = &immr->im_cpm;
209         spi_t __iomem *spi = (spi_t __iomem *)&cp->cp_dparam[PROFF_SPI];
210         cbd_t __iomem *tbdf, *rbdf;
211
212         /* Disable relocation */
213         out_be16(&spi->spi_rpbase, 0);
214
215         /* tx and rx buffer descriptors */
216         tbdf = (cbd_t __iomem *)&cp->cp_dpmem[CPM_SPI_BASE_TX];
217         rbdf = (cbd_t __iomem *)&cp->cp_dpmem[CPM_SPI_BASE_RX];
218
219         /* Allocate memory for RX and TX buffers */
220         rxbuf = (uchar *)malloc(MAX_BUFFER);
221         txbuf = (uchar *)malloc(MAX_BUFFER);
222
223         out_be32(&rbdf->cbd_bufaddr, (ulong)rxbuf);
224         out_be32(&tbdf->cbd_bufaddr, (ulong)txbuf);
225
226         return;
227 }
228
229 /****************************************************************************
230  *  Function:    spi_write
231  **************************************************************************** */
232 ssize_t spi_write(uchar *addr, int alen, uchar *buffer, int len)
233 {
234         int i;
235
236         memset(rxbuf, 0, MAX_BUFFER);
237         memset(txbuf, 0, MAX_BUFFER);
238         *txbuf = SPI_EEPROM_WREN;               /* write enable         */
239         spi_xfer(1);
240         memcpy(txbuf, addr, alen);
241         *txbuf = SPI_EEPROM_WRITE;              /* WRITE memory array   */
242         memcpy(alen + txbuf, buffer, len);
243         spi_xfer(alen + len);
244                                                 /* ignore received data */
245         for (i = 0; i < 1000; i++) {
246                 *txbuf = SPI_EEPROM_RDSR;       /* read status          */
247                 txbuf[1] = 0;
248                 spi_xfer(2);
249                 if (!(rxbuf[1] & 1))
250                         break;
251                 udelay(1000);
252         }
253         if (i >= 1000)
254                 printf("*** spi_write: Time out while writing!\n");
255
256         return len;
257 }
258
259 /****************************************************************************
260  *  Function:    spi_read
261  **************************************************************************** */
262 ssize_t spi_read(uchar *addr, int alen, uchar *buffer, int len)
263 {
264         memset(rxbuf, 0, MAX_BUFFER);
265         memset(txbuf, 0, MAX_BUFFER);
266         memcpy(txbuf, addr, alen);
267         *txbuf = SPI_EEPROM_READ;               /* READ memory array    */
268
269         /*
270          * There is a bug in 860T (?) that cuts the last byte of input
271          * if we're reading into DPRAM. The solution we choose here is
272          * to always read len+1 bytes (we have one extra byte at the
273          * end of the buffer).
274          */
275         spi_xfer(alen + len + 1);
276         memcpy(buffer, alen + rxbuf, len);
277
278         return len;
279 }
280
281 /****************************************************************************
282  *  Function:    spi_xfer
283  **************************************************************************** */
284 ssize_t spi_xfer(size_t count)
285 {
286         immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR;
287         cpm8xx_t __iomem *cp = &immr->im_cpm;
288         spi_t __iomem *spi = (spi_t __iomem *)&cp->cp_dparam[PROFF_SPI];
289         cbd_t __iomem *tbdf, *rbdf;
290         int tm;
291
292         /* Disable relocation */
293         out_be16(&spi->spi_rpbase, 0);
294
295         tbdf = (cbd_t __iomem *)&cp->cp_dpmem[CPM_SPI_BASE_TX];
296         rbdf = (cbd_t __iomem *)&cp->cp_dpmem[CPM_SPI_BASE_RX];
297
298         /* Set CS for device */
299         clrbits_be32(&cp->cp_pbdat, 0x0001);
300
301         /* Setting tx bd status and data length */
302         out_be16(&tbdf->cbd_sc, BD_SC_READY | BD_SC_LAST | BD_SC_WRAP);
303         out_be16(&tbdf->cbd_datlen, count);
304
305         /* Setting rx bd status and data length */
306         out_be16(&rbdf->cbd_sc, BD_SC_EMPTY | BD_SC_WRAP);
307         out_be16(&rbdf->cbd_datlen, 0);  /* rx length has no significance */
308
309         clrsetbits_be16(&cp->cp_spmode, ~SPMODE_LOOP, SPMODE_REV | SPMODE_MSTR |
310                         SPMODE_EN | SPMODE_LEN(8) | SPMODE_PM(0x8));
311         out_8(&cp->cp_spim, 0);         /* Mask  all SPI events */
312         out_8(&cp->cp_spie, SPI_EMASK); /* Clear all SPI events */
313
314         /* start spi transfer */
315         setbits_8(&cp->cp_spcom, SPI_STR);              /* Start transmit */
316
317         /* --------------------------------
318          * Wait for SPI transmit to get out
319          * or time out (1 second = 1000 ms)
320          * -------------------------------- */
321         for (tm = 0; tm < 1000; ++tm) {
322                 if (in_8(&cp->cp_spie) & SPI_TXB)       /* Tx Buffer Empty */
323                         break;
324                 if ((in_be16(&tbdf->cbd_sc) & BD_SC_READY) == 0)
325                         break;
326                 udelay(1000);
327         }
328         if (tm >= 1000)
329                 printf("*** spi_xfer: Time out while xferring to/from SPI!\n");
330
331         /* Clear CS for device */
332         setbits_be32(&cp->cp_pbdat, 0x0001);
333
334         return count;
335 }