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