ssdfb_spi.c revision 1.9.2.1 1 /* $NetBSD: ssdfb_spi.c,v 1.9.2.1 2021/08/09 00:30:09 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 2019 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Tobias Nygren.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: ssdfb_spi.c,v 1.9.2.1 2021/08/09 00:30:09 thorpej Exp $");
34
35 #include <sys/param.h>
36 #include <sys/device.h>
37 #include <sys/kernel.h>
38 #include <dev/wscons/wsdisplayvar.h>
39 #include <dev/rasops/rasops.h>
40
41 #include <dev/spi/spivar.h>
42 #include <dev/ic/ssdfbvar.h>
43 #include "opt_fdt.h"
44 #ifdef FDT
45 #include <dev/fdt/fdtvar.h>
46 #endif /* FDT */
47
48 struct bs_state {
49 uint8_t *base;
50 uint8_t *cur;
51 uint8_t mask;
52 };
53
54 struct ssdfb_spi_softc {
55 struct ssdfb_softc sc;
56 struct spi_handle *sc_sh;
57 #ifdef FDT
58 struct fdtbus_gpio_pin *sc_gpio_dc;
59 struct fdtbus_gpio_pin *sc_gpio_res;
60 #endif /* FDT */
61 bool sc_3wiremode;
62 };
63
64 static int ssdfb_spi_match(device_t, cfdata_t, void *);
65 static void ssdfb_spi_attach(device_t, device_t, void *);
66
67 static int ssdfb_spi_cmd_3wire(void *, uint8_t *, size_t, bool);
68 static int ssdfb_spi_xfer_rect_3wire_ssd1322(void *, uint8_t, uint8_t,
69 uint8_t, uint8_t, uint8_t *, size_t, bool);
70
71 static int ssdfb_spi_cmd_4wire(void *, uint8_t *, size_t, bool);
72 static int ssdfb_spi_xfer_rect_4wire_ssd1322(void *, uint8_t, uint8_t,
73 uint8_t, uint8_t, uint8_t *, size_t, bool);
74 static int ssdfb_spi_xfer_rect_4wire_ssd1353(void *, uint8_t, uint8_t,
75 uint8_t, uint8_t, uint8_t *, size_t, bool);
76
77 static void ssdfb_bitstream_init(struct bs_state *, uint8_t *);
78 static void ssdfb_bitstream_append(struct bs_state *, uint8_t, uint8_t);
79 static void ssdfb_bitstream_append_cmd(struct bs_state *, uint8_t);
80 static void ssdfb_bitstream_append_data(struct bs_state *, uint8_t *,
81 size_t);
82 static void ssdfb_bitstream_final(struct bs_state *);
83
84 CFATTACH_DECL_NEW(ssdfb_spi, sizeof(struct ssdfb_spi_softc),
85 ssdfb_spi_match, ssdfb_spi_attach, NULL, NULL);
86
87 static const struct device_compatible_entry compat_data[] = {
88 { .compat = "solomon,ssd1306", .value = SSDFB_PRODUCT_SSD1306_GENERIC },
89 { .compat = "solomon,ssd1322", .value = SSDFB_PRODUCT_SSD1322_GENERIC },
90 { .compat = "solomon,ssd1353", .value = SSDFB_PRODUCT_SSD1353_GENERIC },
91 { .compat = "dep160128a", .value = SSDFB_PRODUCT_DEP_160128A_RGB },
92 DEVICE_COMPAT_EOL
93 };
94
95 static int
96 ssdfb_spi_match(device_t parent, cfdata_t match, void *aux)
97 {
98 struct spi_attach_args *sa = aux;
99
100 return spi_compatible_match(sa, match, compat_data);
101 }
102
103 #ifdef FDT
104 static void
105 ssdfb_spi_gpio_fdt(struct ssdfb_spi_softc *sc)
106 {
107 devhandle_t devhandle = device_handle(sc->sc.sc_dev);
108 int phandle = devhandle_to_of(devhandle);
109
110 sc->sc_gpio_dc = fdtbus_gpio_acquire(phandle, "dc-gpio",
111 GPIO_PIN_OUTPUT);
112 if (sc->sc_gpio_dc == NULL) {
113 sc->sc_gpio_dc = fdtbus_gpio_acquire(phandle, "cd-gpio",
114 GPIO_PIN_OUTPUT);
115 }
116 if (sc->sc_gpio_dc != NULL) {
117 sc->sc_3wiremode = false;
118 }
119
120 sc->sc_gpio_res = fdtbus_gpio_acquire(phandle, "res-gpio",
121 GPIO_PIN_OUTPUT);
122 if (sc->sc_gpio_res) {
123 fdtbus_gpio_write_raw(sc->sc_gpio_res, 0);
124 DELAY(100);
125 fdtbus_gpio_write_raw(sc->sc_gpio_res, 1);
126 DELAY(100);
127 }
128 }
129 #endif /* FDT */
130
131 static void
132 ssdfb_spi_attach(device_t parent, device_t self, void *aux)
133 {
134 struct ssdfb_spi_softc *sc = device_private(self);
135 devhandle_t devhandle = device_handle(self);
136 struct cfdata *cf = device_cfdata(self);
137 struct spi_attach_args *sa = aux;
138 int flags = cf->cf_flags;
139 int error;
140
141 sc->sc.sc_dev = self;
142 sc->sc_sh = sa->sa_handle;
143 sc->sc.sc_cookie = (void *)sc;
144
145 /*
146 * SSD1306 and SSD1322 data sheets specify 100ns cycle time.
147 */
148 error = spi_configure(sa->sa_handle, SPI_MODE_0, 10000000);
149 if (error) {
150 aprint_error(": spi_configure failed (error = %d)\n",
151 error);
152 return;
153 }
154
155 if ((flags & SSDFB_ATTACH_FLAG_PRODUCT_MASK) == SSDFB_PRODUCT_UNKNOWN) {
156 const struct device_compatible_entry *dce =
157 device_compatible_lookup(sa->sa_compat, sa->sa_ncompat,
158 compat_data);
159 if (dce)
160 flags |= (int)dce->value;
161 else
162 flags |= SSDFB_PRODUCT_SSD1322_GENERIC;
163 }
164
165 /*
166 * Note on interface modes.
167 *
168 * 3 wire mode sends 9 bit sequences over the MOSI, MSB contains
169 * the bit that determines if the lower 8 bits are command or data.
170 *
171 * 4 wire mode sends 8 bit sequences and requires an auxiliary GPIO
172 * pin for the command/data bit.
173 *
174 * Default to 3 wire mode. If the device tree specifies a
175 * D/C GPIO pin, then we will use 4 wire mode.
176 */
177 sc->sc_3wiremode = true;
178 switch (devhandle_type(devhandle)) {
179 #ifdef FDT
180 case DEVHANDLE_TYPE_OF:
181 ssdfb_spi_gpio_fdt(sc);
182 break;
183 #endif /* FDT */
184 default:
185 break;
186 }
187
188 sc->sc.sc_cmd = sc->sc_3wiremode
189 ? ssdfb_spi_cmd_3wire
190 : ssdfb_spi_cmd_4wire;
191
192 switch (flags & SSDFB_ATTACH_FLAG_PRODUCT_MASK) {
193 case SSDFB_PRODUCT_SSD1322_GENERIC:
194 sc->sc.sc_transfer_rect = sc->sc_3wiremode
195 ? ssdfb_spi_xfer_rect_3wire_ssd1322
196 : ssdfb_spi_xfer_rect_4wire_ssd1322;
197 break;
198 case SSDFB_PRODUCT_SSD1353_GENERIC:
199 case SSDFB_PRODUCT_DEP_160128A_RGB:
200 sc->sc.sc_transfer_rect = sc->sc_3wiremode
201 ? NULL /* not supported here */
202 : ssdfb_spi_xfer_rect_4wire_ssd1353;
203 break;
204 }
205
206 if (!sc->sc.sc_transfer_rect) {
207 aprint_error(": sc_transfer_rect not implemented\n");
208 return;
209 }
210
211 ssdfb_attach(&sc->sc, flags);
212
213 aprint_normal_dev(self, "%d-wire SPI interface\n",
214 sc->sc_3wiremode == true ? 3 : 4);
215 }
216
217 static int
218 ssdfb_spi_cmd_3wire(void *cookie, uint8_t *cmd, size_t len, bool usepoll)
219 {
220 struct ssdfb_spi_softc *sc = (struct ssdfb_spi_softc *)cookie;
221 uint8_t bitstream[16 * 9 / 8];
222 struct bs_state s;
223
224 KASSERT(len > 0 && len <= 16);
225 ssdfb_bitstream_init(&s, bitstream);
226 ssdfb_bitstream_append_cmd(&s, *cmd);
227 cmd++;
228 len--;
229 ssdfb_bitstream_append_data(&s, cmd, len);
230 ssdfb_bitstream_final(&s);
231
232 return spi_send(sc->sc_sh, s.cur - s.base, bitstream);
233 }
234
235 static int
236 ssdfb_spi_xfer_rect_3wire_ssd1322(void *cookie, uint8_t fromcol, uint8_t tocol,
237 uint8_t fromrow, uint8_t torow, uint8_t *p, size_t stride, bool usepoll)
238 {
239 struct ssdfb_spi_softc *sc = (struct ssdfb_spi_softc *)cookie;
240 uint8_t bitstream[128 * 9 / 8];
241 struct bs_state s;
242 uint8_t row;
243 size_t rlen = (tocol + 1 - fromcol) * 2;
244 int error;
245
246 /*
247 * Unlike iic(4), there is no way to force spi(4) to use polling.
248 */
249 if (usepoll && !cold)
250 return 0;
251
252 ssdfb_bitstream_init(&s, bitstream);
253 ssdfb_bitstream_append_cmd(&s, SSD1322_CMD_SET_ROW_ADDRESS);
254 ssdfb_bitstream_append_data(&s, &fromrow, 1);
255 ssdfb_bitstream_append_data(&s, &torow, 1);
256 ssdfb_bitstream_append_cmd(&s, SSD1322_CMD_SET_COLUMN_ADDRESS);
257 ssdfb_bitstream_append_data(&s, &fromcol, 1);
258 ssdfb_bitstream_append_data(&s, &tocol, 1);
259 ssdfb_bitstream_append_cmd(&s, SSD1322_CMD_WRITE_RAM);
260 ssdfb_bitstream_final(&s);
261 error = spi_send(sc->sc_sh, s.cur - s.base, bitstream);
262 if (error)
263 return error;
264
265 KASSERT(rlen <= 128);
266 for (row = fromrow; row <= torow; row++) {
267 ssdfb_bitstream_init(&s, bitstream);
268 ssdfb_bitstream_append_data(&s, p, rlen);
269 ssdfb_bitstream_final(&s);
270 error = spi_send(sc->sc_sh, s.cur - s.base, bitstream);
271 if (error)
272 return error;
273 p += stride;
274 }
275
276 return 0;
277 }
278
279 static void
280 ssdfb_bitstream_init(struct bs_state *s, uint8_t *dst)
281 {
282 s->base = s->cur = dst;
283 s->mask = 0x80;
284 }
285
286 static void
287 ssdfb_bitstream_append(struct bs_state *s, uint8_t b, uint8_t srcmask)
288 {
289 while(srcmask) {
290 if (b & srcmask)
291 *s->cur |= s->mask;
292 else
293 *s->cur &= ~s->mask;
294 srcmask >>= 1;
295 s->mask >>= 1;
296 if (!s->mask) {
297 s->mask = 0x80;
298 s->cur++;
299 }
300 }
301 }
302
303 static void
304 ssdfb_bitstream_append_cmd(struct bs_state *s, uint8_t cmd)
305 {
306 ssdfb_bitstream_append(s, 0, 1);
307 ssdfb_bitstream_append(s, cmd, 0x80);
308 }
309
310 static void
311 ssdfb_bitstream_append_data(struct bs_state *s, uint8_t *data, size_t len)
312 {
313 while(len--) {
314 ssdfb_bitstream_append(s, 1, 1);
315 ssdfb_bitstream_append(s, *data++, 0x80);
316 }
317 }
318
319 static void
320 ssdfb_bitstream_final(struct bs_state *s)
321 {
322 uint8_t padding_cmd = SSD1322_CMD_WRITE_RAM;
323 /* padding_cmd = SSDFB_NOP_CMD; */
324
325 while (s->mask != 0x80) {
326 ssdfb_bitstream_append_cmd(s, padding_cmd);
327 }
328 }
329
330 static void
331 ssdfb_spi_4wire_set_dc(struct ssdfb_spi_softc *sc, int value)
332 {
333 /* TODO: refactor this if we ever support more that just FDT. */
334
335 #ifdef FDT
336 KASSERT(sc->sc_gpio_dc != NULL);
337 fdtbus_gpio_write(sc->sc_dc_gpio, value);
338 #else
339 /* TODO: this should toggle an auxilliary GPIO pin */
340 panic("ssdfb_spi_4wire_set_dc");
341 #endif /* FDT */
342 }
343
344 static int
345 ssdfb_spi_cmd_4wire(void *cookie, uint8_t *cmd, size_t len, bool usepoll)
346 {
347 struct ssdfb_spi_softc *sc = (struct ssdfb_spi_softc *)cookie;
348 int error;
349
350 ssdfb_spi_4wire_set_dc(sc, 0);
351 error = spi_send(sc->sc_sh, 1, cmd);
352 if (error)
353 return error;
354 if (len > 1) {
355 ssdfb_spi_4wire_set_dc(sc, 1);
356 len--;
357 cmd++;
358 error = spi_send(sc->sc_sh, len, cmd);
359 if (error)
360 return error;
361 }
362
363 return 0;
364 }
365
366 static int
367 ssdfb_spi_xfer_rect_4wire_ssd1322(void *cookie, uint8_t fromcol, uint8_t tocol,
368 uint8_t fromrow, uint8_t torow, uint8_t *p, size_t stride, bool usepoll)
369 {
370 struct ssdfb_spi_softc *sc = (struct ssdfb_spi_softc *)cookie;
371 uint8_t row;
372 size_t rlen = (tocol + 1 - fromcol) * 2;
373 int error;
374 uint8_t cmd;
375 uint8_t data[2];
376
377 /*
378 * Unlike iic(4), there is no way to force spi(4) to use polling.
379 */
380 if (usepoll && !cold)
381 return 0;
382
383 ssdfb_spi_4wire_set_dc(sc, 0);
384 cmd = SSD1322_CMD_SET_ROW_ADDRESS;
385 error = spi_send(sc->sc_sh, sizeof(cmd), &cmd);
386 if (error)
387 return error;
388 ssdfb_spi_4wire_set_dc(sc, 1);
389 data[0] = fromrow;
390 data[1] = torow;
391 error = spi_send(sc->sc_sh, sizeof(data), data);
392 if (error)
393 return error;
394
395 ssdfb_spi_4wire_set_dc(sc, 0);
396 cmd = SSD1322_CMD_SET_COLUMN_ADDRESS;
397 error = spi_send(sc->sc_sh, sizeof(cmd), &cmd);
398 if (error)
399 return error;
400 ssdfb_spi_4wire_set_dc(sc, 1);
401 data[0] = fromcol;
402 data[1] = tocol;
403 error = spi_send(sc->sc_sh, sizeof(data), data);
404 if (error)
405 return error;
406
407 ssdfb_spi_4wire_set_dc(sc, 0);
408 cmd = SSD1322_CMD_WRITE_RAM;
409 error = spi_send(sc->sc_sh, sizeof(cmd), &cmd);
410 if (error)
411 return error;
412
413 ssdfb_spi_4wire_set_dc(sc, 1);
414 for (row = fromrow; row <= torow; row++) {
415 error = spi_send(sc->sc_sh, rlen, p);
416 if (error)
417 return error;
418 p += stride;
419 }
420
421 return 0;
422 }
423
424 static int
425 ssdfb_spi_xfer_rect_4wire_ssd1353(void *cookie, uint8_t fromcol, uint8_t tocol,
426 uint8_t fromrow, uint8_t torow, uint8_t *p, size_t stride, bool usepoll)
427 {
428 struct ssdfb_spi_softc *sc = (struct ssdfb_spi_softc *)cookie;
429 uint8_t row;
430 size_t rlen = (tocol + 1 - fromcol) * 3;
431 uint8_t bitstream[160 * 3];
432 uint8_t *dstp, *srcp, *endp;
433 int error;
434 uint8_t cmd;
435 uint8_t data[2];
436
437 /*
438 * Unlike iic(4), there is no way to force spi(4) to use polling.
439 */
440 if (usepoll && !cold)
441 return 0;
442
443 ssdfb_spi_4wire_set_dc(sc, 0);
444 cmd = SSD1353_CMD_SET_ROW_ADDRESS;
445 error = spi_send(sc->sc_sh, sizeof(cmd), &cmd);
446 if (error)
447 return error;
448 ssdfb_spi_4wire_set_dc(sc, 1);
449 data[0] = fromrow;
450 data[1] = torow;
451 if (sc->sc.sc_upsidedown) {
452 /* fix picture outside frame on 160x128 panel */
453 data[0] += 132 - sc->sc.sc_p->p_height;
454 data[1] += 132 - sc->sc.sc_p->p_height;
455 }
456 error = spi_send(sc->sc_sh, sizeof(data), data);
457 if (error)
458 return error;
459
460 ssdfb_spi_4wire_set_dc(sc, 0);
461 cmd = SSD1353_CMD_SET_COLUMN_ADDRESS;
462 error = spi_send(sc->sc_sh, sizeof(cmd), &cmd);
463 if (error)
464 return error;
465 ssdfb_spi_4wire_set_dc(sc, 1);
466 data[0] = fromcol;
467 data[1] = tocol;
468 error = spi_send(sc->sc_sh, sizeof(data), data);
469 if (error)
470 return error;
471
472 ssdfb_spi_4wire_set_dc(sc, 0);
473 cmd = SSD1353_CMD_WRITE_RAM;
474 error = spi_send(sc->sc_sh, sizeof(cmd), &cmd);
475 if (error)
476 return error;
477
478 ssdfb_spi_4wire_set_dc(sc, 1);
479 KASSERT(rlen <= sizeof(bitstream));
480 for (row = fromrow; row <= torow; row++) {
481 /* downconvert each row from 32bpp rgba to 18bpp panel format */
482 dstp = bitstream;
483 endp = dstp + rlen;
484 srcp = p;
485 while (dstp < endp) {
486 *dstp++ = (*srcp++) >> 2;
487 *dstp++ = (*srcp++) >> 2;
488 *dstp++ = (*srcp++) >> 2;
489 srcp++;
490 }
491 error = spi_send(sc->sc_sh, rlen, bitstream);
492 if (error)
493 return error;
494 p += stride;
495 }
496
497 return 0;
498 }
499