1*4b552d31Stsutsui /* $NetBSD: lcd.c,v 1.13 2023/01/15 05:08:33 tsutsui Exp $ */
29184265aStsutsui /* $OpenBSD: lcd.c,v 1.7 2015/02/10 22:42:35 miod Exp $ */
395d00ea7Snisimura
495d00ea7Snisimura /*-
595d00ea7Snisimura * Copyright (c) 2000 The NetBSD Foundation, Inc.
695d00ea7Snisimura * All rights reserved.
795d00ea7Snisimura *
895d00ea7Snisimura * This code is derived from software contributed to The NetBSD Foundation
995d00ea7Snisimura * by Tohru Nishimura.
1095d00ea7Snisimura *
1195d00ea7Snisimura * Redistribution and use in source and binary forms, with or without
1295d00ea7Snisimura * modification, are permitted provided that the following conditions
1395d00ea7Snisimura * are met:
1495d00ea7Snisimura * 1. Redistributions of source code must retain the above copyright
1595d00ea7Snisimura * notice, this list of conditions and the following disclaimer.
1695d00ea7Snisimura * 2. Redistributions in binary form must reproduce the above copyright
1795d00ea7Snisimura * notice, this list of conditions and the following disclaimer in the
1895d00ea7Snisimura * documentation and/or other materials provided with the distribution.
1995d00ea7Snisimura *
2095d00ea7Snisimura * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2195d00ea7Snisimura * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2295d00ea7Snisimura * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2395d00ea7Snisimura * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2495d00ea7Snisimura * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2595d00ea7Snisimura * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2695d00ea7Snisimura * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2795d00ea7Snisimura * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2895d00ea7Snisimura * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2995d00ea7Snisimura * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3095d00ea7Snisimura * POSSIBILITY OF SUCH DAMAGE.
3195d00ea7Snisimura */
3295d00ea7Snisimura
3395d00ea7Snisimura #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
3495d00ea7Snisimura
35*4b552d31Stsutsui __KERNEL_RCSID(0, "$NetBSD: lcd.c,v 1.13 2023/01/15 05:08:33 tsutsui Exp $");
3695d00ea7Snisimura
3795d00ea7Snisimura #include <sys/param.h>
3895d00ea7Snisimura #include <sys/systm.h>
399184265aStsutsui #include <sys/conf.h>
4095d00ea7Snisimura #include <sys/device.h>
419184265aStsutsui #include <sys/ioctl.h>
429184265aStsutsui #include <sys/fcntl.h>
439184265aStsutsui #include <sys/errno.h>
4495d00ea7Snisimura
459184265aStsutsui #include <machine/autoconf.h>
463dd15d69Stsutsui #include <machine/board.h>
47460c94ccStsutsui #include <machine/cpu.h>
489184265aStsutsui #include <machine/lcd.h>
499184265aStsutsui
509184265aStsutsui #include "ioconf.h"
51460c94ccStsutsui
5295d00ea7Snisimura #define PIO1_MODE_OUTPUT 0x84
5395d00ea7Snisimura #define PIO1_MODE_INPUT 0x94
5495d00ea7Snisimura
5595d00ea7Snisimura #define POWER 0x10
5695d00ea7Snisimura
5795d00ea7Snisimura #define ENABLE 0x80
5895d00ea7Snisimura #define DISABLE 0x00
5995d00ea7Snisimura
6095d00ea7Snisimura #define WRITE_CMD (0x00 | 0x00)
6195d00ea7Snisimura #define WRITE_DATA (0x00 | 0x40)
6295d00ea7Snisimura #define READ_BUSY (0x20 | 0x00)
6395d00ea7Snisimura #define READ_DATA (0x20 | 0x40)
6495d00ea7Snisimura
6595d00ea7Snisimura #define LCD_INIT 0x38
6695d00ea7Snisimura #define LCD_ENTRY 0x06
6795d00ea7Snisimura #define LCD_ON 0x0c
6895d00ea7Snisimura #define LCD_CLS 0x01
6995d00ea7Snisimura #define LCD_HOME 0x02
7095d00ea7Snisimura #define LCD_LOCATE(X, Y) (((Y) & 1 ? 0xc0 : 0x80) | ((X) & 0x0f))
7195d00ea7Snisimura
729184265aStsutsui #define LCD_MAXBUFLEN 80
739184265aStsutsui
7495d00ea7Snisimura struct pio {
751c325a17Stsutsui volatile uint8_t portA;
761c325a17Stsutsui volatile uint8_t portB;
771c325a17Stsutsui volatile uint8_t portC;
781c325a17Stsutsui volatile uint8_t cntrl;
7995d00ea7Snisimura };
8095d00ea7Snisimura
819184265aStsutsui /* Autoconf stuff */
829184265aStsutsui static int lcd_match(device_t, cfdata_t, void *);
839184265aStsutsui static void lcd_attach(device_t, device_t, void *);
849184265aStsutsui
854a356195Stsutsui static dev_type_open(lcdopen);
864a356195Stsutsui static dev_type_close(lcdclose);
874a356195Stsutsui static dev_type_write(lcdwrite);
884a356195Stsutsui static dev_type_ioctl(lcdioctl);
899184265aStsutsui
909184265aStsutsui const struct cdevsw lcd_cdevsw = {
919184265aStsutsui .d_open = lcdopen,
929184265aStsutsui .d_close = lcdclose,
939184265aStsutsui .d_read = noread,
949184265aStsutsui .d_write = lcdwrite,
959184265aStsutsui .d_ioctl = lcdioctl,
969184265aStsutsui .d_stop = nostop,
979184265aStsutsui .d_tty = notty,
989184265aStsutsui .d_poll = nopoll,
999184265aStsutsui .d_mmap = nommap,
1009184265aStsutsui .d_kqfilter = nokqfilter,
1019184265aStsutsui .d_discard = nodiscard,
1029184265aStsutsui .d_flag = 0
1039184265aStsutsui };
1049184265aStsutsui
1059184265aStsutsui struct lcd_softc {
1069184265aStsutsui device_t sc_dev;
1079184265aStsutsui
1089184265aStsutsui bool sc_opened;
1099184265aStsutsui };
1109184265aStsutsui
1119184265aStsutsui CFATTACH_DECL_NEW(lcd, sizeof(struct lcd_softc),
1129184265aStsutsui lcd_match, lcd_attach, NULL, NULL);
1139184265aStsutsui
1144a356195Stsutsui static void lcdbusywait(void);
1154a356195Stsutsui static void lcdput(int);
1164a356195Stsutsui static void lcdctrl(int);
1174a356195Stsutsui static void lcdshow(char *);
1184a356195Stsutsui static void greeting(void);
11995d00ea7Snisimura /* "1234567890123456" */
12095d00ea7Snisimura static char lcd_boot_message1[] = " NetBSD/luna68k ";
12195d00ea7Snisimura static char lcd_boot_message2[] = " SX-9100/DT ";
12295d00ea7Snisimura
1239184265aStsutsui /*
1249184265aStsutsui * Autoconf functions
1259184265aStsutsui */
1269184265aStsutsui static int
lcd_match(device_t parent,cfdata_t cf,void * aux)1279184265aStsutsui lcd_match(device_t parent, cfdata_t cf, void *aux)
1289184265aStsutsui {
1299184265aStsutsui struct mainbus_attach_args *ma = aux;
1309184265aStsutsui
1319184265aStsutsui if (strcmp(ma->ma_name, lcd_cd.cd_name))
1329184265aStsutsui return 0;
1339184265aStsutsui if (badaddr((void *)ma->ma_addr, 4))
1349184265aStsutsui return 0;
1359184265aStsutsui return 1;
1369184265aStsutsui }
1379184265aStsutsui
1389184265aStsutsui static void
lcd_attach(device_t parent,device_t self,void * aux)1399184265aStsutsui lcd_attach(device_t parent, device_t self, void *aux)
1409184265aStsutsui {
1419184265aStsutsui
1429184265aStsutsui printf("\n");
1439184265aStsutsui
1449184265aStsutsui /* Say hello to the world on LCD. */
1459184265aStsutsui greeting();
1469184265aStsutsui }
1479184265aStsutsui
1489184265aStsutsui /*
1499184265aStsutsui * open/close/write/ioctl
1509184265aStsutsui */
1514a356195Stsutsui static int
lcdopen(dev_t dev,int flags,int fmt,struct lwp * l)1529184265aStsutsui lcdopen(dev_t dev, int flags, int fmt, struct lwp *l)
1539184265aStsutsui {
1549184265aStsutsui int unit;
1559184265aStsutsui struct lcd_softc *sc;
1569184265aStsutsui
1579184265aStsutsui unit = minor(dev);
1589184265aStsutsui sc = device_lookup_private(&lcd_cd, unit);
1599184265aStsutsui if (sc == NULL)
1609184265aStsutsui return ENXIO;
1619184265aStsutsui if (sc->sc_opened)
1629184265aStsutsui return EBUSY;
1639184265aStsutsui sc->sc_opened = true;
1649184265aStsutsui
1659184265aStsutsui return 0;
1669184265aStsutsui }
1679184265aStsutsui
1684a356195Stsutsui static int
lcdclose(dev_t dev,int flags,int fmt,struct lwp * l)1699184265aStsutsui lcdclose(dev_t dev, int flags, int fmt, struct lwp *l)
1709184265aStsutsui {
1719184265aStsutsui int unit;
1729184265aStsutsui struct lcd_softc *sc;
1739184265aStsutsui
1749184265aStsutsui unit = minor(dev);
1759184265aStsutsui sc = device_lookup_private(&lcd_cd, unit);
1769184265aStsutsui sc->sc_opened = false;
1779184265aStsutsui
1789184265aStsutsui return 0;
1799184265aStsutsui }
1809184265aStsutsui
1814a356195Stsutsui static int
lcdwrite(dev_t dev,struct uio * uio,int flag)1829184265aStsutsui lcdwrite(dev_t dev, struct uio *uio, int flag)
1839184265aStsutsui {
1849184265aStsutsui int error;
1859184265aStsutsui size_t len, i;
1869184265aStsutsui char buf[LCD_MAXBUFLEN];
1879184265aStsutsui
1889184265aStsutsui len = uio->uio_resid;
1899184265aStsutsui
1909184265aStsutsui if (len > LCD_MAXBUFLEN)
1919184265aStsutsui return EIO;
1929184265aStsutsui
1939184265aStsutsui error = uiomove(buf, len, uio);
1949184265aStsutsui if (error)
1959184265aStsutsui return EIO;
1969184265aStsutsui
1979184265aStsutsui for (i = 0; i < len; i++) {
1989184265aStsutsui lcdput((int)buf[i]);
1999184265aStsutsui }
2009184265aStsutsui
2019184265aStsutsui return 0;
2029184265aStsutsui }
2039184265aStsutsui
2044a356195Stsutsui static int
lcdioctl(dev_t dev,u_long cmd,void * addr,int flag,struct lwp * l)2059184265aStsutsui lcdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
2069184265aStsutsui {
2079184265aStsutsui int val;
2089184265aStsutsui
2099184265aStsutsui /* check if the device opened with write mode */
2109184265aStsutsui switch (cmd) {
2119184265aStsutsui case LCDCLS:
2129184265aStsutsui case LCDHOME:
2139184265aStsutsui case LCDMODE:
2149184265aStsutsui case LCDDISP:
2159184265aStsutsui case LCDMOVE:
2169184265aStsutsui case LCDSEEK:
2179184265aStsutsui case LCDRESTORE:
2189184265aStsutsui if ((flag & FWRITE) == 0)
2199184265aStsutsui return EACCES;
2209184265aStsutsui }
2219184265aStsutsui
2229184265aStsutsui switch (cmd) {
2239184265aStsutsui case LCDCLS:
2249184265aStsutsui lcdctrl(LCD_CLS);
2259184265aStsutsui break;
2269184265aStsutsui
2279184265aStsutsui case LCDHOME:
2289184265aStsutsui lcdctrl(LCD_HOME);
2299184265aStsutsui break;
2309184265aStsutsui
2319184265aStsutsui case LCDMODE:
2329184265aStsutsui val = *(int *)addr;
2339184265aStsutsui switch (val) {
2349184265aStsutsui case LCDMODE_C_LEFT:
2359184265aStsutsui case LCDMODE_C_RIGHT:
2369184265aStsutsui case LCDMODE_D_LEFT:
2379184265aStsutsui case LCDMODE_D_RIGHT:
2389184265aStsutsui lcdctrl(val);
2399184265aStsutsui break;
2409184265aStsutsui default:
2419184265aStsutsui return EINVAL;
2429184265aStsutsui }
2439184265aStsutsui break;
2449184265aStsutsui
2459184265aStsutsui case LCDDISP:
2469184265aStsutsui val = *(int *)addr;
2479184265aStsutsui if ((val & 0x7) != val)
2489184265aStsutsui return EINVAL;
2499184265aStsutsui lcdctrl(val | 0x8);
2509184265aStsutsui break;
2519184265aStsutsui
2529184265aStsutsui case LCDMOVE:
2539184265aStsutsui val = *(int *)addr;
2549184265aStsutsui switch (val) {
2559184265aStsutsui case LCDMOVE_C_LEFT:
2569184265aStsutsui case LCDMOVE_C_RIGHT:
2579184265aStsutsui case LCDMOVE_D_LEFT:
2589184265aStsutsui case LCDMOVE_D_RIGHT:
2599184265aStsutsui lcdctrl(val);
2609184265aStsutsui break;
2619184265aStsutsui default:
2629184265aStsutsui return EINVAL;
2639184265aStsutsui }
2649184265aStsutsui break;
2659184265aStsutsui
2669184265aStsutsui case LCDSEEK:
2679184265aStsutsui val = *(int *)addr & 0x7f;
2689184265aStsutsui lcdctrl(val | 0x80);
2699184265aStsutsui break;
2709184265aStsutsui
2719184265aStsutsui case LCDRESTORE:
2729184265aStsutsui greeting();
2739184265aStsutsui break;
2749184265aStsutsui
2759184265aStsutsui default:
2769184265aStsutsui return ENOTTY;
2779184265aStsutsui }
2789184265aStsutsui return EPASSTHROUGH;
2799184265aStsutsui }
2809184265aStsutsui
2814a356195Stsutsui static void
lcdbusywait(void)282df7f595eScegger lcdbusywait(void)
28395d00ea7Snisimura {
2843dd15d69Stsutsui struct pio *p1 = (struct pio *)OBIO_PIO1_BASE;
28595d00ea7Snisimura int msb, s;
28695d00ea7Snisimura
28795d00ea7Snisimura s = splhigh();
28895d00ea7Snisimura p1->cntrl = PIO1_MODE_INPUT;
28995d00ea7Snisimura p1->portC = POWER | READ_BUSY | ENABLE;
29095d00ea7Snisimura splx(s);
29195d00ea7Snisimura
29295d00ea7Snisimura do {
29395d00ea7Snisimura msb = p1->portA & ENABLE;
29495d00ea7Snisimura delay(5);
29595d00ea7Snisimura } while (msb != 0);
29695d00ea7Snisimura
29795d00ea7Snisimura s = splhigh();
29895d00ea7Snisimura p1->portC = POWER | READ_BUSY | DISABLE;
29995d00ea7Snisimura splx(s);
30095d00ea7Snisimura }
30195d00ea7Snisimura
3024a356195Stsutsui static void
lcdput(int cc)303454af1c0Sdsl lcdput(int cc)
30495d00ea7Snisimura {
3053dd15d69Stsutsui struct pio *p1 = (struct pio *)OBIO_PIO1_BASE;
30695d00ea7Snisimura int s;
30795d00ea7Snisimura
30895d00ea7Snisimura lcdbusywait();
30995d00ea7Snisimura
31095d00ea7Snisimura s = splhigh();
31195d00ea7Snisimura p1->cntrl = PIO1_MODE_OUTPUT;
31295d00ea7Snisimura
31395d00ea7Snisimura p1->portC = POWER | WRITE_DATA | ENABLE;
31495d00ea7Snisimura p1->portA = cc;
31595d00ea7Snisimura p1->portC = POWER | WRITE_DATA | DISABLE;
31695d00ea7Snisimura splx(s);
31795d00ea7Snisimura }
31895d00ea7Snisimura
3194a356195Stsutsui static void
lcdctrl(int cc)320454af1c0Sdsl lcdctrl(int cc)
32195d00ea7Snisimura {
3223dd15d69Stsutsui struct pio *p1 = (struct pio *)OBIO_PIO1_BASE;
32395d00ea7Snisimura int s;
32495d00ea7Snisimura
32595d00ea7Snisimura lcdbusywait();
32695d00ea7Snisimura
32795d00ea7Snisimura s = splhigh();
32895d00ea7Snisimura p1->cntrl = PIO1_MODE_OUTPUT;
32995d00ea7Snisimura
33095d00ea7Snisimura p1->portC = POWER | WRITE_CMD | ENABLE;
33195d00ea7Snisimura p1->portA = cc;
33295d00ea7Snisimura p1->portC = POWER | WRITE_CMD | DISABLE;
33395d00ea7Snisimura splx(s);
33495d00ea7Snisimura }
33595d00ea7Snisimura
3364a356195Stsutsui static void
lcdshow(char * s)337454af1c0Sdsl lcdshow(char *s)
33895d00ea7Snisimura {
33995d00ea7Snisimura int cc;
34095d00ea7Snisimura
34195d00ea7Snisimura while ((cc = *s++) != '\0')
34295d00ea7Snisimura lcdput(cc);
34395d00ea7Snisimura }
34495d00ea7Snisimura
3454a356195Stsutsui static void
greeting(void)346df7f595eScegger greeting(void)
34795d00ea7Snisimura {
3481c325a17Stsutsui
34995d00ea7Snisimura lcdctrl(LCD_INIT);
35095d00ea7Snisimura lcdctrl(LCD_ENTRY);
35195d00ea7Snisimura lcdctrl(LCD_ON);
35295d00ea7Snisimura
35395d00ea7Snisimura lcdctrl(LCD_CLS);
35495d00ea7Snisimura lcdctrl(LCD_HOME);
35595d00ea7Snisimura
35695d00ea7Snisimura lcdctrl(LCD_LOCATE(0, 0));
35795d00ea7Snisimura lcdshow(lcd_boot_message1);
35895d00ea7Snisimura lcdctrl(LCD_LOCATE(0, 1));
359460c94ccStsutsui if (machtype == LUNA_II)
360460c94ccStsutsui lcd_boot_message2[13] = '2';
36195d00ea7Snisimura lcdshow(lcd_boot_message2);
36295d00ea7Snisimura }
363