Annotation of src/sys/dev/marvell/mvspi.c, Revision 1.5.10.1
1.1 rkujawa 1: /*******************************************************************************
2: Copyright (C) Marvell International Ltd. and its affiliates
3:
4: Developed by Semihalf
5:
6: ********************************************************************************
7: Marvell BSD License
8:
9: If you received this File from Marvell, you may opt to use, redistribute and/or
10: modify this File under the following licensing terms.
11: Redistribution and use in source and binary forms, with or without modification,
12: are permitted provided that the following conditions are met:
13:
14: * Redistributions of source code must retain the above copyright notice,
15: this list of conditions and the following disclaimer.
16:
17: * Redistributions in binary form must reproduce the above copyright
18: notice, this list of conditions and the following disclaimer in the
19: documentation and/or other materials provided with the distribution.
20:
21: * Neither the name of Marvell nor the names of its contributors may be
22: used to endorse or promote products derived from this software without
23: specific prior written permission.
24:
25: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
26: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
27: WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28: DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
29: ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31: LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
32: ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34: SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35:
36: *******************************************************************************/
37:
38: /*
39: * Transfer mechanism extracted from arspi.c corresponding with the lines
40: * 254-262 in this file.
41: */
42:
43: #include <sys/param.h>
44: #include <sys/device.h>
45:
46: #include <dev/spi/spivar.h>
47:
48: #include <dev/marvell/mvspireg.h>
49: #include <dev/marvell/marvellvar.h>
50:
51: #include "locators.h"
52:
53: extern uint32_t mvTclk;
54:
55: struct mvspi_softc {
56: struct device sc_dev;
57: struct spi_controller sc_spi;
58: void *sc_ih;
59: bool sc_interrupts;
60:
61: struct spi_transfer *sc_transfer;
62: struct spi_chunk *sc_wchunk; /* For partial writes */
63: struct spi_transq sc_transq;
64: bus_space_tag_t sc_st;
65: bus_space_handle_t sc_sh;
66: bus_size_t sc_size;
67: };
68:
69: int mvspi_match(struct device *, struct cfdata *, void *);
70: void mvspi_attach(struct device *, struct device *, void *);
71: /* SPI service routines */
72: int mvspi_configure(void *, int, int, int);
73: int mvspi_transfer(void *, struct spi_transfer *);
74: /* Internal support */
75: void mvspi_sched(struct mvspi_softc *);
76: void mvspi_assert(struct mvspi_softc *sc);
77: void mvspi_deassert(struct mvspi_softc *sc);
78:
79: #define GETREG(sc, x) \
80: bus_space_read_4(sc->sc_st, sc->sc_sh, x)
81: #define PUTREG(sc, x, v) \
82: bus_space_write_4(sc->sc_st, sc->sc_sh, x, v)
83:
84: /* Attach structure */
85: CFATTACH_DECL_NEW(mvspi_mbus, sizeof(struct mvspi_softc),
86: mvspi_match, mvspi_attach, NULL, NULL);
87:
88: int
89: mvspi_match(struct device *parent, struct cfdata *cf, void *aux)
90: {
91: struct marvell_attach_args *mva = aux;
92:
93: if (strcmp(mva->mva_name, cf->cf_name) != 0)
94: return 0;
95: if (mva->mva_offset == MVA_OFFSET_DEFAULT ||
96: mva->mva_irq == MVA_IRQ_DEFAULT)
97: return 0;
98:
99: mva->mva_size = MVSPI_SIZE;
100: return 1;
101: }
102:
103: void
104: mvspi_attach(struct device *parent, struct device *self, void *aux)
105: {
106: struct mvspi_softc *sc = device_private(self);
107: struct marvell_attach_args *mva = aux;
108: struct spibus_attach_args sba;
109: int ctl;
110:
111: aprint_normal(": Marvell SPI controller\n");
112:
113: /*
114: * Map registers.
115: */
116: sc->sc_st = mva->mva_iot;
117: sc->sc_size = mva->mva_size;
118:
119: if (bus_space_subregion(sc->sc_st, mva->mva_ioh, mva->mva_offset,
120: mva->mva_size, &sc->sc_sh)) {
121: aprint_error_dev(self, "Cannot map registers\n");
122: return;
123: }
124:
125: /*
126: * Initialize hardware.
127: */
128: ctl = GETREG(sc, MVSPI_INTCONF_REG);
129:
130: ctl &= MVSPI_DIRHS_MASK;
131: ctl &= MVSPI_1BYTE_MASK;
132:
1.4 christos 133: PUTREG(sc, MVSPI_INTCONF_REG, ctl);
1.1 rkujawa 134:
135: /*
136: * Initialize SPI controller.
137: */
138: sc->sc_spi.sct_cookie = sc;
139: sc->sc_spi.sct_configure = mvspi_configure;
140: sc->sc_spi.sct_transfer = mvspi_transfer;
141: sc->sc_spi.sct_nslaves = 1;
142:
143: /*
144: * Initialize the queue.
145: */
146: spi_transq_init(&sc->sc_transq);
147:
148: /*
149: * Initialize and attach bus attach.
150: */
1.5 tnn 151: memset(&sba, 0, sizeof(sba));
1.1 rkujawa 152: sba.sba_controller = &sc->sc_spi;
1.5.10.1! thorpej 153: config_found(self, &sba, spibus_print, CFARG_EOL);
1.1 rkujawa 154: }
155:
156: int
157: mvspi_configure(void *cookie, int slave, int mode, int speed)
158: {
159: struct mvspi_softc *sc = cookie;
160: uint32_t ctl = 0, spr, sppr;
161: uint32_t divider;
162: uint32_t best_spr = 0, best_sppr = 0;
163: uint32_t best_sppr0, best_spprhi;
164: uint8_t exact_match = 0;
165: uint32_t min_baud_offset = 0xFFFFFFFF;
166:
167: if (slave < 0 || slave > 7)
168: return EINVAL;
169:
170: switch(mode) {
171: case SPI_MODE_0:
172: ctl &= ~(MVSPI_CPOL_MASK);
173: /* In boards documentation, CPHA is inverted */
174: ctl &= MVSPI_CPHA_MASK;
175: break;
176: case SPI_MODE_1:
177: ctl |= MVSPI_CPOL_MASK;
178: ctl &= MVSPI_CPHA_MASK;
179: break;
180: case SPI_MODE_2:
181: ctl &= ~(MVSPI_CPOL_MASK);
182: ctl |= ~(MVSPI_CPHA_MASK);
183: break;
184: case SPI_MODE_3:
185: ctl |= MVSPI_CPOL_MASK;
186: ctl |= ~(MVSPI_CPHA_MASK);
187: break;
188: default:
189: return EINVAL;
190: }
191:
192: /* Find the best prescale configuration - less or equal:
193: * SPI actual frecuency = core_clk / (SPR * (2 ^ SPPR))
194: * Try to find the minimal SPR and SPPR values that offer
195: * the best prescale config.
196: *
197: */
198: for (spr = 1; spr <= MVSPI_SPR_MAXVALUE; spr++) {
199: for (sppr = 0; sppr <= MVSPI_SPPR_MAXVALUE; sppr++) {
200: divider = spr * (1 << sppr);
201: /* Check for higher - irrelevant */
202: if ((mvTclk / divider) > speed)
203: continue;
204:
205: /* Check for exact fit */
206: if ((mvTclk / divider) == speed) {
207: best_spr = spr;
208: best_sppr = sppr;
209: exact_match = 1;
210: break;
211: }
212:
213: /* Check if this is better than the previous one */
214: if ((speed - (mvTclk / divider)) < min_baud_offset) {
215: min_baud_offset = (speed - (mvTclk / divider));
216: best_spr = spr;
217: best_sppr = sppr;
218: }
219: }
220:
221: if (exact_match == 1)
222: break;
223: }
224:
225: if (best_spr == 0) {
226: printf("%s ERROR: SPI baud rate prescale error!\n", __func__);
227: return -1;
228: }
229:
230: ctl &= ~(MVSPI_SPR_MASK);
231: ctl &= ~(MVSPI_SPPR_MASK);
232: ctl |= best_spr;
233:
234: best_spprhi = best_sppr & MVSPI_SPPRHI_MASK;
235: best_spprhi = best_spprhi << 5;
236:
237: ctl |= best_spprhi;
238:
239: best_sppr0 = best_sppr & MVSPI_SPPR0_MASK;
240: best_sppr0 = best_sppr0 << 4;
241:
242: ctl |= best_sppr0;
243:
244: PUTREG(sc, MVSPI_INTCONF_REG, ctl);
245:
246: return 0;
247: }
248:
249: int
250: mvspi_transfer(void *cookie, struct spi_transfer *st)
251: {
252: struct mvspi_softc *sc = cookie;
1.2 khorben 253: int s;
1.1 rkujawa 254:
255: s = splbio();
256: spi_transq_enqueue(&sc->sc_transq, st);
257: if (sc->sc_transfer == NULL) {
258: mvspi_sched(sc);
259: }
260: splx(s);
261: return 0;
262: }
263:
264: void
265: mvspi_assert(struct mvspi_softc *sc)
266: {
267: int ctl;
268:
1.3 christos 269: if (sc->sc_transfer->st_slave < 0 || sc->sc_transfer->st_slave > 7) {
1.1 rkujawa 270: printf("%s ERROR: Slave number %d not valid!\n", __func__, sc->sc_transfer->st_slave);
271: return;
272: } else
273: /* Enable appropriate CSn according to its slave number */
274: PUTREG(sc, MVSPI_CTRL_REG, (sc->sc_transfer->st_slave << 2));
275:
276: /* Enable CSnAct */
277: ctl = GETREG(sc, MVSPI_CTRL_REG);
278: ctl |= MVSPI_CSNACT_MASK;
279: PUTREG(sc, MVSPI_CTRL_REG, ctl);
280: }
281:
282: void
283: mvspi_deassert(struct mvspi_softc *sc)
284: {
285: int ctl = GETREG(sc, MVSPI_CTRL_REG);
286: ctl &= ~(MVSPI_CSNACT_MASK);
287: PUTREG(sc, MVSPI_CTRL_REG, ctl);
288: }
289:
290: void
291: mvspi_sched(struct mvspi_softc *sc)
292: {
293: struct spi_transfer *st;
294: struct spi_chunk *chunk;
295: int i, j, ctl;
296: uint8_t byte;
297: int ready = FALSE;
298:
299: for (;;) {
300: if ((st = sc->sc_transfer) == NULL) {
301: if ((st = spi_transq_first(&sc->sc_transq)) == NULL) {
302: /* No work left to do */
303: break;
304: }
305: spi_transq_dequeue(&sc->sc_transq);
306: sc->sc_transfer = st;
307: }
308:
309: chunk = st->st_chunks;
310:
311: mvspi_assert(sc);
312:
313: do {
314: for (i = chunk->chunk_wresid; i > 0; i--) {
315: /* First clear the ready bit */
316: ctl = GETREG(sc, MVSPI_CTRL_REG);
317: ctl &= ~(MVSPI_CR_SMEMRDY);
318: PUTREG(sc, MVSPI_CTRL_REG, ctl);
319:
320: if (chunk->chunk_wptr){
321: byte = *chunk->chunk_wptr;
322: chunk->chunk_wptr++;
323: } else
324: byte = MVSPI_DUMMY_BYTE;
325:
326: /* Transmit data */
327: PUTREG(sc, MVSPI_DATAOUT_REG, byte);
328:
329: /* Wait with timeout for memory ready */
330: for (j = 0; j < MVSPI_WAIT_RDY_MAX_LOOP; j++) {
331: if (GETREG(sc, MVSPI_CTRL_REG) &
332: MVSPI_CR_SMEMRDY) {
333: ready = TRUE;
334: break;
335: }
336:
337: }
338:
339: if (!ready) {
340: mvspi_deassert(sc);
341: spi_done(st, EBUSY);
342: return;
343: }
344:
345: /* Check that the RX data is needed */
346: if (chunk->chunk_rptr) {
347: *chunk->chunk_rptr =
348: GETREG(sc, MVSPI_DATAIN_REG);
349: chunk->chunk_rptr++;
350:
351: }
352:
353: }
354:
355: chunk = chunk->chunk_next;
356:
357: } while (chunk != NULL);
358:
359: mvspi_deassert(sc);
360:
361: spi_done(st, 0);
362: sc->sc_transfer = NULL;
363:
364:
365: break;
366: }
367: }
CVSweb <webmaster@jp.NetBSD.org>