]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/mips/atheros/ar531x/ar5315_spi.c
MFV r308265: Update tzdata to 2016i.
[FreeBSD/FreeBSD.git] / sys / mips / atheros / ar531x / ar5315_spi.c
1 /*-
2  * Copyright (c) 2016, Hiroki Mori
3  * Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice unmodified, this list of conditions, and the following
11  *    disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34
35 #include <sys/bus.h>
36 #include <sys/interrupt.h>
37 #include <sys/malloc.h>
38 #include <sys/kernel.h>
39 #include <sys/module.h>
40 #include <sys/rman.h>
41 #include <sys/sysctl.h>
42
43 #include <vm/vm.h>
44 #include <vm/pmap.h>
45 #include <vm/vm_extern.h>
46
47 #include <machine/bus.h>
48 #include <machine/cpu.h>
49 #include <machine/pmap.h>
50
51 #include <dev/spibus/spi.h>
52 #include <dev/spibus/spibusvar.h>
53 #include "spibus_if.h"
54
55 #include <mips/atheros/ar531x/arspireg.h>
56 #include <mips/atheros/ar531x/ar5315reg.h>
57
58 #undef AR531X_SPI_DEBUG
59 #ifdef AR531X_SPI_DEBUG
60 #define dprintf printf
61 #else
62 #define dprintf(x, arg...)
63 #endif
64
65 /*
66  * register space access macros
67  */
68 #define SPI_WRITE(sc, reg, val) do {    \
69                 bus_write_4(sc->sc_mem_res, (reg), (val)); \
70         } while (0)
71
72 #define SPI_READ(sc, reg)        bus_read_4(sc->sc_mem_res, (reg))
73
74 #define SPI_SET_BITS(sc, reg, bits)     \
75         SPI_WRITE(sc, reg, SPI_READ(sc, (reg)) | (bits))
76
77 #define SPI_CLEAR_BITS(sc, reg, bits)   \
78         SPI_WRITE(sc, reg, SPI_READ(sc, (reg)) & ~(bits))
79
80 struct ar5315_spi_softc {
81         device_t                sc_dev;
82         struct resource         *sc_mem_res;
83         uint32_t                sc_reg_ctrl;
84         uint32_t                sc_debug;
85 };
86
87 static void
88 ar5315_spi_attach_sysctl(device_t dev)
89 {
90         struct ar5315_spi_softc *sc;
91         struct sysctl_ctx_list *ctx;
92         struct sysctl_oid *tree;
93
94         sc = device_get_softc(dev);
95         ctx = device_get_sysctl_ctx(dev);
96         tree = device_get_sysctl_tree(dev);
97
98         SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
99                 "debug", CTLFLAG_RW, &sc->sc_debug, 0,
100                 "ar5315_spi debugging flags");
101 }
102
103 static int
104 ar5315_spi_probe(device_t dev)
105 {
106         device_set_desc(dev, "AR5315 SPI");
107         return (0);
108 }
109
110 static int
111 ar5315_spi_attach(device_t dev)
112 {
113         struct ar5315_spi_softc *sc = device_get_softc(dev);
114         int rid;
115
116         sc->sc_dev = dev;
117         rid = 0;
118         sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 
119             RF_ACTIVE);
120         if (!sc->sc_mem_res) {
121                 device_printf(dev, "Could not map memory\n");
122                 return (ENXIO);
123         }
124
125         device_add_child(dev, "spibus", 0);
126         ar5315_spi_attach_sysctl(dev);
127
128         return (bus_generic_attach(dev));
129 }
130
131 static void
132 ar5315_spi_chip_activate(struct ar5315_spi_softc *sc, int cs)
133 {
134 }
135
136 static void
137 ar5315_spi_chip_deactivate(struct ar5315_spi_softc *sc, int cs)
138 {
139 }
140
141 static int
142 ar5315_spi_get_block(off_t offset, caddr_t data, off_t count)
143 {
144         int i;
145         for(i = 0; i < count / 4; ++i) {
146                 *((uint32_t *)data + i) = ATH_READ_REG(AR5315_MEM1_BASE + offset + i * 4);
147         }
148 //      printf("ar5315_spi_get_blockr: %x %x %x\n", 
149 //              (int)offset, (int)count, *(uint32_t *)data);
150         return (0);
151 }
152
153 static int
154 ar5315_spi_transfer(device_t dev, device_t child, struct spi_command *cmd)
155 {
156         struct ar5315_spi_softc *sc;
157         uint8_t *buf_in, *buf_out;
158         struct spibus_ivar *devi = SPIBUS_IVAR(child);
159         int lin, lout;
160         uint32_t ctl, cnt, op, rdat;
161         int i, j;
162
163         sc = device_get_softc(dev);
164
165         if (sc->sc_debug & 0x8000)
166                 printf("ar5315_spi_transfer: CMD ");
167
168         /* Open SPI controller interface */
169         ar5315_spi_chip_activate(sc, devi->cs);
170
171         do {
172                 ctl = SPI_READ(sc, ARSPI_REG_CTL);
173         } while (ctl & ARSPI_CTL_BUSY);
174
175         /*
176          * Transfer command
177          */
178         buf_out = (uint8_t *)cmd->tx_cmd;
179         op = buf_out[0];
180         if(op == 0x0b) {
181                 int offset = buf_out[1] << 16 | buf_out[2] << 8 | buf_out[3];
182                 ar5315_spi_get_block(offset, cmd->rx_data, cmd->rx_data_sz);
183                 return (0);
184         }
185         do {
186                 ctl = SPI_READ(sc, ARSPI_REG_CTL);
187         } while (ctl & ARSPI_CTL_BUSY);
188         if (sc->sc_debug & 0x8000) {
189                 printf("%08x ", op);
190                 printf("tx_cmd_sz=%d rx_cmd_sz=%d ", cmd->tx_cmd_sz,
191                         cmd->rx_cmd_sz);
192                 if(cmd->tx_cmd_sz != 1) {
193                         printf("%08x ", *((uint32_t *)cmd->tx_cmd));
194                         printf("%08x ", *((uint32_t *)cmd->tx_cmd + 1));
195                 }
196         }
197         SPI_WRITE(sc, ARSPI_REG_OPCODE, op);
198
199         /* clear all of the tx and rx bits */
200         ctl &= ~(ARSPI_CTL_TXCNT_MASK | ARSPI_CTL_RXCNT_MASK);
201
202         /* now set txcnt */
203         cnt = 1;
204
205         ctl |= (cnt << ARSPI_CTL_TXCNT_SHIFT);
206
207         cnt = 24;
208         /* now set txcnt */
209         if(cmd->rx_cmd_sz < 24)
210                 cnt = cmd->rx_cmd_sz;
211         ctl |= (cnt << ARSPI_CTL_RXCNT_SHIFT);
212
213         ctl |= ARSPI_CTL_START;
214
215         SPI_WRITE(sc, ARSPI_REG_CTL, ctl);
216
217         if(op == 0x0b)
218                 SPI_WRITE(sc, ARSPI_REG_DATA, 0);
219         if (sc->sc_debug & 0x8000)
220                 printf("\nDATA ");
221         /*
222          * Receive/transmit data (depends on  command)
223          */
224 //      buf_out = (uint8_t *)cmd->tx_data;
225         buf_in = (uint8_t *)cmd->rx_cmd;
226 //      lout = cmd->tx_data_sz;
227         lin = cmd->rx_cmd_sz;
228         if (sc->sc_debug & 0x8000)
229                 printf("t%d r%d ", lout, lin);
230         for(i = 0; i <= (cnt - 1) / 4; ++i) {
231                 do {
232                         ctl = SPI_READ(sc, ARSPI_REG_CTL);
233                 } while (ctl & ARSPI_CTL_BUSY);
234
235                 rdat = SPI_READ(sc, ARSPI_REG_DATA);
236                 if (sc->sc_debug & 0x8000)
237                         printf("I%08x ", rdat);
238
239                 for(j = 0; j < 4; ++j) {
240                         buf_in[i * 4 + j + 1] = 0xff & (rdat >> (8 * j));
241                         if(i * 4 + j  + 2 == cnt)
242                                 break;
243                 }
244         }
245
246         ar5315_spi_chip_deactivate(sc, devi->cs);
247         /*
248          * Close SPI controller interface, restore flash memory mapped access.
249          */
250         if (sc->sc_debug & 0x8000)
251                 printf("\n");
252
253         return (0);
254 }
255
256 static int
257 ar5315_spi_detach(device_t dev)
258 {
259         struct ar5315_spi_softc *sc = device_get_softc(dev);
260
261         if (sc->sc_mem_res)
262                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
263
264         return (0);
265 }
266
267 static device_method_t ar5315_spi_methods[] = {
268         /* Device interface */
269         DEVMETHOD(device_probe,         ar5315_spi_probe),
270         DEVMETHOD(device_attach,        ar5315_spi_attach),
271         DEVMETHOD(device_detach,        ar5315_spi_detach),
272
273         DEVMETHOD(spibus_transfer,      ar5315_spi_transfer),
274 //      DEVMETHOD(spibus_get_block,     ar5315_spi_get_block),
275
276         DEVMETHOD_END
277 };
278
279 static driver_t ar5315_spi_driver = {
280         "spi",
281         ar5315_spi_methods,
282         sizeof(struct ar5315_spi_softc),
283 };
284
285 static devclass_t ar5315_spi_devclass;
286
287 DRIVER_MODULE(ar5315_spi, nexus, ar5315_spi_driver, ar5315_spi_devclass, 0, 0);