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