Created
November 4, 2023 15:44
-
-
Save tsutsui/825ecf7b3d003917e66cee7c80c4d44c to your computer and use it in GitHub Desktop.
prototype driver of NWS-32x0 LCD-MONO framebuffer for NetBSD/newsmips
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* $NetBSD$ */ | |
/*- | |
* Copyright (c) 2023 Izumi Tsutsui. All rights reserved. | |
* | |
* Redistribution and use in source and binary forms, with or without | |
* modification, are permitted provided that the following conditions | |
* are met: | |
* 1. Redistributions of source code must retain the above copyright | |
* notice, this list of conditions and the following disclaimer. | |
* 2. Redistributions in binary form must reproduce the above copyright | |
* notice, this list of conditions and the following disclaimer in the | |
* documentation and/or other materials provided with the distribution. | |
* | |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
*/ | |
/*- | |
* Copyright (c) 2000 Tsubai Masanari. All rights reserved. | |
* | |
* Redistribution and use in source and binary forms, with or without | |
* modification, are permitted provided that the following conditions | |
* are met: | |
* 1. Redistributions of source code must retain the above copyright | |
* notice, this list of conditions and the following disclaimer. | |
* 2. Redistributions in binary form must reproduce the above copyright | |
* notice, this list of conditions and the following disclaimer in the | |
* documentation and/or other materials provided with the distribution. | |
* 3. The name of the author may not be used to endorse or promote products | |
* derived from this software without specific prior written permission. | |
* | |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
*/ | |
#include <sys/cdefs.h> | |
__KERNEL_RCSID(0, "$NetBSD$"); | |
#include <sys/param.h> | |
#include <sys/device.h> | |
#include <sys/ioctl.h> | |
#include <sys/kmem.h> | |
#include <sys/systm.h> | |
#include <uvm/uvm_extern.h> | |
#include <machine/adrsmap.h> | |
#include <newsmips/dev/hbvar.h> | |
#include <dev/wscons/wsconsio.h> | |
#include <dev/wscons/wsdisplayvar.h> | |
#include <dev/rasops/rasops.h> | |
struct fblcd_devconfig { | |
uint8_t *dc_fbbase; /* VRAM base address */ | |
struct rasops_info dc_ri; | |
}; | |
struct fblcd_softc { | |
device_t sc_dev; | |
struct fblcd_devconfig *sc_dc; | |
int sc_nscreens; | |
}; | |
static int fblcd_match(device_t, cfdata_t, void *); | |
static void fblcd_attach(device_t, device_t, void *); | |
static int fblcd_common_init(struct fblcd_devconfig *); | |
static bool fblcd_is_console(void); | |
static int fblcd_ioctl(void *, void *, u_long, void *, int, struct lwp *); | |
static paddr_t fblcd_mmap(void *, void *, off_t, int); | |
static int fblcd_alloc_screen(void *, const struct wsscreen_descr *, void **, | |
int *, int *, long *); | |
static void fblcd_free_screen(void *, void *); | |
static int fblcd_show_screen(void *, void *, int, void (*)(void *, int, int), | |
void *); | |
void fblcd_cnattach(void); | |
static void fblcdm_init(void); | |
CFATTACH_DECL_NEW(fblcd, sizeof(struct fblcd_softc), | |
fblcd_match, fblcd_attach, NULL, NULL); | |
static struct fblcd_devconfig fblcd_console_dc; | |
static struct wsdisplay_accessops fblcd_accessops = { | |
.ioctl = fblcd_ioctl, | |
.mmap = fblcd_mmap, | |
.alloc_screen = fblcd_alloc_screen, | |
.free_screen = fblcd_free_screen, | |
.show_screen = fblcd_show_screen, | |
}; | |
static struct wsscreen_descr fblcd_stdscreen = { | |
.name = "std", | |
.ncols = 0, | |
.nrows = 0, | |
.textops = NULL, | |
.fontwidth = 0, | |
.fontheight = 0, | |
.capabilities = WSSCREEN_REVERSE, | |
.modecookie = NULL | |
}; | |
static const struct wsscreen_descr *fblcd_scrlist[] = { | |
&fblcd_stdscreen | |
}; | |
static struct wsscreen_list fblcd_screenlist = { | |
__arraycount(fblcd_scrlist), fblcd_scrlist | |
}; | |
#define LCD_PORT ((uint32_t *)0xb0000000) | |
#define LCD_DIMMER ((uint32_t *)0xb0100000) | |
#define LCD_DMMER_ON 0xf0 | |
#define LCD_DMMER_OFF 0xf1 | |
#define LCD_CRTC ((uint8_t *)0xbff60000) | |
#define LCD_VRAM ((uint8_t *)0x90200000) | |
static int | |
fblcd_match(device_t parent, cfdata_t cf, void *aux) | |
{ | |
struct hb_attach_args *ha = aux; | |
if (strcmp(ha->ha_name, "fblcd") != 0) | |
return 0; | |
if (hb_badaddr((void *)0xbff50000, 1)) | |
return 0; | |
if (*(volatile uint8_t *)0xbff50000 == 0xff) | |
return 1; | |
return 0; | |
} | |
static void | |
fblcd_attach(device_t parent, device_t self, void *aux) | |
{ | |
struct fblcd_softc *sc = device_private(self); | |
struct wsemuldisplaydev_attach_args waa; | |
struct fblcd_devconfig *dc; | |
struct rasops_info *ri; | |
bool console; | |
sc->sc_dev = self; | |
console = fblcd_is_console(); | |
if (console) { | |
dc = &fblcd_console_dc; | |
ri = &dc->dc_ri; | |
ri->ri_flg &= ~RI_NO_AUTO; | |
sc->sc_nscreens = 1; | |
} else { | |
dc = kmem_zalloc(sizeof(struct fblcd_devconfig), KM_SLEEP); | |
dc->dc_fbbase = LCD_VRAM; | |
fblcd_common_init(dc); | |
ri = &dc->dc_ri; | |
/* clear screen */ | |
(*ri->ri_ops.eraserows)(ri, 0, ri->ri_rows, 0); | |
fblcdm_init(); | |
} | |
sc->sc_dc = dc; | |
aprint_normal(": LCD-MONO, %d x %d, %dbpp\n", | |
ri->ri_width, ri->ri_height, ri->ri_depth); | |
waa.console = console; | |
waa.scrdata = &fblcd_screenlist; | |
waa.accessops = &fblcd_accessops; | |
waa.accesscookie = sc; | |
config_found(self, &waa, wsemuldisplaydevprint); | |
} | |
int | |
fblcd_common_init(struct fblcd_devconfig *dc) | |
{ | |
struct rasops_info *ri = &dc->dc_ri; | |
int width, height, xoff, yoff, cols, rows; | |
/* initialize rasops */ | |
width = 1120; | |
height = 780; | |
ri->ri_width = width; | |
ri->ri_height = height; | |
ri->ri_depth = 1; | |
ri->ri_stride = width / 8; | |
ri->ri_bits = dc->dc_fbbase; | |
ri->ri_flg = RI_FULLCLEAR; | |
if (dc == &fblcd_console_dc) | |
ri->ri_flg |= RI_NO_AUTO; | |
rasops_init(ri, 24, 80); | |
rows = (height - 2) / ri->ri_font->fontheight; | |
cols = ((width - 2) / ri->ri_font->fontwidth) & ~7; | |
xoff = ((width - cols * ri->ri_font->fontwidth) / 2 / 8) & ~3; | |
yoff = (height - rows * ri->ri_font->fontheight) / 2; | |
rasops_reconfig(ri, rows, cols); | |
ri->ri_xorigin = xoff; | |
ri->ri_yorigin = yoff; | |
ri->ri_bits = dc->dc_fbbase + xoff + ri->ri_stride * yoff; | |
fblcd_stdscreen.nrows = ri->ri_rows; | |
fblcd_stdscreen.ncols = ri->ri_cols; | |
fblcd_stdscreen.textops = &ri->ri_ops; | |
fblcd_stdscreen.capabilities = ri->ri_caps; | |
return 0; | |
} | |
static bool | |
fblcd_is_console(void) | |
{ | |
volatile u_int *dipsw = (void *)DIP_SWITCH; | |
if ((*dipsw & 7) == 0x02) /* SW[1,2,3] = [OFF,ON,OFF] */ | |
return true; | |
return false; | |
} | |
static int | |
fblcd_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l) | |
{ | |
struct fblcd_softc *sc = v; | |
struct fblcd_devconfig *dc = sc->sc_dc; | |
struct wsdisplay_fbinfo *wdf; | |
volatile uint32_t *dimmerreg = LCD_DIMMER; | |
switch (cmd) { | |
case WSDISPLAYIO_GTYPE: | |
*(int *)data = WSDISPLAY_TYPE_UNKNOWN; /* XXX */ | |
return 0; | |
case WSDISPLAYIO_GINFO: | |
wdf = (void *)data; | |
wdf->height = dc->dc_ri.ri_height; | |
wdf->width = dc->dc_ri.ri_width; | |
wdf->depth = dc->dc_ri.ri_depth; | |
wdf->cmsize = 0; | |
return 0; | |
case WSDISPLAYIO_LINEBYTES: | |
*(u_int *)data = dc->dc_ri.ri_stride; | |
return 0; | |
case WSDISPLAYIO_SVIDEO: | |
if (*(int *)data == WSDISPLAYIO_VIDEO_OFF) { | |
*dimmerreg = LCD_DMMER_OFF; | |
} else { | |
*dimmerreg = LCD_DMMER_ON; | |
} | |
return 0; | |
case WSDISPLAYIO_GETCMAP: | |
case WSDISPLAYIO_PUTCMAP: | |
break; | |
} | |
return EPASSTHROUGH; | |
} | |
static paddr_t | |
fblcd_mmap(void *v, void *vs, off_t offset, int prot) | |
{ | |
struct fblcd_softc *sc = v; | |
struct fblcd_devconfig *dc = sc->sc_dc; | |
if (offset >= dc->dc_ri.ri_height * dc->dc_ri.ri_width / 8 || | |
offset < 0) | |
return -1; | |
return mips_btop((int)dc->dc_fbbase + offset); | |
} | |
static int | |
fblcd_alloc_screen(void *v, const struct wsscreen_descr *scrdesc, | |
void **cookiep, int *ccolp, int *crowp, long *attrp) | |
{ | |
struct fblcd_softc *sc = v; | |
struct rasops_info *ri = &sc->sc_dc->dc_ri; | |
long defattr; | |
if (sc->sc_nscreens > 0) | |
return ENOMEM; | |
*cookiep = ri; | |
*ccolp = *crowp = 0; | |
(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr); | |
*attrp = defattr; | |
sc->sc_nscreens++; | |
return 0; | |
} | |
static void | |
fblcd_free_screen(void *v, void *cookie) | |
{ | |
struct fblcd_softc *sc = v; | |
if (sc->sc_dc == &fblcd_console_dc) | |
panic("%s: console", __func__); | |
sc->sc_nscreens--; | |
} | |
static int | |
fblcd_show_screen(void *v, void *cookie, int waitok, | |
void (*cb)(void *, int, int), void *cbarg) | |
{ | |
return 0; | |
} | |
void | |
fblcd_cnattach(void) | |
{ | |
struct fblcd_devconfig *dc = &fblcd_console_dc; | |
struct rasops_info *ri = &dc->dc_ri; | |
long defattr; | |
if (!fblcd_is_console()) | |
return; | |
dc->dc_fbbase = LCD_VRAM; | |
fblcd_common_init(dc); | |
(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr); | |
wsdisplay_cnattach(&fblcd_stdscreen, ri, 0, ri->ri_rows - 1, defattr); | |
} | |
static const uint8_t lcdcrtc_data[] = { | |
0, 47, | |
1, 35, | |
9, 0, | |
10, 0, | |
11, 0, | |
12, 0, | |
13, 0, | |
14, 0, | |
15, 0, | |
18, 35, | |
19, 0x01, | |
20, 0x85, | |
21, 0, | |
22, 0x10 | |
}; | |
static void | |
fblcdm_init(void) | |
{ | |
volatile uint8_t *crtcreg = LCD_CRTC; | |
volatile uint32_t *portreg = LCD_PORT; | |
int i; | |
/* initialize crtc */ | |
for (i = 0; i < 28; i++) { | |
*crtcreg++ = lcdcrtc_data[i]; | |
delay(10); | |
} | |
delay(1000); | |
*portreg = 1; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment