xref: /openbsd/sys/arch/luna88k/dev/lcd.c (revision 5af055cd)
1 /* $OpenBSD: lcd.c,v 1.7 2015/02/10 22:42:35 miod 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/conf.h>
41 #include <machine/lcd.h>
42 
43 #define PIO1_MODE_OUTPUT	0x84
44 #define PIO1_MODE_INPUT		0x94
45 
46 #define POWER	0x10
47 
48 #define ENABLE	0x80
49 #define DISABLE	0x00
50 
51 #define WRITE_CMD	(0x00 | 0x00)
52 #define WRITE_DATA	(0x00 | 0x40)
53 #define READ_BUSY	(0x20 | 0x00)
54 #define READ_DATA	(0x20 | 0x40)
55 
56 #define LCD_INIT	0x38
57 #define LCD_ENTRY	0x06
58 #define LCD_ON		0x0c
59 #define LCD_CLS		0x01
60 #define LCD_HOME	0x02
61 #define LCD_LOCATE(X, Y)	(((Y) & 1 ? 0xc0 : 0x80) | ((X) & 0x0f))
62 
63 #define LCD_MAXBUFLEN	80
64 
65 struct pio {
66 	volatile u_int8_t portA;
67         volatile unsigned : 24;
68 	volatile u_int8_t portB;
69         volatile unsigned : 24;
70 	volatile u_int8_t portC;
71         volatile unsigned : 24;
72 	volatile u_int8_t cntrl;
73         volatile unsigned : 24;
74 };
75 
76 /* Autoconf stuff */
77 int  lcd_match(struct device *, void *, void *);
78 void lcd_attach(struct device *, struct device *, void *);
79 
80 struct lcd_softc {
81 	struct device sc_dev;
82 	int sc_opened;
83 };
84 
85 struct cfattach lcd_ca = {
86 	sizeof(struct lcd_softc), lcd_match, lcd_attach
87 };
88 
89 struct cfdriver lcd_cd = {
90 	NULL, "lcd", DV_DULL, 0
91 };
92 
93 /* Internal prototypes */
94 void lcdbusywait(void);
95 void lcdput(int);
96 void lcdctrl(int);
97 void lcdshow(const char *);
98 void greeting(void);
99 
100 /* Internal variables */
101 				     /* "1234567890123456" */
102 static const char lcd_boot_message1[] = "OpenBSD/luna88k ";
103 static const char lcd_boot_message2[] = "   SX-9100/DT   ";
104 
105 /*
106  * Autoconf functions
107  */
108 int
109 lcd_match(struct device *parent, void *cf, void *aux)
110 {
111 	struct mainbus_attach_args *ma = aux;
112 
113 	if (strcmp(ma->ma_name, lcd_cd.cd_name))
114 		return 0;
115 	if (badaddr((vaddr_t)ma->ma_addr, 4))
116 		return 0;
117 	return 1;
118 }
119 
120 void
121 lcd_attach(struct device *parent, struct device *self, void *aux)
122 {
123 	printf("\n");
124 
125 	/* Say hello to the world on LCD. */
126 	greeting();
127 }
128 
129 /*
130  * open/close/write/ioctl
131  */
132 
133 int
134 lcdopen(dev_t dev, int flags, int fmt, struct proc *p)
135 {
136 	int unit = minor(dev);
137 	struct lcd_softc *sc;
138 
139 	if (unit >= lcd_cd.cd_ndevs)
140 		return ENXIO;
141 	if ((sc = lcd_cd.cd_devs[unit]) == NULL)
142 		return ENXIO;
143 	if (sc->sc_opened)
144 		return EBUSY;
145 	sc->sc_opened = 1;
146 
147 	return 0;
148 }
149 
150 int
151 lcdclose(dev_t dev, int flags, int fmt, struct proc *p)
152 {
153 	int unit = minor(dev);
154 	struct lcd_softc *sc;
155 
156 	sc = lcd_cd.cd_devs[unit];
157 	sc->sc_opened = 0;
158 
159 	return 0;
160 }
161 
162 int
163 lcdwrite(dev_t dev, struct uio *uio, int flag)
164 {
165 	int error;
166 	size_t len;
167 	size_t i, n;
168 	char buf[LCD_MAXBUFLEN];
169 
170 	len = n = uio->uio_resid;
171 
172 	if (len > LCD_MAXBUFLEN)
173 		return EIO;
174 
175 	while (n > 0) {
176 		error = uiomove(buf, n, uio);
177 		if (error)
178 			return EIO;
179 		n = uio->uio_resid;
180 	}
181 
182 	for (i = 0; i < len; i++) {
183 		lcdput((int)buf[i]);
184 	}
185 
186 	return 0;
187 }
188 
189 int
190 lcdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
191 {
192 	int val;
193 
194 	/* check if the device opened with write mode */
195 	switch(cmd) {
196 	case LCDCLS:
197 	case LCDHOME:
198 	case LCDMODE:
199 	case LCDDISP:
200 	case LCDMOVE:
201 	case LCDSEEK:
202 	case LCDRESTORE:
203 		if ((flag & FWRITE) == 0)
204 			return EACCES;
205 		break;
206 	}
207 
208 	switch(cmd) {
209 	case LCDCLS:
210 		lcdctrl(LCD_CLS);
211 		break;
212 
213 	case LCDHOME:
214 		lcdctrl(LCD_HOME);
215 		break;
216 
217 	case LCDMODE:
218 		val = *(int *)addr;
219 		switch (val) {
220 		case LCDMODE_C_LEFT:
221 		case LCDMODE_C_RIGHT:
222 		case LCDMODE_D_LEFT:
223 		case LCDMODE_D_RIGHT:
224 			lcdctrl(val);
225 			break;
226 		default:
227 			return EINVAL;
228 		}
229 		break;
230 
231 	case LCDDISP:
232 		val = *(int *)addr;
233 		if ((val & 0x7) != val)
234 			return EINVAL;
235 		lcdctrl(val | 0x8);
236 		break;
237 
238 	case LCDMOVE:
239 		val = *(int *)addr;
240 		switch (val) {
241 		case LCDMOVE_C_LEFT:
242 		case LCDMOVE_C_RIGHT:
243 		case LCDMOVE_D_LEFT:
244 		case LCDMOVE_D_RIGHT:
245 			lcdctrl(val);
246 			break;
247 		default:
248 			return EINVAL;
249 		}
250 		break;
251 
252 	case LCDSEEK:
253 		val = *(int *)addr & 0x7f;
254 		lcdctrl(val | 0x80);
255 		break;
256 
257 	case LCDRESTORE:
258 		greeting();
259 		break;
260 
261 	default:
262 		return ENOTTY;
263 	}
264 	return 0;
265 }
266 
267 /*
268  * Internal functions
269  */
270 void
271 lcdbusywait()
272 {
273 	struct pio *p1 = (struct pio *)0x4D000000;
274 	int msb, s;
275 
276 	s = splhigh();
277 	p1->cntrl = PIO1_MODE_INPUT;
278 	p1->portC = POWER | READ_BUSY | ENABLE;
279 	splx(s);
280 
281 	do {
282 		msb = p1->portA & ENABLE;
283 		delay(5);
284 	} while (msb != 0);
285 
286 	s = splhigh();
287 	p1->portC = POWER | READ_BUSY | DISABLE;
288 	splx(s);
289 }
290 
291 void
292 lcdput(int cc)
293 {
294 	struct pio *p1 = (struct pio *)0x4D000000;
295 	int s;
296 
297 	lcdbusywait();
298 
299 	s = splhigh();
300 	p1->cntrl = PIO1_MODE_OUTPUT;
301 
302 	p1->portC = POWER | WRITE_DATA | ENABLE;
303 	p1->portA = cc;
304 	p1->portC = POWER | WRITE_DATA | DISABLE;
305 	splx(s);
306 }
307 
308 void
309 lcdctrl(int cc)
310 {
311 	struct pio *p1 = (struct pio *)0x4D000000;
312 	int s;
313 
314 	lcdbusywait();
315 
316 	s = splhigh();
317 	p1->cntrl = PIO1_MODE_OUTPUT;
318 
319 	p1->portC = POWER | WRITE_CMD | ENABLE;
320 	p1->portA = cc;
321 	p1->portC = POWER | WRITE_CMD | DISABLE;
322 	splx(s);
323 }
324 
325 void
326 lcdshow(const char *s)
327 {
328 	int cc;
329 
330 	while ((cc = *s++) != '\0')
331 		lcdput(cc);
332 }
333 
334 void
335 greeting()
336 {
337 	lcdctrl(LCD_INIT);
338 	lcdctrl(LCD_ENTRY);
339 	lcdctrl(LCD_ON);
340 
341 	lcdctrl(LCD_CLS);
342 	lcdctrl(LCD_HOME);
343 
344 	lcdctrl(LCD_LOCATE(0, 0));
345 	lcdshow(lcd_boot_message1);
346 	lcdctrl(LCD_LOCATE(0, 1));
347 	lcdshow(lcd_boot_message2);
348 }
349