]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/devs/spi/arm/mxc/v2_0/src/mxc_spi.c
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / devs / spi / arm / mxc / v2_0 / src / mxc_spi.c
1 //==========================================================================
2 //
3 //      mxc_spi.c
4 //
5 //      SPI support on Freescale MXC platforms
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //==========================================================================
41 //#####DESCRIPTIONBEGIN####
42 //
43 // Author(s):    Kevin Zhang <k.zhang@freescale.com>
44 // Contributors:
45 // Date:         2006-08-24
46 // Purpose:
47 // Description:
48 //
49 //####DESCRIPTIONEND####
50 //
51 //==========================================================================
52
53 #include <redboot.h>
54 #include <stdlib.h>
55 #include <pkgconf/hal.h>
56 #include <cyg/hal/hal_arch.h>
57 #include <cyg/hal/hal_cache.h>
58 #include <cyg/hal/hal_io.h>
59
60 #include <cyg/hal/fsl_board.h>
61 #include <cyg/io/mxc_spi.h>
62
63 void clock_spi_enable(unsigned int spi_clk);
64
65 #undef MXC_SPI_DEBUG
66 //#define MXC_SPI_DEBUG
67
68 #ifdef MXC_SPI_DEBUG
69 #define diag_printf1    diag_printf
70 #else
71 #define diag_printf1(fmt,args...)
72 #endif
73
74 #if defined(MXC_SPI_VER_0_7) || defined(MXC_SPI_VER_0_4)
75 const unsigned int baud_rate_div[] = {
76     4, 8, 16, 32, 64, 128, 256, 512,
77 };
78 static int version = 1;
79 #elif defined(MXC_SPI_VER_XX)
80 const unsigned int baud_rate_div[] = {
81     3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512,
82 };
83 static int version = 2;
84 #elif defined(MXC_SPI_VER_2_3)
85 const unsigned int baud_rate_div[] = {
86     1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
87 };
88 static int version = 3;
89 #else
90 #error No SPI version defined
91 #endif
92
93 const int BAUD_RATE_DIV_MAX = sizeof(baud_rate_div) / sizeof(unsigned int);
94
95 /*!
96  * Initialize and enable a spi module
97  *
98  * @param   base        base address of spi module (also assigned for SPIx_CLK)
99  * @param   baue        the desired data rate
100  * @param   ctrl_val    control register value EXCEPT the data rate
101  *
102  * @return              0 if successful; non-zero otherwise
103  */
104 int spi_init(unsigned int base, unsigned int baud, unsigned int ctrl_val)
105 {
106     unsigned int clock = get_peri_clock(base);
107     int i, div = clock / baud;
108
109     clock_spi_enable(base);
110
111     diag_printf1("base=0x%x, baue=%d, ctrl_val=0x%x, div=%d, clock=%d\n",
112                 base, baud, ctrl_val, div, clock);
113
114     for (i = 0; i < BAUD_RATE_DIV_MAX; i++) {
115         if (div <= baud_rate_div[i]) {
116             break;
117         }
118     }
119     if (i == BAUD_RATE_DIV_MAX) {
120         diag_printf("Baud rate requested (%d) is too slow for spi(0x%x)\n",
121                     baud, base);
122         return -1;
123     }
124
125     // to adjust for differen spi versions
126     if (version == 2) {
127         ctrl_val |= ((i + 1) << SPI_CTRL_REG_RATE_SH);
128     } else
129         ctrl_val |= (i << SPI_CTRL_REG_RATE_SH);
130
131
132     diag_printf1("ctrl_val=0x%x, i=%d, SPI_CTRL_REG_RATE_SH=%d\n",
133                 ctrl_val, i, SPI_CTRL_REG_RATE_SH);
134
135     /* Reinitialize the control register */
136     writel(0, base + SPI_CTRL_REG_OFF);
137     writel(SPI_CTRL_EN, base + SPI_CTRL_REG_OFF);
138
139     writel(ctrl_val, base + SPI_CTRL_REG_OFF);
140
141     writel(0, base + SPI_INT_CTRL_REG_OFF);
142     diag_printf1("requested data rate is: %d, actual rate is: %d\n",
143                  baud, clock / baud_rate_div[i]);
144
145     return 0;
146 }
147
148 #ifdef PMIC_SPI_BASE
149 /*!
150  * It is for the master mode operation to exchange a single word with
151  * external device.
152  *
153  * @param   data        data to be transferred
154  * @param   base        base address of the spi module
155  *
156  * @return              the value received from the Rx register
157  */
158 unsigned int spi_xchg_single(unsigned int data, unsigned int base)
159 {
160     volatile unsigned int cfg_reg = readl(base + SPI_CTRL_REG_OFF);
161
162 #if defined(MXC_SPI_VER_2_3)
163     int ss_num = (PMIC_SPI_CHIP_SELECT_NO >> 18) & 0x3;
164     volatile unsigned int pol_reg = readl(base + SPI_CONFIG_REG_OFF);
165     pol_reg &= ~(1 << (12 + ss_num));
166     /* Activate the SS signal */
167     pol_reg |= PMIC_SPI_SS_POL;
168     writel(pol_reg, base + SPI_CONFIG_REG_OFF);
169 #endif
170
171     hal_delay_us(100);
172
173     writel(data, base + SPI_TX_REG_OFF);
174
175     cfg_reg |= SPI_CTRL_REG_XCH_BIT;
176
177     writel(cfg_reg, base + SPI_CTRL_REG_OFF);
178
179     while ((readl(base + SPI_INT_STAT_REG_OFF) & SPI_INT_STAT_RR) == 0) {
180     }
181
182 #if defined(MXC_SPI_VER_2_3)
183     pol_reg &= ~(1 << (12 + ss_num));
184     pol_reg |= (~PMIC_SPI_SS_POL) & (1 << (12 + ss_num));
185     /* Deactivate the SS signal */
186     writel(PMIC_SPI_SS_POL, base + SPI_CONFIG_REG_OFF);
187 #endif
188
189     return readl(base + SPI_RX_REG_OFF);
190 }
191
192 static void mxc_pmic_init(void)
193 {
194     volatile unsigned int rev_id;
195     unsigned int ctrl;
196
197 #if defined(MXC_SPI_VER_2_3)
198     ctrl = SPI_CTRL_REG_BIT_COUNT32 | SPI_CTRL_MODE_MASTER_0 | SPI_CTRL_EN;
199 #else
200     ctrl = SPI_CTRL_REG_BIT_COUNT32 | SPI_CTRL_SSPOL_HIGH |
201            SPI_CTRL_MODE_MASTER | SPI_CTRL_EN;
202 #endif
203     /* Activate the SS signal */
204     ctrl |= PMIC_SPI_CHIP_SELECT_NO;
205     spi_init(PMIC_SPI_BASE, 6000000,      // 4MHz data rate
206              ctrl);
207
208     rev_id = pmic_reg(7, 0, 0);
209     diag_printf("PMIC ID: 0x%08x [Rev: ", rev_id);
210     switch (rev_id & 0x1F) {
211     case 0x1:
212         diag_printf("1.0");
213         break;
214     case 0x9:
215         diag_printf("1.1");
216         break;
217     case 0xA:
218         diag_printf("1.2");
219         break;
220     case 0x10:
221         diag_printf("2.0");
222         break;
223     case 0x11:
224         diag_printf("2.1");
225         break;
226     case 0x18:
227         diag_printf("3.0");
228         break;
229     case 0x19:
230         diag_printf("3.1");
231         break;
232     case 0x1A:
233         diag_printf("3.2");
234         break;
235     case 0x2:
236         diag_printf("3.2A");
237         break;
238     case 0x1B:
239         diag_printf("3.3");
240         break;
241     case 0x1D:
242         diag_printf("3.5");
243         break;
244     default:
245         diag_printf("unknown");
246         break;
247     }
248     diag_printf("]\n");
249 }
250
251 RedBoot_init(mxc_pmic_init, RedBoot_INIT_PRIO(100));
252
253 static void do_pmic(int argc, char *argv[]);
254 RedBoot_cmd("pmic",
255             "Read/Write internal PMIC register",
256             "<reg num> [value to be written]",
257             do_pmic
258            );
259
260 static void do_pmic(int argc,char *argv[])
261 {
262     unsigned int reg, temp, val = 0, write = 0;
263
264     if (argc == 1) {
265         diag_printf("\tRead:  pmic <reg num>\n");
266         diag_printf("\tWrite: pmic <reg num> <value to be written>\n");
267         return;
268     }
269
270     if (!parse_num(*(&argv[1]), (unsigned long *)&reg, &argv[1], ":")) {
271         diag_printf("Error: Invalid parameter\n");
272         return;
273     }
274
275     if (argc == 3) {
276         if (!parse_num(*(&argv[2]), (unsigned long *)&val, &argv[2], ":")) {
277             diag_printf("Error: Invalid parameter\n");
278             return;
279         }
280         write = 1;
281     }
282
283     temp = pmic_reg(reg, val, write);
284
285     diag_printf("\tval: 0x%08x\n\n", temp);
286 }
287
288 /*!
289  * To read/write to a PMIC register. For write, it does another read for the
290  * actual register value.
291  *
292  * @param   reg         register number inside the PMIC
293  * @param   val         data to be written to the register; don't care for read
294  * @param   write       0 for read; 1 for write
295  *
296  * @return              the actual data in the PMIC register
297  */
298 unsigned int pmic_reg(unsigned int reg, unsigned int val, unsigned int write)
299 {
300     unsigned int temp;
301
302     if (reg > 63 || write > 1 ) {
303         diag_printf("<reg num> = %d is invalide. Should be less then 63\n", reg);
304         return 0;
305     }
306     val = (write << 31) | (reg << 25) | (val & 0x00FFFFFF);
307     diag_printf1("reg=0x%x, val=0x%08x\n", reg, val);
308
309     temp = spi_xchg_single(val, PMIC_SPI_BASE);
310
311     if (write) {
312         val &= ~(1 << 31);
313         temp = spi_xchg_single(val, PMIC_SPI_BASE);
314     }
315
316     return temp;
317 }
318 #endif // PMIC_SPI_BASE
319
320 #ifdef CPLD_SPI_BASE
321
322 unsigned int spi_cpld_xchg_single(unsigned int data, unsigned int data1, unsigned int base)
323 {
324     volatile unsigned int cfg_reg = readl(base + SPI_CTRL_REG_OFF);
325     unsigned int temp;
326
327     /* Activate the SS signal */
328     cfg_reg |= CPLD_SPI_CHIP_SELECT_NO;
329     writel(cfg_reg, CPLD_SPI_BASE + SPI_CTRL_REG_OFF);
330
331     /* Write the data */
332     writel(data, base + SPI_TX_REG_OFF);
333     writel(data1, base + SPI_TX_REG_OFF);
334
335     cfg_reg |= SPI_CTRL_REG_XCH_BIT;
336     writel(cfg_reg, base + SPI_CTRL_REG_OFF);
337
338     while ((((cfg_reg = readl(base + SPI_TEST_REG_OFF)) &
339               SPI_TEST_REG_RXCNT_MASK) >> SPI_TEST_REG_RXCNT_OFFSET) != 2) {
340     }
341
342     /* Deactivate the SS signal */
343     cfg_reg = readl(base + SPI_CTRL_REG_OFF);
344     cfg_reg &= ~SPI_CTRL_CS_MASK;
345     writel(cfg_reg, base + SPI_CTRL_REG_OFF);
346
347     /* Read from RX FIFO, second entry contains the data */
348     temp = readl(base + SPI_RX_REG_OFF);
349     temp = readl(base + SPI_RX_REG_OFF);
350     return ((temp >> 6) & 0xffff);
351 }
352
353 static void mxc_cpld_spi_init(void)
354 {
355     unsigned int ctrl;
356
357     ctrl = SPI_CTRL_REG_BIT_COUNT46 | CPLD_SPI_CTRL_MODE_MASTER | SPI_CTRL_EN;
358
359     spi_init(CPLD_SPI_BASE, 18000000,      // 54MHz data rate
360              ctrl);
361 }
362
363 RedBoot_init(mxc_cpld_spi_init, RedBoot_INIT_PRIO(102));
364
365 static void do_cpld(int argc, char *argv[]);
366
367 RedBoot_cmd("spi_cpld",
368             "Read/Write 16-bit internal CPLD register over CSPI",
369             "<reg num> [16-bit value to be written]",
370             do_cpld
371            );
372
373 static void do_cpld(int argc,char *argv[])
374 {
375     unsigned int reg, temp, val = 0, read = 1;
376
377     if (argc == 1) {
378         diag_printf("\tRead:  spi_cpld <reg num>\n");
379         diag_printf("\tWrite: spi_cpld <reg num> <value to be written>\n");
380         return;
381     }
382
383     if (!parse_num(*(&argv[1]), (unsigned long *)&reg, &argv[1], ":")) {
384         diag_printf("Error: Invalid parameter\n");
385         return;
386     }
387
388     if (argc == 3) {
389         if (!parse_num(*(&argv[2]), (unsigned long *)&val, &argv[2], ":")) {
390             diag_printf("Error: Invalid parameter\n");
391             return;
392         }
393         read = 0;
394     }
395
396     temp = cpld_reg(reg, val, read);
397
398     diag_printf("\tval: 0x%04x\n\n", temp);
399 }
400
401 /*!
402  * To read/write to a CPLD register.
403  *
404  * @param   reg         register number inside the CPLD
405  * @param   val         data to be written to the register; don't care for read
406  * @param   read        0 for write; 1 for read
407  *
408  * @return              the actual data in the CPLD register
409  */
410 unsigned int cpld_reg_xfer(unsigned int reg, unsigned int val, unsigned int read)
411 {
412     unsigned int local_val1, local_val2;
413
414     reg >>= 1;
415
416     local_val1 = (read << 13) | ((reg & 0x0001FFFF) >> 5) | 0x00001000;
417     if (read) {
418         //local_val1 = (read << 22) | (reg << 4) | 0x00200004;
419         //local_val2 = 0x1F;
420         local_val2 = ( ((reg & 0x0000001F) << 27) | 0x0200001f);
421
422     } else {
423         //local_val1 = (read << 22) | (reg << 4) | 0x00200007;
424         //local_val2 = ((val & 0xFFFF) << 6) | 0x00400027;
425         local_val2 = ( ((reg & 0x0000001F) << 27) | ((val & 0x0000FFFF) << 6) | 0x03C00027);
426
427     }
428
429     diag_printf1("reg=0x%x, val=0x%08x\n", reg, val);
430     return spi_cpld_xchg_single(local_val1, local_val2, CPLD_SPI_BASE);
431 }
432
433 /*!
434  * To read/write to a CPLD register. For write, it does another read for the
435  * actual register value.
436  *
437  * @param   reg         register number inside the CPLD
438  * @param   val         data to be written to the register; don't care for read
439  * @param   read        0 for write; 1 for read
440  *
441  * @return              the actual data in the CPLD register
442  */
443 unsigned int cpld_reg(unsigned int reg, unsigned int val, unsigned int read)
444 {
445     unsigned int temp;
446
447     if (reg > 0x20068 || read > 1 ) {
448         diag_printf("<reg num> = %x is invalid. Should be less then 0x20068\n", reg);
449         return 0;
450     }
451
452     temp = cpld_reg_xfer(reg, val, read);
453     diag_printf1("reg=0x%x, val=0x%08x\n", reg, val);
454
455     if (read == 0) {
456         temp = cpld_reg_xfer(reg, val, 1);
457     }
458
459     return temp;
460 }
461
462 #endif // CPLD_SPI_BASE