xref: /openbsd/sys/arch/luna88k/dev/lcd.c (revision 404b540a)
1 /* $OpenBSD: lcd.c,v 1.4 2008/06/26 05:42:11 ray 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(parent, cf, aux)
110 	struct device *parent;
111 	void *cf, *aux;
112 {
113 	struct mainbus_attach_args *ma = aux;
114 
115 	if (strcmp(ma->ma_name, lcd_cd.cd_name))
116 		return 0;
117 	if (badaddr((vaddr_t)ma->ma_addr, 4))
118 		return 0;
119 	return 1;
120 }
121 
122 void
123 lcd_attach(parent, self, aux)
124 	struct device *parent, *self;
125 	void *aux;
126 {
127 	printf("\n");
128 
129 	/* Say hello to the world on LCD. */
130 	greeting();
131 }
132 
133 /*
134  * open/close/write/ioctl
135  */
136 
137 int
138 lcdopen(dev, flags, fmt, p)
139 	dev_t dev;
140 	int flags, fmt;
141 	struct proc *p;
142 {
143 	int unit = minor(dev);
144 	struct lcd_softc *sc;
145 
146 	if (unit >= lcd_cd.cd_ndevs)
147 		return ENXIO;
148 	if ((sc = lcd_cd.cd_devs[unit]) == NULL)
149 		return ENXIO;
150 	if (sc->sc_opened)
151 		return EBUSY;
152 	sc->sc_opened = 1;
153 
154 	return 0;
155 }
156 
157 int
158 lcdclose(dev, flags, fmt, p)
159 	dev_t dev;
160 	int flags, fmt;
161 	struct proc *p;
162 {
163 	int unit = minor(dev);
164 	struct lcd_softc *sc;
165 
166 	sc = lcd_cd.cd_devs[unit];
167 	sc->sc_opened = 0;
168 
169 	return 0;
170 }
171 
172 int
173 lcdwrite(dev, uio, flag)
174 	dev_t dev;
175 	struct uio *uio;
176 	int flag;
177 {
178 	int error, len;
179 	int i, n;
180 	char buf[LCD_MAXBUFLEN];
181 
182 	len = n = uio->uio_resid;
183 
184 	if ((len < 0) || (len > LCD_MAXBUFLEN))
185 		return EIO;
186 
187 	while (n > 0) {
188 		error = uiomove(buf, n, uio);
189 		if (error)
190 			return EIO;
191 		n = uio->uio_resid;
192 	}
193 
194 	for(i = 0; i < len; i++) {
195 		lcdput((int)buf[i]);
196 	}
197 
198 	return 0;
199 }
200 
201 int
202 lcdioctl(dev, cmd, addr, flag, p)
203 	dev_t dev;
204 	u_long cmd;
205 	caddr_t addr;
206 	int flag;
207 	struct proc *p;
208 {
209 	int val;
210 
211 	/* check if the device opened with write mode */
212 	switch(cmd) {
213 	case LCDCLS:
214 	case LCDHOME:
215 	case LCDMODE:
216 	case LCDDISP:
217 	case LCDMOVE:
218 	case LCDSEEK:
219 	case LCDRESTORE:
220 		if ((flag & FWRITE) == 0)
221 			return EACCES;
222 		break;
223 	}
224 
225 	switch(cmd) {
226 	case LCDCLS:
227 		lcdctrl(LCD_CLS);
228 		break;
229 
230 	case LCDHOME:
231 		lcdctrl(LCD_HOME);
232 		break;
233 
234 	case LCDMODE:
235 		val = *(int *)addr;
236 		switch (val) {
237 		case LCDMODE_C_LEFT:
238 		case LCDMODE_C_RIGHT:
239 		case LCDMODE_D_LEFT:
240 		case LCDMODE_D_RIGHT:
241 			lcdctrl(val);
242 			break;
243 		default:
244 			return EINVAL;
245 		}
246 		break;
247 
248 	case LCDDISP:
249 		val = *(int *)addr;
250 		if ((val & 0x7) != val)
251 			return EINVAL;
252 		lcdctrl(val | 0x8);
253 		break;
254 
255 	case LCDMOVE:
256 		val = *(int *)addr;
257 		switch (val) {
258 		case LCDMOVE_C_LEFT:
259 		case LCDMOVE_C_RIGHT:
260 		case LCDMOVE_D_LEFT:
261 		case LCDMOVE_D_RIGHT:
262 			lcdctrl(val);
263 			break;
264 		default:
265 			return EINVAL;
266 		}
267 		break;
268 
269 	case LCDSEEK:
270 		val = *(int *)addr & 0x7f;
271 		lcdctrl(val | 0x80);
272 		break;
273 
274 	case LCDRESTORE:
275 		greeting();
276 		break;
277 
278 	default:
279 		return ENOTTY;
280 	}
281 	return 0;
282 }
283 
284 /*
285  * Internal functions
286  */
287 void
288 lcdbusywait()
289 {
290 	struct pio *p1 = (struct pio *)0x4D000000;
291 	int msb, s;
292 
293 	s = splhigh();
294 	p1->cntrl = PIO1_MODE_INPUT;
295 	p1->portC = POWER | READ_BUSY | ENABLE;
296 	splx(s);
297 
298 	do {
299 		msb = p1->portA & ENABLE;
300 		delay(5);
301 	} while (msb != 0);
302 
303 	s = splhigh();
304 	p1->portC = POWER | READ_BUSY | DISABLE;
305 	splx(s);
306 }
307 
308 void
309 lcdput(cc)
310 	int cc;
311 {
312 	struct pio *p1 = (struct pio *)0x4D000000;
313 	int s;
314 
315 	lcdbusywait();
316 
317 	s = splhigh();
318 	p1->cntrl = PIO1_MODE_OUTPUT;
319 
320 	p1->portC = POWER | WRITE_DATA | ENABLE;
321 	p1->portA = cc;
322 	p1->portC = POWER | WRITE_DATA | DISABLE;
323 	splx(s);
324 }
325 
326 void
327 lcdctrl(cc)
328 	int cc;
329 {
330 	struct pio *p1 = (struct pio *)0x4D000000;
331 	int s;
332 
333 	lcdbusywait();
334 
335 	s = splhigh();
336 	p1->cntrl = PIO1_MODE_OUTPUT;
337 
338 	p1->portC = POWER | WRITE_CMD | ENABLE;
339 	p1->portA = cc;
340 	p1->portC = POWER | WRITE_CMD | DISABLE;
341 	splx(s);
342 }
343 
344 void
345 lcdshow(s)
346 	const char *s;
347 {
348 	int cc;
349 
350 	while ((cc = *s++) != '\0')
351 		lcdput(cc);
352 }
353 
354 void
355 greeting()
356 {
357 	lcdctrl(LCD_INIT);
358 	lcdctrl(LCD_ENTRY);
359 	lcdctrl(LCD_ON);
360 
361 	lcdctrl(LCD_CLS);
362 	lcdctrl(LCD_HOME);
363 
364 	lcdctrl(LCD_LOCATE(0, 0));
365 	lcdshow(lcd_boot_message1);
366 	lcdctrl(LCD_LOCATE(0, 1));
367 	lcdshow(lcd_boot_message2);
368 }
369