struct drm_framebuffer *mtk_drm_mode_fb_create(struct drm_device *dev,
					       struct drm_file *file,
					       struct drm_mode_fb_cmd2 *cmd)
{
	unsigned int hsub, vsub, i;
	struct mtk_drm_fb *mtk_fb;
	struct drm_gem_object *gem[MAX_FB_OBJ];
	int err;

	hsub = drm_format_horz_chroma_subsampling(cmd->pixel_format);
	vsub = drm_format_vert_chroma_subsampling(cmd->pixel_format);
	for (i = 0; i < drm_format_num_planes(cmd->pixel_format); i++) {
		unsigned int width = cmd->width / (i ? hsub : 1);
		unsigned int height = cmd->height / (i ? vsub : 1);
		unsigned int size, bpp;

		gem[i] = drm_gem_object_lookup(dev, file, cmd->handles[i]);
		if (!gem[i]) {
			err = -ENOENT;
			goto unreference;
		}

		bpp = drm_format_plane_cpp(cmd->pixel_format, i);
		size = (height - 1) * cmd->pitches[i] + width * bpp;
		size += cmd->offsets[i];

		if (gem[i]->size < size) {
			err = -EINVAL;
			goto unreference;
		}
	}

	mtk_fb = mtk_drm_framebuffer_init(dev, cmd, gem);

	return &mtk_fb->base;

unreference:
	while (i--)
		drm_gem_object_unreference_unlocked(gem[i]);

	return ERR_PTR(err);
}
Ejemplo n.º 2
0
struct drm_framebuffer *mtk_drm_mode_fb_create(struct drm_device *dev,
					       struct drm_file *file,
					       const struct drm_mode_fb_cmd2 *cmd)
{
	struct mtk_drm_fb *mtk_fb;
	struct drm_gem_object *gem;
	unsigned int width = cmd->width;
	unsigned int height = cmd->height;
	unsigned int size, bpp;
	int ret;

	if (drm_format_num_planes(cmd->pixel_format) != 1)
		return ERR_PTR(-EINVAL);

	gem = drm_gem_object_lookup(file, cmd->handles[0]);
	if (!gem)
		return ERR_PTR(-ENOENT);

	bpp = drm_format_plane_cpp(cmd->pixel_format, 0);
	size = (height - 1) * cmd->pitches[0] + width * bpp;
	size += cmd->offsets[0];

	if (gem->size < size) {
		ret = -EINVAL;
		goto unreference;
	}

	mtk_fb = mtk_drm_framebuffer_init(dev, cmd, gem);
	if (IS_ERR(mtk_fb)) {
		ret = PTR_ERR(mtk_fb);
		goto unreference;
	}

	return &mtk_fb->base;

unreference:
	drm_gem_object_unreference_unlocked(gem);
	return ERR_PTR(ret);
}
static int mtk_fbdev_probe(struct drm_fb_helper *helper,
			     struct drm_fb_helper_surface_size *sizes)
{
	struct drm_device *dev = helper->dev;
	struct drm_mode_fb_cmd2 mode = { 0 };
	struct mtk_drm_fb *mtk_fb;
	struct mtk_drm_gem_obj *mtk_gem;
	struct drm_gem_object *gem;
	struct fb_info *info;
	struct drm_framebuffer *fb;
	unsigned long offset;
	size_t size;
	int err;

	mode.width = sizes->surface_width;
	mode.height = sizes->surface_height;
	mode.pitches[0] = sizes->surface_width * ((sizes->surface_bpp + 7) / 8);
	mode.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
							sizes->surface_depth);

	mode.height = mode.height;/* << 1; for fb use? */
	size = mode.pitches[0] * mode.height;
	dev_info(dev->dev, "mtk_fbdev_probe %dx%d bpp %d pitch %d size %zu\n",
		mode.width, mode.height, sizes->surface_bpp, mode.pitches[0],
		size);

	mtk_gem = mtk_drm_gem_create(dev, size, true);
	if (IS_ERR(mtk_gem)) {
		err = PTR_ERR(mtk_gem);
		goto fini;
	}

	gem = &mtk_gem->base;

	mtk_fb = mtk_drm_framebuffer_init(dev, &mode, &gem);
	if (IS_ERR(mtk_fb)) {
		dev_err(dev->dev, "failed to allocate DRM framebuffer\n");
		err = PTR_ERR(mtk_fb);
		goto free;
	}
	fb = &mtk_fb->base;

	info = framebuffer_alloc(0, dev->dev);
	if (!info) {
		dev_err(dev->dev, "failed to allocate framebuffer info\n");
		err = PTR_ERR(info);
		goto release;
	}

	helper->fb = fb;
	helper->fbdev = info;

	info->par = helper;
	info->flags = FBINFO_FLAG_DEFAULT;
	info->fbops = &mediatek_fb_ops;

	err = fb_alloc_cmap(&info->cmap, 256, 0);
	if (err < 0) {
		dev_err(dev->dev, "failed to allocate color map: %d\n", err);
		goto destroy;
	}

	drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
	drm_fb_helper_fill_var(info, helper, fb->width, fb->height);

	offset = info->var.xoffset * (fb->bits_per_pixel + 7) / 8;
	offset += info->var.yoffset * fb->pitches[0];

	strcpy(info->fix.id, "mtk");
	/* dev->mode_config.fb_base = (resource_size_t)bo->paddr; */
	info->var.yres = info->var.yres_virtual;/* >> 1; for fb use? */
	info->fix.smem_start = mtk_gem->dma_addr + offset;
	info->fix.smem_len = size;
	info->screen_base = mtk_gem->kvaddr + offset;
	info->screen_size = size;

	return 0;

destroy:
	drm_framebuffer_unregister_private(fb);
	mtk_drm_fb_destroy(fb);
release:
	framebuffer_release(info);
free:
	mtk_drm_gem_free_object(&mtk_gem->base);
fini:
	dev_err(dev->dev, "mtk_fbdev_probe fail\n");
	return err;
}