1*78d5ff0eSmpi /* $OpenBSD: lcd.c,v 1.6 2022/03/13 08:04:38 mpi Exp $ */
2b87e57a8Skettenis
3b87e57a8Skettenis /*
4b87e57a8Skettenis * Copyright (c) 2007 Mark Kettenis
5b87e57a8Skettenis *
6b87e57a8Skettenis * Permission to use, copy, modify, and distribute this software for any
7b87e57a8Skettenis * purpose with or without fee is hereby granted, provided that the above
8b87e57a8Skettenis * copyright notice and this permission notice appear in all copies.
9b87e57a8Skettenis *
10b87e57a8Skettenis * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11b87e57a8Skettenis * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12b87e57a8Skettenis * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13b87e57a8Skettenis * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14b87e57a8Skettenis * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15b87e57a8Skettenis * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16b87e57a8Skettenis * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17b87e57a8Skettenis */
18b87e57a8Skettenis
19b87e57a8Skettenis #include <sys/param.h>
20b87e57a8Skettenis #include <sys/device.h>
21b87e57a8Skettenis #include <sys/kernel.h>
22b87e57a8Skettenis #include <sys/systm.h>
23f6908264Skettenis #include <sys/timeout.h>
24b87e57a8Skettenis
25b87e57a8Skettenis #include <machine/autoconf.h>
26b87e57a8Skettenis #include <machine/bus.h>
27f6908264Skettenis #include <machine/cpu.h>
28b87e57a8Skettenis #include <machine/pdc.h>
29b87e57a8Skettenis
30b87e57a8Skettenis #define LCD_CLS 0x01
31b87e57a8Skettenis #define LCD_HOME 0x02
32b87e57a8Skettenis #define LCD_LOCATE(X, Y) (((Y) & 1 ? 0xc0 : 0x80) | ((X) & 0x0f))
33b87e57a8Skettenis
34b87e57a8Skettenis struct lcd_softc {
35f6908264Skettenis struct device sc_dv;
36b87e57a8Skettenis
37b87e57a8Skettenis bus_space_tag_t sc_iot;
38b87e57a8Skettenis bus_space_handle_t sc_cmdh, sc_datah;
39b87e57a8Skettenis
40b87e57a8Skettenis u_int sc_delay;
41f6908264Skettenis u_int8_t sc_heartbeat[3];
42f6908264Skettenis
43f6908264Skettenis struct timeout sc_to;
44f6908264Skettenis int sc_on;
45f6908264Skettenis struct blink_led sc_blink;
46b87e57a8Skettenis };
47b87e57a8Skettenis
48b87e57a8Skettenis int lcd_match(struct device *, void *, void *);
49b87e57a8Skettenis void lcd_attach(struct device *, struct device *, void *);
50b87e57a8Skettenis
51*78d5ff0eSmpi const struct cfattach lcd_ca = {
52b87e57a8Skettenis sizeof(struct lcd_softc), lcd_match, lcd_attach
53b87e57a8Skettenis };
54b87e57a8Skettenis
55b87e57a8Skettenis struct cfdriver lcd_cd = {
56b87e57a8Skettenis NULL, "lcd", DV_DULL
57b87e57a8Skettenis };
58b87e57a8Skettenis
59ef89f9e6Smpi void lcd_mountroot(struct device *);
60b87e57a8Skettenis void lcd_write(struct lcd_softc *, const char *);
61f6908264Skettenis void lcd_blink(void *, int);
62f6908264Skettenis void lcd_blink_finish(void *);
63b87e57a8Skettenis
64b87e57a8Skettenis int
lcd_match(struct device * parent,void * match,void * aux)65b87e57a8Skettenis lcd_match(struct device *parent, void *match, void *aux)
66b87e57a8Skettenis {
67b87e57a8Skettenis struct confargs *ca = aux;
68b87e57a8Skettenis
69b87e57a8Skettenis if (strcmp(ca->ca_name, "lcd") == 0)
70b87e57a8Skettenis return (1);
71b87e57a8Skettenis
72b87e57a8Skettenis return (0);
73b87e57a8Skettenis }
74b87e57a8Skettenis
75b87e57a8Skettenis void
lcd_attach(struct device * parent,struct device * self,void * aux)76b87e57a8Skettenis lcd_attach(struct device *parent, struct device *self, void *aux)
77b87e57a8Skettenis {
78b87e57a8Skettenis struct lcd_softc *sc = (struct lcd_softc *)self;
79b87e57a8Skettenis struct confargs *ca = aux;
80b87e57a8Skettenis struct pdc_chassis_lcd *pdc_lcd = (void *)ca->ca_pdc_iodc_read;
81f6908264Skettenis int i;
82b87e57a8Skettenis
83b87e57a8Skettenis sc->sc_iot = ca->ca_iot;
84b87e57a8Skettenis if (bus_space_map(sc->sc_iot, pdc_lcd->cmd_addr,
85b87e57a8Skettenis 1, 0, &sc->sc_cmdh)) {
86b87e57a8Skettenis printf(": cannot map cmd register\n");
87b87e57a8Skettenis return;
88b87e57a8Skettenis }
89b87e57a8Skettenis
90b87e57a8Skettenis if (bus_space_map(sc->sc_iot, pdc_lcd->data_addr,
91b87e57a8Skettenis 1, 0, &sc->sc_datah)) {
92b87e57a8Skettenis printf(": cannot map data register\n");
93b87e57a8Skettenis bus_space_unmap(sc->sc_iot, sc->sc_cmdh, 1);
94b87e57a8Skettenis return;
95b87e57a8Skettenis }
96b87e57a8Skettenis
97f6908264Skettenis printf(": model %d\n", pdc_lcd->model);
98f6908264Skettenis
99b87e57a8Skettenis sc->sc_delay = pdc_lcd->delay;
100f6908264Skettenis for (i = 0; i < 3; i++)
101f6908264Skettenis sc->sc_heartbeat[i] = pdc_lcd->heartbeat[i];
102b87e57a8Skettenis
1032038bf0aSjsing timeout_set(&sc->sc_to, lcd_blink_finish, sc);
1042038bf0aSjsing
1052038bf0aSjsing sc->sc_blink.bl_func = lcd_blink;
1062038bf0aSjsing sc->sc_blink.bl_arg = sc;
1072038bf0aSjsing blink_led_register(&sc->sc_blink);
1082038bf0aSjsing
109ef89f9e6Smpi config_mountroot(self, lcd_mountroot);
1102038bf0aSjsing }
1112038bf0aSjsing
1122038bf0aSjsing void
lcd_mountroot(struct device * self)113ef89f9e6Smpi lcd_mountroot(struct device *self)
1142038bf0aSjsing {
115ef89f9e6Smpi struct lcd_softc *sc = (struct lcd_softc *)self;
1162038bf0aSjsing
117b87e57a8Skettenis bus_space_write_1(sc->sc_iot, sc->sc_cmdh, 0, LCD_CLS);
118b87e57a8Skettenis delay(100 * sc->sc_delay);
119b87e57a8Skettenis
120b87e57a8Skettenis bus_space_write_1(sc->sc_iot, sc->sc_cmdh, 0, LCD_LOCATE(0, 0));
121b87e57a8Skettenis delay(sc->sc_delay);
122b87e57a8Skettenis lcd_write(sc, "OpenBSD/" MACHINE);
123b87e57a8Skettenis }
124b87e57a8Skettenis
125b87e57a8Skettenis void
lcd_write(struct lcd_softc * sc,const char * str)126b87e57a8Skettenis lcd_write(struct lcd_softc *sc, const char *str)
127b87e57a8Skettenis {
128b87e57a8Skettenis while (*str) {
129b87e57a8Skettenis bus_space_write_1(sc->sc_iot, sc->sc_datah, 0, *str++);
130b87e57a8Skettenis delay(sc->sc_delay);
131b87e57a8Skettenis }
132b87e57a8Skettenis }
133f6908264Skettenis
134f6908264Skettenis void
lcd_blink(void * v,int on)135f6908264Skettenis lcd_blink(void *v, int on)
136f6908264Skettenis {
137f6908264Skettenis struct lcd_softc *sc = v;
138f6908264Skettenis
139f6908264Skettenis sc->sc_on = on;
140f6908264Skettenis bus_space_write_1(sc->sc_iot, sc->sc_cmdh, 0, sc->sc_heartbeat[0]);
141b895fb73Scheloha timeout_add_usec(&sc->sc_to, sc->sc_delay);
142f6908264Skettenis }
143f6908264Skettenis
144f6908264Skettenis void
lcd_blink_finish(void * v)145f6908264Skettenis lcd_blink_finish(void *v)
146f6908264Skettenis {
147f6908264Skettenis struct lcd_softc *sc = v;
148f6908264Skettenis u_int8_t data;
149f6908264Skettenis
150f6908264Skettenis if (sc->sc_on)
151f6908264Skettenis data = sc->sc_heartbeat[1];
152f6908264Skettenis else
153f6908264Skettenis data = sc->sc_heartbeat[2];
154f6908264Skettenis
155f6908264Skettenis bus_space_write_1(sc->sc_iot, sc->sc_datah, 0, data);
156f6908264Skettenis }
157