#include <drm/drm_atomic.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_crtc_helper.h>
+#include <linux/memblock.h>
#include "rockchip_drm_drv.h"
#include "rockchip_drm_gem.h"
struct rockchip_drm_fb {
struct drm_framebuffer fb;
+ dma_addr_t dma_addr[ROCKCHIP_MAX_FB_BUFFER];
struct drm_gem_object *obj[ROCKCHIP_MAX_FB_BUFFER];
+ struct rockchip_logo *logo;
};
-struct drm_gem_object *rockchip_fb_get_gem_obj(struct drm_framebuffer *fb,
- unsigned int plane)
+dma_addr_t rockchip_fb_get_dma_addr(struct drm_framebuffer *fb,
+ unsigned int plane)
{
struct rockchip_drm_fb *rk_fb = to_rockchip_fb(fb);
- if (plane >= ROCKCHIP_MAX_FB_BUFFER)
- return NULL;
+ if (WARN_ON(plane >= ROCKCHIP_MAX_FB_BUFFER))
+ return 0;
- return rk_fb->obj[plane];
+ return rk_fb->dma_addr[plane];
}
static void rockchip_drm_fb_destroy(struct drm_framebuffer *fb)
drm_gem_object_unreference_unlocked(obj);
}
+#ifndef MODULE
+ if (rockchip_fb->logo) {
+ struct rockchip_logo *logo = rockchip_fb->logo;
+
+ if (!--logo->count) {
+ void *start = phys_to_virt(logo->start);
+ void *end = phys_to_virt(logo->size);
+
+ dma_unmap_sg(fb->dev->dev, logo->sgt->sgl,
+ logo->sgt->nents, DMA_TO_DEVICE);
+ sg_free_table(logo->sgt);
+ memblock_free(logo->start, logo->size);
+ free_reserved_area(start, end, -1, "drm_logo");
+ }
+ }
+#else
+ WARN_ON(rockchip_fb->logo);
+#endif
+
drm_framebuffer_cleanup(fb);
kfree(rockchip_fb);
}
.create_handle = rockchip_drm_fb_create_handle,
};
-static struct rockchip_drm_fb *
+struct drm_framebuffer *
rockchip_fb_alloc(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd,
- struct drm_gem_object **obj, unsigned int num_planes)
+ struct drm_gem_object **obj, struct rockchip_logo *logo,
+ unsigned int num_planes)
{
struct rockchip_drm_fb *rockchip_fb;
- int ret;
+ struct rockchip_gem_object *rk_obj;
+ int ret = 0;
int i;
rockchip_fb = kzalloc(sizeof(*rockchip_fb), GFP_KERNEL);
drm_helper_mode_fill_fb_struct(&rockchip_fb->fb, mode_cmd);
- for (i = 0; i < num_planes; i++)
- rockchip_fb->obj[i] = obj[i];
-
ret = drm_framebuffer_init(dev, &rockchip_fb->fb,
&rockchip_drm_fb_funcs);
if (ret) {
dev_err(dev->dev, "Failed to initialize framebuffer: %d\n",
ret);
- kfree(rockchip_fb);
- return ERR_PTR(ret);
+ goto err_free_fb;
+ }
+
+ if (obj) {
+ for (i = 0; i < num_planes; i++)
+ rockchip_fb->obj[i] = obj[i];
+
+ for (i = 0; i < num_planes; i++) {
+ rk_obj = to_rockchip_obj(obj[i]);
+ rockchip_fb->dma_addr[i] = rk_obj->dma_addr;
+ }
+#ifndef MODULE
+ } else if (logo) {
+ rockchip_fb->dma_addr[0] = logo->dma_addr;
+ rockchip_fb->logo = logo;
+ logo->count++;
+#endif
+ } else {
+ ret = -EINVAL;
+ dev_err(dev->dev, "Failed to find available buffer\n");
+ goto err_deinit_drm_fb;
}
- return rockchip_fb;
+ return &rockchip_fb->fb;
+
+err_deinit_drm_fb:
+ drm_framebuffer_cleanup(&rockchip_fb->fb);
+err_free_fb:
+ kfree(rockchip_fb);
+ return ERR_PTR(ret);
}
static struct drm_framebuffer *
rockchip_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
struct drm_mode_fb_cmd2 *mode_cmd)
{
- struct rockchip_drm_fb *rockchip_fb;
+ struct drm_framebuffer *fb;
struct drm_gem_object *objs[ROCKCHIP_MAX_FB_BUFFER];
struct drm_gem_object *obj;
unsigned int hsub;
unsigned int width = mode_cmd->width / (i ? hsub : 1);
unsigned int height = mode_cmd->height / (i ? vsub : 1);
unsigned int min_size;
+ unsigned int bpp =
+ drm_format_plane_bpp(mode_cmd->pixel_format, i);
obj = drm_gem_object_lookup(dev, file_priv,
mode_cmd->handles[i]);
}
min_size = (height - 1) * mode_cmd->pitches[i] +
- mode_cmd->offsets[i] +
- width * drm_format_plane_cpp(mode_cmd->pixel_format, i);
-
+ mode_cmd->offsets[i] + roundup(width * bpp, 8) / 8;
if (obj->size < min_size) {
drm_gem_object_unreference_unlocked(obj);
ret = -EINVAL;
objs[i] = obj;
}
- rockchip_fb = rockchip_fb_alloc(dev, mode_cmd, objs, i);
- if (IS_ERR(rockchip_fb)) {
- ret = PTR_ERR(rockchip_fb);
+ fb = rockchip_fb_alloc(dev, mode_cmd, objs, NULL, i);
+ if (IS_ERR(fb)) {
+ ret = PTR_ERR(fb);
goto err_gem_object_unreference;
}
- return &rockchip_fb->fb;
+ return fb;
err_gem_object_unreference:
for (i--; i >= 0; i--)
static void rockchip_drm_output_poll_changed(struct drm_device *dev)
{
struct rockchip_drm_private *private = dev->dev_private;
- struct drm_fb_helper *fb_helper = &private->fbdev_helper;
+ struct drm_fb_helper *fb_helper = private->fbdev_helper;
if (fb_helper)
drm_fb_helper_hotplug_event(fb_helper);
struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj)
{
- struct rockchip_drm_fb *rockchip_fb;
+ struct drm_framebuffer *fb;
- rockchip_fb = rockchip_fb_alloc(dev, mode_cmd, &obj, 1);
- if (IS_ERR(rockchip_fb))
+ fb = rockchip_fb_alloc(dev, mode_cmd, &obj, NULL, 1);
+ if (IS_ERR(fb))
return NULL;
- return &rockchip_fb->fb;
+ return fb;
}
void rockchip_drm_mode_config_init(struct drm_device *dev)