diff --git a/sys/arch/arm/rockchip/rk_anxdp.c b/sys/arch/arm/rockchip/rk_anxdp.c index ebe4ef86d136..da1914b7a2b4 100644 --- a/sys/arch/arm/rockchip/rk_anxdp.c +++ b/sys/arch/arm/rockchip/rk_anxdp.c @@ -172,7 +172,7 @@ rk_anxdp_ep_activate(device_t dev, struct fdt_endpoint *ep, bool activate) break; } - sc->sc_encoder.possible_crtcs = 0x3; /* XXX */ + sc->sc_encoder.possible_crtcs = 0x2; /* VOPB only */ drm_encoder_init(crtc->dev, &sc->sc_encoder, &rk_anxdp_encoder_funcs, DRM_MODE_ENCODER_TMDS, NULL); drm_encoder_helper_add(&sc->sc_encoder, &rk_anxdp_encoder_helper_funcs); diff --git a/sys/arch/arm/rockchip/rk_drm.c b/sys/arch/arm/rockchip/rk_drm.c index 2d57727f1b77..4c35778be227 100644 --- a/sys/arch/arm/rockchip/rk_drm.c +++ b/sys/arch/arm/rockchip/rk_drm.c @@ -82,6 +82,8 @@ static void rk_drm_disable_vblank(struct drm_device *, unsigned int); static int rk_drm_load(struct drm_device *, unsigned long); static void rk_drm_unload(struct drm_device *); +static void rk_drm_task_work(struct work *, void *); + static struct drm_driver rk_drm_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM, .dev_priv_size = 0, @@ -131,6 +133,14 @@ rk_drm_attach(device_t parent, device_t self, void *aux) sc->sc_dmat = faa->faa_dmat; sc->sc_bst = faa->faa_bst; sc->sc_phandle = faa->faa_phandle; + sc->sc_task_thread = NULL; + SIMPLEQ_INIT(&sc->sc_tasks); + if (workqueue_create(&sc->sc_task_wq, "rkdrm", + &rk_drm_task_work, NULL, PRI_NONE, IPL_NONE, WQ_MPSAFE)) { + aprint_error_dev(self, "unable to create workqueue\n"); + sc->sc_task_wq = NULL; + return; + } aprint_naive("\n"); @@ -164,16 +174,39 @@ rk_drm_init(device_t dev) struct drm_driver * const driver = &rk_drm_driver; int error; + /* + * Cause any tasks issued synchronously during attach to be + * processed at the end of this function. + */ + sc->sc_task_thread = curlwp; + error = -drm_dev_register(sc->sc_ddev, 0); if (error) { aprint_error_dev(dev, "couldn't register DRM device: %d\n", error); - return; + goto out; } aprint_normal_dev(dev, "initialized %s %d.%d.%d %s on minor %d\n", driver->name, driver->major, driver->minor, driver->patchlevel, driver->date, sc->sc_ddev->primary->index); + /* + * Process asynchronous tasks queued synchronously during + * attach. This will be for display detection to attach a + * framebuffer, so we have the opportunity for a console device + * to attach before autoconf has completed, in time for init(8) + * to find that console without panicking. + */ + while (!SIMPLEQ_EMPTY(&sc->sc_tasks)) { + struct rk_drm_task *const task = + SIMPLEQ_FIRST(&sc->sc_tasks); + + SIMPLEQ_REMOVE_HEAD(&sc->sc_tasks, sdt_u.queue); + (*task->sdt_fn)(task); + } + +out: /* Cause any subesquent tasks to be processed by the workqueue. */ + atomic_store_relaxed(&sc->sc_task_thread, NULL); } static vmem_t * @@ -235,16 +268,8 @@ rk_drm_fb_create(struct drm_device *ddev, struct drm_file *file, return NULL; fb = kmem_zalloc(sizeof(*fb), KM_SLEEP); + drm_helper_mode_fill_fb_struct(ddev, &fb->base, cmd); fb->obj = to_drm_gem_cma_obj(gem_obj); - fb->base.pitches[0] = cmd->pitches[0]; - fb->base.pitches[1] = cmd->pitches[1]; - fb->base.pitches[2] = cmd->pitches[2]; - fb->base.offsets[0] = cmd->offsets[0]; - fb->base.offsets[1] = cmd->offsets[2]; - fb->base.offsets[2] = cmd->offsets[1]; - fb->base.width = cmd->width; - fb->base.height = cmd->height; - fb->base.format = drm_format_info(cmd->pixel_format); error = drm_framebuffer_init(ddev, &fb->base, &rk_drm_framebuffer_funcs); if (error != 0) @@ -296,10 +321,14 @@ rk_drm_fb_probe(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size return -ENOMEM; } + /* similar to drm_helper_mode_fill_fb_struct(), but we have no cmd */ fb->pitches[0] = pitch; fb->offsets[0] = 0; fb->width = width; fb->height = height; + fb->dev = ddev; + fb->modifier = 0; + fb->flags = 0; #ifdef __ARM_BIG_ENDIAN fb->format = drm_format_info(DRM_FORMAT_BGRX8888); #else @@ -485,3 +514,31 @@ rk_drm_port_device(struct fdt_device_ports *port) return NULL; } + +static void +rk_drm_task_work(struct work *work, void *cookie) +{ + struct rk_drm_task *task = container_of(work, struct rk_drm_task, + sdt_u.work); + + (*task->sdt_fn)(task); +} + +void +rk_task_init(struct rk_drm_task *task, + void (*fn)(struct rk_drm_task *)) +{ + + task->sdt_fn = fn; +} + +void +rk_task_schedule(device_t self, struct rk_drm_task *task) +{ + struct rk_drm_softc *sc = device_private(self); + + if (atomic_load_relaxed(&sc->sc_task_thread) == curlwp) + SIMPLEQ_INSERT_TAIL(&sc->sc_tasks, task, sdt_u.queue); + else + workqueue_enqueue(sc->sc_task_wq, &task->sdt_u.work, NULL); +} diff --git a/sys/arch/arm/rockchip/rk_drm.h b/sys/arch/arm/rockchip/rk_drm.h index fecaa1db8f51..adab375273c6 100644 --- a/sys/arch/arm/rockchip/rk_drm.h +++ b/sys/arch/arm/rockchip/rk_drm.h @@ -29,6 +29,7 @@ #ifndef _ARM_RK_DRM_H #define _ARM_RK_DRM_H +#include #include #include @@ -62,6 +63,12 @@ struct rk_drm_softc { int sc_phandle; + struct lwp *sc_task_thread; + SIMPLEQ_HEAD(, rk_drm_task) sc_tasks; + struct workqueue *sc_task_wq; + + bool sc_dev_registered; + struct rk_drm_vblank sc_vbl[RK_DRM_MAX_CRTC]; }; @@ -90,10 +97,22 @@ struct rk_drmfb_attach_args { uint32_t sfa_fb_linebytes; }; +struct rk_drm_task { + union { + SIMPLEQ_ENTRY(rk_drm_task) queue; + struct work work; + } sdt_u; + void (*sdt_fn)(struct rk_drm_task *); +}; + #define rk_drm_private(ddev) (ddev)->dev_private #define to_rk_drm_framebuffer(x) container_of(x, struct rk_drm_framebuffer, base) int rk_drm_register_port(int, struct fdt_device_ports *); struct drm_device *rk_drm_port_device(struct fdt_device_ports *); +void rk_task_init(struct rk_drm_task *, + void (*)(struct rk_drm_task *)); +void rk_task_schedule(device_t, struct rk_drm_task *); + #endif /* _ARM_RK_DRM_H */ diff --git a/sys/arch/arm/rockchip/rk_fb.c b/sys/arch/arm/rockchip/rk_fb.c index b165daf2e89f..b00d5fd53664 100644 --- a/sys/arch/arm/rockchip/rk_fb.c +++ b/sys/arch/arm/rockchip/rk_fb.c @@ -45,6 +45,8 @@ __KERNEL_RCSID(0, "$NetBSD: rk_fb.c,v 1.1 2019/11/09 23:30:14 jmcneill Exp $"); static int rk_fb_match(device_t, cfdata_t, void *); static void rk_fb_attach(device_t, device_t, void *); +static void rk_fb_init(struct rk_drm_task *task); + static bool rk_fb_shutdown(device_t, int); struct rk_fb_softc { @@ -52,6 +54,7 @@ struct rk_fb_softc { device_t sc_dev; struct rk_drm_framebuffer *sc_fb; struct rk_drmfb_attach_args sc_sfa; + struct rk_drm_task sc_attach_task; }; static paddr_t rk_fb_mmapfb(struct drmfb_softc *, off_t, int); @@ -78,7 +81,6 @@ rk_fb_attach(device_t parent, device_t self, void *aux) { struct rk_fb_softc * const sc = device_private(self); struct rk_drmfb_attach_args * const sfa = aux; - int error; sc->sc_dev = self; sc->sc_sfa = *sfa; @@ -93,6 +95,19 @@ rk_fb_attach(device_t parent, device_t self, void *aux) prop_dictionary_set_bool(dict, "is_console", is_console); #endif + rk_task_init(&sc->sc_attach_task, &rk_fb_init); + rk_task_schedule(parent, &sc->sc_attach_task); +} + +static void +rk_fb_init(struct rk_drm_task *task) +{ + struct rk_fb_softc * const sc = + container_of(task, struct rk_fb_softc, sc_attach_task); + device_t self = sc->sc_dev; + struct rk_drmfb_attach_args * const sfa = &sc->sc_sfa; + int error; + const struct drmfb_attach_args da = { .da_dev = self, .da_fb_helper = sfa->sfa_fb_helper, @@ -102,7 +117,9 @@ rk_fb_attach(device_t parent, device_t self, void *aux) .da_params = &rkfb_drmfb_params, }; + //mutex_unlock(&sfa->sfa_fb_helper->lock); /* XXX */ error = drmfb_attach(&sc->sc_drmfb, &da); + //mutex_lock(&sfa->sfa_fb_helper->lock); /* XXX */ if (error) { aprint_error_dev(self, "failed to attach drmfb: %d\n", error); return;