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