1 /*-
2  * Copyright (c) 2016, Hiroki Mori
3  * Copyright (c) 2009, Oleksandr Tymoshenko <[email protected]>
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
ar5315_spi_attach_sysctl(device_t dev)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
ar5315_spi_probe(device_t dev)104 ar5315_spi_probe(device_t dev)
105 {
106 	device_set_desc(dev, "AR5315 SPI");
107 	return (0);
108 }
109 
110 static int
ar5315_spi_attach(device_t dev)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
ar5315_spi_chip_activate(struct ar5315_spi_softc * sc,int cs)132 ar5315_spi_chip_activate(struct ar5315_spi_softc *sc, int cs)
133 {
134 }
135 
136 static void
ar5315_spi_chip_deactivate(struct ar5315_spi_softc * sc,int cs)137 ar5315_spi_chip_deactivate(struct ar5315_spi_softc *sc, int cs)
138 {
139 }
140 
141 static int
ar5315_spi_get_block(off_t offset,caddr_t data,off_t count)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
ar5315_spi_transfer(device_t dev,device_t child,struct spi_command * cmd)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
ar5315_spi_detach(device_t dev)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);
291