genode/repos/dde_linux/src/drivers/framebuffer/imx8/lx_emul_c.c

170 lines
3.9 KiB
C

/*
* \brief Linux emulation C helper functions
* \author Stefan Kalkowski
* \author Christian Prochaska
* \date 2016-03-22
*/
/*
* Copyright (C) 2016-2019 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
/* Genode includes */
#include <lx_emul.h>
#include <lx_emul_c.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_encoder.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_modeset_helper.h>
#include <imx/imx-drm.h>
void lx_c_allocate_framebuffer(struct drm_device * dev,
struct lx_c_fb_config *c)
{
/* from drm_fbdev_cma_create() */
struct drm_gem_cma_object *obj;
c->pitch = c->width * c->bpp;
c->size = c->pitch * c->height;
obj = drm_gem_cma_create(dev, c->size);
if (obj == NULL)
return;
c->addr = obj->vaddr;
/* from drm_gem_fb_alloc() */
struct drm_framebuffer *fb = kzalloc(sizeof(*fb), GFP_KERNEL);
if (fb == NULL)
goto err;
struct drm_mode_fb_cmd2 mode_cmd = { 0 };
mode_cmd.width = c->width;
mode_cmd.height = c->height;
mode_cmd.pitches[0] = c->pitch;
mode_cmd.pixel_format = DRM_FORMAT_XRGB8888;
drm_helper_mode_fill_fb_struct(dev, fb, &mode_cmd);
fb->obj[0] = &obj->base;
static const struct drm_framebuffer_funcs drm_fb_cma_funcs = {
.destroy = drm_gem_fb_destroy,
};
if (drm_framebuffer_init(dev, fb, &drm_fb_cma_funcs) != 0) {
kfree(fb);
goto err;
}
c->lx_fb = fb;
memset_io(c->addr, 0, c->size);
return;
err:
drm_gem_object_put_unlocked(&obj->base); /* as in drm_gem_cma_create() */
return;
}
void lx_c_set_mode(struct drm_device * dev, struct drm_connector * connector,
struct drm_framebuffer *fb, struct drm_display_mode *mode)
{
struct drm_crtc * crtc = NULL;
struct drm_encoder * encoder = connector->encoder;
if (!encoder) {
struct drm_encoder *enc;
list_for_each_entry(enc, &dev->mode_config.encoder_list, head) {
unsigned i;
for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++)
if (connector->encoder_ids[i] == enc->base.id) break;
if (i == DRM_CONNECTOR_MAX_ENCODER) continue;
bool used = false;
struct drm_connector *c;
list_for_each_entry(c, &dev->mode_config.connector_list, head) {
if (c->encoder == enc) used = true;
}
if (used) continue;
encoder = enc;
break;
}
}
if (!encoder) {
lx_printf("Found no encoder for the connector %s\n", connector->name);
return;
}
unsigned used_crtc = 0;
crtc = encoder->crtc;
if (!crtc) {
unsigned i = 0;
struct drm_crtc *c;
list_for_each_entry(c, &dev->mode_config.crtc_list, head) {
if (!(encoder->possible_crtcs & (1 << i))) continue;
if (c->state->enable) {
used_crtc ++;
continue;
}
crtc = c;
break;
}
}
if (!crtc) {
if (mode)
lx_printf("Found no crtc for the connector %s used/max %u+1/%u\n",
connector->name, used_crtc, dev->mode_config.num_crtc);
return;
}
DRM_DEBUG("%s%s for connector %s\n", mode ? "set mode " : "no mode",
mode ? mode->name : "", connector->name);
struct drm_mode_set set;
set.crtc = crtc;
set.x = 0;
set.y = 0;
set.mode = mode;
set.connectors = &connector;
set.num_connectors = mode ? 1 : 0;
set.fb = mode ? fb : 0;
uint32_t const ref_cnt_before = drm_framebuffer_read_refcount(fb);
int ret = drm_atomic_helper_set_config(&set, dev->mode_config.acquire_ctx);
if (ret)
lx_printf("Error: set config failed ret=%d refcnt before=%u after=%u\n",
ret, ref_cnt_before, drm_framebuffer_read_refcount(fb));
}
void lx_c_set_driver(struct drm_device * dev, void * driver)
{
struct imx_drm_device *dev_priv = dev->dev_private;
ASSERT(!dev_priv->fbhelper);
dev_priv->fbhelper = (struct drm_fbdev_cma *) driver;
}
void* lx_c_get_driver(struct drm_device * dev)
{
struct imx_drm_device *dev_priv = dev->dev_private;
return (void*) dev_priv->fbhelper;
}