Home | History | Annotate | Line # | Download | only in sunxi
sunxi_debe.c revision 1.1
      1 /* $NetBSD: sunxi_debe.c,v 1.1 2017/08/26 22:24:50 jmcneill Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2017 Jared McNeill <jmcneill (at) invisible.ca>
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  */
     28 
     29 #include <sys/cdefs.h>
     30 __KERNEL_RCSID(0, "$NetBSD: sunxi_debe.c,v 1.1 2017/08/26 22:24:50 jmcneill Exp $");
     31 
     32 #include <sys/param.h>
     33 #include <sys/bus.h>
     34 #include <sys/device.h>
     35 #include <sys/systm.h>
     36 
     37 #include <dev/fdt/fdtvar.h>
     38 
     39 #include <dev/wsfb/genfbvar.h>
     40 
     41 #define	SUNXI_SDRAM_BASE		0x40000000
     42 
     43 #define	DEBE_MAX_LAYER			4
     44 
     45 #define	DEBE_MODCTL_REG			0x800
     46 #define	 DEBE_MODCTL_LAYn_EN(n)		__BIT(8 + (n))
     47 #define	 DEBE_MODCTL_EN			__BIT(0)
     48 #define	DEBE_LAYSIZE_REG(n)		(0x810 + (n) * 0x10)
     49 #define	 DEBE_LAYSIZE_HEIGHT		__BITS(28,16)
     50 #define	 DEBE_LAYSIZE_WIDTH		__BITS(12,0)
     51 #define	DEBE_LAYCOOR_REG(n)		(0x820 + (n) * 0x4)
     52 #define	DEBE_LAYLINEWIDTH_REG(n)	(0x840 + (n) * 0x4)
     53 #define	DEBE_L32ADD_REG(n)		(0x850 + (n) * 0x4)
     54 #define	DEBE_H4ADD_REG			0x860
     55 #define	 DEBE_H4ADD(n)			__BITS((n) * 8 + 3, (n) * 8)
     56 
     57 static const char * const compatible[] = {
     58 	"allwinner,sun5i-a13-display-backend",
     59 	NULL
     60 };
     61 
     62 struct sunxi_debe_softc {
     63 	struct genfb_softc sc_gen;
     64 	bus_space_tag_t sc_bst;
     65 	bus_space_handle_t sc_bsh;
     66 	int sc_phandle;
     67 
     68 	bus_space_handle_t sc_fb_bsh;
     69 	bus_addr_t sc_fb_paddr;
     70 };
     71 
     72 #define BE_READ(sc, reg) \
     73     bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
     74 #define BE_WRITE(sc, reg, val) \
     75     bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
     76 
     77 static bool
     78 sunxi_debe_shutdown(device_t self, int flags)
     79 {
     80 	genfb_enable_polling(self);
     81 	return true;
     82 }
     83 
     84 static int
     85 sunxi_debe_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, lwp_t *l)
     86 {
     87 	struct sunxi_debe_softc * const sc = v;
     88 	struct wsdisplayio_bus_id *busid;
     89 	struct wsdisplayio_fbinfo *fbi;
     90 	struct rasops_info *ri;
     91 	int error;
     92 
     93 	switch (cmd) {
     94 	case WSDISPLAYIO_GTYPE:
     95 		*(u_int *)data = WSDISPLAY_TYPE_ALLWINNER;
     96 		return 0;
     97 	case WSDISPLAYIO_GET_BUSID:
     98 		busid = data;
     99 		busid->bus_type = WSDISPLAYIO_BUS_SOC;
    100 		return 0;
    101 	case WSDISPLAYIO_GET_FBINFO:
    102 		fbi = data;
    103 		ri = &sc->sc_gen.vd.active->scr_ri;
    104 		error = wsdisplayio_get_fbinfo(ri, fbi);
    105 		if (error == 0)
    106 			fbi->fbi_flags |= WSFB_VRAM_IS_RAM;
    107 		return error;
    108 	default:
    109 		return EPASSTHROUGH;
    110 	}
    111 }
    112 
    113 static paddr_t
    114 sunxi_debe_mmap(void *v, void *vs, off_t off, int prot)
    115 {
    116 	struct sunxi_debe_softc * const sc = v;
    117 
    118 	if (off < 0 || off >= sc->sc_gen.sc_fbsize)
    119 		return -1;
    120 
    121 	return bus_space_mmap(sc->sc_bst, sc->sc_fb_paddr, off, prot,
    122 	    BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE);
    123 }
    124 
    125 static void
    126 sunxi_debe_attach_layer(struct sunxi_debe_softc *sc, u_int lay)
    127 {
    128 	prop_dictionary_t dict = device_properties(sc->sc_gen.sc_dev);
    129 	struct genfb_ops ops;
    130 
    131 	const uint32_t size = BE_READ(sc, DEBE_LAYSIZE_REG(lay));
    132 	const uint32_t linewidth = BE_READ(sc, DEBE_LAYLINEWIDTH_REG(lay));
    133 	const uint32_t l32add = BE_READ(sc, DEBE_L32ADD_REG(lay));
    134 	const uint32_t h4add = BE_READ(sc, DEBE_H4ADD_REG);
    135 
    136 	const int width = __SHIFTOUT(size, DEBE_LAYSIZE_WIDTH) + 1;
    137 	const int height = __SHIFTOUT(size, DEBE_LAYSIZE_HEIGHT) + 1;
    138 	const int stride = linewidth / NBBY;
    139 	const uint64_t fbaddr_bits =
    140 	    l32add | (__SHIFTOUT(h4add, DEBE_H4ADD(lay)) << 32);
    141 	const uint32_t fbaddr = SUNXI_SDRAM_BASE +
    142 	    (uint32_t)(fbaddr_bits / NBBY);
    143 	const int fbsize = height * stride;
    144 
    145 	aprint_normal_dev(sc->sc_gen.sc_dev,
    146 	    "attaching %dx%d fb to layer %d @ 0x%08x size 0x%x\n",
    147 	    width, height, lay, fbaddr, fbsize);
    148 
    149 	if (bus_space_map(sc->sc_bst, fbaddr, fbsize,
    150 	    BUS_SPACE_MAP_LINEAR, &sc->sc_fb_bsh) != 0) {
    151 		aprint_error_dev(sc->sc_gen.sc_dev, "failed to map fb\n");
    152 		return;
    153 	}
    154 
    155 	sc->sc_fb_paddr = fbaddr;
    156 
    157 	prop_dictionary_set_uint32(dict, "width", width);
    158 	prop_dictionary_set_uint32(dict, "height", height);
    159 	prop_dictionary_set_uint8(dict, "depth", 32);
    160 	prop_dictionary_set_uint16(dict, "linebytes", stride);
    161 	prop_dictionary_set_uint32(dict, "address", fbaddr);
    162 	prop_dictionary_set_uint32(dict, "virtual_address",
    163 	    (uintptr_t)bus_space_vaddr(sc->sc_bst, sc->sc_fb_bsh));
    164 
    165 	genfb_init(&sc->sc_gen);
    166 
    167 	if (sc->sc_gen.sc_width == 0 || sc->sc_gen.sc_fbsize == 0) {
    168 		aprint_normal(": disabled\n");
    169 		return;
    170 	}
    171 
    172 	pmf_device_register1(sc->sc_gen.sc_dev, NULL, NULL,
    173 	    sunxi_debe_shutdown);
    174 
    175 	memset(&ops, 0, sizeof(ops));
    176 	ops.genfb_ioctl = sunxi_debe_ioctl;
    177 	ops.genfb_mmap = sunxi_debe_mmap;
    178 
    179 	bool is_console = false;
    180 	prop_dictionary_get_bool(dict, "is_console", &is_console);
    181 	prop_dictionary_set_bool(dict, "is_console", is_console);
    182 
    183 	if (is_console)
    184 		aprint_normal_dev(sc->sc_gen.sc_dev,
    185 		    "switching to framebuffer console\n");
    186 
    187 	genfb_attach(&sc->sc_gen, &ops);
    188 }
    189 
    190 static int
    191 sunxi_debe_match(device_t parent, cfdata_t cf, void *aux)
    192 {
    193 	struct fdt_attach_args * const faa = aux;
    194 
    195 	return of_match_compatible(faa->faa_phandle, compatible);
    196 }
    197 
    198 static void
    199 sunxi_debe_attach(device_t parent, device_t self, void *aux)
    200 {
    201 	struct sunxi_debe_softc * const sc = device_private(self);
    202 	struct fdt_attach_args * const faa = aux;
    203 	const int phandle = faa->faa_phandle;
    204 	struct fdtbus_reset *rst;
    205 	struct clk *clk;
    206 	bus_addr_t addr;
    207 	bus_size_t size;
    208 	u_int lay;
    209 
    210 	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
    211 		aprint_error(": couldn't get registers\n");
    212 		return;
    213 	}
    214 
    215 	if ((clk = fdtbus_clock_get(phandle, "ahb")) == NULL ||
    216 	    clk_enable(clk) != 0) {
    217 		aprint_error(": couldn't enable ahb clock\n");
    218 		return;
    219 	}
    220 	if ((rst = fdtbus_reset_get_index(phandle, 0)) == NULL ||
    221 	    fdtbus_reset_deassert(rst) != 0) {
    222 		aprint_error(": couldn't de-assert reset\n");
    223 		return;
    224 	}
    225 
    226 	sc->sc_gen.sc_dev = self;
    227 	sc->sc_phandle = phandle;
    228 	sc->sc_bst = faa->faa_bst;
    229 	if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
    230 		aprint_error(": couldn't map registers\n");
    231 		return;
    232 	}
    233 
    234 	aprint_naive("\n");
    235 	aprint_normal(": Display Backend\n");
    236 
    237 	aprint_normal_dev(self, "boot config:");
    238 	const uint32_t modctl = BE_READ(sc, DEBE_MODCTL_REG);
    239 	aprint_normal(" %08x\n", modctl);
    240 
    241 	if ((modctl & DEBE_MODCTL_EN) == 0) {
    242 		aprint_normal_dev(self, "not enabled by firmware\n");
    243 		return;
    244 	}
    245 
    246 	for (lay = 0; lay < DEBE_MAX_LAYER; lay++) {
    247 		if ((modctl & DEBE_MODCTL_LAYn_EN(lay)) == 0)
    248 			continue;
    249 		sunxi_debe_attach_layer(sc, lay);
    250 		break;
    251 	}
    252 	if (lay == DEBE_MAX_LAYER) {
    253 		aprint_error_dev(self, "no layers enabled\n");
    254 		return;
    255 	}
    256 }
    257 
    258 CFATTACH_DECL_NEW(sunxi_debe, sizeof(struct sunxi_debe_softc),
    259 	sunxi_debe_match, sunxi_debe_attach, NULL, NULL);
    260