1 /* $OpenBSD: ssdfb.c,v 1.9 2019/01/17 13:33:51 patrick Exp $ */ 2 /* 3 * Copyright (c) 2018 Patrick Wildt <patrick@blueri.se> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/kernel.h> 21 #include <sys/device.h> 22 #include <sys/malloc.h> 23 #include <sys/stdint.h> 24 25 #include <dev/i2c/i2cvar.h> 26 #include <dev/spi/spivar.h> 27 28 #include <dev/ofw/openfirm.h> 29 #include <dev/ofw/ofw_gpio.h> 30 #include <dev/ofw/ofw_pinctrl.h> 31 32 #include <dev/wscons/wsconsio.h> 33 #include <dev/wscons/wsdisplayvar.h> 34 #include <dev/rasops/rasops.h> 35 36 #define SSDFB_SET_LOWER_COLUMN_START_ADDRESS 0x00 37 #define SSDFB_SET_HIGHER_COLUMN_START_ADDRESS 0x10 38 #define SSDFB_SET_MEMORY_ADDRESSING_MODE 0x20 39 #define SSDFB_SET_COLUMN_RANGE 0x21 40 #define SSDFB_SET_PAGE_RANGE 0x22 41 #define SSDFB_SET_START_LINE 0x40 42 #define SSDFB_SET_CONTRAST_CONTROL 0x81 43 #define SSDFB_CHARGE_PUMP 0x8d 44 #define SSDFB_SET_COLUMN_DIRECTION_NORMAL 0xa0 45 #define SSDFB_SET_COLUMN_DIRECTION_REVERSE 0xa1 46 #define SSDFB_SET_MULTIPLEX_RATIO 0xa8 47 #define SSDFB_SET_COM_OUTPUT_DIRECTION_NORMAL 0xc0 48 #define SSDFB_SET_COM_OUTPUT_DIRECTION_REMAP 0xc8 49 #define SSDFB_ENTIRE_DISPLAY_ON 0xa4 50 #define SSDFB_SET_DISPLAY_MODE_NORMAL 0xa6 51 #define SSDFB_SET_DISPLAY_MODE_INVERS 0xa7 52 #define SSDFB_SET_DISPLAY_OFF 0xae 53 #define SSDFB_SET_DISPLAY_ON 0xaf 54 #define SSDFB_SET_DISPLAY_OFFSET 0xd3 55 #define SSDFB_SET_DISPLAY_CLOCK_DIVIDE_RATIO 0xd5 56 #define SSDFB_SET_PRE_CHARGE_PERIOD 0xd9 57 #define SSDFB_SET_COM_PINS_HARD_CONF 0xda 58 #define SSDFB_SET_VCOM_DESELECT_LEVEL 0xdb 59 #define SSDFB_SET_PAGE_START_ADDRESS 0xb0 60 61 #define SSDFB_I2C_COMMAND 0x00 62 #define SSDFB_I2C_DATA 0x40 63 64 struct ssdfb_softc { 65 struct device sc_dev; 66 int sc_node; 67 int sc_width; 68 int sc_height; 69 int sc_pgoff; 70 71 uint8_t *sc_fb; 72 size_t sc_fbsize; 73 struct rasops_info sc_rinfo; 74 struct wsdisplay_emulops sc_riops; 75 int (*sc_ri_do_cursor)(struct rasops_info *); 76 77 uint8_t sc_column_range[2]; 78 uint8_t sc_page_range[2]; 79 80 /* I2C */ 81 i2c_tag_t sc_i2c_tag; 82 i2c_addr_t sc_i2c_addr; 83 84 /* SPI */ 85 spi_tag_t sc_spi_tag; 86 struct spi_config sc_spi_conf; 87 uint32_t *sc_gpio; 88 size_t sc_gpiolen; 89 int sc_cd; 90 91 void (*sc_write_command)(struct ssdfb_softc *, 92 char *, size_t); 93 void (*sc_write_data)(struct ssdfb_softc *, 94 char *, size_t); 95 96 }; 97 98 int ssdfb_i2c_match(struct device *, void *, void *); 99 void ssdfb_i2c_attach(struct device *, struct device *, void *); 100 int ssdfb_i2c_detach(struct device *, int); 101 void ssdfb_i2c_write_command(struct ssdfb_softc *, char *, size_t); 102 void ssdfb_i2c_write_data(struct ssdfb_softc *, char *, size_t); 103 104 int ssdfb_spi_match(struct device *, void *, void *); 105 void ssdfb_spi_attach(struct device *, struct device *, void *); 106 int ssdfb_spi_detach(struct device *, int); 107 void ssdfb_spi_write_command(struct ssdfb_softc *, char *, size_t); 108 void ssdfb_spi_write_data(struct ssdfb_softc *, char *, size_t); 109 110 void ssdfb_attach(struct ssdfb_softc *); 111 int ssdfb_detach(struct ssdfb_softc *, int); 112 void ssdfb_write_command(struct ssdfb_softc *, char *, size_t); 113 void ssdfb_write_data(struct ssdfb_softc *, char *, size_t); 114 115 void ssdfb_init(struct ssdfb_softc *); 116 void ssdfb_update(void *); 117 118 void ssdfb_partial(struct ssdfb_softc *, uint32_t, uint32_t, 119 uint32_t, uint32_t); 120 void ssdfb_set_range(struct ssdfb_softc *, uint8_t, uint8_t, 121 uint8_t, uint8_t); 122 123 int ssdfb_ioctl(void *, u_long, caddr_t, int, struct proc *); 124 paddr_t ssdfb_mmap(void *, off_t, int); 125 int ssdfb_alloc_screen(void *, const struct wsscreen_descr *, void **, 126 int *, int *, long *); 127 void ssdfb_free_screen(void *, void *); 128 int ssdfb_show_screen(void *, void *, int, void (*cb) (void *, int, int), 129 void *); 130 int ssdfb_list_font(void *, struct wsdisplay_font *); 131 int ssdfb_load_font(void *, void *, struct wsdisplay_font *); 132 133 int ssdfb_putchar(void *, int, int, u_int, long); 134 int ssdfb_copycols(void *, int, int, int, int); 135 int ssdfb_erasecols(void *, int, int, int, long); 136 int ssdfb_copyrows(void *, int, int, int); 137 int ssdfb_eraserows(void *, int, int, long); 138 int ssdfb_do_cursor(struct rasops_info *); 139 140 struct cfattach ssdfb_i2c_ca = { 141 sizeof(struct ssdfb_softc), 142 ssdfb_i2c_match, 143 ssdfb_i2c_attach, 144 ssdfb_i2c_detach, 145 }; 146 147 struct cfattach ssdfb_spi_ca = { 148 sizeof(struct ssdfb_softc), 149 ssdfb_spi_match, 150 ssdfb_spi_attach, 151 ssdfb_spi_detach, 152 }; 153 154 struct cfdriver ssdfb_cd = { 155 NULL, "ssdfb", DV_DULL 156 }; 157 158 struct wsscreen_descr ssdfb_std_descr = { "std" }; 159 160 const struct wsscreen_descr *ssdfb_descrs[] = { 161 &ssdfb_std_descr 162 }; 163 164 const struct wsscreen_list ssdfb_screen_list = { 165 nitems(ssdfb_descrs), ssdfb_descrs 166 }; 167 168 struct wsdisplay_accessops ssdfb_accessops = { 169 .ioctl = ssdfb_ioctl, 170 .mmap = ssdfb_mmap, 171 .alloc_screen = ssdfb_alloc_screen, 172 .free_screen = ssdfb_free_screen, 173 .show_screen = ssdfb_show_screen, 174 .load_font = ssdfb_load_font, 175 .list_font = ssdfb_list_font 176 }; 177 178 int 179 ssdfb_i2c_match(struct device *parent, void *match, void *aux) 180 { 181 struct i2c_attach_args *ia = aux; 182 183 if (strcmp(ia->ia_name, "solomon,ssd1306fb-i2c") == 0 || 184 strcmp(ia->ia_name, "solomon,ssd1309fb-i2c") == 0) 185 return 1; 186 187 return 0; 188 } 189 190 void 191 ssdfb_i2c_attach(struct device *parent, struct device *self, void *aux) 192 { 193 struct ssdfb_softc *sc = (struct ssdfb_softc *)self; 194 struct i2c_attach_args *ia = aux; 195 196 sc->sc_i2c_tag = ia->ia_tag; 197 sc->sc_i2c_addr = ia->ia_addr; 198 sc->sc_node = *(int *)ia->ia_cookie; 199 200 sc->sc_write_command = ssdfb_i2c_write_command; 201 sc->sc_write_data = ssdfb_i2c_write_data; 202 203 ssdfb_attach(sc); 204 } 205 206 int 207 ssdfb_i2c_detach(struct device *self, int flags) 208 { 209 struct ssdfb_softc *sc = (struct ssdfb_softc *)self; 210 ssdfb_detach(sc, flags); 211 return 0; 212 } 213 214 int 215 ssdfb_spi_match(struct device *parent, void *match, void *aux) 216 { 217 struct spi_attach_args *sa = aux; 218 219 if (strcmp(sa->sa_name, "solomon,ssd1309fb-spi") == 0) 220 return 1; 221 222 return 0; 223 } 224 225 void 226 ssdfb_spi_attach(struct device *parent, struct device *self, void *aux) 227 { 228 struct ssdfb_softc *sc = (struct ssdfb_softc *)self; 229 struct spi_attach_args *sa = aux; 230 ssize_t len; 231 232 sc->sc_spi_tag = sa->sa_tag; 233 sc->sc_node = *(int *)sa->sa_cookie; 234 235 sc->sc_spi_conf.sc_bpw = 8; 236 sc->sc_spi_conf.sc_freq = 1000 * 1000; 237 sc->sc_spi_conf.sc_cs = OF_getpropint(sc->sc_node, "reg", 0); 238 if (OF_getproplen(sc->sc_node, "spi-cpol") == 0) 239 sc->sc_spi_conf.sc_flags |= SPI_CONFIG_CPOL; 240 if (OF_getproplen(sc->sc_node, "spi-cpha") == 0) 241 sc->sc_spi_conf.sc_flags |= SPI_CONFIG_CPHA; 242 if (OF_getproplen(sc->sc_node, "spi-cs-high") == 0) 243 sc->sc_spi_conf.sc_flags |= SPI_CONFIG_CS_HIGH; 244 245 len = OF_getproplen(sc->sc_node, "cd-gpio"); 246 if (len <= 0) 247 return; 248 249 sc->sc_gpio = malloc(len, M_DEVBUF, M_WAITOK); 250 OF_getpropintarray(sc->sc_node, "cd-gpio", sc->sc_gpio, len); 251 sc->sc_gpiolen = len; 252 gpio_controller_config_pin(sc->sc_gpio, GPIO_CONFIG_OUTPUT); 253 gpio_controller_set_pin(sc->sc_gpio, 0); 254 255 sc->sc_write_command = ssdfb_spi_write_command; 256 sc->sc_write_data = ssdfb_spi_write_data; 257 258 ssdfb_attach(sc); 259 } 260 261 int 262 ssdfb_spi_detach(struct device *self, int flags) 263 { 264 struct ssdfb_softc *sc = (struct ssdfb_softc *)self; 265 ssdfb_detach(sc, flags); 266 free(sc->sc_gpio, M_DEVBUF, sc->sc_gpiolen); 267 return 0; 268 } 269 270 void 271 ssdfb_attach(struct ssdfb_softc *sc) 272 { 273 struct wsemuldisplaydev_attach_args aa; 274 struct rasops_info *ri; 275 uint32_t *gpio; 276 ssize_t len; 277 278 pinctrl_byname(sc->sc_node, "default"); 279 280 len = OF_getproplen(sc->sc_node, "reset-gpios"); 281 if (len > 0) { 282 gpio = malloc(len, M_DEVBUF, M_WAITOK); 283 OF_getpropintarray(sc->sc_node, "reset-gpios", 284 gpio, len); 285 gpio_controller_config_pin(gpio, GPIO_CONFIG_OUTPUT); 286 gpio_controller_set_pin(gpio, 1); 287 delay(100 * 1000); 288 gpio_controller_set_pin(gpio, 0); 289 delay(1000 * 1000); 290 free(gpio, M_DEVBUF, len); 291 } 292 293 sc->sc_width = OF_getpropint(sc->sc_node, "solomon,width", 96); 294 sc->sc_height = OF_getpropint(sc->sc_node, "solomon,height", 16); 295 sc->sc_pgoff = OF_getpropint(sc->sc_node, "solomon,page-offset", 1); 296 297 sc->sc_fbsize = (sc->sc_width * sc->sc_height) / 8; 298 sc->sc_fb = malloc(sc->sc_fbsize, M_DEVBUF, M_WAITOK | M_ZERO); 299 300 ri = &sc->sc_rinfo; 301 ri->ri_bits = malloc(sc->sc_fbsize, M_DEVBUF, M_WAITOK | M_ZERO); 302 ri->ri_bs = mallocarray(sc->sc_width * sc->sc_height, 303 sizeof(struct wsdisplay_charcell), M_DEVBUF, M_WAITOK | M_ZERO); 304 ri->ri_flg = RI_CLEAR | RI_VCONS; 305 ri->ri_depth = 1; 306 ri->ri_width = sc->sc_width; 307 ri->ri_height = sc->sc_height; 308 ri->ri_stride = ri->ri_width * ri->ri_depth / 8; 309 ri->ri_hw = sc; 310 311 rasops_init(ri, sc->sc_height, sc->sc_width); 312 ssdfb_std_descr.ncols = ri->ri_cols; 313 ssdfb_std_descr.nrows = ri->ri_rows; 314 ssdfb_std_descr.textops = &ri->ri_ops; 315 ssdfb_std_descr.fontwidth = ri->ri_font->fontwidth; 316 ssdfb_std_descr.fontheight = ri->ri_font->fontheight; 317 ssdfb_std_descr.capabilities = ri->ri_caps; 318 319 sc->sc_riops.putchar = ri->ri_putchar; 320 sc->sc_riops.copycols = ri->ri_copycols; 321 sc->sc_riops.erasecols = ri->ri_erasecols; 322 sc->sc_riops.copyrows = ri->ri_copyrows; 323 sc->sc_riops.eraserows = ri->ri_eraserows; 324 sc->sc_ri_do_cursor = ri->ri_do_cursor; 325 326 ri->ri_putchar = ssdfb_putchar; 327 ri->ri_copycols = ssdfb_copycols; 328 ri->ri_erasecols = ssdfb_erasecols; 329 ri->ri_copyrows = ssdfb_copyrows; 330 ri->ri_eraserows = ssdfb_eraserows; 331 ri->ri_do_cursor = ssdfb_do_cursor; 332 333 printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth); 334 335 memset(&aa, 0, sizeof(aa)); 336 aa.console = 0; 337 aa.scrdata = &ssdfb_screen_list; 338 aa.accessops = &ssdfb_accessops; 339 aa.accesscookie = sc; 340 aa.defaultscreens = 0; 341 342 config_found_sm(&sc->sc_dev, &aa, wsemuldisplaydevprint, 343 wsemuldisplaydevsubmatch); 344 ssdfb_init(sc); 345 } 346 347 int 348 ssdfb_detach(struct ssdfb_softc *sc, int flags) 349 { 350 struct rasops_info *ri = &sc->sc_rinfo; 351 free(ri->ri_bs, M_DEVBUF, sc->sc_width * sc->sc_height * 352 sizeof(struct wsdisplay_charcell)); 353 free(ri->ri_bits, M_DEVBUF, sc->sc_fbsize); 354 free(sc->sc_fb, M_DEVBUF, sc->sc_fbsize); 355 return 0; 356 } 357 358 void 359 ssdfb_init(struct ssdfb_softc *sc) 360 { 361 uint8_t reg[2]; 362 363 reg[0] = SSDFB_SET_DISPLAY_OFF; 364 ssdfb_write_command(sc, reg, 1); 365 366 reg[0] = SSDFB_SET_MEMORY_ADDRESSING_MODE; 367 reg[1] = 0x00; /* Horizontal Addressing Mode */ 368 ssdfb_write_command(sc, reg, 2); 369 reg[0] = SSDFB_SET_PAGE_START_ADDRESS; 370 ssdfb_write_command(sc, reg, 1); 371 ssdfb_set_range(sc, 0, sc->sc_width - 1, 372 0, (sc->sc_height / 8) - 1); 373 if (OF_is_compatible(sc->sc_node, "solomon,ssd1309fb-i2c") || 374 OF_is_compatible(sc->sc_node, "solomon,ssd1309fb-spi")) { 375 reg[0] = SSDFB_SET_DISPLAY_CLOCK_DIVIDE_RATIO; 376 reg[1] = 0xa0; 377 ssdfb_write_command(sc, reg, 2); 378 } 379 if (OF_is_compatible(sc->sc_node, "solomon,ssd1306fb-i2c")) { 380 reg[0] = SSDFB_SET_DISPLAY_CLOCK_DIVIDE_RATIO; 381 reg[1] = 0x80; 382 ssdfb_write_command(sc, reg, 2); 383 } 384 reg[0] = SSDFB_SET_MULTIPLEX_RATIO; 385 reg[1] = 0x3f; 386 ssdfb_write_command(sc, reg, 2); 387 reg[0] = SSDFB_SET_DISPLAY_OFFSET; 388 reg[1] = OF_getpropint(sc->sc_node, "solomon,com-offset", 0); 389 ssdfb_write_command(sc, reg, 2); 390 reg[0] = SSDFB_SET_START_LINE | 0x00; 391 ssdfb_write_command(sc, reg, 1); 392 reg[0] = SSDFB_SET_COLUMN_DIRECTION_NORMAL; 393 if (OF_getproplen(sc->sc_node, "solomon,com-invdir") == 0) 394 reg[0] = SSDFB_SET_COLUMN_DIRECTION_REVERSE; 395 ssdfb_write_command(sc, reg, 1); 396 reg[0] = SSDFB_SET_COM_OUTPUT_DIRECTION_REMAP; 397 if (OF_getproplen(sc->sc_node, "solomon,segment-no-remap") == 0) 398 reg[0] = SSDFB_SET_COM_OUTPUT_DIRECTION_NORMAL; 399 ssdfb_write_command(sc, reg, 1); 400 reg[0] = SSDFB_SET_COM_PINS_HARD_CONF; 401 reg[1] = 0x12; 402 if (OF_getproplen(sc->sc_node, "solomon,com-seq") == 0) 403 reg[1] &= ~(1 << 4); 404 if (OF_getproplen(sc->sc_node, "solomon,com-lrremap") == 0) 405 reg[1] |= 1 << 5; 406 ssdfb_write_command(sc, reg, 2); 407 reg[0] = SSDFB_SET_CONTRAST_CONTROL; 408 reg[1] = 223; 409 ssdfb_write_command(sc, reg, 2); 410 reg[0] = SSDFB_SET_PRE_CHARGE_PERIOD; 411 reg[1] = (OF_getpropint(sc->sc_node, "solomon,prechargep1", 2) & 0xf) << 0; 412 reg[1] |= (OF_getpropint(sc->sc_node, "solomon,prechargep2", 2) & 0xf) << 4; 413 ssdfb_write_command(sc, reg, 2); 414 if (OF_is_compatible(sc->sc_node, "solomon,ssd1309fb-i2c") || 415 OF_is_compatible(sc->sc_node, "solomon,ssd1309fb-spi")) { 416 reg[0] = SSDFB_SET_VCOM_DESELECT_LEVEL; 417 reg[1] = 0x34; 418 ssdfb_write_command(sc, reg, 2); 419 } 420 if (OF_is_compatible(sc->sc_node, "solomon,ssd1306fb-i2c")) { 421 reg[0] = SSDFB_SET_VCOM_DESELECT_LEVEL; 422 reg[1] = 0x20; 423 ssdfb_write_command(sc, reg, 2); 424 } 425 reg[0] = SSDFB_CHARGE_PUMP; 426 reg[1] = 0x10; 427 if (OF_is_compatible(sc->sc_node, "solomon,ssd1306fb-i2c")) 428 reg[1] |= 1 << 2; 429 ssdfb_write_command(sc, reg, 2); 430 reg[0] = SSDFB_ENTIRE_DISPLAY_ON; 431 ssdfb_write_command(sc, reg, 1); 432 reg[0] = SSDFB_SET_DISPLAY_MODE_NORMAL; 433 ssdfb_write_command(sc, reg, 1); 434 435 ssdfb_partial(sc, 0, sc->sc_width, 0, sc->sc_height); 436 437 reg[0] = SSDFB_SET_DISPLAY_ON; 438 ssdfb_write_command(sc, reg, 1); 439 } 440 441 void 442 ssdfb_set_range(struct ssdfb_softc *sc, uint8_t x1, uint8_t x2, 443 uint8_t y1, uint8_t y2) 444 { 445 uint8_t reg[3]; 446 447 y1 += sc->sc_pgoff; 448 y2 += sc->sc_pgoff; 449 450 if (sc->sc_column_range[0] != x1 || sc->sc_column_range[1] != x2) { 451 sc->sc_column_range[0] = x1; 452 sc->sc_column_range[1] = x2; 453 reg[0] = SSDFB_SET_COLUMN_RANGE; 454 reg[1] = sc->sc_column_range[0]; 455 reg[2] = sc->sc_column_range[1]; 456 ssdfb_write_command(sc, reg, 3); 457 } 458 if (sc->sc_page_range[0] != y1 || sc->sc_page_range[1] != y2) { 459 sc->sc_page_range[0] = y1; 460 sc->sc_page_range[1] = y2; 461 reg[0] = SSDFB_SET_PAGE_RANGE; 462 reg[1] = sc->sc_page_range[0]; 463 reg[2] = sc->sc_page_range[1]; 464 ssdfb_write_command(sc, reg, 3); 465 } 466 } 467 468 void 469 ssdfb_partial(struct ssdfb_softc *sc, uint32_t x1, uint32_t x2, 470 uint32_t y1, uint32_t y2) 471 { 472 struct rasops_info *ri = &sc->sc_rinfo; 473 uint32_t off, width, height; 474 uint8_t *bit, val; 475 int i, j, k; 476 477 if (x2 < x1 || y2 < y1) 478 return; 479 480 if (x2 > sc->sc_width || y2 > sc->sc_height) 481 return; 482 483 y1 = y1 & ~0x7; 484 y2 = roundup(y2, 8); 485 486 width = x2 - x1; 487 height = y2 - y1; 488 489 memset(sc->sc_fb, 0, (width * height) / 8); 490 491 for (i = 0; i < height; i += 8) { 492 for (j = 0; j < width; j++) { 493 bit = &sc->sc_fb[(i / 8) * width + j]; 494 for (k = 0; k < 8; k++) { 495 off = ri->ri_stride * (y1 + i + k); 496 off += (x1 + j) / 8; 497 val = *(ri->ri_bits + off); 498 val &= (1 << ((x1 + j) % 8)); 499 *bit |= !!val << k; 500 } 501 } 502 } 503 504 ssdfb_set_range(sc, x1, x2 - 1, y1 / 8, (y2 / 8) - 1); 505 ssdfb_write_data(sc, sc->sc_fb, (width * height) / 8); 506 } 507 508 void 509 ssdfb_write_command(struct ssdfb_softc *sc, char *buf, size_t len) 510 { 511 return sc->sc_write_command(sc, buf, len); 512 } 513 514 void 515 ssdfb_write_data(struct ssdfb_softc *sc, char *buf, size_t len) 516 { 517 return sc->sc_write_data(sc, buf, len); 518 } 519 520 void 521 ssdfb_i2c_write_command(struct ssdfb_softc *sc, char *buf, size_t len) 522 { 523 uint8_t type; 524 525 type = SSDFB_I2C_COMMAND; 526 iic_acquire_bus(sc->sc_i2c_tag, 0); 527 if (iic_exec(sc->sc_i2c_tag, I2C_OP_WRITE_WITH_STOP, 528 sc->sc_i2c_addr, &type, sizeof(type), buf, len, 0)) { 529 printf("%s: cannot write\n", sc->sc_dev.dv_xname); 530 } 531 iic_release_bus(sc->sc_i2c_tag, 0); 532 } 533 534 void 535 ssdfb_i2c_write_data(struct ssdfb_softc *sc, char *buf, size_t len) 536 { 537 uint8_t type; 538 539 type = SSDFB_I2C_DATA; 540 iic_acquire_bus(sc->sc_i2c_tag, 0); 541 if (iic_exec(sc->sc_i2c_tag, I2C_OP_WRITE_WITH_STOP, 542 sc->sc_i2c_addr, &type, sizeof(type), buf, len, 0)) { 543 printf("%s: cannot write\n", sc->sc_dev.dv_xname); 544 } 545 iic_release_bus(sc->sc_i2c_tag, 0); 546 } 547 548 void 549 ssdfb_spi_write_command(struct ssdfb_softc *sc, char *buf, size_t len) 550 { 551 if (sc->sc_cd != 0) { 552 gpio_controller_set_pin(sc->sc_gpio, 0); 553 sc->sc_cd = 0; 554 delay(1); 555 } 556 557 spi_acquire_bus(sc->sc_spi_tag, 0); 558 spi_config(sc->sc_spi_tag, &sc->sc_spi_conf); 559 if (spi_write(sc->sc_spi_tag, buf, len)) 560 printf("%s: cannot write\n", sc->sc_dev.dv_xname); 561 spi_release_bus(sc->sc_spi_tag, 0); 562 } 563 564 void 565 ssdfb_spi_write_data(struct ssdfb_softc *sc, char *buf, size_t len) 566 { 567 if (sc->sc_cd != 1) { 568 gpio_controller_set_pin(sc->sc_gpio, 1); 569 sc->sc_cd = 1; 570 delay(1); 571 } 572 573 spi_acquire_bus(sc->sc_spi_tag, 0); 574 spi_config(sc->sc_spi_tag, &sc->sc_spi_conf); 575 if (spi_write(sc->sc_spi_tag, buf, len)) 576 printf("%s: cannot write\n", sc->sc_dev.dv_xname); 577 spi_release_bus(sc->sc_spi_tag, 0); 578 } 579 580 int 581 ssdfb_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 582 { 583 struct ssdfb_softc *sc = v; 584 struct rasops_info *ri = &sc->sc_rinfo; 585 struct wsdisplay_fbinfo *wdf; 586 587 switch (cmd) { 588 case WSDISPLAYIO_GETPARAM: 589 case WSDISPLAYIO_SETPARAM: 590 return (-1); 591 case WSDISPLAYIO_GTYPE: 592 *(u_int *)data = WSDISPLAY_TYPE_UNKNOWN; 593 break; 594 case WSDISPLAYIO_GINFO: 595 wdf = (struct wsdisplay_fbinfo *)data; 596 wdf->width = ri->ri_width; 597 wdf->height = ri->ri_height; 598 wdf->depth = ri->ri_depth; 599 wdf->cmsize = 0; /* color map is unavailable */ 600 break; 601 case WSDISPLAYIO_LINEBYTES: 602 *(u_int *)data = ri->ri_stride; 603 break; 604 case WSDISPLAYIO_SMODE: 605 break; 606 case WSDISPLAYIO_GETSUPPORTEDDEPTH: 607 *(u_int *)data = WSDISPLAYIO_DEPTH_1; 608 break; 609 default: 610 return (-1); 611 } 612 613 return (0); 614 } 615 616 paddr_t 617 ssdfb_mmap(void *v, off_t off, int prot) 618 { 619 return -1; 620 } 621 622 int 623 ssdfb_alloc_screen(void *v, const struct wsscreen_descr *descr, 624 void **cookiep, int *curxp, int *curyp, long *attrp) 625 { 626 struct ssdfb_softc *sc = v; 627 struct rasops_info *ri = &sc->sc_rinfo; 628 629 return rasops_alloc_screen(ri, cookiep, curxp, curyp, attrp); 630 } 631 632 void 633 ssdfb_free_screen(void *v, void *cookie) 634 { 635 struct ssdfb_softc *sc = v; 636 struct rasops_info *ri = &sc->sc_rinfo; 637 638 rasops_free_screen(ri, cookie); 639 } 640 641 int 642 ssdfb_show_screen(void *v, void *cookie, int waitok, 643 void (*cb) (void *, int, int), void *cb_arg) 644 { 645 struct ssdfb_softc *sc = v; 646 struct rasops_info *ri = &sc->sc_rinfo; 647 648 return rasops_show_screen(ri, cookie, waitok, cb, cb_arg); 649 } 650 651 int 652 ssdfb_load_font(void *v, void *cookie, struct wsdisplay_font *font) 653 { 654 struct ssdfb_softc *sc = v; 655 struct rasops_info *ri = &sc->sc_rinfo; 656 657 return (rasops_load_font(ri, cookie, font)); 658 } 659 660 int 661 ssdfb_list_font(void *v, struct wsdisplay_font *font) 662 { 663 struct ssdfb_softc *sc = v; 664 struct rasops_info *ri = &sc->sc_rinfo; 665 666 return (rasops_list_font(ri, font)); 667 } 668 669 int 670 ssdfb_putchar(void *cookie, int row, int col, u_int uc, long attr) 671 { 672 struct rasops_info *ri = (struct rasops_info *)cookie; 673 struct ssdfb_softc *sc = ri->ri_hw; 674 675 sc->sc_riops.putchar(cookie, row, col, uc, attr); 676 ssdfb_partial(sc, 677 col * ri->ri_font->fontwidth, 678 (col + 1) * ri->ri_font->fontwidth, 679 row * ri->ri_font->fontheight, 680 (row + 1) * ri->ri_font->fontheight); 681 return 0; 682 } 683 684 int 685 ssdfb_copycols(void *cookie, int row, int src, int dst, int num) 686 { 687 struct rasops_info *ri = (struct rasops_info *)cookie; 688 struct ssdfb_softc *sc = ri->ri_hw; 689 690 sc->sc_riops.copycols(cookie, row, src, dst, num); 691 ssdfb_partial(sc, 692 dst * ri->ri_font->fontwidth, 693 (dst + num) * ri->ri_font->fontwidth, 694 row * ri->ri_font->fontheight, 695 (row + 1) * ri->ri_font->fontheight); 696 return 0; 697 } 698 699 int 700 ssdfb_erasecols(void *cookie, int row, int col, int num, long attr) 701 { 702 struct rasops_info *ri = (struct rasops_info *)cookie; 703 struct ssdfb_softc *sc = ri->ri_hw; 704 705 sc->sc_riops.erasecols(cookie, row, col, num, attr); 706 ssdfb_partial(sc, 707 col * ri->ri_font->fontwidth, 708 (col + num) * ri->ri_font->fontwidth, 709 row * ri->ri_font->fontheight, 710 (row + 1) * ri->ri_font->fontheight); 711 return 0; 712 } 713 714 int 715 ssdfb_copyrows(void *cookie, int src, int dst, int num) 716 { 717 struct rasops_info *ri = (struct rasops_info *)cookie; 718 struct ssdfb_softc *sc = ri->ri_hw; 719 720 sc->sc_riops.copyrows(cookie, src, dst, num); 721 ssdfb_partial(sc, 0, sc->sc_width, 722 dst * ri->ri_font->fontheight, 723 (dst + num) * ri->ri_font->fontheight); 724 return 0; 725 } 726 727 int 728 ssdfb_eraserows(void *cookie, int row, int num, long attr) 729 { 730 struct rasops_info *ri = (struct rasops_info *)cookie; 731 struct ssdfb_softc *sc = ri->ri_hw; 732 733 sc->sc_riops.eraserows(cookie, row, num, attr); 734 if (num == ri->ri_rows && (ri->ri_flg & RI_FULLCLEAR) != 0) 735 ssdfb_partial(sc, 0, sc->sc_width, 0, sc->sc_height); 736 else 737 ssdfb_partial(sc, 0, sc->sc_width, 738 row * ri->ri_font->fontheight, 739 (row + num) * ri->ri_font->fontheight); 740 return 0; 741 } 742 743 int 744 ssdfb_do_cursor(struct rasops_info *ri) 745 { 746 struct ssdfb_softc *sc = ri->ri_hw; 747 int orow, ocol, nrow, ncol; 748 749 orow = ri->ri_crow; 750 ocol = ri->ri_ccol; 751 sc->sc_ri_do_cursor(ri); 752 nrow = ri->ri_crow; 753 ncol = ri->ri_ccol; 754 755 ssdfb_partial(sc, 756 ocol * ri->ri_font->fontwidth, 757 (ocol + 1) * ri->ri_font->fontwidth, 758 orow * ri->ri_font->fontheight, 759 (orow + 1) * ri->ri_font->fontheight); 760 ssdfb_partial(sc, 761 ncol * ri->ri_font->fontwidth, 762 (ncol + 1) * ri->ri_font->fontwidth, 763 nrow * ri->ri_font->fontheight, 764 (nrow + 1) * ri->ri_font->fontheight); 765 766 return 0; 767 } 768