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