lcd.c revision 1.12 1 1.12 tsutsui /* $NetBSD: lcd.c,v 1.12 2020/12/29 17:17:14 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.12 tsutsui __KERNEL_RCSID(0, "$NetBSD: lcd.c,v 1.12 2020/12/29 17:17:14 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.11 tsutsui #include <machine/board.h>
47 1.7 tsutsui #include <machine/cpu.h>
48 1.8 tsutsui #include <machine/lcd.h>
49 1.8 tsutsui
50 1.8 tsutsui #include "ioconf.h"
51 1.7 tsutsui
52 1.1 nisimura #define PIO1_MODE_OUTPUT 0x84
53 1.1 nisimura #define PIO1_MODE_INPUT 0x94
54 1.1 nisimura
55 1.1 nisimura #define POWER 0x10
56 1.1 nisimura
57 1.1 nisimura #define ENABLE 0x80
58 1.1 nisimura #define DISABLE 0x00
59 1.1 nisimura
60 1.1 nisimura #define WRITE_CMD (0x00 | 0x00)
61 1.1 nisimura #define WRITE_DATA (0x00 | 0x40)
62 1.1 nisimura #define READ_BUSY (0x20 | 0x00)
63 1.1 nisimura #define READ_DATA (0x20 | 0x40)
64 1.1 nisimura
65 1.1 nisimura #define LCD_INIT 0x38
66 1.1 nisimura #define LCD_ENTRY 0x06
67 1.1 nisimura #define LCD_ON 0x0c
68 1.1 nisimura #define LCD_CLS 0x01
69 1.1 nisimura #define LCD_HOME 0x02
70 1.1 nisimura #define LCD_LOCATE(X, Y) (((Y) & 1 ? 0xc0 : 0x80) | ((X) & 0x0f))
71 1.1 nisimura
72 1.8 tsutsui #define LCD_MAXBUFLEN 80
73 1.8 tsutsui
74 1.1 nisimura struct pio {
75 1.10 tsutsui volatile uint8_t portA;
76 1.10 tsutsui volatile uint8_t portB;
77 1.10 tsutsui volatile uint8_t portC;
78 1.10 tsutsui volatile uint8_t cntrl;
79 1.1 nisimura };
80 1.1 nisimura
81 1.8 tsutsui /* Autoconf stuff */
82 1.8 tsutsui static int lcd_match(device_t, cfdata_t, void *);
83 1.8 tsutsui static void lcd_attach(device_t, device_t, void *);
84 1.8 tsutsui
85 1.12 tsutsui static dev_type_open(lcdopen);
86 1.12 tsutsui static dev_type_close(lcdclose);
87 1.12 tsutsui static dev_type_write(lcdwrite);
88 1.12 tsutsui static dev_type_ioctl(lcdioctl);
89 1.8 tsutsui
90 1.8 tsutsui const struct cdevsw lcd_cdevsw = {
91 1.8 tsutsui .d_open = lcdopen,
92 1.8 tsutsui .d_close = lcdclose,
93 1.8 tsutsui .d_read = noread,
94 1.8 tsutsui .d_write = lcdwrite,
95 1.8 tsutsui .d_ioctl = lcdioctl,
96 1.8 tsutsui .d_stop = nostop,
97 1.8 tsutsui .d_tty = notty,
98 1.8 tsutsui .d_poll = nopoll,
99 1.8 tsutsui .d_mmap = nommap,
100 1.8 tsutsui .d_kqfilter = nokqfilter,
101 1.8 tsutsui .d_discard = nodiscard,
102 1.8 tsutsui .d_flag = 0
103 1.8 tsutsui };
104 1.8 tsutsui
105 1.8 tsutsui struct lcd_softc {
106 1.8 tsutsui device_t sc_dev;
107 1.8 tsutsui
108 1.8 tsutsui bool sc_opened;
109 1.8 tsutsui };
110 1.8 tsutsui
111 1.8 tsutsui CFATTACH_DECL_NEW(lcd, sizeof(struct lcd_softc),
112 1.8 tsutsui lcd_match, lcd_attach, NULL, NULL);
113 1.8 tsutsui
114 1.12 tsutsui static void lcdbusywait(void);
115 1.12 tsutsui static void lcdput(int);
116 1.12 tsutsui static void lcdctrl(int);
117 1.12 tsutsui static void lcdshow(char *);
118 1.12 tsutsui static void greeting(void);
119 1.1 nisimura /* "1234567890123456" */
120 1.1 nisimura static char lcd_boot_message1[] = " NetBSD/luna68k ";
121 1.1 nisimura static char lcd_boot_message2[] = " SX-9100/DT ";
122 1.1 nisimura
123 1.8 tsutsui /*
124 1.8 tsutsui * Autoconf functions
125 1.8 tsutsui */
126 1.8 tsutsui static int
127 1.8 tsutsui lcd_match(device_t parent, cfdata_t cf, void *aux)
128 1.8 tsutsui {
129 1.8 tsutsui struct mainbus_attach_args *ma = aux;
130 1.8 tsutsui
131 1.8 tsutsui if (strcmp(ma->ma_name, lcd_cd.cd_name))
132 1.8 tsutsui return 0;
133 1.8 tsutsui if (badaddr((void *)ma->ma_addr, 4))
134 1.8 tsutsui return 0;
135 1.8 tsutsui return 1;
136 1.8 tsutsui }
137 1.8 tsutsui
138 1.8 tsutsui static void
139 1.8 tsutsui lcd_attach(device_t parent, device_t self, void *aux)
140 1.8 tsutsui {
141 1.8 tsutsui
142 1.8 tsutsui printf("\n");
143 1.8 tsutsui
144 1.8 tsutsui /* Say hello to the world on LCD. */
145 1.8 tsutsui greeting();
146 1.8 tsutsui }
147 1.8 tsutsui
148 1.8 tsutsui /*
149 1.8 tsutsui * open/close/write/ioctl
150 1.8 tsutsui */
151 1.12 tsutsui static int
152 1.8 tsutsui lcdopen(dev_t dev, int flags, int fmt, struct lwp *l)
153 1.8 tsutsui {
154 1.8 tsutsui int unit;
155 1.8 tsutsui struct lcd_softc *sc;
156 1.8 tsutsui
157 1.8 tsutsui unit = minor(dev);
158 1.8 tsutsui sc = device_lookup_private(&lcd_cd, unit);
159 1.8 tsutsui if (sc == NULL)
160 1.8 tsutsui return ENXIO;
161 1.8 tsutsui if (sc->sc_opened)
162 1.8 tsutsui return EBUSY;
163 1.8 tsutsui sc->sc_opened = true;
164 1.8 tsutsui
165 1.8 tsutsui return 0;
166 1.8 tsutsui }
167 1.8 tsutsui
168 1.12 tsutsui static int
169 1.8 tsutsui lcdclose(dev_t dev, int flags, int fmt, struct lwp *l)
170 1.8 tsutsui {
171 1.8 tsutsui int unit;
172 1.8 tsutsui struct lcd_softc *sc;
173 1.8 tsutsui
174 1.8 tsutsui unit = minor(dev);
175 1.8 tsutsui sc = device_lookup_private(&lcd_cd, unit);
176 1.8 tsutsui sc->sc_opened = false;
177 1.8 tsutsui
178 1.8 tsutsui return 0;
179 1.8 tsutsui }
180 1.8 tsutsui
181 1.12 tsutsui static int
182 1.8 tsutsui lcdwrite(dev_t dev, struct uio *uio, int flag)
183 1.8 tsutsui {
184 1.8 tsutsui int error;
185 1.8 tsutsui size_t len, i;
186 1.8 tsutsui char buf[LCD_MAXBUFLEN];
187 1.8 tsutsui
188 1.8 tsutsui len = uio->uio_resid;
189 1.8 tsutsui
190 1.8 tsutsui if (len > LCD_MAXBUFLEN)
191 1.8 tsutsui return EIO;
192 1.8 tsutsui
193 1.8 tsutsui error = uiomove(buf, len, uio);
194 1.8 tsutsui if (error)
195 1.8 tsutsui return EIO;
196 1.8 tsutsui
197 1.8 tsutsui for (i = 0; i < len; i++) {
198 1.8 tsutsui lcdput((int)buf[i]);
199 1.8 tsutsui }
200 1.8 tsutsui
201 1.8 tsutsui return 0;
202 1.8 tsutsui }
203 1.8 tsutsui
204 1.12 tsutsui static int
205 1.8 tsutsui lcdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
206 1.8 tsutsui {
207 1.8 tsutsui int val;
208 1.8 tsutsui
209 1.8 tsutsui /* check if the device opened with write mode */
210 1.8 tsutsui switch (cmd) {
211 1.8 tsutsui case LCDCLS:
212 1.8 tsutsui case LCDHOME:
213 1.8 tsutsui case LCDMODE:
214 1.8 tsutsui case LCDDISP:
215 1.8 tsutsui case LCDMOVE:
216 1.8 tsutsui case LCDSEEK:
217 1.8 tsutsui case LCDRESTORE:
218 1.9 mrg if ((flag & FWRITE) == 0)
219 1.9 mrg return EACCES;
220 1.8 tsutsui }
221 1.8 tsutsui
222 1.8 tsutsui switch (cmd) {
223 1.8 tsutsui case LCDCLS:
224 1.8 tsutsui lcdctrl(LCD_CLS);
225 1.8 tsutsui break;
226 1.8 tsutsui
227 1.8 tsutsui case LCDHOME:
228 1.8 tsutsui lcdctrl(LCD_HOME);
229 1.8 tsutsui break;
230 1.8 tsutsui
231 1.8 tsutsui case LCDMODE:
232 1.8 tsutsui val = *(int *)addr;
233 1.8 tsutsui switch (val) {
234 1.8 tsutsui case LCDMODE_C_LEFT:
235 1.8 tsutsui case LCDMODE_C_RIGHT:
236 1.8 tsutsui case LCDMODE_D_LEFT:
237 1.8 tsutsui case LCDMODE_D_RIGHT:
238 1.8 tsutsui lcdctrl(val);
239 1.8 tsutsui break;
240 1.8 tsutsui default:
241 1.8 tsutsui return EINVAL;
242 1.8 tsutsui }
243 1.8 tsutsui break;
244 1.8 tsutsui
245 1.8 tsutsui case LCDDISP:
246 1.8 tsutsui val = *(int *)addr;
247 1.8 tsutsui if ((val & 0x7) != val)
248 1.8 tsutsui return EINVAL;
249 1.8 tsutsui lcdctrl(val | 0x8);
250 1.8 tsutsui break;
251 1.8 tsutsui
252 1.8 tsutsui case LCDMOVE:
253 1.8 tsutsui val = *(int *)addr;
254 1.8 tsutsui switch (val) {
255 1.8 tsutsui case LCDMOVE_C_LEFT:
256 1.8 tsutsui case LCDMOVE_C_RIGHT:
257 1.8 tsutsui case LCDMOVE_D_LEFT:
258 1.8 tsutsui case LCDMOVE_D_RIGHT:
259 1.8 tsutsui lcdctrl(val);
260 1.8 tsutsui break;
261 1.8 tsutsui default:
262 1.8 tsutsui return EINVAL;
263 1.8 tsutsui }
264 1.8 tsutsui break;
265 1.8 tsutsui
266 1.8 tsutsui case LCDSEEK:
267 1.8 tsutsui val = *(int *)addr & 0x7f;
268 1.8 tsutsui lcdctrl(val | 0x80);
269 1.8 tsutsui break;
270 1.8 tsutsui
271 1.8 tsutsui case LCDRESTORE:
272 1.8 tsutsui greeting();
273 1.8 tsutsui break;
274 1.8 tsutsui
275 1.8 tsutsui default:
276 1.8 tsutsui return ENOTTY;
277 1.8 tsutsui }
278 1.8 tsutsui return EPASSTHROUGH;
279 1.8 tsutsui }
280 1.8 tsutsui
281 1.12 tsutsui static void
282 1.6 cegger lcdbusywait(void)
283 1.1 nisimura {
284 1.11 tsutsui struct pio *p1 = (struct pio *)OBIO_PIO1_BASE;
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.12 tsutsui static void
303 1.5 dsl lcdput(int cc)
304 1.1 nisimura {
305 1.11 tsutsui struct pio *p1 = (struct pio *)OBIO_PIO1_BASE;
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.12 tsutsui static void
320 1.5 dsl lcdctrl(int cc)
321 1.1 nisimura {
322 1.11 tsutsui struct pio *p1 = (struct pio *)OBIO_PIO1_BASE;
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.12 tsutsui static 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.12 tsutsui static void
346 1.6 cegger greeting(void)
347 1.1 nisimura {
348 1.10 tsutsui
349 1.1 nisimura lcdctrl(LCD_INIT);
350 1.1 nisimura lcdctrl(LCD_ENTRY);
351 1.1 nisimura lcdctrl(LCD_ON);
352 1.1 nisimura
353 1.1 nisimura lcdctrl(LCD_CLS);
354 1.1 nisimura lcdctrl(LCD_HOME);
355 1.1 nisimura
356 1.1 nisimura lcdctrl(LCD_LOCATE(0, 0));
357 1.1 nisimura lcdshow(lcd_boot_message1);
358 1.1 nisimura lcdctrl(LCD_LOCATE(0, 1));
359 1.7 tsutsui if (machtype == LUNA_II)
360 1.7 tsutsui lcd_boot_message2[13] = '2';
361 1.1 nisimura lcdshow(lcd_boot_message2);
362 1.1 nisimura }
363