source: trunk/boot/tsar_mips32/boot_spi_utils.c @ 582

Last change on this file since 582 was 547, checked in by nicolas.van.phan@…, 6 years ago

Implement bootloader SPI SD card driver (VERY SLOW)

Rectify boot_spi_driver frequency

File size: 8.7 KB
Line 
1///////////////////////////////////////////////////////////////////////////////////
2// File     : spi_driver.c
3// Date     : 31/08/2012
4// Author   : cesar fuguet
5// Copyright (c) UPMC-LIP6
6///////////////////////////////////////////////////////////////////////////////////
7
8#include <boot_spi_utils.h>
9#include <boot_utils.h>
10///////////////////////////////////////////////////////////////////////////////
11//      bswap32()
12// This function makes a byte swap for a 4 bytes word
13// Arguments are:
14// - x : word
15// Returns the word x swapped
16///////////////////////////////////////////////////////////////////////////////
17static unsigned int bswap32(unsigned int x)
18{
19  unsigned int y;
20  y =  (x & 0x000000ff) << 24;
21  y |= (x & 0x0000ff00) <<  8;
22  y |= (x & 0x00ff0000) >>  8;
23  y |= (x & 0xff000000) >> 24;
24  return y;
25}
26
27///////////////////////////////////////////////////////////////////////////////
28//      _spi_wait_if_busy()
29// This function returns when the SPI controller has finished a transfer
30// Arguments are:
31// - spi : initialized pointer to the SPI controller
32///////////////////////////////////////////////////////////////////////////////
33static void _spi_wait_if_busy(struct boot_spi_dev * spi)
34{
35    register int delay;
36    volatile resp;
37
38    while(resp = SPI_IS_BUSY(spi))
39    {
40        for (delay = 0; delay < 100; delay++);
41    }
42}
43
44///////////////////////////////////////////////////////////////////////////////
45//      _spi_init_transfer()
46// This function trigger transfer of the tx registers to the selected slaves
47// Arguments are:
48// - spi : initialized pointer to the SPI controller
49///////////////////////////////////////////////////////////////////////////////
50static void _spi_init_transfer(struct boot_spi_dev * spi)
51{
52    unsigned int spi_ctrl = ioread32(&spi->ctrl);
53
54    iowrite32(&spi->ctrl, spi_ctrl | SPI_CTRL_GO_BSY);
55}
56
57///////////////////////////////////////////////////////////////////////////////
58//      _spi_calc_divider_value()
59// This function computes the value for the divider register in order to obtain
60// the SPI desired clock frequency
61// - spi_freq : desired frequency for the generated clock from the SPI
62//              controller
63// - sys_freq : system clock frequency
64// Returns the computed frequency
65///////////////////////////////////////////////////////////////////////////////
66static unsigned int _spi_calc_divider_value( unsigned int spi_freq ,
67                                             unsigned int sys_freq )
68{
69    return ((sys_freq / (spi_freq * 2)) - 1);
70}
71
72///////////////////////////////////////////////////////////////////////////////
73//      spi_put_tx()
74// This function writes a byte on the tx register and trigger transfert
75// - spi  : initialized pointer to the SPI controller
76// - byte : byte to write on tx register
77// - index: index of the tx register
78///////////////////////////////////////////////////////////////////////////////
79void spi_put_tx(struct boot_spi_dev * spi, unsigned char byte, int index)
80{
81    _spi_wait_if_busy(spi);
82    {
83        iowrite8(&spi->rx_tx[index % 4], byte);
84        _spi_init_transfer(spi);
85    }
86    _spi_wait_if_busy(spi);
87}
88
89///////////////////////////////////////////////////////////////////////////////
90//      spi_get_rx()
91// This function reads a byte on the rx register
92// - spi  : initialized pointer to the SPI controller
93// - index: index of the rx register
94// Returns the byte read
95///////////////////////////////////////////////////////////////////////////////
96volatile unsigned char spi_get_rx(struct boot_spi_dev * spi, int index)
97{
98    return ioread8(&spi->rx_tx[index % 4]);
99}
100
101///////////////////////////////////////////////////////////////////////////////
102//      spi_get_data()
103// This function reads count bytes and store them on a memory buffer
104// - spi   : initialized pointer to the SPI controller
105// - buffer: physical address of the buffer containing the read data
106// - count : number of bytes to get (must be 512 bytes)
107// Returns 0 if success and other value when failure
108///////////////////////////////////////////////////////////////////////////////
109unsigned int spi_get_data( struct boot_spi_dev * spi,
110                           paddr_t buffer      ,
111                           unsigned int count  )
112{
113    unsigned int spi_ctrl0; // ctrl value before calling this function
114    unsigned int spi_ctrl;
115    int i;
116
117    /*
118     * Only reading of one block (512 bytes) are supported
119     */
120    if ( count != 512 ) return 1;
121
122    _spi_wait_if_busy(spi);
123
124    spi_ctrl0 = ioread32(&spi->ctrl);
125
126#if 0
127    /*
128     * Read data using SPI DMA mechanism
129     * Two restrictions:
130     *   1. Can transfer only one block (512 bytes).
131     *   2. The destination buffer must be aligned to SPI burst size (64 bytes)
132     */
133    if ((buffer & 0x3f) == 0)
134    {
135        _puts("spi_get_data(): Starting DMA transfer / count = ");
136        _putx(count);
137        _puts("\n");
138
139        _puts("spi_get_data(): buffer = ");
140        _putx(buffer);
141        _puts("\n");
142
143        spi->dma_base  = (buffer      ) & ((1 << 32) - 1); // 32 lsb
144        spi->dma_baseh = (buffer >> 32) & ((1 << 8 ) - 1); // 8  msb
145        spi->dma_count = count | SPI_DMA_COUNT_READ;
146
147        while ( (spi->dma_count >> 1) );
148
149        goto reset_ctrl;
150    }
151#endif
152
153    /*
154     * Read data without SPI DMA mechanism
155     *
156     * Switch to 128 bits words
157     */
158
159    spi_ctrl = (spi_ctrl0 & ~SPI_CTRL_CHAR_LEN_MASK) | 128;
160    iowrite32(&spi->ctrl, spi_ctrl);
161
162    /*
163     * Read data.
164     * Four 32 bits words at each iteration (128 bits = 16 bytes)
165     */
166    for (i = 0; i < count/16; i++)
167    {
168        iowrite32(&spi->rx_tx[0], 0xffffffff);
169        iowrite32(&spi->rx_tx[1], 0xffffffff);
170        iowrite32(&spi->rx_tx[2], 0xffffffff);
171        iowrite32(&spi->rx_tx[3], 0xffffffff);
172        iowrite32(&spi->ctrl,  spi_ctrl | SPI_CTRL_GO_BSY);
173
174        _spi_wait_if_busy(spi);
175
176        boot_remote_sw( buffer, bswap32(ioread32(&spi->rx_tx[3])) ); 
177        buffer += 4;
178        boot_remote_sw( buffer, bswap32(ioread32(&spi->rx_tx[2])) ); 
179        buffer += 4;
180        boot_remote_sw( buffer, bswap32(ioread32(&spi->rx_tx[1])) ); 
181        buffer += 4;
182        boot_remote_sw( buffer, bswap32(ioread32(&spi->rx_tx[0])) ); 
183        buffer += 4;
184    }
185
186#if 0
187reset_ctrl:
188#endif
189
190    /* Switch back to original word size */
191    iowrite32(&spi->ctrl, spi_ctrl0);
192
193    return 0;
194}
195
196///////////////////////////////////////////////////////////////////////////////
197//      spi_ss_assert()
198// This function enables a SPI slave
199// - spi   : initialized pointer to the SPI controller
200// - index : slave index
201///////////////////////////////////////////////////////////////////////////////
202void spi_ss_assert(struct boot_spi_dev * spi, int index)
203{
204    unsigned int spi_ss = ioread32(&spi->ss);
205
206    iowrite32(&spi->ss, spi_ss | (1 << index));
207}
208
209///////////////////////////////////////////////////////////////////////////////
210//      spi_ss_deassert()
211// This function disables a SPI slave
212// - spi   : initialized pointer to the SPI controller
213// - index : slave index
214///////////////////////////////////////////////////////////////////////////////
215void spi_ss_deassert(struct boot_spi_dev * spi, int index)
216{
217    unsigned int spi_ss = ioread32(&spi->ss);
218
219    iowrite32(&spi->ss, spi_ss & ~(1 << index));
220}
221
222///////////////////////////////////////////////////////////////////////////////
223//      _spi_init()
224// This function initializes the configuration register of SPI controller
225// - spi      : initialized pointer to the SPI controller
226// - spi_freq : SPI desired frequency (Hz)
227// - sys_freq : system frequency (Hz)
228// - char_len : bits per transfer
229// - tx_edge  : if 1, transfer on positive edge
230// - rx_edge  : if 1, latch received data on negative edge
231///////////////////////////////////////////////////////////////////////////////
232void _spi_init ( struct boot_spi_dev * spi,
233                 int spi_freq        ,
234                 int sys_freq        ,
235                 int char_len        ,
236                 int tx_edge         ,
237                 int rx_edge         )
238{
239    unsigned int spi_ctrl = ioread32(&spi->ctrl);
240
241    if      ( tx_edge == 0 ) spi_ctrl |=  SPI_CTRL_TXN_EN;
242    else if ( tx_edge == 1 ) spi_ctrl &= ~SPI_CTRL_TXN_EN;
243    if      ( rx_edge == 0 ) spi_ctrl |=  SPI_CTRL_RXN_EN;
244    else if ( rx_edge == 1 ) spi_ctrl &= ~SPI_CTRL_RXN_EN;
245    if      ( char_len > 0 ) spi_ctrl  = (spi_ctrl & ~SPI_CTRL_CHAR_LEN_MASK) |
246                                         (char_len &  SPI_CTRL_CHAR_LEN_MASK);
247
248    iowrite32(&spi->ctrl, spi_ctrl);
249
250    if (spi_freq > 0 && sys_freq > 0)
251        iowrite32(&spi->divider, _spi_calc_divider_value(spi_freq, sys_freq));
252}
253
254
255// Local Variables:
256// tab-width: 4
257// c-basic-offset: 4
258// c-file-offsets:((innamespace . 0)(inline-open . 0))
259// indent-tabs-mode: nil
260// End:
261// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
Note: See TracBrowser for help on using the repository browser.