1 /* $NetBSD: ssdfb_spi.c,v 1.9 2021/08/05 19:17:22 tnn 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 2021/08/05 19:17:22 tnn 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 #include <dev/spi/spivar.h> 41 #include <dev/ic/ssdfbvar.h> 42 #include "opt_fdt.h" 43 #ifdef FDT 44 #include <dev/fdt/fdtvar.h> 45 #endif 46 47 struct bs_state { 48 uint8_t *base; 49 uint8_t *cur; 50 uint8_t mask; 51 }; 52 53 struct ssdfb_spi_softc { 54 struct ssdfb_softc sc; 55 struct spi_handle *sc_sh; 56 #ifdef FDT 57 struct fdtbus_gpio_pin *sc_gpio_dc; 58 struct fdtbus_gpio_pin *sc_gpio_res; 59 #endif 60 bool sc_3wiremode; 61 }; 62 63 static int ssdfb_spi_match(device_t, cfdata_t, void *); 64 static void ssdfb_spi_attach(device_t, device_t, void *); 65 66 static int ssdfb_spi_cmd_3wire(void *, uint8_t *, size_t, bool); 67 static int ssdfb_spi_xfer_rect_3wire_ssd1322(void *, uint8_t, uint8_t, 68 uint8_t, uint8_t, uint8_t *, size_t, bool); 69 70 static int ssdfb_spi_cmd_4wire(void *, uint8_t *, size_t, bool); 71 static int ssdfb_spi_xfer_rect_4wire_ssd1322(void *, uint8_t, uint8_t, 72 uint8_t, uint8_t, uint8_t *, size_t, bool); 73 static int ssdfb_spi_xfer_rect_4wire_ssd1353(void *, uint8_t, uint8_t, 74 uint8_t, uint8_t, uint8_t *, size_t, bool); 75 76 static void ssdfb_bitstream_init(struct bs_state *, uint8_t *); 77 static void ssdfb_bitstream_append(struct bs_state *, uint8_t, uint8_t); 78 static void ssdfb_bitstream_append_cmd(struct bs_state *, uint8_t); 79 static void ssdfb_bitstream_append_data(struct bs_state *, uint8_t *, 80 size_t); 81 static void ssdfb_bitstream_final(struct bs_state *); 82 83 CFATTACH_DECL_NEW(ssdfb_spi, sizeof(struct ssdfb_spi_softc), 84 ssdfb_spi_match, ssdfb_spi_attach, NULL, NULL); 85 86 static const struct device_compatible_entry compat_data[] = { 87 { .compat = "solomon,ssd1306", .value = SSDFB_PRODUCT_SSD1306_GENERIC }, 88 { .compat = "solomon,ssd1322", .value = SSDFB_PRODUCT_SSD1322_GENERIC }, 89 { .compat = "solomon,ssd1353", .value = SSDFB_PRODUCT_SSD1353_GENERIC }, 90 { .compat = "dep160128a", .value = SSDFB_PRODUCT_DEP_160128A_RGB }, 91 DEVICE_COMPAT_EOL 92 }; 93 94 static int 95 ssdfb_spi_match(device_t parent, cfdata_t match, void *aux) 96 { 97 struct spi_attach_args *sa = aux; 98 int res; 99 100 res = spi_compatible_match(sa, match, compat_data); 101 if (!res) 102 return res; 103 104 /* 105 * SSD1306 and SSD1322 data sheets specify 100ns cycle time. 106 */ 107 if (spi_configure(sa->sa_handle, SPI_MODE_0, 10000000)) 108 res = 0; 109 110 return res; 111 } 112 113 static void 114 ssdfb_spi_attach(device_t parent, device_t self, void *aux) 115 { 116 struct ssdfb_spi_softc *sc = device_private(self); 117 struct cfdata *cf = device_cfdata(self); 118 struct spi_attach_args *sa = aux; 119 int flags = cf->cf_flags; 120 121 sc->sc.sc_dev = self; 122 sc->sc_sh = sa->sa_handle; 123 sc->sc.sc_cookie = (void *)sc; 124 if ((flags & SSDFB_ATTACH_FLAG_PRODUCT_MASK) == SSDFB_PRODUCT_UNKNOWN) { 125 const struct device_compatible_entry *dce = 126 device_compatible_lookup(sa->sa_compat, sa->sa_ncompat, compat_data); 127 if (dce) 128 flags |= (int)dce->value; 129 else 130 flags |= SSDFB_PRODUCT_SSD1322_GENERIC; 131 } 132 /* 133 * Note on interface modes. 134 * 135 * 3 wire mode sends 9 bit sequences over the MOSI, MSB contains 136 * the bit that determines if the lower 8 bits are command or data. 137 * 138 * 4 wire mode sends 8 bit sequences and requires an auxiliary GPIO 139 * pin for the command/data bit. 140 */ 141 #ifdef FDT 142 const int phandle = sa->sa_cookie; 143 sc->sc_gpio_dc = 144 fdtbus_gpio_acquire(phandle, "dc-gpio", GPIO_PIN_OUTPUT); 145 if (!sc->sc_gpio_dc) 146 sc->sc_gpio_dc = 147 fdtbus_gpio_acquire(phandle, "cd-gpio", GPIO_PIN_OUTPUT); 148 sc->sc_3wiremode = (sc->sc_gpio_dc == NULL); 149 sc->sc_gpio_res = 150 fdtbus_gpio_acquire(phandle, "res-gpio", GPIO_PIN_OUTPUT); 151 if (sc->sc_gpio_res) { 152 fdtbus_gpio_write_raw(sc->sc_gpio_res, 0); 153 DELAY(100); 154 fdtbus_gpio_write_raw(sc->sc_gpio_res, 1); 155 DELAY(100); 156 } 157 #else 158 sc->sc_3wiremode = true; 159 #endif 160 161 sc->sc.sc_cmd = sc->sc_3wiremode 162 ? ssdfb_spi_cmd_3wire 163 : ssdfb_spi_cmd_4wire; 164 165 switch (flags & SSDFB_ATTACH_FLAG_PRODUCT_MASK) { 166 case SSDFB_PRODUCT_SSD1322_GENERIC: 167 sc->sc.sc_transfer_rect = sc->sc_3wiremode 168 ? ssdfb_spi_xfer_rect_3wire_ssd1322 169 : ssdfb_spi_xfer_rect_4wire_ssd1322; 170 break; 171 case SSDFB_PRODUCT_SSD1353_GENERIC: 172 case SSDFB_PRODUCT_DEP_160128A_RGB: 173 sc->sc.sc_transfer_rect = sc->sc_3wiremode 174 ? NULL /* not supported here */ 175 : ssdfb_spi_xfer_rect_4wire_ssd1353; 176 break; 177 } 178 179 if (!sc->sc.sc_transfer_rect) { 180 aprint_error(": sc_transfer_rect not implemented\n"); 181 return; 182 } 183 184 ssdfb_attach(&sc->sc, flags); 185 186 aprint_normal_dev(self, "%d-wire SPI interface\n", 187 sc->sc_3wiremode == true ? 3 : 4); 188 } 189 190 static int 191 ssdfb_spi_cmd_3wire(void *cookie, uint8_t *cmd, size_t len, bool usepoll) 192 { 193 struct ssdfb_spi_softc *sc = (struct ssdfb_spi_softc *)cookie; 194 uint8_t bitstream[16 * 9 / 8]; 195 struct bs_state s; 196 197 KASSERT(len > 0 && len <= 16); 198 ssdfb_bitstream_init(&s, bitstream); 199 ssdfb_bitstream_append_cmd(&s, *cmd); 200 cmd++; 201 len--; 202 ssdfb_bitstream_append_data(&s, cmd, len); 203 ssdfb_bitstream_final(&s); 204 205 return spi_send(sc->sc_sh, s.cur - s.base, bitstream); 206 } 207 208 static int 209 ssdfb_spi_xfer_rect_3wire_ssd1322(void *cookie, uint8_t fromcol, uint8_t tocol, 210 uint8_t fromrow, uint8_t torow, uint8_t *p, size_t stride, bool usepoll) 211 { 212 struct ssdfb_spi_softc *sc = (struct ssdfb_spi_softc *)cookie; 213 uint8_t bitstream[128 * 9 / 8]; 214 struct bs_state s; 215 uint8_t row; 216 size_t rlen = (tocol + 1 - fromcol) * 2; 217 int error; 218 219 /* 220 * Unlike iic(4), there is no way to force spi(4) to use polling. 221 */ 222 if (usepoll && !cold) 223 return 0; 224 225 ssdfb_bitstream_init(&s, bitstream); 226 ssdfb_bitstream_append_cmd(&s, SSD1322_CMD_SET_ROW_ADDRESS); 227 ssdfb_bitstream_append_data(&s, &fromrow, 1); 228 ssdfb_bitstream_append_data(&s, &torow, 1); 229 ssdfb_bitstream_append_cmd(&s, SSD1322_CMD_SET_COLUMN_ADDRESS); 230 ssdfb_bitstream_append_data(&s, &fromcol, 1); 231 ssdfb_bitstream_append_data(&s, &tocol, 1); 232 ssdfb_bitstream_append_cmd(&s, SSD1322_CMD_WRITE_RAM); 233 ssdfb_bitstream_final(&s); 234 error = spi_send(sc->sc_sh, s.cur - s.base, bitstream); 235 if (error) 236 return error; 237 238 KASSERT(rlen <= 128); 239 for (row = fromrow; row <= torow; row++) { 240 ssdfb_bitstream_init(&s, bitstream); 241 ssdfb_bitstream_append_data(&s, p, rlen); 242 ssdfb_bitstream_final(&s); 243 error = spi_send(sc->sc_sh, s.cur - s.base, bitstream); 244 if (error) 245 return error; 246 p += stride; 247 } 248 249 return 0; 250 } 251 252 static void 253 ssdfb_bitstream_init(struct bs_state *s, uint8_t *dst) 254 { 255 s->base = s->cur = dst; 256 s->mask = 0x80; 257 } 258 259 static void 260 ssdfb_bitstream_append(struct bs_state *s, uint8_t b, uint8_t srcmask) 261 { 262 while(srcmask) { 263 if (b & srcmask) 264 *s->cur |= s->mask; 265 else 266 *s->cur &= ~s->mask; 267 srcmask >>= 1; 268 s->mask >>= 1; 269 if (!s->mask) { 270 s->mask = 0x80; 271 s->cur++; 272 } 273 } 274 } 275 276 static void 277 ssdfb_bitstream_append_cmd(struct bs_state *s, uint8_t cmd) 278 { 279 ssdfb_bitstream_append(s, 0, 1); 280 ssdfb_bitstream_append(s, cmd, 0x80); 281 } 282 283 static void 284 ssdfb_bitstream_append_data(struct bs_state *s, uint8_t *data, size_t len) 285 { 286 while(len--) { 287 ssdfb_bitstream_append(s, 1, 1); 288 ssdfb_bitstream_append(s, *data++, 0x80); 289 } 290 } 291 292 static void 293 ssdfb_bitstream_final(struct bs_state *s) 294 { 295 uint8_t padding_cmd = SSD1322_CMD_WRITE_RAM; 296 /* padding_cmd = SSDFB_NOP_CMD; */ 297 298 while (s->mask != 0x80) { 299 ssdfb_bitstream_append_cmd(s, padding_cmd); 300 } 301 } 302 303 static void 304 ssdfb_spi_4wire_set_dc(struct ssdfb_spi_softc *sc, int value) 305 { 306 #ifdef FDT 307 fdtbus_gpio_write_raw(sc->sc_gpio_dc, value); 308 #else 309 panic("ssdfb_spi_4wire_set_dc"); 310 #endif 311 } 312 313 static int 314 ssdfb_spi_cmd_4wire(void *cookie, uint8_t *cmd, size_t len, bool usepoll) 315 { 316 struct ssdfb_spi_softc *sc = (struct ssdfb_spi_softc *)cookie; 317 int error; 318 319 ssdfb_spi_4wire_set_dc(sc, 0); 320 error = spi_send(sc->sc_sh, 1, cmd); 321 if (error) 322 return error; 323 if (len > 1) { 324 ssdfb_spi_4wire_set_dc(sc, 1); 325 len--; 326 cmd++; 327 error = spi_send(sc->sc_sh, len, cmd); 328 if (error) 329 return error; 330 } 331 332 return 0; 333 } 334 335 static int 336 ssdfb_spi_xfer_rect_4wire_ssd1322(void *cookie, uint8_t fromcol, uint8_t tocol, 337 uint8_t fromrow, uint8_t torow, uint8_t *p, size_t stride, bool usepoll) 338 { 339 struct ssdfb_spi_softc *sc = (struct ssdfb_spi_softc *)cookie; 340 uint8_t row; 341 size_t rlen = (tocol + 1 - fromcol) * 2; 342 int error; 343 uint8_t cmd; 344 uint8_t data[2]; 345 346 /* 347 * Unlike iic(4), there is no way to force spi(4) to use polling. 348 */ 349 if (usepoll && !cold) 350 return 0; 351 352 ssdfb_spi_4wire_set_dc(sc, 0); 353 cmd = SSD1322_CMD_SET_ROW_ADDRESS; 354 error = spi_send(sc->sc_sh, sizeof(cmd), &cmd); 355 if (error) 356 return error; 357 ssdfb_spi_4wire_set_dc(sc, 1); 358 data[0] = fromrow; 359 data[1] = torow; 360 error = spi_send(sc->sc_sh, sizeof(data), data); 361 if (error) 362 return error; 363 364 ssdfb_spi_4wire_set_dc(sc, 0); 365 cmd = SSD1322_CMD_SET_COLUMN_ADDRESS; 366 error = spi_send(sc->sc_sh, sizeof(cmd), &cmd); 367 if (error) 368 return error; 369 ssdfb_spi_4wire_set_dc(sc, 1); 370 data[0] = fromcol; 371 data[1] = tocol; 372 error = spi_send(sc->sc_sh, sizeof(data), data); 373 if (error) 374 return error; 375 376 ssdfb_spi_4wire_set_dc(sc, 0); 377 cmd = SSD1322_CMD_WRITE_RAM; 378 error = spi_send(sc->sc_sh, sizeof(cmd), &cmd); 379 if (error) 380 return error; 381 382 ssdfb_spi_4wire_set_dc(sc, 1); 383 for (row = fromrow; row <= torow; row++) { 384 error = spi_send(sc->sc_sh, rlen, p); 385 if (error) 386 return error; 387 p += stride; 388 } 389 390 return 0; 391 } 392 393 static int 394 ssdfb_spi_xfer_rect_4wire_ssd1353(void *cookie, uint8_t fromcol, uint8_t tocol, 395 uint8_t fromrow, uint8_t torow, uint8_t *p, size_t stride, bool usepoll) 396 { 397 struct ssdfb_spi_softc *sc = (struct ssdfb_spi_softc *)cookie; 398 uint8_t row; 399 size_t rlen = (tocol + 1 - fromcol) * 3; 400 uint8_t bitstream[160 * 3]; 401 uint8_t *dstp, *srcp, *endp; 402 int error; 403 uint8_t cmd; 404 uint8_t data[2]; 405 406 /* 407 * Unlike iic(4), there is no way to force spi(4) to use polling. 408 */ 409 if (usepoll && !cold) 410 return 0; 411 412 ssdfb_spi_4wire_set_dc(sc, 0); 413 cmd = SSD1353_CMD_SET_ROW_ADDRESS; 414 error = spi_send(sc->sc_sh, sizeof(cmd), &cmd); 415 if (error) 416 return error; 417 ssdfb_spi_4wire_set_dc(sc, 1); 418 data[0] = fromrow; 419 data[1] = torow; 420 if (sc->sc.sc_upsidedown) { 421 /* fix picture outside frame on 160x128 panel */ 422 data[0] += 132 - sc->sc.sc_p->p_height; 423 data[1] += 132 - sc->sc.sc_p->p_height; 424 } 425 error = spi_send(sc->sc_sh, sizeof(data), data); 426 if (error) 427 return error; 428 429 ssdfb_spi_4wire_set_dc(sc, 0); 430 cmd = SSD1353_CMD_SET_COLUMN_ADDRESS; 431 error = spi_send(sc->sc_sh, sizeof(cmd), &cmd); 432 if (error) 433 return error; 434 ssdfb_spi_4wire_set_dc(sc, 1); 435 data[0] = fromcol; 436 data[1] = tocol; 437 error = spi_send(sc->sc_sh, sizeof(data), data); 438 if (error) 439 return error; 440 441 ssdfb_spi_4wire_set_dc(sc, 0); 442 cmd = SSD1353_CMD_WRITE_RAM; 443 error = spi_send(sc->sc_sh, sizeof(cmd), &cmd); 444 if (error) 445 return error; 446 447 ssdfb_spi_4wire_set_dc(sc, 1); 448 KASSERT(rlen <= sizeof(bitstream)); 449 for (row = fromrow; row <= torow; row++) { 450 /* downconvert each row from 32bpp rgba to 18bpp panel format */ 451 dstp = bitstream; 452 endp = dstp + rlen; 453 srcp = p; 454 while (dstp < endp) { 455 *dstp++ = (*srcp++) >> 2; 456 *dstp++ = (*srcp++) >> 2; 457 *dstp++ = (*srcp++) >> 2; 458 srcp++; 459 } 460 error = spi_send(sc->sc_sh, rlen, bitstream); 461 if (error) 462 return error; 463 p += stride; 464 } 465 466 return 0; 467 } 468