xref: /openbsd-src/sys/dev/fdt/rkdrm.c (revision d66736b0c0d3b2b4462f281b35a9b1cdf3dbe7b8)
1*d66736b0Sjsg /* $OpenBSD: rkdrm.c,v 1.23 2024/08/21 11:24:12 jsg Exp $ */
260afa471Spatrick /* $NetBSD: rk_drm.c,v 1.3 2019/12/15 01:00:58 mrg Exp $ */
360afa471Spatrick /*-
460afa471Spatrick  * Copyright (c) 2019 Jared D. McNeill <jmcneill@invisible.ca>
560afa471Spatrick  * Copyright (c) 2020 Patrick Wildt <patrick@blueri.se>
660afa471Spatrick  * All rights reserved.
760afa471Spatrick  *
860afa471Spatrick  * Redistribution and use in source and binary forms, with or without
960afa471Spatrick  * modification, are permitted provided that the following conditions
1060afa471Spatrick  * are met:
1160afa471Spatrick  * 1. Redistributions of source code must retain the above copyright
1260afa471Spatrick  *    notice, this list of conditions and the following disclaimer.
1360afa471Spatrick  * 2. Redistributions in binary form must reproduce the above copyright
1460afa471Spatrick  *    notice, this list of conditions and the following disclaimer in the
1560afa471Spatrick  *    documentation and/or other materials provided with the distribution.
1660afa471Spatrick  *
1760afa471Spatrick  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1860afa471Spatrick  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1960afa471Spatrick  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2060afa471Spatrick  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2160afa471Spatrick  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2260afa471Spatrick  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2360afa471Spatrick  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2460afa471Spatrick  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2560afa471Spatrick  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2660afa471Spatrick  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2760afa471Spatrick  * SUCH DAMAGE.
2860afa471Spatrick  */
2960afa471Spatrick 
3060afa471Spatrick #include <sys/param.h>
3160afa471Spatrick #include <sys/device.h>
3260afa471Spatrick #include <sys/systm.h>
3360afa471Spatrick 
3460afa471Spatrick #include <machine/bus.h>
3560afa471Spatrick #include <machine/fdt.h>
3660afa471Spatrick 
3760afa471Spatrick #include <dev/ofw/openfirm.h>
3860afa471Spatrick #include <dev/ofw/ofw_misc.h>
3960afa471Spatrick 
40c349dbc7Sjsg #include <drm/drm_atomic_helper.h>
41c349dbc7Sjsg #include <drm/drm_drv.h>
4260afa471Spatrick #include <drm/drm_fb_helper.h>
4360afa471Spatrick #include <drm/drm_gem.h>
4460afa471Spatrick 
4560afa471Spatrick #include <dev/fdt/rkdrm.h>
4660afa471Spatrick 
4760afa471Spatrick #define	RK_DRM_MAX_WIDTH	3840
4860afa471Spatrick #define	RK_DRM_MAX_HEIGHT	2160
4960afa471Spatrick 
5060afa471Spatrick int	rkdrm_match(struct device *, void *, void *);
5160afa471Spatrick void	rkdrm_attach(struct device *, struct device *, void *);
5260afa471Spatrick void	rkdrm_attachhook(struct device *);
5360afa471Spatrick 
5460afa471Spatrick int	rkdrm_unload(struct drm_device *);
5560afa471Spatrick 
5660afa471Spatrick struct drm_driver rkdrm_driver = {
57c349dbc7Sjsg 	.driver_features = DRIVER_ATOMIC | DRIVER_MODESET | DRIVER_GEM,
5860afa471Spatrick 
591bb76ff1Sjsg 	.dumb_create = drm_gem_dma_dumb_create,
60c349dbc7Sjsg 	.dumb_map_offset = drm_gem_dumb_map_offset,
6160afa471Spatrick 
621bb76ff1Sjsg 	.gem_fault = drm_gem_dma_fault,
6360afa471Spatrick 
6460afa471Spatrick 	.name = DRIVER_NAME,
6560afa471Spatrick 	.desc = DRIVER_DESC,
6660afa471Spatrick 	.date = DRIVER_DATE,
6760afa471Spatrick 	.major = DRIVER_MAJOR,
6860afa471Spatrick 	.minor = DRIVER_MINOR,
6960afa471Spatrick 	.patchlevel = DRIVER_PATCHLEVEL,
7060afa471Spatrick };
7160afa471Spatrick 
725ca02815Sjsg const struct drm_gem_object_funcs rkdrm_gem_object_funcs = {
731bb76ff1Sjsg 	.free = drm_gem_dma_free_object,
745ca02815Sjsg };
755ca02815Sjsg 
76471aeecfSnaddy const struct cfattach rkdrm_ca = {
7760afa471Spatrick 	sizeof (struct rkdrm_softc), rkdrm_match, rkdrm_attach
7860afa471Spatrick };
7960afa471Spatrick 
8060afa471Spatrick struct cfdriver rkdrm_cd = {
8160afa471Spatrick 	NULL, "rkdrm", DV_DULL
8260afa471Spatrick };
8360afa471Spatrick 
8460afa471Spatrick int
8560afa471Spatrick rkdrm_match(struct device *parent, void *match, void *aux)
8660afa471Spatrick {
8760afa471Spatrick 	struct fdt_attach_args *faa = aux;
8860afa471Spatrick 
8960afa471Spatrick 	return OF_is_compatible(faa->fa_node, "rockchip,display-subsystem");
9060afa471Spatrick }
9160afa471Spatrick 
9260afa471Spatrick void
9360afa471Spatrick rkdrm_attach(struct device *parent, struct device *self, void *aux)
9460afa471Spatrick {
9560afa471Spatrick 	struct rkdrm_softc *sc = (struct rkdrm_softc *)self;
9660afa471Spatrick 	struct fdt_attach_args *faa = aux;
9760afa471Spatrick 
9860afa471Spatrick 	sc->sc_dmat = faa->fa_dmat;
9960afa471Spatrick 	sc->sc_iot = faa->fa_iot;
10060afa471Spatrick 	sc->sc_node = faa->fa_node;
10160afa471Spatrick 
10260afa471Spatrick 	printf("\n");
10360afa471Spatrick 
1047dd3f745Skettenis 	/*
1057dd3f745Skettenis 	 * Update our understanding of the console output node if
1067dd3f745Skettenis 	 * we're using the framebuffer console.
1077dd3f745Skettenis 	 */
1087dd3f745Skettenis 	if (OF_is_compatible(stdout_node, "simple-framebuffer"))
1097dd3f745Skettenis 		stdout_node = sc->sc_node;
1107dd3f745Skettenis 
111c349dbc7Sjsg 	drm_attach_platform(&rkdrm_driver, faa->fa_iot, faa->fa_dmat, self,
112c349dbc7Sjsg 	    &sc->sc_ddev);
11360afa471Spatrick 	config_mountroot(self, rkdrm_attachhook);
11460afa471Spatrick }
11560afa471Spatrick 
11660afa471Spatrick int
11760afa471Spatrick rkdrm_fb_create_handle(struct drm_framebuffer *fb,
11860afa471Spatrick     struct drm_file *file, unsigned int *handle)
11960afa471Spatrick {
12060afa471Spatrick 	struct rkdrm_framebuffer *sfb = to_rkdrm_framebuffer(fb);
12160afa471Spatrick 
12260afa471Spatrick 	return drm_gem_handle_create(file, &sfb->obj->base, handle);
12360afa471Spatrick }
12460afa471Spatrick 
12560afa471Spatrick void
12660afa471Spatrick rkdrm_fb_destroy(struct drm_framebuffer *fb)
12760afa471Spatrick {
12860afa471Spatrick 	struct rkdrm_framebuffer *sfb = to_rkdrm_framebuffer(fb);
12960afa471Spatrick 
13060afa471Spatrick 	drm_framebuffer_cleanup(fb);
131ad8b1aafSjsg 	drm_gem_object_put(&sfb->obj->base);
13260afa471Spatrick 	free(sfb, M_DRM, sizeof(*sfb));
13360afa471Spatrick }
13460afa471Spatrick 
13560afa471Spatrick struct drm_framebuffer_funcs rkdrm_framebuffer_funcs = {
13660afa471Spatrick 	.create_handle = rkdrm_fb_create_handle,
13760afa471Spatrick 	.destroy = rkdrm_fb_destroy,
13860afa471Spatrick };
13960afa471Spatrick 
14060afa471Spatrick struct drm_framebuffer *
14160afa471Spatrick rkdrm_fb_create(struct drm_device *ddev, struct drm_file *file,
14260afa471Spatrick     const struct drm_mode_fb_cmd2 *cmd)
14360afa471Spatrick {
14460afa471Spatrick 	struct rkdrm_framebuffer *fb;
14560afa471Spatrick 	struct drm_gem_object *gem_obj;
14660afa471Spatrick 	int error;
14760afa471Spatrick 
14860afa471Spatrick 	if (cmd->flags)
14960afa471Spatrick 		return NULL;
15060afa471Spatrick 
15160afa471Spatrick 	gem_obj = drm_gem_object_lookup(file, cmd->handles[0]);
15260afa471Spatrick 	if (gem_obj == NULL)
15360afa471Spatrick 		return NULL;
15460afa471Spatrick 
15560afa471Spatrick 	fb = malloc(sizeof(*fb), M_DRM, M_ZERO | M_WAITOK);
15660afa471Spatrick 	drm_helper_mode_fill_fb_struct(ddev, &fb->base, cmd);
15760afa471Spatrick 	fb->base.format = drm_format_info(DRM_FORMAT_ARGB8888);
1585ca02815Sjsg 	fb->base.obj[0] = gem_obj;
1591bb76ff1Sjsg 	fb->obj = to_drm_gem_dma_obj(gem_obj);
16060afa471Spatrick 
16160afa471Spatrick 	error = drm_framebuffer_init(ddev, &fb->base, &rkdrm_framebuffer_funcs);
16260afa471Spatrick 	if (error != 0)
16360afa471Spatrick 		goto dealloc;
16460afa471Spatrick 
16560afa471Spatrick 	return &fb->base;
16660afa471Spatrick 
16760afa471Spatrick dealloc:
16860afa471Spatrick 	drm_framebuffer_cleanup(&fb->base);
16960afa471Spatrick 	free(fb, M_DRM, sizeof(*fb));
170ad8b1aafSjsg 	drm_gem_object_put(gem_obj);
17160afa471Spatrick 
17260afa471Spatrick 	return NULL;
17360afa471Spatrick }
17460afa471Spatrick 
175c349dbc7Sjsg struct drm_mode_config_helper_funcs rkdrm_mode_config_helper_funcs =
176c349dbc7Sjsg {
177c349dbc7Sjsg 	.atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
178c349dbc7Sjsg };
179c349dbc7Sjsg 
18060afa471Spatrick struct drm_mode_config_funcs rkdrm_mode_config_funcs = {
18160afa471Spatrick 	.fb_create = rkdrm_fb_create,
182c349dbc7Sjsg 	.atomic_check = drm_atomic_helper_check,
183c349dbc7Sjsg 	.atomic_commit = drm_atomic_helper_commit,
18460afa471Spatrick };
18560afa471Spatrick 
18660afa471Spatrick int rkdrm_fb_probe(struct drm_fb_helper *, struct drm_fb_helper_surface_size *);
18760afa471Spatrick 
18860afa471Spatrick struct drm_fb_helper_funcs rkdrm_fb_helper_funcs = {
18960afa471Spatrick 	.fb_probe = rkdrm_fb_probe,
19060afa471Spatrick };
19160afa471Spatrick 
19260afa471Spatrick int
19360afa471Spatrick rkdrm_unload(struct drm_device *ddev)
19460afa471Spatrick {
19560afa471Spatrick 	drm_mode_config_cleanup(ddev);
19660afa471Spatrick 
19760afa471Spatrick 	return 0;
19860afa471Spatrick }
19960afa471Spatrick 
20060afa471Spatrick void rkdrm_burner(void *, u_int, u_int);
20160afa471Spatrick int rkdrm_wsioctl(void *, u_long, caddr_t, int, struct proc *);
20260afa471Spatrick paddr_t rkdrm_wsmmap(void *, off_t, int);
20360afa471Spatrick int rkdrm_alloc_screen(void *, const struct wsscreen_descr *,
204e0c3e559Sjsg     void **, int *, int *, uint32_t *);
20560afa471Spatrick void rkdrm_free_screen(void *, void *);
20660afa471Spatrick int rkdrm_show_screen(void *, void *, int,
20760afa471Spatrick     void (*)(void *, int, int), void *);
20860afa471Spatrick void rkdrm_doswitch(void *);
20960afa471Spatrick void rkdrm_enter_ddb(void *, void *);
21060afa471Spatrick 
21160afa471Spatrick struct wsscreen_descr rkdrm_stdscreen = {
21260afa471Spatrick 	"std",
21360afa471Spatrick 	0, 0,
21460afa471Spatrick 	0,
21560afa471Spatrick 	0, 0,
21660afa471Spatrick 	WSSCREEN_UNDERLINE | WSSCREEN_HILIT |
21760afa471Spatrick 	WSSCREEN_REVERSE | WSSCREEN_WSCOLORS
21860afa471Spatrick };
21960afa471Spatrick 
22060afa471Spatrick const struct wsscreen_descr *rkdrm_scrlist[] = {
22160afa471Spatrick 	&rkdrm_stdscreen,
22260afa471Spatrick };
22360afa471Spatrick 
22460afa471Spatrick struct wsscreen_list rkdrm_screenlist = {
22560afa471Spatrick 	nitems(rkdrm_scrlist), rkdrm_scrlist
22660afa471Spatrick };
22760afa471Spatrick 
22860afa471Spatrick struct wsdisplay_accessops rkdrm_accessops = {
22960afa471Spatrick 	.ioctl = rkdrm_wsioctl,
23060afa471Spatrick 	.mmap = rkdrm_wsmmap,
23160afa471Spatrick 	.alloc_screen = rkdrm_alloc_screen,
23260afa471Spatrick 	.free_screen = rkdrm_free_screen,
23360afa471Spatrick 	.show_screen = rkdrm_show_screen,
23460afa471Spatrick 	.enter_ddb = rkdrm_enter_ddb,
23560afa471Spatrick 	.getchar = rasops_getchar,
23660afa471Spatrick 	.load_font = rasops_load_font,
23760afa471Spatrick 	.list_font = rasops_list_font,
23860afa471Spatrick 	.scrollback = rasops_scrollback,
23960afa471Spatrick #ifdef notyet
24060afa471Spatrick 	.burn_screen = rkdrm_burner
24160afa471Spatrick #endif
24260afa471Spatrick };
24360afa471Spatrick 
24460afa471Spatrick int
24560afa471Spatrick rkdrm_wsioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
24660afa471Spatrick {
24760afa471Spatrick 	struct rasops_info *ri = v;
24860afa471Spatrick 	struct wsdisplay_param *dp = (struct wsdisplay_param *)data;
24960afa471Spatrick 	struct wsdisplay_fbinfo *wdf;
25060afa471Spatrick 
25160afa471Spatrick 	switch (cmd) {
252728f54cfSbmercer 	case WSDISPLAYIO_GETPARAM:
253728f54cfSbmercer 		if (ws_get_param)
254728f54cfSbmercer 			return ws_get_param(dp);
255728f54cfSbmercer 		return -1;
256728f54cfSbmercer 	case WSDISPLAYIO_SETPARAM:
257728f54cfSbmercer 		if (ws_set_param)
258728f54cfSbmercer 			return ws_set_param(dp);
259728f54cfSbmercer 		return -1;
26060afa471Spatrick 	case WSDISPLAYIO_GTYPE:
261aa99957fSkettenis 		*(u_int *)data = WSDISPLAY_TYPE_KMS;
26260afa471Spatrick 		return 0;
26360afa471Spatrick 	case WSDISPLAYIO_GINFO:
26460afa471Spatrick 		wdf = (struct wsdisplay_fbinfo *)data;
26560afa471Spatrick 		wdf->width = ri->ri_width;
26660afa471Spatrick 		wdf->height = ri->ri_height;
26760afa471Spatrick 		wdf->depth = ri->ri_depth;
26863294167Skettenis 		wdf->stride = ri->ri_stride;
26963294167Skettenis 		wdf->offset = 0;
27060afa471Spatrick 		wdf->cmsize = 0;
27160afa471Spatrick 		return 0;
27260afa471Spatrick 	case WSDISPLAYIO_LINEBYTES:
27360afa471Spatrick 		*(u_int *)data = ri->ri_stride;
27460afa471Spatrick 		return 0;
275804fcafaSjsg 	case WSDISPLAYIO_SVIDEO:
276804fcafaSjsg 	case WSDISPLAYIO_GVIDEO:
277804fcafaSjsg 		return 0;
27860afa471Spatrick 	}
27960afa471Spatrick 
28060afa471Spatrick 	return (-1);
28160afa471Spatrick }
28260afa471Spatrick 
28360afa471Spatrick paddr_t
28460afa471Spatrick rkdrm_wsmmap(void *v, off_t off, int prot)
28560afa471Spatrick {
28660afa471Spatrick 	struct rasops_info *ri = v;
28760afa471Spatrick 	struct rkdrm_softc *sc = ri->ri_hw;
28860afa471Spatrick 	struct drm_fb_helper *helper = &sc->helper;
28960afa471Spatrick 	struct rkdrm_framebuffer *sfb = to_rkdrm_framebuffer(helper->fb);
29060afa471Spatrick 	uint64_t paddr = (uint64_t)sfb->obj->dmamap->dm_segs[0].ds_addr;
29160afa471Spatrick 	size_t size = sfb->obj->dmamap->dm_segs[0].ds_len;
29260afa471Spatrick 
29360afa471Spatrick 	if (off < 0 || off >= size)
29460afa471Spatrick 		return -1;
29560afa471Spatrick 
29660afa471Spatrick 	return ((paddr + off) | PMAP_NOCACHE);
29760afa471Spatrick }
29860afa471Spatrick 
29960afa471Spatrick int
30060afa471Spatrick rkdrm_alloc_screen(void *v, const struct wsscreen_descr *type,
301e0c3e559Sjsg     void **cookiep, int *curxp, int *curyp, uint32_t *attrp)
30260afa471Spatrick {
30360afa471Spatrick 	return rasops_alloc_screen(v, cookiep, curxp, curyp, attrp);
30460afa471Spatrick }
30560afa471Spatrick 
30660afa471Spatrick void
30760afa471Spatrick rkdrm_free_screen(void *v, void *cookie)
30860afa471Spatrick {
30960afa471Spatrick 	return rasops_free_screen(v, cookie);
31060afa471Spatrick }
31160afa471Spatrick 
31260afa471Spatrick int
31360afa471Spatrick rkdrm_show_screen(void *v, void *cookie, int waitok,
31460afa471Spatrick     void (*cb)(void *, int, int), void *cbarg)
31560afa471Spatrick {
31660afa471Spatrick 	struct rasops_info *ri = v;
31760afa471Spatrick 	struct rkdrm_softc *sc = ri->ri_hw;
31860afa471Spatrick 
31960afa471Spatrick 	if (cookie == ri->ri_active)
32060afa471Spatrick 		return (0);
32160afa471Spatrick 
32260afa471Spatrick 	sc->switchcb = cb;
32360afa471Spatrick 	sc->switchcbarg = cbarg;
32460afa471Spatrick 	sc->switchcookie = cookie;
32560afa471Spatrick 	if (cb) {
32660afa471Spatrick 		task_add(systq, &sc->switchtask);
32760afa471Spatrick 		return (EAGAIN);
32860afa471Spatrick 	}
32960afa471Spatrick 
33060afa471Spatrick 	rkdrm_doswitch(v);
33160afa471Spatrick 
33260afa471Spatrick 	return (0);
33360afa471Spatrick }
33460afa471Spatrick 
33560afa471Spatrick void
33660afa471Spatrick rkdrm_doswitch(void *v)
33760afa471Spatrick {
33860afa471Spatrick 	struct rasops_info *ri = v;
33960afa471Spatrick 	struct rkdrm_softc *sc = ri->ri_hw;
34060afa471Spatrick 
34160afa471Spatrick 	rasops_show_screen(ri, sc->switchcookie, 0, NULL, NULL);
34260afa471Spatrick 	drm_fb_helper_restore_fbdev_mode_unlocked(&sc->helper);
34360afa471Spatrick 
34460afa471Spatrick 	if (sc->switchcb)
34560afa471Spatrick 		(sc->switchcb)(sc->switchcbarg, 0, 0);
34660afa471Spatrick }
34760afa471Spatrick 
34860afa471Spatrick void
34960afa471Spatrick rkdrm_enter_ddb(void *v, void *cookie)
35060afa471Spatrick {
35160afa471Spatrick 	struct rasops_info *ri = v;
35260afa471Spatrick 	struct rkdrm_softc *sc = ri->ri_hw;
35360afa471Spatrick 	struct drm_fb_helper *fb_helper = &sc->helper;
35460afa471Spatrick 
35560afa471Spatrick 	if (cookie == ri->ri_active)
35660afa471Spatrick 		return;
35760afa471Spatrick 
35860afa471Spatrick 	rasops_show_screen(ri, cookie, 0, NULL, NULL);
359f005ef32Sjsg 	drm_fb_helper_debug_enter(fb_helper->info);
36060afa471Spatrick }
36160afa471Spatrick 
36260afa471Spatrick void
36360afa471Spatrick rkdrm_attachhook(struct device *dev)
36460afa471Spatrick {
36560afa471Spatrick 	struct rkdrm_softc *sc = (struct rkdrm_softc *)dev;
36660afa471Spatrick 	struct wsemuldisplaydev_attach_args aa;
36760afa471Spatrick 	struct drm_fb_helper *helper = &sc->helper;
36860afa471Spatrick 	struct rasops_info *ri = &sc->ro;
36960afa471Spatrick 	struct rkdrm_framebuffer *sfb;
37060afa471Spatrick 	uint32_t *ports;
37160afa471Spatrick 	int i, portslen, nports;
3727dd3f745Skettenis 	int console = 0;
373e0c3e559Sjsg 	uint32_t defattr;
374eebea054Skettenis 	int error;
37560afa471Spatrick 
3767dd3f745Skettenis 	if (sc->sc_node == stdout_node)
3777dd3f745Skettenis 		console = 1;
3787dd3f745Skettenis 
37960afa471Spatrick 	portslen = OF_getproplen(sc->sc_node, "ports");
38060afa471Spatrick 	if (portslen < 0) {
38160afa471Spatrick 		printf("%s: no display interface ports specified\n",
38260afa471Spatrick 		    sc->sc_dev.dv_xname);
38360afa471Spatrick 		return;
38460afa471Spatrick 	}
38560afa471Spatrick 
38660afa471Spatrick 	drm_mode_config_init(&sc->sc_ddev);
38760afa471Spatrick 	sc->sc_ddev.mode_config.min_width = 0;
38860afa471Spatrick 	sc->sc_ddev.mode_config.min_height = 0;
38960afa471Spatrick 	sc->sc_ddev.mode_config.max_width = RK_DRM_MAX_WIDTH;
39060afa471Spatrick 	sc->sc_ddev.mode_config.max_height = RK_DRM_MAX_HEIGHT;
39160afa471Spatrick 	sc->sc_ddev.mode_config.funcs = &rkdrm_mode_config_funcs;
392c349dbc7Sjsg 	sc->sc_ddev.mode_config.helper_private =
393c349dbc7Sjsg 	    &rkdrm_mode_config_helper_funcs;
39460afa471Spatrick 
39560afa471Spatrick 	nports = 0;
39660afa471Spatrick 	ports = malloc(portslen, M_TEMP, M_WAITOK);
39760afa471Spatrick 	OF_getpropintarray(sc->sc_node, "ports", ports, portslen);
39860afa471Spatrick 	for (i = 0; i < portslen / sizeof(uint32_t); i++) {
399eebea054Skettenis 		error = device_port_activate(ports[i], &sc->sc_ddev);
400eebea054Skettenis 		if (error == 0)
40160afa471Spatrick 			nports++;
40260afa471Spatrick 	}
40360afa471Spatrick 	free(ports, M_TEMP, portslen);
40460afa471Spatrick 
40560afa471Spatrick 	if (nports == 0) {
40660afa471Spatrick 		printf("%s: no display interface ports configured\n",
40760afa471Spatrick 		    sc->sc_dev.dv_xname);
40860afa471Spatrick 		drm_mode_config_cleanup(&sc->sc_ddev);
40960afa471Spatrick 		return;
41060afa471Spatrick 	}
41160afa471Spatrick 
412c349dbc7Sjsg 	drm_mode_config_reset(&sc->sc_ddev);
413c349dbc7Sjsg 
414f005ef32Sjsg 	drm_fb_helper_prepare(&sc->sc_ddev, &sc->helper, 32,
415f005ef32Sjsg 	    &rkdrm_fb_helper_funcs);
416c349dbc7Sjsg 	if (drm_fb_helper_init(&sc->sc_ddev, &sc->helper)) {
41760afa471Spatrick 		printf("%s: can't initialize framebuffer helper\n",
41860afa471Spatrick 		    sc->sc_dev.dv_xname);
41960afa471Spatrick 		drm_mode_config_cleanup(&sc->sc_ddev);
42060afa471Spatrick 		return;
42160afa471Spatrick 	}
42260afa471Spatrick 
42360afa471Spatrick 	sc->helper.fb = malloc(sizeof(struct rkdrm_framebuffer),
42460afa471Spatrick 	    M_DRM, M_WAITOK | M_ZERO);
42560afa471Spatrick 
426f005ef32Sjsg 	drm_fb_helper_initial_config(&sc->helper);
42760afa471Spatrick 
42860afa471Spatrick 	task_set(&sc->switchtask, rkdrm_doswitch, ri);
42960afa471Spatrick 
43060afa471Spatrick 	drm_fb_helper_restore_fbdev_mode_unlocked(&sc->helper);
43160afa471Spatrick 
43260afa471Spatrick 	sfb = to_rkdrm_framebuffer(helper->fb);
43360afa471Spatrick 	ri->ri_bits = sfb->obj->vaddr;
43460afa471Spatrick 	ri->ri_flg = RI_CENTER | RI_VCONS;
43560afa471Spatrick 	ri->ri_depth = helper->fb->format->depth;
43660afa471Spatrick 	ri->ri_width = helper->fb->width;
43760afa471Spatrick 	ri->ri_height = helper->fb->height;
43860afa471Spatrick 	ri->ri_stride = ri->ri_width * ri->ri_depth / 8;
4395dc98519Skettenis 	ri->ri_rnum = 8;	/* ARGB8888 */
4405dc98519Skettenis 	ri->ri_rpos = 16;
4415dc98519Skettenis 	ri->ri_gnum = 8;
4425dc98519Skettenis 	ri->ri_gpos = 8;
4435dc98519Skettenis 	ri->ri_bnum = 8;
4445dc98519Skettenis 	ri->ri_bpos = 0;
4455dc98519Skettenis 	rasops_init(ri, 160, 160);
44660afa471Spatrick 	ri->ri_hw = sc;
44760afa471Spatrick 
44860afa471Spatrick 	rkdrm_stdscreen.capabilities = ri->ri_caps;
44960afa471Spatrick 	rkdrm_stdscreen.nrows = ri->ri_rows;
45060afa471Spatrick 	rkdrm_stdscreen.ncols = ri->ri_cols;
45160afa471Spatrick 	rkdrm_stdscreen.textops = &ri->ri_ops;
45260afa471Spatrick 	rkdrm_stdscreen.fontwidth = ri->ri_font->fontwidth;
45360afa471Spatrick 	rkdrm_stdscreen.fontheight = ri->ri_font->fontheight;
45460afa471Spatrick 
4557dd3f745Skettenis 	if (console) {
456fc223b23Sjsg 		ri->ri_ops.pack_attr(ri->ri_active, 0, 0, 0, &defattr);
4577dd3f745Skettenis 		wsdisplay_cnattach(&rkdrm_stdscreen, ri->ri_active,
4587dd3f745Skettenis 		    ri->ri_ccol, ri->ri_crow, defattr);
4597dd3f745Skettenis 	}
4607dd3f745Skettenis 
46160afa471Spatrick 	memset(&aa, 0, sizeof(aa));
46260afa471Spatrick 	aa.scrdata = &rkdrm_screenlist;
46360afa471Spatrick 	aa.accessops = &rkdrm_accessops;
46460afa471Spatrick 	aa.accesscookie = ri;
4657dd3f745Skettenis 	aa.console = console;
46660afa471Spatrick 
46760afa471Spatrick 	printf("%s: %dx%d, %dbpp\n", sc->sc_dev.dv_xname,
46860afa471Spatrick 	    ri->ri_width, ri->ri_height, ri->ri_depth);
46960afa471Spatrick 
47060afa471Spatrick 	config_found_sm(&sc->sc_dev, &aa, wsemuldisplaydevprint,
47160afa471Spatrick 	    wsemuldisplaydevsubmatch);
47260afa471Spatrick 
47360afa471Spatrick 	drm_dev_register(&sc->sc_ddev, 0);
47460afa471Spatrick }
47560afa471Spatrick 
47660afa471Spatrick int
47760afa471Spatrick rkdrm_fb_probe(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes)
47860afa471Spatrick {
47960afa471Spatrick 	struct drm_device *ddev = helper->dev;
48060afa471Spatrick 	struct rkdrm_framebuffer *sfb = to_rkdrm_framebuffer(helper->fb);
48160afa471Spatrick 	struct drm_mode_fb_cmd2 mode_cmd = { 0 };
48260afa471Spatrick 	struct drm_framebuffer *fb = helper->fb;
48360afa471Spatrick 	unsigned int bytes_per_pixel;
48460afa471Spatrick 	struct fb_info *info;
48560afa471Spatrick 	size_t size;
48660afa471Spatrick 	int error;
48760afa471Spatrick 
48860afa471Spatrick 	bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8);
48960afa471Spatrick 
49060afa471Spatrick 	mode_cmd.width = sizes->surface_width;
49160afa471Spatrick 	mode_cmd.height = sizes->surface_height;
49260afa471Spatrick 	mode_cmd.pitches[0] = sizes->surface_width * bytes_per_pixel;
49360afa471Spatrick 	mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
49460afa471Spatrick 	    sizes->surface_depth);
49560afa471Spatrick 
49660afa471Spatrick 	size = roundup(mode_cmd.pitches[0] * mode_cmd.height, PAGE_SIZE);
49760afa471Spatrick 
49860afa471Spatrick 	/* FIXME: CMA pool? */
49960afa471Spatrick 
5001bb76ff1Sjsg 	sfb->obj = drm_gem_dma_create(ddev, size);
50160afa471Spatrick 	if (sfb->obj == NULL) {
50260afa471Spatrick 		DRM_ERROR("failed to allocate memory for framebuffer\n");
50360afa471Spatrick 		return -ENOMEM;
50460afa471Spatrick 	}
50560afa471Spatrick 
50660afa471Spatrick 	drm_helper_mode_fill_fb_struct(ddev, fb, &mode_cmd);
50760afa471Spatrick 	fb->format = drm_format_info(DRM_FORMAT_ARGB8888);
5085ca02815Sjsg 	fb->obj[0] = &sfb->obj->base;
50960afa471Spatrick 	error = drm_framebuffer_init(ddev, fb, &rkdrm_framebuffer_funcs);
51060afa471Spatrick 	if (error != 0) {
51160afa471Spatrick 		DRM_ERROR("failed to initialize framebuffer\n");
51260afa471Spatrick 		return error;
51360afa471Spatrick 	}
51460afa471Spatrick 
515f005ef32Sjsg 	info = drm_fb_helper_alloc_info(helper);
51660afa471Spatrick 	if (IS_ERR(info)) {
51760afa471Spatrick 		DRM_ERROR("Failed to allocate fb_info\n");
5188988417bSjsg 		return PTR_ERR(info);
51960afa471Spatrick 	}
52060afa471Spatrick 	info->par = helper;
52160afa471Spatrick 	return 0;
52260afa471Spatrick }
523