]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/mips/atheros/ar531x/ar5315_spi.c
Merge in changes from ^/vendor/NetBSD/tests/dist@r313245
[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", -1);
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         int lin, lout;
159         uint32_t ctl, cnt, op, rdat, cs;
160         int i, j;
161
162         sc = device_get_softc(dev);
163
164         if (sc->sc_debug & 0x8000)
165                 printf("ar5315_spi_transfer: CMD ");
166
167         spibus_get_cs(child, &cs);
168
169         cs &= ~SPIBUS_CS_HIGH;
170
171         /* Open SPI controller interface */
172         ar5315_spi_chip_activate(sc, cs);
173
174         do {
175                 ctl = SPI_READ(sc, ARSPI_REG_CTL);
176         } while (ctl & ARSPI_CTL_BUSY);
177
178         /*
179          * Transfer command
180          */
181         buf_out = (uint8_t *)cmd->tx_cmd;
182         op = buf_out[0];
183         if(op == 0x0b) {
184                 int offset = buf_out[1] << 16 | buf_out[2] << 8 | buf_out[3];
185                 ar5315_spi_get_block(offset, cmd->rx_data, cmd->rx_data_sz);
186                 return (0);
187         }
188         do {
189                 ctl = SPI_READ(sc, ARSPI_REG_CTL);
190         } while (ctl & ARSPI_CTL_BUSY);
191         if (sc->sc_debug & 0x8000) {
192                 printf("%08x ", op);
193                 printf("tx_cmd_sz=%d rx_cmd_sz=%d ", cmd->tx_cmd_sz,
194                         cmd->rx_cmd_sz);
195                 if(cmd->tx_cmd_sz != 1) {
196                         printf("%08x ", *((uint32_t *)cmd->tx_cmd));
197                         printf("%08x ", *((uint32_t *)cmd->tx_cmd + 1));
198                 }
199         }
200         SPI_WRITE(sc, ARSPI_REG_OPCODE, op);
201
202         /* clear all of the tx and rx bits */
203         ctl &= ~(ARSPI_CTL_TXCNT_MASK | ARSPI_CTL_RXCNT_MASK);
204
205         /* now set txcnt */
206         cnt = 1;
207
208         ctl |= (cnt << ARSPI_CTL_TXCNT_SHIFT);
209
210         cnt = 24;
211         /* now set txcnt */
212         if(cmd->rx_cmd_sz < 24)
213                 cnt = cmd->rx_cmd_sz;
214         ctl |= (cnt << ARSPI_CTL_RXCNT_SHIFT);
215
216         ctl |= ARSPI_CTL_START;
217
218         SPI_WRITE(sc, ARSPI_REG_CTL, ctl);
219
220         if(op == 0x0b)
221                 SPI_WRITE(sc, ARSPI_REG_DATA, 0);
222         if (sc->sc_debug & 0x8000)
223                 printf("\nDATA ");
224         /*
225          * Receive/transmit data (depends on  command)
226          */
227 //      buf_out = (uint8_t *)cmd->tx_data;
228         buf_in = (uint8_t *)cmd->rx_cmd;
229 //      lout = cmd->tx_data_sz;
230         lin = cmd->rx_cmd_sz;
231         if (sc->sc_debug & 0x8000)
232                 printf("t%d r%d ", lout, lin);
233         for(i = 0; i <= (cnt - 1) / 4; ++i) {
234                 do {
235                         ctl = SPI_READ(sc, ARSPI_REG_CTL);
236                 } while (ctl & ARSPI_CTL_BUSY);
237
238                 rdat = SPI_READ(sc, ARSPI_REG_DATA);
239                 if (sc->sc_debug & 0x8000)
240                         printf("I%08x ", rdat);
241
242                 for(j = 0; j < 4; ++j) {
243                         buf_in[i * 4 + j + 1] = 0xff & (rdat >> (8 * j));
244                         if(i * 4 + j  + 2 == cnt)
245                                 break;
246                 }
247         }
248
249         ar5315_spi_chip_deactivate(sc, cs);
250         /*
251          * Close SPI controller interface, restore flash memory mapped access.
252          */
253         if (sc->sc_debug & 0x8000)
254                 printf("\n");
255
256         return (0);
257 }
258
259 static int
260 ar5315_spi_detach(device_t dev)
261 {
262         struct ar5315_spi_softc *sc = device_get_softc(dev);
263
264         if (sc->sc_mem_res)
265                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
266
267         return (0);
268 }
269
270 static device_method_t ar5315_spi_methods[] = {
271         /* Device interface */
272         DEVMETHOD(device_probe,         ar5315_spi_probe),
273         DEVMETHOD(device_attach,        ar5315_spi_attach),
274         DEVMETHOD(device_detach,        ar5315_spi_detach),
275
276         DEVMETHOD(spibus_transfer,      ar5315_spi_transfer),
277 //      DEVMETHOD(spibus_get_block,     ar5315_spi_get_block),
278
279         DEVMETHOD_END
280 };
281
282 static driver_t ar5315_spi_driver = {
283         "spi",
284         ar5315_spi_methods,
285         sizeof(struct ar5315_spi_softc),
286 };
287
288 static devclass_t ar5315_spi_devclass;
289
290 DRIVER_MODULE(ar5315_spi, nexus, ar5315_spi_driver, ar5315_spi_devclass, 0, 0);