1 1.13 tsutsui /* $NetBSD: lcd.c,v 1.13 2023/01/15 05:08:33 tsutsui Exp $ */ 2 1.8 tsutsui /* $OpenBSD: lcd.c,v 1.7 2015/02/10 22:42:35 miod Exp $ */ 3 1.1 nisimura 4 1.1 nisimura /*- 5 1.1 nisimura * Copyright (c) 2000 The NetBSD Foundation, Inc. 6 1.1 nisimura * All rights reserved. 7 1.1 nisimura * 8 1.1 nisimura * This code is derived from software contributed to The NetBSD Foundation 9 1.1 nisimura * by Tohru Nishimura. 10 1.1 nisimura * 11 1.1 nisimura * Redistribution and use in source and binary forms, with or without 12 1.1 nisimura * modification, are permitted provided that the following conditions 13 1.1 nisimura * are met: 14 1.1 nisimura * 1. Redistributions of source code must retain the above copyright 15 1.1 nisimura * notice, this list of conditions and the following disclaimer. 16 1.1 nisimura * 2. Redistributions in binary form must reproduce the above copyright 17 1.1 nisimura * notice, this list of conditions and the following disclaimer in the 18 1.1 nisimura * documentation and/or other materials provided with the distribution. 19 1.1 nisimura * 20 1.1 nisimura * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 1.1 nisimura * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 1.1 nisimura * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 1.1 nisimura * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 1.1 nisimura * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 1.1 nisimura * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 1.1 nisimura * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 1.1 nisimura * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 1.1 nisimura * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 1.1 nisimura * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 1.1 nisimura * POSSIBILITY OF SUCH DAMAGE. 31 1.1 nisimura */ 32 1.1 nisimura 33 1.1 nisimura #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 34 1.1 nisimura 35 1.13 tsutsui __KERNEL_RCSID(0, "$NetBSD: lcd.c,v 1.13 2023/01/15 05:08:33 tsutsui Exp $"); 36 1.1 nisimura 37 1.1 nisimura #include <sys/param.h> 38 1.1 nisimura #include <sys/systm.h> 39 1.8 tsutsui #include <sys/conf.h> 40 1.1 nisimura #include <sys/device.h> 41 1.8 tsutsui #include <sys/ioctl.h> 42 1.8 tsutsui #include <sys/fcntl.h> 43 1.8 tsutsui #include <sys/errno.h> 44 1.1 nisimura 45 1.8 tsutsui #include <machine/autoconf.h> 46 1.11 tsutsui #include <machine/board.h> 47 1.7 tsutsui #include <machine/cpu.h> 48 1.8 tsutsui #include <machine/lcd.h> 49 1.8 tsutsui 50 1.8 tsutsui #include "ioconf.h" 51 1.7 tsutsui 52 1.1 nisimura #define PIO1_MODE_OUTPUT 0x84 53 1.1 nisimura #define PIO1_MODE_INPUT 0x94 54 1.1 nisimura 55 1.1 nisimura #define POWER 0x10 56 1.1 nisimura 57 1.1 nisimura #define ENABLE 0x80 58 1.1 nisimura #define DISABLE 0x00 59 1.1 nisimura 60 1.1 nisimura #define WRITE_CMD (0x00 | 0x00) 61 1.1 nisimura #define WRITE_DATA (0x00 | 0x40) 62 1.1 nisimura #define READ_BUSY (0x20 | 0x00) 63 1.1 nisimura #define READ_DATA (0x20 | 0x40) 64 1.1 nisimura 65 1.1 nisimura #define LCD_INIT 0x38 66 1.1 nisimura #define LCD_ENTRY 0x06 67 1.1 nisimura #define LCD_ON 0x0c 68 1.1 nisimura #define LCD_CLS 0x01 69 1.1 nisimura #define LCD_HOME 0x02 70 1.1 nisimura #define LCD_LOCATE(X, Y) (((Y) & 1 ? 0xc0 : 0x80) | ((X) & 0x0f)) 71 1.1 nisimura 72 1.8 tsutsui #define LCD_MAXBUFLEN 80 73 1.8 tsutsui 74 1.1 nisimura struct pio { 75 1.10 tsutsui volatile uint8_t portA; 76 1.10 tsutsui volatile uint8_t portB; 77 1.10 tsutsui volatile uint8_t portC; 78 1.10 tsutsui volatile uint8_t cntrl; 79 1.1 nisimura }; 80 1.1 nisimura 81 1.8 tsutsui /* Autoconf stuff */ 82 1.8 tsutsui static int lcd_match(device_t, cfdata_t, void *); 83 1.8 tsutsui static void lcd_attach(device_t, device_t, void *); 84 1.8 tsutsui 85 1.12 tsutsui static dev_type_open(lcdopen); 86 1.12 tsutsui static dev_type_close(lcdclose); 87 1.12 tsutsui static dev_type_write(lcdwrite); 88 1.12 tsutsui static dev_type_ioctl(lcdioctl); 89 1.8 tsutsui 90 1.8 tsutsui const struct cdevsw lcd_cdevsw = { 91 1.8 tsutsui .d_open = lcdopen, 92 1.8 tsutsui .d_close = lcdclose, 93 1.8 tsutsui .d_read = noread, 94 1.8 tsutsui .d_write = lcdwrite, 95 1.8 tsutsui .d_ioctl = lcdioctl, 96 1.8 tsutsui .d_stop = nostop, 97 1.8 tsutsui .d_tty = notty, 98 1.8 tsutsui .d_poll = nopoll, 99 1.8 tsutsui .d_mmap = nommap, 100 1.8 tsutsui .d_kqfilter = nokqfilter, 101 1.8 tsutsui .d_discard = nodiscard, 102 1.8 tsutsui .d_flag = 0 103 1.8 tsutsui }; 104 1.8 tsutsui 105 1.8 tsutsui struct lcd_softc { 106 1.8 tsutsui device_t sc_dev; 107 1.8 tsutsui 108 1.8 tsutsui bool sc_opened; 109 1.8 tsutsui }; 110 1.8 tsutsui 111 1.8 tsutsui CFATTACH_DECL_NEW(lcd, sizeof(struct lcd_softc), 112 1.8 tsutsui lcd_match, lcd_attach, NULL, NULL); 113 1.8 tsutsui 114 1.12 tsutsui static void lcdbusywait(void); 115 1.12 tsutsui static void lcdput(int); 116 1.12 tsutsui static void lcdctrl(int); 117 1.12 tsutsui static void lcdshow(char *); 118 1.12 tsutsui static void greeting(void); 119 1.1 nisimura /* "1234567890123456" */ 120 1.1 nisimura static char lcd_boot_message1[] = " NetBSD/luna68k "; 121 1.1 nisimura static char lcd_boot_message2[] = " SX-9100/DT "; 122 1.1 nisimura 123 1.8 tsutsui /* 124 1.8 tsutsui * Autoconf functions 125 1.8 tsutsui */ 126 1.8 tsutsui static int 127 1.8 tsutsui lcd_match(device_t parent, cfdata_t cf, void *aux) 128 1.8 tsutsui { 129 1.8 tsutsui struct mainbus_attach_args *ma = aux; 130 1.8 tsutsui 131 1.8 tsutsui if (strcmp(ma->ma_name, lcd_cd.cd_name)) 132 1.8 tsutsui return 0; 133 1.8 tsutsui if (badaddr((void *)ma->ma_addr, 4)) 134 1.8 tsutsui return 0; 135 1.8 tsutsui return 1; 136 1.8 tsutsui } 137 1.8 tsutsui 138 1.8 tsutsui static void 139 1.8 tsutsui lcd_attach(device_t parent, device_t self, void *aux) 140 1.8 tsutsui { 141 1.8 tsutsui 142 1.8 tsutsui printf("\n"); 143 1.8 tsutsui 144 1.8 tsutsui /* Say hello to the world on LCD. */ 145 1.8 tsutsui greeting(); 146 1.8 tsutsui } 147 1.8 tsutsui 148 1.8 tsutsui /* 149 1.8 tsutsui * open/close/write/ioctl 150 1.8 tsutsui */ 151 1.12 tsutsui static int 152 1.8 tsutsui lcdopen(dev_t dev, int flags, int fmt, struct lwp *l) 153 1.8 tsutsui { 154 1.8 tsutsui int unit; 155 1.8 tsutsui struct lcd_softc *sc; 156 1.8 tsutsui 157 1.8 tsutsui unit = minor(dev); 158 1.8 tsutsui sc = device_lookup_private(&lcd_cd, unit); 159 1.8 tsutsui if (sc == NULL) 160 1.8 tsutsui return ENXIO; 161 1.8 tsutsui if (sc->sc_opened) 162 1.8 tsutsui return EBUSY; 163 1.8 tsutsui sc->sc_opened = true; 164 1.8 tsutsui 165 1.8 tsutsui return 0; 166 1.8 tsutsui } 167 1.8 tsutsui 168 1.12 tsutsui static int 169 1.8 tsutsui lcdclose(dev_t dev, int flags, int fmt, struct lwp *l) 170 1.8 tsutsui { 171 1.8 tsutsui int unit; 172 1.8 tsutsui struct lcd_softc *sc; 173 1.8 tsutsui 174 1.8 tsutsui unit = minor(dev); 175 1.8 tsutsui sc = device_lookup_private(&lcd_cd, unit); 176 1.8 tsutsui sc->sc_opened = false; 177 1.8 tsutsui 178 1.8 tsutsui return 0; 179 1.8 tsutsui } 180 1.8 tsutsui 181 1.12 tsutsui static int 182 1.8 tsutsui lcdwrite(dev_t dev, struct uio *uio, int flag) 183 1.8 tsutsui { 184 1.8 tsutsui int error; 185 1.8 tsutsui size_t len, i; 186 1.8 tsutsui char buf[LCD_MAXBUFLEN]; 187 1.8 tsutsui 188 1.8 tsutsui len = uio->uio_resid; 189 1.8 tsutsui 190 1.8 tsutsui if (len > LCD_MAXBUFLEN) 191 1.8 tsutsui return EIO; 192 1.8 tsutsui 193 1.8 tsutsui error = uiomove(buf, len, uio); 194 1.8 tsutsui if (error) 195 1.8 tsutsui return EIO; 196 1.8 tsutsui 197 1.8 tsutsui for (i = 0; i < len; i++) { 198 1.8 tsutsui lcdput((int)buf[i]); 199 1.8 tsutsui } 200 1.8 tsutsui 201 1.8 tsutsui return 0; 202 1.8 tsutsui } 203 1.8 tsutsui 204 1.12 tsutsui static int 205 1.8 tsutsui lcdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) 206 1.8 tsutsui { 207 1.8 tsutsui int val; 208 1.8 tsutsui 209 1.8 tsutsui /* check if the device opened with write mode */ 210 1.8 tsutsui switch (cmd) { 211 1.8 tsutsui case LCDCLS: 212 1.8 tsutsui case LCDHOME: 213 1.8 tsutsui case LCDMODE: 214 1.8 tsutsui case LCDDISP: 215 1.8 tsutsui case LCDMOVE: 216 1.8 tsutsui case LCDSEEK: 217 1.8 tsutsui case LCDRESTORE: 218 1.9 mrg if ((flag & FWRITE) == 0) 219 1.9 mrg return EACCES; 220 1.8 tsutsui } 221 1.8 tsutsui 222 1.8 tsutsui switch (cmd) { 223 1.8 tsutsui case LCDCLS: 224 1.8 tsutsui lcdctrl(LCD_CLS); 225 1.8 tsutsui break; 226 1.8 tsutsui 227 1.8 tsutsui case LCDHOME: 228 1.8 tsutsui lcdctrl(LCD_HOME); 229 1.8 tsutsui break; 230 1.8 tsutsui 231 1.8 tsutsui case LCDMODE: 232 1.8 tsutsui val = *(int *)addr; 233 1.8 tsutsui switch (val) { 234 1.8 tsutsui case LCDMODE_C_LEFT: 235 1.8 tsutsui case LCDMODE_C_RIGHT: 236 1.8 tsutsui case LCDMODE_D_LEFT: 237 1.8 tsutsui case LCDMODE_D_RIGHT: 238 1.8 tsutsui lcdctrl(val); 239 1.8 tsutsui break; 240 1.8 tsutsui default: 241 1.8 tsutsui return EINVAL; 242 1.8 tsutsui } 243 1.8 tsutsui break; 244 1.8 tsutsui 245 1.8 tsutsui case LCDDISP: 246 1.8 tsutsui val = *(int *)addr; 247 1.8 tsutsui if ((val & 0x7) != val) 248 1.8 tsutsui return EINVAL; 249 1.8 tsutsui lcdctrl(val | 0x8); 250 1.8 tsutsui break; 251 1.8 tsutsui 252 1.8 tsutsui case LCDMOVE: 253 1.8 tsutsui val = *(int *)addr; 254 1.8 tsutsui switch (val) { 255 1.8 tsutsui case LCDMOVE_C_LEFT: 256 1.8 tsutsui case LCDMOVE_C_RIGHT: 257 1.8 tsutsui case LCDMOVE_D_LEFT: 258 1.8 tsutsui case LCDMOVE_D_RIGHT: 259 1.8 tsutsui lcdctrl(val); 260 1.8 tsutsui break; 261 1.8 tsutsui default: 262 1.8 tsutsui return EINVAL; 263 1.8 tsutsui } 264 1.8 tsutsui break; 265 1.8 tsutsui 266 1.8 tsutsui case LCDSEEK: 267 1.8 tsutsui val = *(int *)addr & 0x7f; 268 1.8 tsutsui lcdctrl(val | 0x80); 269 1.8 tsutsui break; 270 1.8 tsutsui 271 1.8 tsutsui case LCDRESTORE: 272 1.8 tsutsui greeting(); 273 1.8 tsutsui break; 274 1.8 tsutsui 275 1.8 tsutsui default: 276 1.8 tsutsui return ENOTTY; 277 1.8 tsutsui } 278 1.8 tsutsui return EPASSTHROUGH; 279 1.8 tsutsui } 280 1.8 tsutsui 281 1.12 tsutsui static void 282 1.6 cegger lcdbusywait(void) 283 1.1 nisimura { 284 1.11 tsutsui struct pio *p1 = (struct pio *)OBIO_PIO1_BASE; 285 1.1 nisimura int msb, s; 286 1.1 nisimura 287 1.1 nisimura s = splhigh(); 288 1.1 nisimura p1->cntrl = PIO1_MODE_INPUT; 289 1.1 nisimura p1->portC = POWER | READ_BUSY | ENABLE; 290 1.1 nisimura splx(s); 291 1.1 nisimura 292 1.1 nisimura do { 293 1.1 nisimura msb = p1->portA & ENABLE; 294 1.1 nisimura delay(5); 295 1.1 nisimura } while (msb != 0); 296 1.1 nisimura 297 1.1 nisimura s = splhigh(); 298 1.1 nisimura p1->portC = POWER | READ_BUSY | DISABLE; 299 1.1 nisimura splx(s); 300 1.13 tsutsui } 301 1.1 nisimura 302 1.12 tsutsui static void 303 1.5 dsl lcdput(int cc) 304 1.1 nisimura { 305 1.11 tsutsui struct pio *p1 = (struct pio *)OBIO_PIO1_BASE; 306 1.1 nisimura int s; 307 1.1 nisimura 308 1.1 nisimura lcdbusywait(); 309 1.1 nisimura 310 1.1 nisimura s = splhigh(); 311 1.1 nisimura p1->cntrl = PIO1_MODE_OUTPUT; 312 1.1 nisimura 313 1.1 nisimura p1->portC = POWER | WRITE_DATA | ENABLE; 314 1.1 nisimura p1->portA = cc; 315 1.1 nisimura p1->portC = POWER | WRITE_DATA | DISABLE; 316 1.1 nisimura splx(s); 317 1.1 nisimura } 318 1.1 nisimura 319 1.12 tsutsui static void 320 1.5 dsl lcdctrl(int cc) 321 1.1 nisimura { 322 1.11 tsutsui struct pio *p1 = (struct pio *)OBIO_PIO1_BASE; 323 1.1 nisimura int s; 324 1.1 nisimura 325 1.1 nisimura lcdbusywait(); 326 1.1 nisimura 327 1.1 nisimura s = splhigh(); 328 1.1 nisimura p1->cntrl = PIO1_MODE_OUTPUT; 329 1.1 nisimura 330 1.1 nisimura p1->portC = POWER | WRITE_CMD | ENABLE; 331 1.1 nisimura p1->portA = cc; 332 1.1 nisimura p1->portC = POWER | WRITE_CMD | DISABLE; 333 1.1 nisimura splx(s); 334 1.1 nisimura } 335 1.1 nisimura 336 1.12 tsutsui static void 337 1.5 dsl lcdshow(char *s) 338 1.1 nisimura { 339 1.1 nisimura int cc; 340 1.1 nisimura 341 1.1 nisimura while ((cc = *s++) != '\0') 342 1.1 nisimura lcdput(cc); 343 1.1 nisimura } 344 1.1 nisimura 345 1.12 tsutsui static void 346 1.6 cegger greeting(void) 347 1.1 nisimura { 348 1.10 tsutsui 349 1.1 nisimura lcdctrl(LCD_INIT); 350 1.1 nisimura lcdctrl(LCD_ENTRY); 351 1.1 nisimura lcdctrl(LCD_ON); 352 1.1 nisimura 353 1.1 nisimura lcdctrl(LCD_CLS); 354 1.1 nisimura lcdctrl(LCD_HOME); 355 1.1 nisimura 356 1.1 nisimura lcdctrl(LCD_LOCATE(0, 0)); 357 1.1 nisimura lcdshow(lcd_boot_message1); 358 1.1 nisimura lcdctrl(LCD_LOCATE(0, 1)); 359 1.7 tsutsui if (machtype == LUNA_II) 360 1.7 tsutsui lcd_boot_message2[13] = '2'; 361 1.1 nisimura lcdshow(lcd_boot_message2); 362 1.1 nisimura } 363