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