source: trunk/softs/tsar_boot/src/spi.c @ 406

Last change on this file since 406 was 398, checked in by bouyer, 11 years ago

Use 128bits transfers at the SPI controller level when possible;
this speeds up the boot

File size: 4.2 KB
Line 
1/**
2 * \file    spi.c
3 * \date    31 August 2012
4 * \author  Cesar Fuguet <cesar.fuguet-tortolero@lip6.fr>
5 */
6#include <spi.h>
7
8/**
9 * \param   x: input value
10 *
11 * \return  byte-swapped value
12 *
13 * \brief   byte-swap a 32bit word
14 */
15static unsigned int bswap32(unsigned int x)
16{
17  unsigned int y;
18  y =  (x & 0x000000ff) << 24;
19  y |= (x & 0x0000ff00) <<  8;
20  y |= (x & 0x00ff0000) >>  8;
21  y |= (x & 0xff000000) >> 24;
22  return y;
23}
24
25/**
26 * \param   spi :   Initialized pointer to the SPI controller
27 *
28 * \brief   Wait until the SPI controller has finished a transfer
29 *
30 * Wait until the GO_BUSY bit of the SPI controller be deasserted
31 */
32static void _spi_wait_if_busy(struct spi_dev * spi)
33{
34    register int delay;
35
36    while(SPI_IS_BUSY(spi))
37    {
38        for (delay = 0; delay < 100; delay++);
39    }
40}
41
42/**
43 * \param   spi : Initialized pointer to the SPI controller
44 *
45 * \return  void
46 *
47 * \brief   Init transfer of the tx registers to the selected slaves
48 */
49static void _spi_init_transfer(struct spi_dev * spi)
50{
51    unsigned int spi_ctrl = ioread32(&spi->ctrl);
52
53    iowrite32(&spi->ctrl, spi_ctrl | SPI_CTRL_GO_BSY);
54}
55
56/**
57 * \param   spi_freq    : Desired frequency for the generated clock from the SPI
58 *                        controller
59 * \param   sys_freq    : System clock frequency
60 *
61 * \brief   Calculated the value for the divider register in order to obtain the SPI
62 *          desired clock frequency
63 */
64static unsigned int _spi_calc_divider_value  (
65    unsigned int spi_freq   ,
66    unsigned int sys_freq   )
67{
68    return ((sys_freq / (spi_freq * 2)) - 1);
69}
70
71void spi_put_tx(struct spi_dev * spi, unsigned char byte, int index)
72{
73    _spi_wait_if_busy(spi);
74    {
75        iowrite8(&spi->rx_tx[index % 4], byte);
76        _spi_init_transfer(spi);
77    }
78    _spi_wait_if_busy(spi);
79}
80
81volatile unsigned char spi_get_rx(struct spi_dev * spi, int index)
82{
83    return ioread8(&spi->rx_tx[index % 4]);
84}
85
86void spi_get_data(struct spi_dev * spi, void *buf, unsigned int count)
87{
88    unsigned int *data = buf;
89    unsigned char *data8;
90    unsigned int spi_ctrl0, spi_ctrl;
91    int i;
92
93    _spi_wait_if_busy(spi);
94    /* switch to 128 bits words */
95    spi_ctrl0 = ioread32(&spi->ctrl);
96    spi_ctrl = (spi_ctrl0 & ~SPI_CTRL_CHAR_LEN_MASK) | 128;
97    iowrite32(&spi->ctrl, spi_ctrl);
98
99    /* read data */
100    for (i = 0; i + 3 < count / 4; i += 4) {
101        iowrite32(&spi->rx_tx[0], 0xffffffff);
102        iowrite32(&spi->rx_tx[1], 0xffffffff);
103        iowrite32(&spi->rx_tx[2], 0xffffffff);
104        iowrite32(&spi->rx_tx[3], 0xffffffff);
105        iowrite32(&spi->ctrl,  spi_ctrl | SPI_CTRL_GO_BSY);
106        _spi_wait_if_busy(spi);
107        *data = bswap32(ioread32(&spi->rx_tx[3]));
108        data++;
109        *data = bswap32(ioread32(&spi->rx_tx[2]));
110        data++;
111        *data = bswap32(ioread32(&spi->rx_tx[1]));
112        data++;
113        *data = bswap32(ioread32(&spi->rx_tx[0]));
114        data++;
115    }
116    /* switch back to original word size */
117    iowrite32(&spi->ctrl, spi_ctrl0);
118    /* read missing bits */
119    data8 = (void *)data;
120    i = i * 4;
121    for (; i < count; i++) {
122        iowrite32(&spi->rx_tx[0], 0xffffffff);
123        iowrite32(&spi->ctrl,  spi_ctrl0 | SPI_CTRL_GO_BSY);
124        _spi_wait_if_busy(spi);
125        *data8 = spi_get_rx(spi, 0);
126        data8++;
127    }
128    return;
129}
130
131void spi_ss_assert(struct spi_dev * spi, int index)
132{
133    unsigned int spi_ss = ioread32(&spi->ss);
134
135    iowrite32(&spi->ss, spi_ss | (1 << index));
136}
137
138void spi_ss_deassert(struct spi_dev * spi, int index)
139{
140    unsigned int spi_ss = ioread32(&spi->ss);
141
142    iowrite32(&spi->ss, spi_ss & ~(1 << index));
143}
144
145void spi_dev_config (
146    struct spi_dev * spi,
147    int spi_freq        ,
148    int sys_freq        ,
149    int char_len                ,
150    int tx_edge                 ,
151    int rx_edge                 )
152{
153    unsigned int spi_ctrl = ioread32(&spi->ctrl);
154
155    if      ( tx_edge == 0 ) spi_ctrl |=  SPI_CTRL_TXN_EN;
156    else if ( tx_edge == 1 ) spi_ctrl &= ~SPI_CTRL_TXN_EN;
157    if      ( rx_edge == 0 ) spi_ctrl |=  SPI_CTRL_RXN_EN;
158    else if ( rx_edge == 1 ) spi_ctrl &= ~SPI_CTRL_RXN_EN;
159    if      ( char_len > 0 ) spi_ctrl  = (spi_ctrl & ~SPI_CTRL_CHAR_LEN_MASK) |
160                                         (char_len &  SPI_CTRL_CHAR_LEN_MASK);
161
162    iowrite32(&spi->ctrl, spi_ctrl);
163
164    if (spi_freq > 0 && sys_freq > 0)
165        iowrite32(&spi->divider, _spi_calc_divider_value(spi_freq, sys_freq));
166}
167
168/*
169 * vim: tabstop=4 : shiftwidth=4 : expandtab : softtabstop=4
170 */
Note: See TracBrowser for help on using the repository browser.