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