1 1.24 nat /* $NetBSD: hd44780_subr.c,v 1.24 2023/08/08 17:31:13 nat Exp $ */ 2 1.1 soren 3 1.1 soren /* 4 1.1 soren * Copyright (c) 2002 Dennis I. Chernoivanov 5 1.1 soren * All rights reserved. 6 1.1 soren * 7 1.1 soren * Redistribution and use in source and binary forms, with or without 8 1.1 soren * modification, are permitted provided that the following conditions 9 1.1 soren * are met: 10 1.1 soren * 1. Redistributions of source code must retain the above copyright 11 1.1 soren * notice, this list of conditions and the following disclaimer. 12 1.1 soren * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 soren * notice, this list of conditions and the following disclaimer in the 14 1.1 soren * documentation and/or other materials provided with the distribution. 15 1.1 soren * 3. The name of the author may not be used to endorse or promote products 16 1.1 soren * derived from this software without specific prior written permission 17 1.1 soren * 18 1.1 soren * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 1.1 soren * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 1.1 soren * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 1.1 soren * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 1.1 soren * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 1.1 soren * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 1.1 soren * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 1.1 soren * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 1.1 soren * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 1.1 soren * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 1.1 soren */ 29 1.1 soren 30 1.1 soren /* 31 1.1 soren * Subroutines for Hitachi HD44870 style displays 32 1.1 soren */ 33 1.1 soren 34 1.1 soren #include <sys/cdefs.h> 35 1.24 nat __KERNEL_RCSID(0, "$NetBSD: hd44780_subr.c,v 1.24 2023/08/08 17:31:13 nat Exp $"); 36 1.1 soren 37 1.1 soren #include <sys/param.h> 38 1.1 soren #include <sys/systm.h> 39 1.1 soren #include <sys/conf.h> 40 1.1 soren #include <sys/kernel.h> 41 1.5 joff #include <sys/malloc.h> 42 1.1 soren #include <sys/types.h> 43 1.1 soren #include <sys/ioccom.h> 44 1.1 soren 45 1.1 soren #include <machine/autoconf.h> 46 1.12 ad #include <sys/intr.h> 47 1.12 ad #include <sys/bus.h> 48 1.1 soren 49 1.5 joff #include <dev/wscons/wsdisplayvar.h> 50 1.5 joff #include <dev/wscons/wsconsio.h> 51 1.5 joff #include <dev/wscons/wscons_callbacks.h> 52 1.5 joff 53 1.1 soren #include <dev/ic/hd44780reg.h> 54 1.4 joff #include <dev/ic/hd44780var.h> 55 1.1 soren 56 1.5 joff #define COORD_TO_IDX(x, y) ((y) * sc->sc_cols + (x)) 57 1.5 joff #define COORD_TO_DADDR(x, y) ((y) * HD_ROW2_ADDR + (x)) 58 1.7 joff #define IDX_TO_ROW(idx) ((idx) / sc->sc_cols) 59 1.7 joff #define IDX_TO_COL(idx) ((idx) % sc->sc_cols) 60 1.7 joff #define IDX_TO_DADDR(idx) (IDX_TO_ROW((idx)) * HD_ROW2_ADDR + \ 61 1.7 joff IDX_TO_COL((idx))) 62 1.7 joff #define DADDR_TO_ROW(daddr) ((daddr) / HD_ROW2_ADDR) 63 1.7 joff #define DADDR_TO_COL(daddr) ((daddr) % HD_ROW2_ADDR) 64 1.7 joff #define DADDR_TO_CHIPDADDR(daddr) ((daddr) % (HD_ROW2_ADDR * 2)) 65 1.7 joff #define DADDR_TO_CHIPNO(daddr) ((daddr) / (HD_ROW2_ADDR * 2)) 66 1.5 joff 67 1.5 joff static void hlcd_cursor(void *, int, int, int); 68 1.5 joff static int hlcd_mapchar(void *, int, unsigned int *); 69 1.5 joff static void hlcd_putchar(void *, int, int, u_int, long); 70 1.5 joff static void hlcd_copycols(void *, int, int, int,int); 71 1.5 joff static void hlcd_erasecols(void *, int, int, int, long); 72 1.5 joff static void hlcd_copyrows(void *, int, int, int); 73 1.5 joff static void hlcd_eraserows(void *, int, int, long); 74 1.5 joff static int hlcd_allocattr(void *, int, int, int, long *); 75 1.5 joff static void hlcd_updatechar(struct hd44780_chip *, int, int); 76 1.5 joff static void hlcd_redraw(void *); 77 1.5 joff 78 1.5 joff const struct wsdisplay_emulops hlcd_emulops = { 79 1.5 joff hlcd_cursor, 80 1.5 joff hlcd_mapchar, 81 1.5 joff hlcd_putchar, 82 1.5 joff hlcd_copycols, 83 1.5 joff hlcd_erasecols, 84 1.5 joff hlcd_copyrows, 85 1.5 joff hlcd_eraserows, 86 1.5 joff hlcd_allocattr 87 1.5 joff }; 88 1.5 joff 89 1.10 christos static int hlcd_ioctl(void *, void *, u_long, void *, int, struct lwp *); 90 1.9 jmmv static paddr_t hlcd_mmap(void *, void *, off_t, int); 91 1.5 joff static int hlcd_alloc_screen(void *, const struct wsscreen_descr *, 92 1.5 joff void **, int *, int *, long *); 93 1.5 joff static void hlcd_free_screen(void *, void *); 94 1.5 joff static int hlcd_show_screen(void *, void *, int, 95 1.5 joff void (*) (void *, int, int), void *); 96 1.5 joff 97 1.5 joff const struct wsdisplay_accessops hlcd_accessops = { 98 1.5 joff hlcd_ioctl, 99 1.5 joff hlcd_mmap, 100 1.5 joff hlcd_alloc_screen, 101 1.5 joff hlcd_free_screen, 102 1.5 joff hlcd_show_screen, 103 1.5 joff 0 /* load_font */ 104 1.5 joff }; 105 1.5 joff 106 1.5 joff static void 107 1.18 dsl hlcd_cursor(void *id, int on, int row, int col) 108 1.5 joff { 109 1.5 joff struct hlcd_screen *hdscr = id; 110 1.5 joff 111 1.5 joff hdscr->hlcd_curon = on; 112 1.5 joff hdscr->hlcd_curx = col; 113 1.5 joff hdscr->hlcd_cury = row; 114 1.5 joff } 115 1.5 joff 116 1.5 joff static int 117 1.17 dsl hlcd_mapchar(void *id, int uni, unsigned int *index) 118 1.5 joff { 119 1.20 tsutsui 120 1.5 joff if (uni < 256) { 121 1.5 joff *index = uni; 122 1.20 tsutsui return 5; 123 1.5 joff } 124 1.5 joff *index = ' '; 125 1.20 tsutsui return 0; 126 1.5 joff } 127 1.5 joff 128 1.5 joff static void 129 1.18 dsl hlcd_putchar(void *id, int row, int col, u_int c, long attr) 130 1.5 joff { 131 1.5 joff struct hlcd_screen *hdscr = id; 132 1.6 perry 133 1.5 joff c &= 0xff; 134 1.7 joff if (row > 0 && (hdscr->hlcd_sc->sc_flags & (HD_MULTILINE|HD_MULTICHIP))) 135 1.5 joff hdscr->image[hdscr->hlcd_sc->sc_cols * row + col] = c; 136 1.5 joff else 137 1.5 joff hdscr->image[col] = c; 138 1.5 joff } 139 1.5 joff 140 1.5 joff /* 141 1.5 joff * copies columns inside a row. 142 1.5 joff */ 143 1.5 joff static void 144 1.18 dsl hlcd_copycols(void *id, int row, int srccol, int dstcol, int ncols) 145 1.5 joff { 146 1.5 joff struct hlcd_screen *hdscr = id; 147 1.5 joff 148 1.5 joff if ((dstcol + ncols - 1) > hdscr->hlcd_sc->sc_cols) 149 1.5 joff ncols = hdscr->hlcd_sc->sc_cols - srccol; 150 1.5 joff 151 1.7 joff if (row > 0 && (hdscr->hlcd_sc->sc_flags & (HD_MULTILINE|HD_MULTICHIP))) 152 1.13 tsutsui memmove(&hdscr->image[hdscr->hlcd_sc->sc_cols * row + dstcol], 153 1.13 tsutsui &hdscr->image[hdscr->hlcd_sc->sc_cols * row + srccol], 154 1.13 tsutsui ncols); 155 1.5 joff else 156 1.13 tsutsui memmove(&hdscr->image[dstcol], &hdscr->image[srccol], ncols); 157 1.5 joff } 158 1.5 joff 159 1.5 joff 160 1.5 joff /* 161 1.5 joff * Erases a bunch of chars inside one row. 162 1.5 joff */ 163 1.5 joff static void 164 1.18 dsl hlcd_erasecols(void *id, int row, int startcol, int ncols, long fillattr) 165 1.5 joff { 166 1.5 joff struct hlcd_screen *hdscr = id; 167 1.5 joff 168 1.5 joff if ((startcol + ncols) > hdscr->hlcd_sc->sc_cols) 169 1.5 joff ncols = hdscr->hlcd_sc->sc_cols - startcol; 170 1.5 joff 171 1.7 joff if (row > 0 && (hdscr->hlcd_sc->sc_flags & (HD_MULTILINE|HD_MULTICHIP))) 172 1.6 perry memset(&hdscr->image[hdscr->hlcd_sc->sc_cols * row + startcol], 173 1.5 joff ' ', ncols); 174 1.5 joff else 175 1.5 joff memset(&hdscr->image[startcol], ' ', ncols); 176 1.5 joff } 177 1.5 joff 178 1.5 joff 179 1.5 joff static void 180 1.18 dsl hlcd_copyrows(void *id, int srcrow, int dstrow, int nrows) 181 1.5 joff { 182 1.5 joff struct hlcd_screen *hdscr = id; 183 1.5 joff int ncols = hdscr->hlcd_sc->sc_cols; 184 1.6 perry 185 1.7 joff if (!(hdscr->hlcd_sc->sc_flags & (HD_MULTILINE|HD_MULTICHIP))) 186 1.5 joff return; 187 1.13 tsutsui memmove(&hdscr->image[dstrow * ncols], &hdscr->image[srcrow * ncols], 188 1.5 joff nrows * ncols); 189 1.5 joff } 190 1.5 joff 191 1.5 joff static void 192 1.18 dsl hlcd_eraserows(void *id, int startrow, int nrows, long fillattr) 193 1.5 joff { 194 1.5 joff struct hlcd_screen *hdscr = id; 195 1.5 joff int ncols = hdscr->hlcd_sc->sc_cols; 196 1.5 joff 197 1.5 joff memset(&hdscr->image[startrow * ncols], ' ', ncols * nrows); 198 1.5 joff } 199 1.5 joff 200 1.5 joff 201 1.5 joff static int 202 1.18 dsl hlcd_allocattr(void *id, int fg, int bg, int flags, long *attrp) 203 1.5 joff { 204 1.20 tsutsui 205 1.5 joff *attrp = flags; 206 1.5 joff return 0; 207 1.5 joff } 208 1.5 joff 209 1.5 joff static int 210 1.17 dsl hlcd_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l) 211 1.5 joff { 212 1.5 joff 213 1.5 joff switch (cmd) { 214 1.5 joff case WSDISPLAYIO_GTYPE: 215 1.5 joff *(u_int *)data = WSDISPLAY_TYPE_HDLCD; 216 1.5 joff break; 217 1.5 joff 218 1.5 joff case WSDISPLAYIO_SVIDEO: 219 1.5 joff break; 220 1.5 joff 221 1.5 joff case WSDISPLAYIO_GVIDEO: 222 1.5 joff *(u_int *)data = WSDISPLAYIO_VIDEO_ON; 223 1.5 joff break; 224 1.5 joff 225 1.5 joff default: 226 1.5 joff return EPASSTHROUGH; 227 1.5 joff } 228 1.5 joff return 0; 229 1.5 joff } 230 1.5 joff 231 1.5 joff static paddr_t 232 1.17 dsl hlcd_mmap(void *v, void *vs, off_t offset, int prot) 233 1.5 joff { 234 1.20 tsutsui 235 1.5 joff return -1; 236 1.5 joff } 237 1.5 joff 238 1.5 joff static int 239 1.20 tsutsui hlcd_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, 240 1.20 tsutsui int *curxp, int *curyp, long *defattrp) 241 1.5 joff { 242 1.5 joff struct hlcd_screen *hdscr = v, *new; 243 1.5 joff 244 1.16 cegger new = *cookiep = malloc(sizeof(struct hlcd_screen), 245 1.16 cegger M_DEVBUF, M_WAITOK|M_ZERO); 246 1.5 joff new->hlcd_sc = hdscr->hlcd_sc; 247 1.5 joff new->image = malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK); 248 1.5 joff memset(new->image, ' ', PAGE_SIZE); 249 1.5 joff *curxp = *curyp = *defattrp = 0; 250 1.5 joff return 0; 251 1.5 joff } 252 1.5 joff 253 1.5 joff static void 254 1.18 dsl hlcd_free_screen(void *v, void *cookie) 255 1.5 joff { 256 1.5 joff } 257 1.5 joff 258 1.5 joff static int 259 1.20 tsutsui hlcd_show_screen(void *v, void *cookie, int waitok, 260 1.20 tsutsui void (*cb)(void *, int, int), void *cbarg) 261 1.5 joff { 262 1.5 joff struct hlcd_screen *hdscr = v; 263 1.5 joff 264 1.5 joff hdscr->hlcd_sc->sc_curscr = cookie; 265 1.5 joff callout_schedule(&hdscr->hlcd_sc->redraw, 1); 266 1.20 tsutsui return 0; 267 1.5 joff } 268 1.5 joff 269 1.5 joff static void 270 1.18 dsl hlcd_updatechar(struct hd44780_chip *sc, int daddr, int c) 271 1.5 joff { 272 1.7 joff int curdaddr, en, chipdaddr; 273 1.5 joff 274 1.5 joff curdaddr = COORD_TO_DADDR(sc->sc_screen.hlcd_curx, 275 1.5 joff sc->sc_screen.hlcd_cury); 276 1.7 joff en = DADDR_TO_CHIPNO(daddr); 277 1.7 joff chipdaddr = DADDR_TO_CHIPDADDR(daddr); 278 1.5 joff if (daddr != curdaddr) 279 1.7 joff hd44780_ir_write(sc, en, cmd_ddramset(chipdaddr)); 280 1.5 joff 281 1.7 joff hd44780_dr_write(sc, en, c); 282 1.5 joff 283 1.5 joff daddr++; 284 1.5 joff sc->sc_screen.hlcd_curx = DADDR_TO_COL(daddr); 285 1.5 joff sc->sc_screen.hlcd_cury = DADDR_TO_ROW(daddr); 286 1.5 joff } 287 1.5 joff 288 1.5 joff static void 289 1.17 dsl hlcd_redraw(void *arg) 290 1.5 joff { 291 1.5 joff struct hd44780_chip *sc = arg; 292 1.5 joff int len, crsridx, startidx, x, y; 293 1.7 joff int old_en, new_en; 294 1.20 tsutsui uint8_t *img, *curimg; 295 1.6 perry 296 1.5 joff if (sc->sc_curscr == NULL) 297 1.5 joff return; 298 1.5 joff 299 1.5 joff if (sc->sc_flags & HD_MULTILINE) 300 1.5 joff len = 2 * sc->sc_cols; 301 1.5 joff else 302 1.5 joff len = sc->sc_cols; 303 1.5 joff 304 1.7 joff if (sc->sc_flags & HD_MULTICHIP) 305 1.7 joff len = len * 2; 306 1.7 joff 307 1.7 joff x = sc->sc_screen.hlcd_curx; 308 1.7 joff y = sc->sc_screen.hlcd_cury; 309 1.7 joff old_en = DADDR_TO_CHIPNO(COORD_TO_DADDR(x, y)); 310 1.7 joff 311 1.5 joff img = sc->sc_screen.image; 312 1.5 joff curimg = sc->sc_curscr->image; 313 1.5 joff startidx = crsridx = 314 1.5 joff COORD_TO_IDX(sc->sc_screen.hlcd_curx, sc->sc_screen.hlcd_cury); 315 1.5 joff do { 316 1.5 joff if (img[crsridx] != curimg[crsridx]) { 317 1.7 joff hlcd_updatechar(sc, IDX_TO_DADDR(crsridx), 318 1.5 joff curimg[crsridx]); 319 1.5 joff img[crsridx] = curimg[crsridx]; 320 1.5 joff } 321 1.5 joff crsridx++; 322 1.5 joff if (crsridx == len) 323 1.5 joff crsridx = 0; 324 1.5 joff } while (crsridx != startidx); 325 1.6 perry 326 1.7 joff x = sc->sc_curscr->hlcd_curx; 327 1.7 joff y = sc->sc_curscr->hlcd_cury; 328 1.7 joff new_en = DADDR_TO_CHIPNO(COORD_TO_DADDR(x, y)); 329 1.7 joff 330 1.5 joff if (sc->sc_screen.hlcd_curx != sc->sc_curscr->hlcd_curx || 331 1.5 joff sc->sc_screen.hlcd_cury != sc->sc_curscr->hlcd_cury) { 332 1.7 joff 333 1.5 joff x = sc->sc_screen.hlcd_curx = sc->sc_curscr->hlcd_curx; 334 1.5 joff y = sc->sc_screen.hlcd_cury = sc->sc_curscr->hlcd_cury; 335 1.7 joff 336 1.7 joff hd44780_ir_write(sc, new_en, cmd_ddramset( 337 1.7 joff DADDR_TO_CHIPDADDR(COORD_TO_DADDR(x, y)))); 338 1.7 joff 339 1.7 joff } 340 1.7 joff 341 1.7 joff /* visible cursor switched to other chip */ 342 1.7 joff if (old_en != new_en && sc->sc_screen.hlcd_curon) { 343 1.7 joff hd44780_ir_write(sc, old_en, cmd_dispctl(1, 0, 0)); 344 1.7 joff hd44780_ir_write(sc, new_en, cmd_dispctl(1, 1, 1)); 345 1.5 joff } 346 1.5 joff 347 1.5 joff if (sc->sc_screen.hlcd_curon != sc->sc_curscr->hlcd_curon) { 348 1.5 joff sc->sc_screen.hlcd_curon = sc->sc_curscr->hlcd_curon; 349 1.5 joff if (sc->sc_screen.hlcd_curon) 350 1.7 joff hd44780_ir_write(sc, new_en, cmd_dispctl(1, 1, 1)); 351 1.5 joff else 352 1.7 joff hd44780_ir_write(sc, new_en, cmd_dispctl(1, 0, 0)); 353 1.5 joff } 354 1.5 joff 355 1.5 joff callout_schedule(&sc->redraw, 1); 356 1.5 joff } 357 1.5 joff 358 1.5 joff 359 1.1 soren /* 360 1.1 soren * Finish device attach. sc_writereg, sc_readreg and sc_flags must be properly 361 1.1 soren * initialized prior to this call. 362 1.1 soren */ 363 1.1 soren void 364 1.17 dsl hd44780_attach_subr(struct hd44780_chip *sc) 365 1.1 soren { 366 1.3 joff int err = 0; 367 1.20 tsutsui 368 1.1 soren /* Putc/getc are supposed to be set by platform-dependent code. */ 369 1.2 joff if ((sc->sc_writereg == NULL) || (sc->sc_readreg == NULL)) 370 1.1 soren sc->sc_dev_ok = 0; 371 1.1 soren 372 1.1 soren /* Make sure that HD_MAX_CHARS is enough. */ 373 1.5 joff if ((sc->sc_flags & HD_MULTILINE) && (2 * sc->sc_cols > HD_MAX_CHARS)) 374 1.1 soren sc->sc_dev_ok = 0; 375 1.5 joff else if (sc->sc_cols > HD_MAX_CHARS) 376 1.1 soren sc->sc_dev_ok = 0; 377 1.1 soren 378 1.1 soren if (sc->sc_dev_ok) { 379 1.6 perry if ((sc->sc_flags & HD_UP) == 0) 380 1.3 joff err = hd44780_init(sc); 381 1.3 joff if (err != 0) 382 1.20 tsutsui aprint_error_dev(sc->sc_dev, 383 1.20 tsutsui "LCD not responding or unconnected\n"); 384 1.1 soren } 385 1.5 joff 386 1.5 joff sc->sc_screen.hlcd_sc = sc; 387 1.6 perry 388 1.5 joff sc->sc_screen.image = malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK); 389 1.5 joff memset(sc->sc_screen.image, ' ', PAGE_SIZE); 390 1.5 joff sc->sc_curscr = NULL; 391 1.7 joff sc->sc_curchip = 0; 392 1.11 ad callout_init(&sc->redraw, 0); 393 1.5 joff callout_setfunc(&sc->redraw, hlcd_redraw, sc); 394 1.1 soren } 395 1.1 soren 396 1.22 nat void hd44780_detach(struct hd44780_chip *sc) 397 1.22 nat { 398 1.22 nat callout_stop(&sc->redraw); 399 1.22 nat callout_destroy(&sc->redraw); 400 1.22 nat 401 1.22 nat if (sc->sc_screen.image) 402 1.22 nat free(sc->sc_screen.image, M_DEVBUF); 403 1.22 nat } 404 1.22 nat 405 1.20 tsutsui int hd44780_init(struct hd44780_chip *sc) 406 1.7 joff { 407 1.7 joff int ret; 408 1.7 joff 409 1.7 joff ret = hd44780_chipinit(sc, 0); 410 1.20 tsutsui if (ret != 0 || !(sc->sc_flags & HD_MULTICHIP)) 411 1.20 tsutsui return ret; 412 1.20 tsutsui else 413 1.20 tsutsui return hd44780_chipinit(sc, 1); 414 1.7 joff } 415 1.7 joff 416 1.1 soren /* 417 1.1 soren * Initialize 4-bit or 8-bit connected device. 418 1.1 soren */ 419 1.3 joff int 420 1.20 tsutsui hd44780_chipinit(struct hd44780_chip *sc, uint32_t en) 421 1.1 soren { 422 1.20 tsutsui uint8_t cmd, dat; 423 1.1 soren 424 1.3 joff sc->sc_flags &= ~(HD_TIMEDOUT|HD_UP); 425 1.3 joff sc->sc_dev_ok = 1; 426 1.7 joff 427 1.1 soren cmd = cmd_init(sc->sc_flags & HD_8BIT); 428 1.7 joff hd44780_ir_write(sc, en, cmd); 429 1.2 joff delay(HD_TIMEOUT_LONG); 430 1.7 joff hd44780_ir_write(sc, en, cmd); 431 1.7 joff hd44780_ir_write(sc, en, cmd); 432 1.1 soren 433 1.1 soren cmd = cmd_funcset( 434 1.1 soren sc->sc_flags & HD_8BIT, 435 1.1 soren sc->sc_flags & HD_MULTILINE, 436 1.1 soren sc->sc_flags & HD_BIGFONT); 437 1.1 soren 438 1.1 soren if ((sc->sc_flags & HD_8BIT) == 0) 439 1.7 joff hd44780_ir_write(sc, en, cmd); 440 1.1 soren 441 1.2 joff sc->sc_flags |= HD_UP; 442 1.2 joff 443 1.7 joff hd44780_ir_write(sc, en, cmd); 444 1.7 joff hd44780_ir_write(sc, en, cmd_dispctl(0, 0, 0)); 445 1.7 joff hd44780_ir_write(sc, en, cmd_clear()); 446 1.7 joff hd44780_ir_write(sc, en, cmd_modset(1, 0)); 447 1.3 joff 448 1.3 joff if (sc->sc_flags & HD_TIMEDOUT) { 449 1.3 joff sc->sc_flags &= ~HD_UP; 450 1.3 joff return EIO; 451 1.6 perry } 452 1.3 joff 453 1.3 joff /* Turn display on and clear it. */ 454 1.7 joff hd44780_ir_write(sc, en, cmd_clear()); 455 1.7 joff hd44780_ir_write(sc, en, cmd_dispctl(1, 0, 0)); 456 1.3 joff 457 1.3 joff /* Attempt a simple probe for presence */ 458 1.7 joff hd44780_ir_write(sc, en, cmd_ddramset(0x5)); 459 1.7 joff hd44780_ir_write(sc, en, cmd_shift(0, 1)); 460 1.7 joff hd44780_busy_wait(sc, en); 461 1.24 nat if (!(sc->sc_flags & HD_WRITEONLY) && 462 1.24 nat (dat = hd44780_ir_read(sc, en) & 0x7f) != 0x6) { 463 1.3 joff sc->sc_dev_ok = 0; 464 1.3 joff sc->sc_flags &= ~HD_UP; 465 1.3 joff return EIO; 466 1.3 joff } 467 1.7 joff hd44780_ir_write(sc, en, cmd_ddramset(0)); 468 1.3 joff 469 1.3 joff return 0; 470 1.1 soren } 471 1.1 soren 472 1.1 soren /* 473 1.1 soren * Standard hd44780 ioctl() functions. 474 1.1 soren */ 475 1.1 soren int 476 1.17 dsl hd44780_ioctl_subr(struct hd44780_chip *sc, u_long cmd, void *data) 477 1.1 soren { 478 1.20 tsutsui uint8_t tmp; 479 1.1 soren int error = 0; 480 1.20 tsutsui uint32_t en = sc->sc_curchip; 481 1.1 soren 482 1.1 soren #define hd44780_io() ((struct hd44780_io *)data) 483 1.20 tsutsui #define hd44780_info() ((struct hd44780_info *)data) 484 1.20 tsutsui #define hd44780_ctrl() ((struct hd44780_dispctl *)data) 485 1.1 soren 486 1.1 soren switch (cmd) { 487 1.20 tsutsui case HLCD_CLEAR: 488 1.1 soren /* Clear the LCD. */ 489 1.20 tsutsui hd44780_ir_write(sc, en, cmd_clear()); 490 1.20 tsutsui break; 491 1.1 soren 492 1.20 tsutsui case HLCD_CURSOR_LEFT: 493 1.1 soren /* Move the cursor one position to the left. */ 494 1.20 tsutsui hd44780_ir_write(sc, en, cmd_shift(0, 0)); 495 1.1 soren break; 496 1.1 soren 497 1.20 tsutsui case HLCD_CURSOR_RIGHT: 498 1.1 soren /* Move the cursor one position to the right. */ 499 1.20 tsutsui hd44780_ir_write(sc, en, cmd_shift(0, 1)); 500 1.20 tsutsui break; 501 1.1 soren 502 1.20 tsutsui case HLCD_DISPCTL: 503 1.1 soren /* Control the LCD. */ 504 1.20 tsutsui hd44780_ir_write(sc, en, cmd_dispctl( 505 1.20 tsutsui hd44780_ctrl()->display_on, 506 1.20 tsutsui hd44780_ctrl()->cursor_on, 507 1.20 tsutsui hd44780_ctrl()->blink_on)); 508 1.20 tsutsui break; 509 1.1 soren 510 1.20 tsutsui case HLCD_GET_INFO: 511 1.1 soren /* Get LCD configuration. */ 512 1.20 tsutsui hd44780_info()->lines 513 1.20 tsutsui = (sc->sc_flags & HD_MULTILINE) ? 2 : 1; 514 1.20 tsutsui if (sc->sc_flags & HD_MULTICHIP) 515 1.20 tsutsui hd44780_info()->lines *= 2; 516 1.20 tsutsui hd44780_info()->phys_rows = sc->sc_cols; 517 1.20 tsutsui hd44780_info()->virt_rows = sc->sc_vcols; 518 1.20 tsutsui hd44780_info()->is_wide = sc->sc_flags & HD_8BIT; 519 1.20 tsutsui hd44780_info()->is_bigfont = sc->sc_flags & HD_BIGFONT; 520 1.20 tsutsui hd44780_info()->kp_present = sc->sc_flags & HD_KEYPAD; 521 1.20 tsutsui break; 522 1.1 soren 523 1.1 soren 524 1.20 tsutsui case HLCD_RESET: 525 1.1 soren /* Reset the LCD. */ 526 1.20 tsutsui error = hd44780_init(sc); 527 1.20 tsutsui break; 528 1.1 soren 529 1.20 tsutsui case HLCD_GET_CURSOR_POS: 530 1.1 soren /* Get the current cursor position. */ 531 1.20 tsutsui hd44780_io()->dat = (hd44780_ir_read(sc, en) & 0x7f); 532 1.20 tsutsui break; 533 1.1 soren 534 1.20 tsutsui case HLCD_SET_CURSOR_POS: 535 1.1 soren /* Set the cursor position. */ 536 1.20 tsutsui hd44780_ir_write(sc, en, cmd_ddramset(hd44780_io()->dat)); 537 1.20 tsutsui break; 538 1.1 soren 539 1.20 tsutsui case HLCD_GETC: 540 1.1 soren /* Get the value at the current cursor position. */ 541 1.20 tsutsui tmp = (hd44780_ir_read(sc, en) & 0x7f); 542 1.20 tsutsui hd44780_ir_write(sc, en, cmd_ddramset(tmp)); 543 1.20 tsutsui hd44780_io()->dat = hd44780_dr_read(sc, en); 544 1.20 tsutsui break; 545 1.1 soren 546 1.20 tsutsui case HLCD_PUTC: 547 1.1 soren /* Set the character at the cursor position + advance cursor. */ 548 1.20 tsutsui hd44780_dr_write(sc, en, hd44780_io()->dat); 549 1.20 tsutsui break; 550 1.1 soren 551 1.20 tsutsui case HLCD_SHIFT_LEFT: 552 1.1 soren /* Shift display left. */ 553 1.20 tsutsui hd44780_ir_write(sc, en, cmd_shift(1, 0)); 554 1.20 tsutsui break; 555 1.1 soren 556 1.20 tsutsui case HLCD_SHIFT_RIGHT: 557 1.1 soren /* Shift display right. */ 558 1.20 tsutsui hd44780_ir_write(sc, en, cmd_shift(1, 1)); 559 1.20 tsutsui break; 560 1.1 soren 561 1.20 tsutsui case HLCD_HOME: 562 1.1 soren /* Return home. */ 563 1.20 tsutsui hd44780_ir_write(sc, en, cmd_rethome()); 564 1.20 tsutsui break; 565 1.1 soren 566 1.20 tsutsui case HLCD_WRITE: 567 1.1 soren /* Write a string to the LCD virtual area. */ 568 1.20 tsutsui error = hd44780_ddram_io(sc, en, hd44780_io(), HD_DDRAM_WRITE); 569 1.20 tsutsui break; 570 1.1 soren 571 1.20 tsutsui case HLCD_READ: 572 1.1 soren /* Read LCD virtual area. */ 573 1.20 tsutsui error = hd44780_ddram_io(sc, en, hd44780_io(), HD_DDRAM_READ); 574 1.20 tsutsui break; 575 1.1 soren 576 1.20 tsutsui case HLCD_REDRAW: 577 1.1 soren /* Write to the LCD visible area. */ 578 1.20 tsutsui hd44780_ddram_redraw(sc, en, hd44780_io()); 579 1.20 tsutsui break; 580 1.1 soren 581 1.20 tsutsui case HLCD_WRITE_INST: 582 1.1 soren /* Write raw instruction. */ 583 1.20 tsutsui hd44780_ir_write(sc, en, hd44780_io()->dat); 584 1.20 tsutsui break; 585 1.1 soren 586 1.20 tsutsui case HLCD_WRITE_DATA: 587 1.1 soren /* Write raw data. */ 588 1.20 tsutsui hd44780_dr_write(sc, en, hd44780_io()->dat); 589 1.20 tsutsui break; 590 1.7 joff 591 1.20 tsutsui case HLCD_GET_CHIPNO: 592 1.7 joff /* Get current chip 0 or 1 (top or bottom) */ 593 1.20 tsutsui *(uint8_t *)data = sc->sc_curchip; 594 1.20 tsutsui break; 595 1.7 joff 596 1.20 tsutsui case HLCD_SET_CHIPNO: 597 1.7 joff /* Set current chip 0 or 1 (top or bottom) */ 598 1.20 tsutsui sc->sc_curchip = *(uint8_t *)data; 599 1.20 tsutsui break; 600 1.1 soren 601 1.20 tsutsui default: 602 1.20 tsutsui error = EINVAL; 603 1.1 soren } 604 1.1 soren 605 1.3 joff if (sc->sc_flags & HD_TIMEDOUT) 606 1.3 joff error = EIO; 607 1.3 joff 608 1.1 soren return error; 609 1.1 soren } 610 1.1 soren 611 1.1 soren /* 612 1.1 soren * Read/write particular area of the LCD screen. 613 1.1 soren */ 614 1.1 soren int 615 1.20 tsutsui hd44780_ddram_io(struct hd44780_chip *sc, uint32_t en, struct hd44780_io *io, 616 1.20 tsutsui uint8_t dir) 617 1.1 soren { 618 1.20 tsutsui uint8_t hi; 619 1.20 tsutsui uint8_t addr; 620 1.1 soren int error = 0; 621 1.20 tsutsui uint8_t i = 0; 622 1.1 soren 623 1.5 joff if (io->dat < sc->sc_vcols) { 624 1.5 joff hi = HD_ROW1_ADDR + sc->sc_vcols; 625 1.1 soren addr = HD_ROW1_ADDR + io->dat; 626 1.1 soren for (; (addr < hi) && (i < io->len); addr++, i++) { 627 1.7 joff hd44780_ir_write(sc, en, cmd_ddramset(addr)); 628 1.1 soren if (dir == HD_DDRAM_READ) 629 1.7 joff io->buf[i] = hd44780_dr_read(sc, en); 630 1.1 soren else 631 1.7 joff hd44780_dr_write(sc, en, io->buf[i]); 632 1.1 soren } 633 1.1 soren } 634 1.5 joff if (io->dat < 2 * sc->sc_vcols) { 635 1.5 joff hi = HD_ROW2_ADDR + sc->sc_vcols; 636 1.5 joff if (io->dat >= sc->sc_vcols) 637 1.5 joff addr = HD_ROW2_ADDR + io->dat - sc->sc_vcols; 638 1.1 soren else 639 1.1 soren addr = HD_ROW2_ADDR; 640 1.1 soren for (; (addr < hi) && (i < io->len); addr++, i++) { 641 1.7 joff hd44780_ir_write(sc, en, cmd_ddramset(addr)); 642 1.1 soren if (dir == HD_DDRAM_READ) 643 1.7 joff io->buf[i] = hd44780_dr_read(sc, en); 644 1.1 soren else 645 1.7 joff hd44780_dr_write(sc, en, io->buf[i]); 646 1.1 soren } 647 1.1 soren if (i < io->len) 648 1.1 soren io->len = i; 649 1.1 soren } else { 650 1.1 soren error = EINVAL; 651 1.1 soren } 652 1.1 soren return error; 653 1.1 soren } 654 1.1 soren 655 1.1 soren /* 656 1.1 soren * Write to the visible area of the display. 657 1.1 soren */ 658 1.1 soren void 659 1.20 tsutsui hd44780_ddram_redraw(struct hd44780_chip *sc, uint32_t en, 660 1.20 tsutsui struct hd44780_io *io) 661 1.1 soren { 662 1.20 tsutsui uint8_t i; 663 1.1 soren 664 1.7 joff hd44780_ir_write(sc, en, cmd_clear()); 665 1.7 joff hd44780_ir_write(sc, en, cmd_rethome()); 666 1.13 tsutsui hd44780_ir_write(sc, en, cmd_ddramset(HD_ROW1_ADDR)); 667 1.5 joff for (i = 0; (i < io->len) && (i < sc->sc_cols); i++) { 668 1.7 joff hd44780_dr_write(sc, en, io->buf[i]); 669 1.1 soren } 670 1.7 joff hd44780_ir_write(sc, en, cmd_ddramset(HD_ROW2_ADDR)); 671 1.1 soren for (; (i < io->len); i++) 672 1.7 joff hd44780_dr_write(sc, en, io->buf[i]); 673 1.1 soren } 674 1.1 soren 675 1.3 joff void 676 1.20 tsutsui hd44780_busy_wait(struct hd44780_chip *sc, uint32_t en) 677 1.3 joff { 678 1.3 joff int nloops = 100; 679 1.3 joff 680 1.3 joff if (sc->sc_flags & HD_TIMEDOUT) 681 1.3 joff return; 682 1.3 joff 683 1.20 tsutsui while (nloops-- && (hd44780_ir_read(sc, en) & BUSY_FLAG) == BUSY_FLAG) 684 1.20 tsutsui continue; 685 1.3 joff 686 1.3 joff if (nloops == 0) { 687 1.3 joff sc->sc_flags |= HD_TIMEDOUT; 688 1.3 joff sc->sc_dev_ok = 0; 689 1.3 joff } 690 1.3 joff } 691 1.3 joff 692 1.1 soren #if defined(HD44780_STD_WIDE) 693 1.1 soren /* 694 1.2 joff * Standard 8-bit version of 'sc_writereg' (8-bit port, 8-bit access) 695 1.1 soren */ 696 1.1 soren void 697 1.20 tsutsui hd44780_writereg(struct hd44780_chip *sc, uint32_t en, uint32_t reg, 698 1.20 tsutsui uint8_t cmd) 699 1.1 soren { 700 1.2 joff bus_space_tag_t iot = sc->sc_iot; 701 1.2 joff bus_space_handle_t ioh; 702 1.2 joff 703 1.3 joff if (sc->sc_dev_ok == 0) 704 1.3 joff return; 705 1.3 joff 706 1.2 joff if (reg == 0) 707 1.6 perry ioh = sc->sc_ioir; 708 1.2 joff else 709 1.2 joff ioh = sc->sc_iodr; 710 1.2 joff 711 1.1 soren bus_space_write_1(iot, ioh, 0x00, cmd); 712 1.2 joff delay(HD_TIMEOUT_NORMAL); 713 1.1 soren } 714 1.1 soren 715 1.1 soren /* 716 1.2 joff * Standard 8-bit version of 'sc_readreg' (8-bit port, 8-bit access) 717 1.1 soren */ 718 1.20 tsutsui uint8_t 719 1.20 tsutsui hd44780_readreg(struct hd44780_chip *sc, uint32_t en, uint32_t reg) 720 1.2 joff { 721 1.2 joff bus_space_tag_t iot = sc->sc_iot; 722 1.1 soren bus_space_handle_t ioh; 723 1.2 joff 724 1.3 joff if (sc->sc_dev_ok == 0) 725 1.3 joff return; 726 1.3 joff 727 1.2 joff if (reg == 0) 728 1.6 perry ioh = sc->sc_ioir; 729 1.2 joff else 730 1.2 joff ioh = sc->sc_iodr; 731 1.2 joff 732 1.2 joff delay(HD_TIMEOUT_NORMAL); 733 1.1 soren return bus_space_read_1(iot, ioh, 0x00); 734 1.1 soren } 735 1.1 soren #elif defined(HD44780_STD_SHORT) 736 1.1 soren /* 737 1.2 joff * Standard 4-bit version of 'sc_writereg' (4-bit port, 8-bit access) 738 1.1 soren */ 739 1.1 soren void 740 1.20 tsutsui hd44780_writereg(struct hd44780_chip *sc, uint32_t en, uint32_t reg, 741 1.20 tsutsui uint8_t cmd) 742 1.1 soren { 743 1.2 joff bus_space_tag_t iot = sc->sc_iot; 744 1.2 joff bus_space_handle_t ioh; 745 1.2 joff 746 1.3 joff if (sc->sc_dev_ok == 0) 747 1.3 joff return; 748 1.3 joff 749 1.2 joff if (reg == 0) 750 1.6 perry ioh = sc->sc_ioir; 751 1.2 joff else 752 1.2 joff ioh = sc->sc_iodr; 753 1.1 soren 754 1.1 soren bus_space_write_1(iot, ioh, 0x00, hi_bits(cmd)); 755 1.6 perry if (sc->sc_flags & HD_UP) 756 1.2 joff bus_space_write_1(iot, ioh, 0x00, lo_bits(cmd)); 757 1.2 joff delay(HD_TIMEOUT_NORMAL); 758 1.1 soren } 759 1.1 soren 760 1.1 soren /* 761 1.2 joff * Standard 4-bit version of 'sc_readreg' (4-bit port, 8-bit access) 762 1.1 soren */ 763 1.20 tsutsui uint8_t 764 1.20 tsutsui hd44780_readreg(struct hd44780_chip *sc, uint32_t en, uint32_t reg) 765 1.2 joff { 766 1.2 joff bus_space_tag_t iot = sc->sc_iot; 767 1.1 soren bus_space_handle_t ioh; 768 1.20 tsutsui uint8_t rd, dat; 769 1.2 joff 770 1.3 joff if (sc->sc_dev_ok == 0) 771 1.3 joff return; 772 1.3 joff 773 1.2 joff if (reg == 0) 774 1.6 perry ioh = sc->sc_ioir; 775 1.2 joff else 776 1.2 joff ioh = sc->sc_iodr; 777 1.1 soren 778 1.1 soren rd = bus_space_read_1(iot, ioh, 0x00); 779 1.1 soren dat = (rd & 0x0f) << 4; 780 1.1 soren rd = bus_space_read_1(iot, ioh, 0x00); 781 1.1 soren return (dat | (rd & 0x0f)); 782 1.1 soren } 783 1.1 soren #endif 784