1/*-
2 * Copyright (c) 2006 M. Warner Losh.
3 * Copyright (c) 2011-2012 Ian Lepore.
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, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD$");
30
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <sys/bus.h>
34#include <sys/conf.h>
35#include <sys/kernel.h>
36#include <sys/lock.h>
37#include <sys/mbuf.h>
38#include <sys/malloc.h>
39#include <sys/module.h>
40#include <sys/rman.h>
41#include <sys/sx.h>
42
43#include <machine/bus.h>
44
45#include <arm/at91/at91var.h>
46#include <arm/at91/at91_spireg.h>
47#include <arm/at91/at91_pdcreg.h>
48
49#include <dev/spibus/spi.h>
50#include <dev/spibus/spibusvar.h>
51
52#include "spibus_if.h"
53
54struct at91_spi_softc
55{
56	device_t dev;			/* Myself */
57	void *intrhand;			/* Interrupt handle */
58	struct resource *irq_res;	/* IRQ resource */
59	struct resource	*mem_res;	/* Memory resource */
60	bus_dma_tag_t dmatag;		/* bus dma tag for transfers */
61	bus_dmamap_t map[4];		/* Maps for the transaction */
62	struct sx xfer_mtx;		/* Enforce one transfer at a time */
63	uint32_t xfer_done;		/* interrupt<->mainthread signaling */
64};
65
66#define CS_TO_MR(cs)	((~(1 << (cs)) & 0x0f) << 16)
67
68static inline uint32_t
69RD4(struct at91_spi_softc *sc, bus_size_t off)
70{
71
72	return (bus_read_4(sc->mem_res, off));
73}
74
75static inline void
76WR4(struct at91_spi_softc *sc, bus_size_t off, uint32_t val)
77{
78
79	bus_write_4(sc->mem_res, off, val);
80}
81
82/* bus entry points */
83static int at91_spi_attach(device_t dev);
84static int at91_spi_detach(device_t dev);
85static int at91_spi_probe(device_t dev);
86static int at91_spi_transfer(device_t dev, device_t child,
87    struct spi_command *cmd);
88
89/* helper routines */
90static void at91_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs,
91    int error);
92static int at91_spi_activate(device_t dev);
93static void at91_spi_deactivate(device_t dev);
94static void at91_spi_intr(void *arg);
95
96static int
97at91_spi_probe(device_t dev)
98{
99
100	device_set_desc(dev, "AT91 SPI");
101	return (0);
102}
103
104static int
105at91_spi_attach(device_t dev)
106{
107	struct at91_spi_softc *sc;
108	int err;
109	uint32_t csr;
110
111	sc = device_get_softc(dev);
112
113	sc->dev = dev;
114	sx_init(&sc->xfer_mtx, device_get_nameunit(dev));
115
116	/*
117	 * Allocate resources.
118	 */
119	err = at91_spi_activate(dev);
120	if (err)
121		goto out;
122
123	/*
124	 * Set up the hardware.
125	 */
126
127	WR4(sc, SPI_CR, SPI_CR_SWRST);
128	/* "Software Reset must be Written Twice" erratum */
129	WR4(sc, SPI_CR, SPI_CR_SWRST);
130	WR4(sc, SPI_IDR, 0xffffffff);
131
132	WR4(sc, SPI_MR, (0xf << 24) | SPI_MR_MSTR | SPI_MR_MODFDIS |
133	    CS_TO_MR(0));
134
135	/*
136	 * For now, run the bus at the slowest speed possible as otherwise we
137	 * may encounter data corruption on transmit as seen with ETHERNUT5
138	 * and AT45DB321D even though both board and slave device can take
139	 * more.
140	 * This also serves as a work-around for the "NPCSx rises if no data
141	 * data is to be transmitted" erratum.  The ideal workaround for the
142	 * latter is to take the chip select control away from the peripheral
143	 * and manage it directly as a GPIO line.  The easy solution is to
144	 * slow down the bus so dramatically that it just never gets starved
145	 * as may be seen when the OCHI controller is running and consuming
146	 * memory and APB bandwidth.
147	 * Also, currently we lack a way for lettting both the board and the
148	 * slave devices take their maximum supported SPI clocks into account.
149	 * Also, we hard-wire SPI mode to 3.
150	 */
151	csr = SPI_CSR_CPOL | (4 << 16) | (0xff << 8);
152	WR4(sc, SPI_CSR0, csr);
153	WR4(sc, SPI_CSR1, csr);
154	WR4(sc, SPI_CSR2, csr);
155	WR4(sc, SPI_CSR3, csr);
156
157	WR4(sc, SPI_CR, SPI_CR_SPIEN);
158
159	WR4(sc, PDC_PTCR, PDC_PTCR_TXTDIS);
160	WR4(sc, PDC_PTCR, PDC_PTCR_RXTDIS);
161	WR4(sc, PDC_RNPR, 0);
162	WR4(sc, PDC_RNCR, 0);
163	WR4(sc, PDC_TNPR, 0);
164	WR4(sc, PDC_TNCR, 0);
165	WR4(sc, PDC_RPR, 0);
166	WR4(sc, PDC_RCR, 0);
167	WR4(sc, PDC_TPR, 0);
168	WR4(sc, PDC_TCR, 0);
169	RD4(sc, SPI_RDR);
170	RD4(sc, SPI_SR);
171
172	device_add_child(dev, "spibus", -1);
173	bus_generic_attach(dev);
174out:
175	if (err)
176		at91_spi_deactivate(dev);
177	return (err);
178}
179
180static int
181at91_spi_detach(device_t dev)
182{
183
184	return (EBUSY);	/* XXX */
185}
186
187static int
188at91_spi_activate(device_t dev)
189{
190	struct at91_spi_softc *sc;
191	int err, i, rid;
192
193	sc = device_get_softc(dev);
194	err = ENOMEM;
195
196	rid = 0;
197	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
198	    RF_ACTIVE);
199	if (sc->mem_res == NULL)
200		goto out;
201
202	rid = 0;
203	sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
204	    RF_ACTIVE);
205	if (sc->irq_res == NULL)
206		goto out;
207	err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
208	    NULL, at91_spi_intr, sc, &sc->intrhand);
209	if (err != 0)
210		goto out;
211
212	err = bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0,
213	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 2048, 1,
214	    2048, BUS_DMA_ALLOCNOW, NULL, NULL, &sc->dmatag);
215	if (err != 0)
216		goto out;
217
218	for (i = 0; i < 4; i++) {
219		err = bus_dmamap_create(sc->dmatag, 0,  &sc->map[i]);
220		if (err != 0)
221			goto out;
222	}
223out:
224	if (err != 0)
225		at91_spi_deactivate(dev);
226	return (err);
227}
228
229static void
230at91_spi_deactivate(device_t dev)
231{
232	struct at91_spi_softc *sc;
233	int i;
234
235	sc = device_get_softc(dev);
236	bus_generic_detach(dev);
237
238	for (i = 0; i < 4; i++)
239		if (sc->map[i])
240			bus_dmamap_destroy(sc->dmatag, sc->map[i]);
241
242	if (sc->dmatag)
243		bus_dma_tag_destroy(sc->dmatag);
244
245	if (sc->intrhand)
246		bus_teardown_intr(dev, sc->irq_res, sc->intrhand);
247	sc->intrhand = NULL;
248	if (sc->irq_res)
249		bus_release_resource(dev, SYS_RES_IRQ,
250		    rman_get_rid(sc->irq_res), sc->irq_res);
251	sc->irq_res = NULL;
252
253	if (sc->mem_res)
254		bus_release_resource(dev, SYS_RES_MEMORY,
255		    rman_get_rid(sc->mem_res), sc->mem_res);
256	sc->mem_res = NULL;
257}
258
259static void
260at91_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs __unused,
261    int error)
262{
263
264	if (error != 0)
265		return;
266	*(bus_addr_t *)arg = segs[0].ds_addr;
267}
268
269static int
270at91_spi_transfer(device_t dev, device_t child, struct spi_command *cmd)
271{
272	struct at91_spi_softc *sc;
273	bus_addr_t addr;
274	int err, i, j, mode[4], cs;
275
276	KASSERT(cmd->tx_cmd_sz == cmd->rx_cmd_sz,
277	    ("%s: TX/RX command sizes should be equal", __func__));
278	KASSERT(cmd->tx_data_sz == cmd->rx_data_sz,
279	    ("%s: TX/RX data sizes should be equal", __func__));
280
281	/* get the proper chip select */
282	spibus_get_cs(child, &cs);
283
284	sc = device_get_softc(dev);
285	i = 0;
286
287	sx_xlock(&sc->xfer_mtx);
288
289	/*
290	 * Disable transfers while we set things up.
291	 */
292	WR4(sc, PDC_PTCR, PDC_PTCR_TXTDIS | PDC_PTCR_RXTDIS);
293
294	/*
295	 * PSCDEC = 0 has a range of 0..3 for chip select.  We
296	 * don't support PSCDEC = 1 which has a range of 0..15.
297	 */
298	if (cs < 0 || cs > 3) {
299		device_printf(dev,
300		    "Invalid chip select %d requested by %s\n", cs,
301		    device_get_nameunit(child));
302		err = EINVAL;
303		goto out;
304	}
305
306#ifdef SPI_CHIP_SELECT_HIGH_SUPPORT
307	/*
308	 * The AT91RM9200 couldn't do CS high for CS 0.  Other chips can, but we
309	 * don't support that yet, or other spi modes.
310	 */
311	if (at91_is_rm92() && cs == 0 &&
312	    (cmd->flags & SPI_CHIP_SELECT_HIGH) != 0) {
313		device_printf(dev,
314		    "Invalid chip select high requested by %s for cs 0.\n",
315		    device_get_nameunit(child));
316		err = EINVAL;
317		goto out;
318	}
319#endif
320	err = (RD4(sc, SPI_MR) & ~0x000f0000) | CS_TO_MR(cs);
321	WR4(sc, SPI_MR, err);
322
323	/*
324	 * Set up the TX side of the transfer.
325	 */
326	if ((err = bus_dmamap_load(sc->dmatag, sc->map[i], cmd->tx_cmd,
327	    cmd->tx_cmd_sz, at91_getaddr, &addr, 0)) != 0)
328		goto out;
329	WR4(sc, PDC_TPR, addr);
330	WR4(sc, PDC_TCR, cmd->tx_cmd_sz);
331	bus_dmamap_sync(sc->dmatag, sc->map[i], BUS_DMASYNC_PREWRITE);
332	mode[i++] = BUS_DMASYNC_POSTWRITE;
333	if (cmd->tx_data_sz > 0) {
334		if ((err = bus_dmamap_load(sc->dmatag, sc->map[i],
335		    cmd->tx_data, cmd->tx_data_sz, at91_getaddr, &addr, 0)) !=
336		    0)
337			goto out;
338		WR4(sc, PDC_TNPR, addr);
339		WR4(sc, PDC_TNCR, cmd->tx_data_sz);
340		bus_dmamap_sync(sc->dmatag, sc->map[i], BUS_DMASYNC_PREWRITE);
341		mode[i++] = BUS_DMASYNC_POSTWRITE;
342	}
343
344	/*
345	 * Set up the RX side of the transfer.
346	 */
347	if ((err = bus_dmamap_load(sc->dmatag, sc->map[i], cmd->rx_cmd,
348	    cmd->rx_cmd_sz, at91_getaddr, &addr, 0)) != 0)
349		goto out;
350	WR4(sc, PDC_RPR, addr);
351	WR4(sc, PDC_RCR, cmd->rx_cmd_sz);
352	bus_dmamap_sync(sc->dmatag, sc->map[i], BUS_DMASYNC_PREREAD);
353	mode[i++] = BUS_DMASYNC_POSTREAD;
354	if (cmd->rx_data_sz > 0) {
355		if ((err = bus_dmamap_load(sc->dmatag, sc->map[i],
356		    cmd->rx_data, cmd->rx_data_sz, at91_getaddr, &addr, 0)) !=
357		    0)
358			goto out;
359		WR4(sc, PDC_RNPR, addr);
360		WR4(sc, PDC_RNCR, cmd->rx_data_sz);
361		bus_dmamap_sync(sc->dmatag, sc->map[i], BUS_DMASYNC_PREREAD);
362		mode[i++] = BUS_DMASYNC_POSTREAD;
363	}
364
365	/*
366	 * Start the transfer, wait for it to complete.
367	 */
368	sc->xfer_done = 0;
369	WR4(sc, SPI_IER, SPI_SR_RXBUFF);
370	WR4(sc, PDC_PTCR, PDC_PTCR_TXTEN | PDC_PTCR_RXTEN);
371	do
372		err = tsleep(&sc->xfer_done, PCATCH | PZERO, "at91_spi", hz);
373	while (sc->xfer_done == 0 && err != EINTR);
374
375	/*
376	 * Stop the transfer and clean things up.
377	 */
378	WR4(sc, PDC_PTCR, PDC_PTCR_TXTDIS | PDC_PTCR_RXTDIS);
379	if (err == 0)
380		for (j = 0; j < i; j++)
381			bus_dmamap_sync(sc->dmatag, sc->map[j], mode[j]);
382out:
383	for (j = 0; j < i; j++)
384		bus_dmamap_unload(sc->dmatag, sc->map[j]);
385
386	sx_xunlock(&sc->xfer_mtx);
387
388	return (err);
389}
390
391static void
392at91_spi_intr(void *arg)
393{
394	struct at91_spi_softc *sc;
395	uint32_t sr;
396
397	sc = (struct at91_spi_softc*)arg;
398
399	sr = RD4(sc, SPI_SR) & RD4(sc, SPI_IMR);
400	if ((sr & SPI_SR_RXBUFF) != 0) {
401		sc->xfer_done = 1;
402		WR4(sc, SPI_IDR, SPI_SR_RXBUFF);
403		wakeup(&sc->xfer_done);
404	}
405	if ((sr & ~SPI_SR_RXBUFF) != 0) {
406		device_printf(sc->dev, "Unexpected ISR %#x\n", sr);
407		WR4(sc, SPI_IDR, sr & ~SPI_SR_RXBUFF);
408	}
409}
410
411static devclass_t at91_spi_devclass;
412
413static device_method_t at91_spi_methods[] = {
414	/* Device interface */
415	DEVMETHOD(device_probe,		at91_spi_probe),
416	DEVMETHOD(device_attach,	at91_spi_attach),
417	DEVMETHOD(device_detach,	at91_spi_detach),
418
419	/* spibus interface */
420	DEVMETHOD(spibus_transfer,	at91_spi_transfer),
421
422	DEVMETHOD_END
423};
424
425static driver_t at91_spi_driver = {
426	"spi",
427	at91_spi_methods,
428	sizeof(struct at91_spi_softc),
429};
430
431DRIVER_MODULE(at91_spi, atmelarm, at91_spi_driver, at91_spi_devclass, NULL,
432    NULL);
433