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: releng/12.0/sys/mips/atheros/ar531x/ar5315_spi.c 310229 2016-12-18 14:54:20Z manu $");
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);
Cache object: d1cb418bc593cac95113a4e42e79ca92
|