xref: /openbsd-src/sys/arch/luna88k/dev/lcd.c (revision 0408a2d27c0ed803aa8e342f69800dbe2b30d80d)
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