1*0408a2d2Sderaadt /* $OpenBSD: lcd.c,v 1.11 2021/10/24 09:18:51 deraadt Exp $ */
202b01b5eSaoyama /* $NetBSD: lcd.c,v 1.2 2000/01/07 05:13:08 nisimura Exp $ */
302b01b5eSaoyama
402b01b5eSaoyama /*-
502b01b5eSaoyama * Copyright (c) 2000 The NetBSD Foundation, Inc.
602b01b5eSaoyama * All rights reserved.
702b01b5eSaoyama *
802b01b5eSaoyama * This code is derived from software contributed to The NetBSD Foundation
902b01b5eSaoyama * by Tohru Nishimura.
1002b01b5eSaoyama *
1102b01b5eSaoyama * Redistribution and use in source and binary forms, with or without
1202b01b5eSaoyama * modification, are permitted provided that the following conditions
1302b01b5eSaoyama * are met:
1402b01b5eSaoyama * 1. Redistributions of source code must retain the above copyright
1502b01b5eSaoyama * notice, this list of conditions and the following disclaimer.
1602b01b5eSaoyama * 2. Redistributions in binary form must reproduce the above copyright
1702b01b5eSaoyama * notice, this list of conditions and the following disclaimer in the
1802b01b5eSaoyama * documentation and/or other materials provided with the distribution.
1902b01b5eSaoyama *
2002b01b5eSaoyama * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2102b01b5eSaoyama * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2202b01b5eSaoyama * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2302b01b5eSaoyama * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2402b01b5eSaoyama * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2502b01b5eSaoyama * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2602b01b5eSaoyama * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2702b01b5eSaoyama * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2802b01b5eSaoyama * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2902b01b5eSaoyama * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3002b01b5eSaoyama * POSSIBILITY OF SUCH DAMAGE.
3102b01b5eSaoyama */
3202b01b5eSaoyama
3302b01b5eSaoyama #include <sys/param.h>
3402b01b5eSaoyama #include <sys/systm.h>
3502b01b5eSaoyama #include <sys/device.h>
360f82e710Saoyama #include <sys/ioctl.h>
370f82e710Saoyama #include <sys/fcntl.h>
380f82e710Saoyama
39b3e2baf6Saoyama #include <machine/autoconf.h>
408aed167bSmiod #include <machine/board.h>
410f82e710Saoyama #include <machine/conf.h>
420f82e710Saoyama #include <machine/lcd.h>
4302b01b5eSaoyama
4402b01b5eSaoyama #define PIO1_MODE_OUTPUT 0x84
4502b01b5eSaoyama #define PIO1_MODE_INPUT 0x94
4602b01b5eSaoyama
4702b01b5eSaoyama #define POWER 0x10
4802b01b5eSaoyama
4902b01b5eSaoyama #define ENABLE 0x80
5002b01b5eSaoyama #define DISABLE 0x00
5102b01b5eSaoyama
5202b01b5eSaoyama #define WRITE_CMD (0x00 | 0x00)
5302b01b5eSaoyama #define WRITE_DATA (0x00 | 0x40)
5402b01b5eSaoyama #define READ_BUSY (0x20 | 0x00)
5502b01b5eSaoyama #define READ_DATA (0x20 | 0x40)
5602b01b5eSaoyama
5702b01b5eSaoyama #define LCD_INIT 0x38
5802b01b5eSaoyama #define LCD_ENTRY 0x06
5902b01b5eSaoyama #define LCD_ON 0x0c
6002b01b5eSaoyama #define LCD_CLS 0x01
6102b01b5eSaoyama #define LCD_HOME 0x02
6202b01b5eSaoyama #define LCD_LOCATE(X, Y) (((Y) & 1 ? 0xc0 : 0x80) | ((X) & 0x0f))
6302b01b5eSaoyama
640f82e710Saoyama #define LCD_MAXBUFLEN 80
650f82e710Saoyama
6602b01b5eSaoyama struct pio {
6702b01b5eSaoyama volatile u_int8_t portA;
6802b01b5eSaoyama volatile unsigned : 24;
6902b01b5eSaoyama volatile u_int8_t portB;
7002b01b5eSaoyama volatile unsigned : 24;
7102b01b5eSaoyama volatile u_int8_t portC;
7202b01b5eSaoyama volatile unsigned : 24;
7302b01b5eSaoyama volatile u_int8_t cntrl;
7402b01b5eSaoyama volatile unsigned : 24;
7502b01b5eSaoyama };
7602b01b5eSaoyama
77b3e2baf6Saoyama /* Autoconf stuff */
78b3e2baf6Saoyama int lcd_match(struct device *, void *, void *);
79b3e2baf6Saoyama void lcd_attach(struct device *, struct device *, void *);
80b3e2baf6Saoyama
81b3e2baf6Saoyama struct lcd_softc {
82b3e2baf6Saoyama struct device sc_dev;
83b3e2baf6Saoyama int sc_opened;
84b3e2baf6Saoyama };
85b3e2baf6Saoyama
868aed167bSmiod const struct cfattach lcd_ca = {
87b3e2baf6Saoyama sizeof(struct lcd_softc), lcd_match, lcd_attach
88b3e2baf6Saoyama };
89b3e2baf6Saoyama
90b3e2baf6Saoyama struct cfdriver lcd_cd = {
91*0408a2d2Sderaadt NULL, "lcd", DV_DULL,
92b3e2baf6Saoyama };
93b3e2baf6Saoyama
940f82e710Saoyama /* Internal prototypes */
9502b01b5eSaoyama void lcdbusywait(void);
9602b01b5eSaoyama void lcdput(int);
9702b01b5eSaoyama void lcdctrl(int);
9802b01b5eSaoyama void lcdshow(const char *);
9902b01b5eSaoyama void greeting(void);
1000f82e710Saoyama
1010f82e710Saoyama /* Internal variables */
10202b01b5eSaoyama /* "1234567890123456" */
10302b01b5eSaoyama static const char lcd_boot_message1[] = "OpenBSD/luna88k ";
10402b01b5eSaoyama static const char lcd_boot_message2[] = " SX-9100/DT ";
10502b01b5eSaoyama
1060f82e710Saoyama /*
107b3e2baf6Saoyama * Autoconf functions
108b3e2baf6Saoyama */
109b3e2baf6Saoyama int
lcd_match(struct device * parent,void * cf,void * aux)11080bc78ddSaoyama lcd_match(struct device *parent, void *cf, void *aux)
111b3e2baf6Saoyama {
112b3e2baf6Saoyama struct mainbus_attach_args *ma = aux;
113b3e2baf6Saoyama
114b3e2baf6Saoyama if (strcmp(ma->ma_name, lcd_cd.cd_name))
115b3e2baf6Saoyama return 0;
116b3e2baf6Saoyama if (badaddr((vaddr_t)ma->ma_addr, 4))
117b3e2baf6Saoyama return 0;
118b3e2baf6Saoyama return 1;
119b3e2baf6Saoyama }
120b3e2baf6Saoyama
121b3e2baf6Saoyama void
lcd_attach(struct device * parent,struct device * self,void * aux)12280bc78ddSaoyama lcd_attach(struct device *parent, struct device *self, void *aux)
123b3e2baf6Saoyama {
124b3e2baf6Saoyama printf("\n");
125b3e2baf6Saoyama
126b3e2baf6Saoyama /* Say hello to the world on LCD. */
127b3e2baf6Saoyama greeting();
128b3e2baf6Saoyama }
129b3e2baf6Saoyama
130b3e2baf6Saoyama /*
1310f82e710Saoyama * open/close/write/ioctl
1320f82e710Saoyama */
1330f82e710Saoyama
1340f82e710Saoyama int
lcdopen(dev_t dev,int flags,int fmt,struct proc * p)13580bc78ddSaoyama lcdopen(dev_t dev, int flags, int fmt, struct proc *p)
1360f82e710Saoyama {
137b3e2baf6Saoyama int unit = minor(dev);
138b3e2baf6Saoyama struct lcd_softc *sc;
139b3e2baf6Saoyama
140b3e2baf6Saoyama if (unit >= lcd_cd.cd_ndevs)
1410f82e710Saoyama return ENXIO;
142b3e2baf6Saoyama if ((sc = lcd_cd.cd_devs[unit]) == NULL)
143b3e2baf6Saoyama return ENXIO;
144b3e2baf6Saoyama if (sc->sc_opened)
1450f82e710Saoyama return EBUSY;
146b3e2baf6Saoyama sc->sc_opened = 1;
1470f82e710Saoyama
1480f82e710Saoyama return 0;
1490f82e710Saoyama }
1500f82e710Saoyama
1510f82e710Saoyama int
lcdclose(dev_t dev,int flags,int fmt,struct proc * p)15280bc78ddSaoyama lcdclose(dev_t dev, int flags, int fmt, struct proc *p)
1530f82e710Saoyama {
154b3e2baf6Saoyama int unit = minor(dev);
155b3e2baf6Saoyama struct lcd_softc *sc;
156b3e2baf6Saoyama
157b3e2baf6Saoyama sc = lcd_cd.cd_devs[unit];
158b3e2baf6Saoyama sc->sc_opened = 0;
1590f82e710Saoyama
1600f82e710Saoyama return 0;
1610f82e710Saoyama }
1620f82e710Saoyama
1630f82e710Saoyama int
lcdwrite(dev_t dev,struct uio * uio,int flag)16480bc78ddSaoyama lcdwrite(dev_t dev, struct uio *uio, int flag)
1650f82e710Saoyama {
166e395704dSmiod int error;
167c368aea8Saoyama size_t len, i;
1680f82e710Saoyama char buf[LCD_MAXBUFLEN];
1690f82e710Saoyama
170c368aea8Saoyama len = uio->uio_resid;
1710f82e710Saoyama
172e395704dSmiod if (len > LCD_MAXBUFLEN)
1730f82e710Saoyama return EIO;
1740f82e710Saoyama
175c368aea8Saoyama error = uiomove(buf, len, uio);
1760f82e710Saoyama if (error)
1770f82e710Saoyama return EIO;
1780f82e710Saoyama
1790f82e710Saoyama for (i = 0; i < len; i++) {
1800f82e710Saoyama lcdput((int)buf[i]);
1810f82e710Saoyama }
1820f82e710Saoyama
1830f82e710Saoyama return 0;
1840f82e710Saoyama }
1850f82e710Saoyama
1860f82e710Saoyama int
lcdioctl(dev_t dev,u_long cmd,caddr_t addr,int flag,struct proc * p)18780bc78ddSaoyama lcdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
1880f82e710Saoyama {
1890f82e710Saoyama int val;
1900f82e710Saoyama
1910f82e710Saoyama /* check if the device opened with write mode */
1920f82e710Saoyama switch(cmd) {
1930f82e710Saoyama case LCDCLS:
1940f82e710Saoyama case LCDHOME:
1950f82e710Saoyama case LCDMODE:
1960f82e710Saoyama case LCDDISP:
1970f82e710Saoyama case LCDMOVE:
1980f82e710Saoyama case LCDSEEK:
1990f82e710Saoyama case LCDRESTORE:
2000f82e710Saoyama if ((flag & FWRITE) == 0)
2010f82e710Saoyama return EACCES;
2020f82e710Saoyama break;
2030f82e710Saoyama }
2040f82e710Saoyama
2050f82e710Saoyama switch(cmd) {
2060f82e710Saoyama case LCDCLS:
2070f82e710Saoyama lcdctrl(LCD_CLS);
2080f82e710Saoyama break;
2090f82e710Saoyama
2100f82e710Saoyama case LCDHOME:
2110f82e710Saoyama lcdctrl(LCD_HOME);
2120f82e710Saoyama break;
2130f82e710Saoyama
2140f82e710Saoyama case LCDMODE:
2150f82e710Saoyama val = *(int *)addr;
2160f82e710Saoyama switch (val) {
2170f82e710Saoyama case LCDMODE_C_LEFT:
2180f82e710Saoyama case LCDMODE_C_RIGHT:
2190f82e710Saoyama case LCDMODE_D_LEFT:
2200f82e710Saoyama case LCDMODE_D_RIGHT:
2210f82e710Saoyama lcdctrl(val);
2220f82e710Saoyama break;
2230f82e710Saoyama default:
2240f82e710Saoyama return EINVAL;
2250f82e710Saoyama }
2260f82e710Saoyama break;
2270f82e710Saoyama
2280f82e710Saoyama case LCDDISP:
2290f82e710Saoyama val = *(int *)addr;
2300f82e710Saoyama if ((val & 0x7) != val)
2310f82e710Saoyama return EINVAL;
2320f82e710Saoyama lcdctrl(val | 0x8);
2330f82e710Saoyama break;
2340f82e710Saoyama
2350f82e710Saoyama case LCDMOVE:
2360f82e710Saoyama val = *(int *)addr;
2370f82e710Saoyama switch (val) {
2380f82e710Saoyama case LCDMOVE_C_LEFT:
2390f82e710Saoyama case LCDMOVE_C_RIGHT:
2400f82e710Saoyama case LCDMOVE_D_LEFT:
2410f82e710Saoyama case LCDMOVE_D_RIGHT:
2420f82e710Saoyama lcdctrl(val);
2430f82e710Saoyama break;
2440f82e710Saoyama default:
2450f82e710Saoyama return EINVAL;
2460f82e710Saoyama }
2470f82e710Saoyama break;
2480f82e710Saoyama
2490f82e710Saoyama case LCDSEEK:
2500f82e710Saoyama val = *(int *)addr & 0x7f;
2510f82e710Saoyama lcdctrl(val | 0x80);
2520f82e710Saoyama break;
2530f82e710Saoyama
2540f82e710Saoyama case LCDRESTORE:
2550f82e710Saoyama greeting();
2560f82e710Saoyama break;
2570f82e710Saoyama
2580f82e710Saoyama default:
2590f82e710Saoyama return ENOTTY;
2600f82e710Saoyama }
2610f82e710Saoyama return 0;
2620f82e710Saoyama }
2630f82e710Saoyama
2640f82e710Saoyama /*
2650f82e710Saoyama * Internal functions
2660f82e710Saoyama */
26702b01b5eSaoyama void
lcdbusywait()26802b01b5eSaoyama lcdbusywait()
26902b01b5eSaoyama {
2708aed167bSmiod struct pio *p1 = (struct pio *)OBIO_PIO1_BASE;
27102b01b5eSaoyama int msb, s;
27202b01b5eSaoyama
27302b01b5eSaoyama s = splhigh();
27402b01b5eSaoyama p1->cntrl = PIO1_MODE_INPUT;
27502b01b5eSaoyama p1->portC = POWER | READ_BUSY | ENABLE;
27602b01b5eSaoyama splx(s);
27702b01b5eSaoyama
27802b01b5eSaoyama do {
27902b01b5eSaoyama msb = p1->portA & ENABLE;
28002b01b5eSaoyama delay(5);
28102b01b5eSaoyama } while (msb != 0);
28202b01b5eSaoyama
28302b01b5eSaoyama s = splhigh();
28402b01b5eSaoyama p1->portC = POWER | READ_BUSY | DISABLE;
28502b01b5eSaoyama splx(s);
28602b01b5eSaoyama }
28702b01b5eSaoyama
28802b01b5eSaoyama void
lcdput(int cc)28980bc78ddSaoyama lcdput(int cc)
29002b01b5eSaoyama {
2918aed167bSmiod struct pio *p1 = (struct pio *)OBIO_PIO1_BASE;
29202b01b5eSaoyama int s;
29302b01b5eSaoyama
29402b01b5eSaoyama lcdbusywait();
29502b01b5eSaoyama
29602b01b5eSaoyama s = splhigh();
29702b01b5eSaoyama p1->cntrl = PIO1_MODE_OUTPUT;
29802b01b5eSaoyama
29902b01b5eSaoyama p1->portC = POWER | WRITE_DATA | ENABLE;
30002b01b5eSaoyama p1->portA = cc;
30102b01b5eSaoyama p1->portC = POWER | WRITE_DATA | DISABLE;
30202b01b5eSaoyama splx(s);
30302b01b5eSaoyama }
30402b01b5eSaoyama
30502b01b5eSaoyama void
lcdctrl(int cc)30680bc78ddSaoyama lcdctrl(int cc)
30702b01b5eSaoyama {
3088aed167bSmiod struct pio *p1 = (struct pio *)OBIO_PIO1_BASE;
30902b01b5eSaoyama int s;
31002b01b5eSaoyama
31102b01b5eSaoyama lcdbusywait();
31202b01b5eSaoyama
31302b01b5eSaoyama s = splhigh();
31402b01b5eSaoyama p1->cntrl = PIO1_MODE_OUTPUT;
31502b01b5eSaoyama
31602b01b5eSaoyama p1->portC = POWER | WRITE_CMD | ENABLE;
31702b01b5eSaoyama p1->portA = cc;
31802b01b5eSaoyama p1->portC = POWER | WRITE_CMD | DISABLE;
31902b01b5eSaoyama splx(s);
32002b01b5eSaoyama }
32102b01b5eSaoyama
32202b01b5eSaoyama void
lcdshow(const char * s)32380bc78ddSaoyama lcdshow(const char *s)
32402b01b5eSaoyama {
32502b01b5eSaoyama int cc;
32602b01b5eSaoyama
32702b01b5eSaoyama while ((cc = *s++) != '\0')
32802b01b5eSaoyama lcdput(cc);
32902b01b5eSaoyama }
33002b01b5eSaoyama
33102b01b5eSaoyama void
greeting()33202b01b5eSaoyama greeting()
33302b01b5eSaoyama {
33402b01b5eSaoyama lcdctrl(LCD_INIT);
33502b01b5eSaoyama lcdctrl(LCD_ENTRY);
33602b01b5eSaoyama lcdctrl(LCD_ON);
33702b01b5eSaoyama
33802b01b5eSaoyama lcdctrl(LCD_CLS);
33902b01b5eSaoyama lcdctrl(LCD_HOME);
34002b01b5eSaoyama
34102b01b5eSaoyama lcdctrl(LCD_LOCATE(0, 0));
34202b01b5eSaoyama lcdshow(lcd_boot_message1);
34302b01b5eSaoyama lcdctrl(LCD_LOCATE(0, 1));
34402b01b5eSaoyama lcdshow(lcd_boot_message2);
34502b01b5eSaoyama }
346