lcd.c revision 1.10 1 1.10 tsutsui /* $NetBSD: lcd.c,v 1.10 2019/06/30 02:11:56 tsutsui Exp $ */
2 1.8 tsutsui /* $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.10 tsutsui __KERNEL_RCSID(0, "$NetBSD: lcd.c,v 1.10 2019/06/30 02:11:56 tsutsui Exp $");
36 1.1 nisimura
37 1.1 nisimura #include <sys/param.h>
38 1.1 nisimura #include <sys/systm.h>
39 1.8 tsutsui #include <sys/conf.h>
40 1.1 nisimura #include <sys/device.h>
41 1.8 tsutsui #include <sys/ioctl.h>
42 1.8 tsutsui #include <sys/fcntl.h>
43 1.8 tsutsui #include <sys/errno.h>
44 1.1 nisimura
45 1.8 tsutsui #include <machine/autoconf.h>
46 1.7 tsutsui #include <machine/cpu.h>
47 1.8 tsutsui #include <machine/lcd.h>
48 1.8 tsutsui
49 1.8 tsutsui #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.8 tsutsui #define LCD_MAXBUFLEN 80
72 1.8 tsutsui
73 1.1 nisimura struct pio {
74 1.10 tsutsui volatile uint8_t portA;
75 1.10 tsutsui volatile uint8_t portB;
76 1.10 tsutsui volatile uint8_t portC;
77 1.10 tsutsui volatile uint8_t cntrl;
78 1.1 nisimura };
79 1.1 nisimura
80 1.8 tsutsui /* Autoconf stuff */
81 1.8 tsutsui static int lcd_match(device_t, cfdata_t, void *);
82 1.8 tsutsui static void lcd_attach(device_t, device_t, void *);
83 1.8 tsutsui
84 1.8 tsutsui dev_type_open(lcdopen);
85 1.8 tsutsui dev_type_close(lcdclose);
86 1.8 tsutsui dev_type_write(lcdwrite);
87 1.8 tsutsui dev_type_ioctl(lcdioctl);
88 1.8 tsutsui
89 1.8 tsutsui const struct cdevsw lcd_cdevsw = {
90 1.8 tsutsui .d_open = lcdopen,
91 1.8 tsutsui .d_close = lcdclose,
92 1.8 tsutsui .d_read = noread,
93 1.8 tsutsui .d_write = lcdwrite,
94 1.8 tsutsui .d_ioctl = lcdioctl,
95 1.8 tsutsui .d_stop = nostop,
96 1.8 tsutsui .d_tty = notty,
97 1.8 tsutsui .d_poll = nopoll,
98 1.8 tsutsui .d_mmap = nommap,
99 1.8 tsutsui .d_kqfilter = nokqfilter,
100 1.8 tsutsui .d_discard = nodiscard,
101 1.8 tsutsui .d_flag = 0
102 1.8 tsutsui };
103 1.8 tsutsui
104 1.8 tsutsui struct lcd_softc {
105 1.8 tsutsui device_t sc_dev;
106 1.8 tsutsui
107 1.8 tsutsui bool sc_opened;
108 1.8 tsutsui };
109 1.8 tsutsui
110 1.8 tsutsui CFATTACH_DECL_NEW(lcd, sizeof(struct lcd_softc),
111 1.8 tsutsui lcd_match, lcd_attach, NULL, NULL);
112 1.8 tsutsui
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.8 tsutsui /*
123 1.8 tsutsui * Autoconf functions
124 1.8 tsutsui */
125 1.8 tsutsui static int
126 1.8 tsutsui lcd_match(device_t parent, cfdata_t cf, void *aux)
127 1.8 tsutsui {
128 1.8 tsutsui struct mainbus_attach_args *ma = aux;
129 1.8 tsutsui
130 1.8 tsutsui if (strcmp(ma->ma_name, lcd_cd.cd_name))
131 1.8 tsutsui return 0;
132 1.8 tsutsui if (badaddr((void *)ma->ma_addr, 4))
133 1.8 tsutsui return 0;
134 1.8 tsutsui return 1;
135 1.8 tsutsui }
136 1.8 tsutsui
137 1.8 tsutsui static void
138 1.8 tsutsui lcd_attach(device_t parent, device_t self, void *aux)
139 1.8 tsutsui {
140 1.8 tsutsui
141 1.8 tsutsui printf("\n");
142 1.8 tsutsui
143 1.8 tsutsui /* Say hello to the world on LCD. */
144 1.8 tsutsui greeting();
145 1.8 tsutsui }
146 1.8 tsutsui
147 1.8 tsutsui /*
148 1.8 tsutsui * open/close/write/ioctl
149 1.8 tsutsui */
150 1.8 tsutsui int
151 1.8 tsutsui lcdopen(dev_t dev, int flags, int fmt, struct lwp *l)
152 1.8 tsutsui {
153 1.8 tsutsui int unit;
154 1.8 tsutsui struct lcd_softc *sc;
155 1.8 tsutsui
156 1.8 tsutsui unit = minor(dev);
157 1.8 tsutsui sc = device_lookup_private(&lcd_cd, unit);
158 1.8 tsutsui if (sc == NULL)
159 1.8 tsutsui return ENXIO;
160 1.8 tsutsui if (sc->sc_opened)
161 1.8 tsutsui return EBUSY;
162 1.8 tsutsui sc->sc_opened = true;
163 1.8 tsutsui
164 1.8 tsutsui return 0;
165 1.8 tsutsui }
166 1.8 tsutsui
167 1.8 tsutsui int
168 1.8 tsutsui lcdclose(dev_t dev, int flags, int fmt, struct lwp *l)
169 1.8 tsutsui {
170 1.8 tsutsui int unit;
171 1.8 tsutsui struct lcd_softc *sc;
172 1.8 tsutsui
173 1.8 tsutsui unit = minor(dev);
174 1.8 tsutsui sc = device_lookup_private(&lcd_cd, unit);
175 1.8 tsutsui sc->sc_opened = false;
176 1.8 tsutsui
177 1.8 tsutsui return 0;
178 1.8 tsutsui }
179 1.8 tsutsui
180 1.8 tsutsui int
181 1.8 tsutsui lcdwrite(dev_t dev, struct uio *uio, int flag)
182 1.8 tsutsui {
183 1.8 tsutsui int error;
184 1.8 tsutsui size_t len, i;
185 1.8 tsutsui char buf[LCD_MAXBUFLEN];
186 1.8 tsutsui
187 1.8 tsutsui len = uio->uio_resid;
188 1.8 tsutsui
189 1.8 tsutsui if (len > LCD_MAXBUFLEN)
190 1.8 tsutsui return EIO;
191 1.8 tsutsui
192 1.8 tsutsui error = uiomove(buf, len, uio);
193 1.8 tsutsui if (error)
194 1.8 tsutsui return EIO;
195 1.8 tsutsui
196 1.8 tsutsui for (i = 0; i < len; i++) {
197 1.8 tsutsui lcdput((int)buf[i]);
198 1.8 tsutsui }
199 1.8 tsutsui
200 1.8 tsutsui return 0;
201 1.8 tsutsui }
202 1.8 tsutsui
203 1.8 tsutsui int
204 1.8 tsutsui lcdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
205 1.8 tsutsui {
206 1.8 tsutsui int val;
207 1.8 tsutsui
208 1.8 tsutsui /* check if the device opened with write mode */
209 1.8 tsutsui switch (cmd) {
210 1.8 tsutsui case LCDCLS:
211 1.8 tsutsui case LCDHOME:
212 1.8 tsutsui case LCDMODE:
213 1.8 tsutsui case LCDDISP:
214 1.8 tsutsui case LCDMOVE:
215 1.8 tsutsui case LCDSEEK:
216 1.8 tsutsui case LCDRESTORE:
217 1.9 mrg if ((flag & FWRITE) == 0)
218 1.9 mrg return EACCES;
219 1.8 tsutsui }
220 1.8 tsutsui
221 1.8 tsutsui switch (cmd) {
222 1.8 tsutsui case LCDCLS:
223 1.8 tsutsui lcdctrl(LCD_CLS);
224 1.8 tsutsui break;
225 1.8 tsutsui
226 1.8 tsutsui case LCDHOME:
227 1.8 tsutsui lcdctrl(LCD_HOME);
228 1.8 tsutsui break;
229 1.8 tsutsui
230 1.8 tsutsui case LCDMODE:
231 1.8 tsutsui val = *(int *)addr;
232 1.8 tsutsui switch (val) {
233 1.8 tsutsui case LCDMODE_C_LEFT:
234 1.8 tsutsui case LCDMODE_C_RIGHT:
235 1.8 tsutsui case LCDMODE_D_LEFT:
236 1.8 tsutsui case LCDMODE_D_RIGHT:
237 1.8 tsutsui lcdctrl(val);
238 1.8 tsutsui break;
239 1.8 tsutsui default:
240 1.8 tsutsui return EINVAL;
241 1.8 tsutsui }
242 1.8 tsutsui break;
243 1.8 tsutsui
244 1.8 tsutsui case LCDDISP:
245 1.8 tsutsui val = *(int *)addr;
246 1.8 tsutsui if ((val & 0x7) != val)
247 1.8 tsutsui return EINVAL;
248 1.8 tsutsui lcdctrl(val | 0x8);
249 1.8 tsutsui break;
250 1.8 tsutsui
251 1.8 tsutsui case LCDMOVE:
252 1.8 tsutsui val = *(int *)addr;
253 1.8 tsutsui switch (val) {
254 1.8 tsutsui case LCDMOVE_C_LEFT:
255 1.8 tsutsui case LCDMOVE_C_RIGHT:
256 1.8 tsutsui case LCDMOVE_D_LEFT:
257 1.8 tsutsui case LCDMOVE_D_RIGHT:
258 1.8 tsutsui lcdctrl(val);
259 1.8 tsutsui break;
260 1.8 tsutsui default:
261 1.8 tsutsui return EINVAL;
262 1.8 tsutsui }
263 1.8 tsutsui break;
264 1.8 tsutsui
265 1.8 tsutsui case LCDSEEK:
266 1.8 tsutsui val = *(int *)addr & 0x7f;
267 1.8 tsutsui lcdctrl(val | 0x80);
268 1.8 tsutsui break;
269 1.8 tsutsui
270 1.8 tsutsui case LCDRESTORE:
271 1.8 tsutsui greeting();
272 1.8 tsutsui break;
273 1.8 tsutsui
274 1.8 tsutsui default:
275 1.8 tsutsui return ENOTTY;
276 1.8 tsutsui }
277 1.8 tsutsui return EPASSTHROUGH;
278 1.8 tsutsui }
279 1.8 tsutsui
280 1.1 nisimura void
281 1.6 cegger lcdbusywait(void)
282 1.1 nisimura {
283 1.1 nisimura struct pio *p1 = (struct pio *)0x4D000000;
284 1.1 nisimura int msb, s;
285 1.1 nisimura
286 1.1 nisimura s = splhigh();
287 1.1 nisimura p1->cntrl = PIO1_MODE_INPUT;
288 1.1 nisimura p1->portC = POWER | READ_BUSY | ENABLE;
289 1.1 nisimura splx(s);
290 1.1 nisimura
291 1.1 nisimura do {
292 1.1 nisimura msb = p1->portA & ENABLE;
293 1.1 nisimura delay(5);
294 1.1 nisimura } while (msb != 0);
295 1.1 nisimura
296 1.1 nisimura s = splhigh();
297 1.1 nisimura p1->portC = POWER | READ_BUSY | DISABLE;
298 1.1 nisimura splx(s);
299 1.1 nisimura }
300 1.1 nisimura
301 1.1 nisimura void
302 1.5 dsl lcdput(int cc)
303 1.1 nisimura {
304 1.1 nisimura struct pio *p1 = (struct pio *)0x4D000000;
305 1.1 nisimura int s;
306 1.1 nisimura
307 1.1 nisimura lcdbusywait();
308 1.1 nisimura
309 1.1 nisimura s = splhigh();
310 1.1 nisimura p1->cntrl = PIO1_MODE_OUTPUT;
311 1.1 nisimura
312 1.1 nisimura p1->portC = POWER | WRITE_DATA | ENABLE;
313 1.1 nisimura p1->portA = cc;
314 1.1 nisimura p1->portC = POWER | WRITE_DATA | DISABLE;
315 1.1 nisimura splx(s);
316 1.1 nisimura }
317 1.1 nisimura
318 1.1 nisimura void
319 1.5 dsl lcdctrl(int cc)
320 1.1 nisimura {
321 1.1 nisimura struct pio *p1 = (struct pio *)0x4D000000;
322 1.1 nisimura int s;
323 1.1 nisimura
324 1.1 nisimura lcdbusywait();
325 1.1 nisimura
326 1.1 nisimura s = splhigh();
327 1.1 nisimura p1->cntrl = PIO1_MODE_OUTPUT;
328 1.1 nisimura
329 1.1 nisimura p1->portC = POWER | WRITE_CMD | ENABLE;
330 1.1 nisimura p1->portA = cc;
331 1.1 nisimura p1->portC = POWER | WRITE_CMD | DISABLE;
332 1.1 nisimura splx(s);
333 1.1 nisimura }
334 1.1 nisimura
335 1.1 nisimura void
336 1.5 dsl lcdshow(char *s)
337 1.1 nisimura {
338 1.1 nisimura int cc;
339 1.1 nisimura
340 1.1 nisimura while ((cc = *s++) != '\0')
341 1.1 nisimura lcdput(cc);
342 1.1 nisimura }
343 1.1 nisimura
344 1.1 nisimura void
345 1.6 cegger greeting(void)
346 1.1 nisimura {
347 1.10 tsutsui
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